documentation-hub 5.7.2

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 (271) hide show
  1. package/.eslintrc.json +43 -0
  2. package/.github/workflows/build.yml +64 -0
  3. package/.github/workflows/ci.yml +39 -0
  4. package/.vscode/extensions.json +3 -0
  5. package/Current.md +97 -0
  6. package/DocHub_Image.png +0 -0
  7. package/README.md +666 -0
  8. package/USER_GUIDE.md +1173 -0
  9. package/Updater.md +311 -0
  10. package/build/256x256.png +0 -0
  11. package/build/512x512.png +0 -0
  12. package/build/app-update.yml +4 -0
  13. package/build/create-icon.js +208 -0
  14. package/build/icon.ico +0 -0
  15. package/build/icon.png +0 -0
  16. package/build/icon_1024x1024.png +0 -0
  17. package/dist/assets/Analytics-BpsG9895.js +1 -0
  18. package/dist/assets/Card-IAZin8kp.js +1 -0
  19. package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
  20. package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
  21. package/dist/assets/Documents-CqZ25axS.js +1 -0
  22. package/dist/assets/Input-l89xwXBi.js +1 -0
  23. package/dist/assets/Reporting-DqdHJY_a.js +1 -0
  24. package/dist/assets/Search-XNbu5z_3.js +1 -0
  25. package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
  26. package/dist/assets/Sessions-ClZOPYNc.js +1 -0
  27. package/dist/assets/Settings-DUEHGURa.js +11 -0
  28. package/dist/assets/index-8xUe8ptc.js +24 -0
  29. package/dist/assets/index-RYyJqF7O.css +1 -0
  30. package/dist/assets/path-BkOl0AGO.js +1 -0
  31. package/dist/assets/promises-ID_B9S-h.js +1 -0
  32. package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
  33. package/dist/assets/useToast-yRSO1dkm.js +1 -0
  34. package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
  35. package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
  36. package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
  37. package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
  38. package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
  39. package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
  40. package/dist/electron/main-CXkNtyv-.js +19789 -0
  41. package/dist/electron/main.js +5 -0
  42. package/dist/electron/preload.js +1 -0
  43. package/dist/icon.png +0 -0
  44. package/dist/index.html +27 -0
  45. package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
  46. package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
  47. package/docs/README.md +115 -0
  48. package/docs/TOC_WIRING_GUIDE.md +344 -0
  49. package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
  50. package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
  51. package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
  52. package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
  53. package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
  54. package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
  55. package/docs/analysis/List_Implementation.md +206 -0
  56. package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
  57. package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
  58. package/docs/analysis/RefactorStyles.md +852 -0
  59. package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
  60. package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
  61. package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
  62. package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
  63. package/docs/analysis/github-issues-to-create.md +237 -0
  64. package/docs/api/API_README.md +538 -0
  65. package/docs/api/API_REFERENCE.md +751 -0
  66. package/docs/api/TYPE_DEFINITIONS.md +869 -0
  67. package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
  68. package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
  69. package/docs/docxmlater-readme.md +1341 -0
  70. package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
  71. package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
  72. package/docs/fixes/README.md +37 -0
  73. package/docs/github-issues/issue-1-body.md +125 -0
  74. package/docs/github-issues/issue-10-body.md +850 -0
  75. package/docs/github-issues/issue-2-body.md +200 -0
  76. package/docs/github-issues/issue-3-body.md +270 -0
  77. package/docs/github-issues/issue-4-body.md +169 -0
  78. package/docs/github-issues/issue-5-body.md +173 -0
  79. package/docs/github-issues/issue-6-body.md +158 -0
  80. package/docs/github-issues/issue-7-body.md +171 -0
  81. package/docs/github-issues/issue-8-body.md +407 -0
  82. package/docs/github-issues/issue-9-body.md +515 -0
  83. package/docs/github-issues/issue-tracker.md +274 -0
  84. package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
  85. package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
  86. package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
  87. package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
  88. package/docs/implementation/RefactorStyles.md +588 -0
  89. package/docs/implementation/implement-plan.md +489 -0
  90. package/docs/implementation/missing-helpers-implementation.md +391 -0
  91. package/docs/implementation/refactor-plan.md +520 -0
  92. package/docs/implementation/session-implementation-complete.md +233 -0
  93. package/docs/implementation/session-management-plan.md +250 -0
  94. package/docs/setup-checklist.md +77 -0
  95. package/docs/versions/changelog.md +345 -0
  96. package/electron/customUpdater.ts +656 -0
  97. package/electron/main.ts +2441 -0
  98. package/electron/memoryConfig.ts +187 -0
  99. package/electron/preload.ts +394 -0
  100. package/electron/proxyConfig.ts +340 -0
  101. package/electron/services/BackupService.ts +452 -0
  102. package/electron/services/DictionaryService.ts +402 -0
  103. package/electron/services/LocalDictionaryLookupService.ts +147 -0
  104. package/electron/services/PowerAutomateApiService.ts +231 -0
  105. package/electron/services/SharePointSyncService.ts +474 -0
  106. package/electron/windowsCertStore.ts +427 -0
  107. package/electron/zscalerConfig.ts +381 -0
  108. package/eslint.config.js +92 -0
  109. package/jest.config.js +52 -0
  110. package/package.json +214 -0
  111. package/postcss.config.mjs +6 -0
  112. package/public/icon.png +0 -0
  113. package/publish-release.ps1 +5 -0
  114. package/renovate.json +30 -0
  115. package/src/App.tsx +216 -0
  116. package/src/__mocks__/p-limit.js +12 -0
  117. package/src/__mocks__/styleMock.js +1 -0
  118. package/src/components/common/BugReportButton.tsx +44 -0
  119. package/src/components/common/BugReportDialog.tsx +193 -0
  120. package/src/components/common/Button.tsx +153 -0
  121. package/src/components/common/Card.tsx +86 -0
  122. package/src/components/common/ColorPickerDialog.tsx +177 -0
  123. package/src/components/common/ConfirmDialog.tsx +96 -0
  124. package/src/components/common/DebugConsole.tsx +275 -0
  125. package/src/components/common/EmptyState.tsx +183 -0
  126. package/src/components/common/ErrorBoundary.tsx +98 -0
  127. package/src/components/common/ErrorDetailsDialog.tsx +153 -0
  128. package/src/components/common/ErrorFallback.tsx +218 -0
  129. package/src/components/common/Input.tsx +109 -0
  130. package/src/components/common/Skeleton.tsx +184 -0
  131. package/src/components/common/SplashScreen.tsx +81 -0
  132. package/src/components/common/Toast.tsx +155 -0
  133. package/src/components/common/Tooltip.tsx +79 -0
  134. package/src/components/common/UpdateNotification.tsx +320 -0
  135. package/src/components/comparison/ComparisonWindow.tsx +374 -0
  136. package/src/components/comparison/SideBySideDiff.tsx +486 -0
  137. package/src/components/comparison/index.ts +8 -0
  138. package/src/components/document/DocumentUploader.tsx +288 -0
  139. package/src/components/document/HyperlinkPreview.tsx +430 -0
  140. package/src/components/document/HyperlinkService.md +1484 -0
  141. package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
  142. package/src/components/document/InlineChangesView.tsx +707 -0
  143. package/src/components/document/ProcessingProgress.tsx +303 -0
  144. package/src/components/document/ProcessingResults.tsx +256 -0
  145. package/src/components/document/TrackedChangesDetail.tsx +530 -0
  146. package/src/components/document/TrackedChangesPanel.tsx +546 -0
  147. package/src/components/document/VirtualDocumentList.tsx +240 -0
  148. package/src/components/editor/DocumentEditor.tsx +723 -0
  149. package/src/components/editor/DocumentEditorModal.tsx +640 -0
  150. package/src/components/editor/EditorQuickActions.tsx +502 -0
  151. package/src/components/editor/EditorToolbar.tsx +312 -0
  152. package/src/components/editor/TableEditor.tsx +926 -0
  153. package/src/components/editor/index.ts +18 -0
  154. package/src/components/layout/Header.tsx +190 -0
  155. package/src/components/layout/Sidebar.tsx +313 -0
  156. package/src/components/layout/TitleBar.tsx +190 -0
  157. package/src/components/navigation/CommandPalette.tsx +233 -0
  158. package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
  159. package/src/components/sessions/ChangeItem.tsx +408 -0
  160. package/src/components/sessions/ChangeViewer.tsx +1155 -0
  161. package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
  162. package/src/components/sessions/ProcessingOptions.tsx +297 -0
  163. package/src/components/sessions/ReplacementsTab.tsx +438 -0
  164. package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
  165. package/src/components/sessions/SessionManager.tsx +188 -0
  166. package/src/components/sessions/StylesEditor.tsx +1335 -0
  167. package/src/components/sessions/TabContainer.tsx +151 -0
  168. package/src/components/sessions/VirtualSessionList.tsx +157 -0
  169. package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
  170. package/src/components/settings/CertificateManager.tsx +410 -0
  171. package/src/components/settings/SegmentedControl.tsx +88 -0
  172. package/src/components/settings/SettingRow.tsx +52 -0
  173. package/src/contexts/GlobalStatsContext.tsx +396 -0
  174. package/src/contexts/SessionContext.tsx +2129 -0
  175. package/src/contexts/ThemeContext.tsx +428 -0
  176. package/src/contexts/UserSettingsContext.tsx +290 -0
  177. package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
  178. package/src/global.d.ts +273 -0
  179. package/src/hooks/useDocumentQueue.tsx +210 -0
  180. package/src/hooks/useToast.tsx +55 -0
  181. package/src/main.tsx +10 -0
  182. package/src/pages/Analytics.tsx +386 -0
  183. package/src/pages/CurrentSession.tsx +1174 -0
  184. package/src/pages/Dashboard.tsx +319 -0
  185. package/src/pages/Documents.tsx +317 -0
  186. package/src/pages/Projects.tsx +250 -0
  187. package/src/pages/Reporting.tsx +386 -0
  188. package/src/pages/Search.tsx +349 -0
  189. package/src/pages/Sessions.tsx +285 -0
  190. package/src/pages/Settings.tsx +2662 -0
  191. package/src/services/HyperlinkService.ts +1085 -0
  192. package/src/services/document/DocXMLaterProcessor.ts +617 -0
  193. package/src/services/document/DocumentProcessingComparison.ts +856 -0
  194. package/src/services/document/DocumentSnapshotService.ts +575 -0
  195. package/src/services/document/WordDocumentProcessor.ts +10509 -0
  196. package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
  197. package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
  198. package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
  199. package/src/services/document/blanklines/BlankLineManager.ts +658 -0
  200. package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
  201. package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
  202. package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
  203. package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
  204. package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
  205. package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
  206. package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
  207. package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
  208. package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
  209. package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
  210. package/src/services/document/blanklines/index.ts +67 -0
  211. package/src/services/document/blanklines/rules/additionRules.ts +337 -0
  212. package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
  213. package/src/services/document/blanklines/rules/removalRules.ts +362 -0
  214. package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
  215. package/src/services/document/blanklines/types.ts +29 -0
  216. package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
  217. package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
  218. package/src/services/document/helpers/whitespace.ts +117 -0
  219. package/src/services/document/list/ListNormalizer.ts +947 -0
  220. package/src/services/document/list/index.ts +45 -0
  221. package/src/services/document/list/list-detection.ts +275 -0
  222. package/src/services/document/list/list-types.ts +162 -0
  223. package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
  224. package/src/services/document/processors/ListProcessor.ts +257 -0
  225. package/src/services/document/processors/StructureProcessor.ts +176 -0
  226. package/src/services/document/processors/StyleProcessor.ts +389 -0
  227. package/src/services/document/processors/TableProcessor.ts +2238 -0
  228. package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
  229. package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
  230. package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
  231. package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
  232. package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
  233. package/src/services/document/processors/index.ts +28 -0
  234. package/src/services/document/types/docx-processing.ts +310 -0
  235. package/src/services/editor/EditorActionHandlers.ts +901 -0
  236. package/src/services/editor/index.ts +13 -0
  237. package/src/setupTests.ts +47 -0
  238. package/src/styles/global.css +782 -0
  239. package/src/types/backup.ts +132 -0
  240. package/src/types/dictionary.ts +125 -0
  241. package/src/types/document-processing.ts +331 -0
  242. package/src/types/docxmlater-augments.d.ts +142 -0
  243. package/src/types/editor.ts +280 -0
  244. package/src/types/electron.ts +340 -0
  245. package/src/types/globalStats.ts +155 -0
  246. package/src/types/hyperlink.ts +471 -0
  247. package/src/types/operations.ts +354 -0
  248. package/src/types/session.ts +427 -0
  249. package/src/types/settings.ts +112 -0
  250. package/src/utils/MemoryMonitor.ts +248 -0
  251. package/src/utils/cn.ts +6 -0
  252. package/src/utils/colorConvert.ts +306 -0
  253. package/src/utils/diffUtils.ts +347 -0
  254. package/src/utils/documentUtils.ts +202 -0
  255. package/src/utils/electronGuard.ts +62 -0
  256. package/src/utils/indexedDB.ts +915 -0
  257. package/src/utils/logger.ts +717 -0
  258. package/src/utils/pathSecurity.ts +232 -0
  259. package/src/utils/pathValidator.ts +236 -0
  260. package/src/utils/processingTimeEstimator.ts +153 -0
  261. package/src/utils/safeJsonParse.ts +62 -0
  262. package/src/utils/textSanitizer.ts +162 -0
  263. package/src/utils/urlHelpers.ts +304 -0
  264. package/src/utils/urlPatterns.ts +198 -0
  265. package/src/utils/urlSanitizer.ts +152 -0
  266. package/src/vite-env.d.ts +11 -0
  267. package/tsconfig.electron.json +19 -0
  268. package/tsconfig.json +36 -0
  269. package/tsconfig.node.json +12 -0
  270. package/typedoc.json +45 -0
  271. package/vite.config.ts +152 -0
@@ -0,0 +1,250 @@
1
+ import { useState } from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import {
4
+ Card,
5
+ CardContent,
6
+ CardDescription,
7
+ CardHeader,
8
+ CardTitle,
9
+ } from '@/components/common/Card';
10
+ import { Button } from '@/components/common/Button';
11
+ import { Input } from '@/components/common/Input';
12
+ import { Plus, FolderOpen, Clock, Users, MoreVertical, Grid, List } from 'lucide-react';
13
+ import { cn } from '@/utils/cn';
14
+
15
+ const projects = [
16
+ {
17
+ id: 1,
18
+ name: 'E-Commerce Platform',
19
+ description: 'Modern online shopping platform with AI recommendations',
20
+ status: 'In Progress',
21
+ progress: 65,
22
+ team: 5,
23
+ updated: '2 hours ago',
24
+ color: 'bg-blue-500',
25
+ },
26
+ {
27
+ id: 2,
28
+ name: 'Mobile Banking App',
29
+ description: 'Secure and intuitive mobile banking solution',
30
+ status: 'Planning',
31
+ progress: 20,
32
+ team: 3,
33
+ updated: '1 day ago',
34
+ color: 'bg-purple-500',
35
+ },
36
+ {
37
+ id: 3,
38
+ name: 'Analytics Dashboard',
39
+ description: 'Real-time data visualization and reporting tool',
40
+ status: 'In Progress',
41
+ progress: 80,
42
+ team: 4,
43
+ updated: '3 hours ago',
44
+ color: 'bg-green-500',
45
+ },
46
+ {
47
+ id: 4,
48
+ name: 'Content Management System',
49
+ description: 'Flexible CMS for enterprise content management',
50
+ status: 'Review',
51
+ progress: 90,
52
+ team: 6,
53
+ updated: '5 hours ago',
54
+ color: 'bg-orange-500',
55
+ },
56
+ {
57
+ id: 5,
58
+ name: 'Social Media Platform',
59
+ description: 'Next-generation social networking application',
60
+ status: 'Planning',
61
+ progress: 15,
62
+ team: 8,
63
+ updated: '2 days ago',
64
+ color: 'bg-pink-500',
65
+ },
66
+ {
67
+ id: 6,
68
+ name: 'IoT Management System',
69
+ description: 'Cloud-based IoT device management and monitoring',
70
+ status: 'In Progress',
71
+ progress: 45,
72
+ team: 4,
73
+ updated: '6 hours ago',
74
+ color: 'bg-indigo-500',
75
+ },
76
+ ];
77
+
78
+ const containerVariants = {
79
+ hidden: { opacity: 0 },
80
+ visible: {
81
+ opacity: 1,
82
+ transition: {
83
+ staggerChildren: 0.1,
84
+ },
85
+ },
86
+ };
87
+
88
+ const itemVariants = {
89
+ hidden: { opacity: 0, y: 20 },
90
+ visible: {
91
+ opacity: 1,
92
+ y: 0,
93
+ transition: {
94
+ duration: 0.5,
95
+ },
96
+ },
97
+ };
98
+
99
+ export function Projects() {
100
+ const [searchQuery, setSearchQuery] = useState('');
101
+ const [viewMode, setViewMode] = useState<'grid' | 'list'>('grid');
102
+
103
+ const filteredProjects = projects.filter(
104
+ (project) =>
105
+ project.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
106
+ project.description.toLowerCase().includes(searchQuery.toLowerCase())
107
+ );
108
+
109
+ return (
110
+ <motion.div
111
+ className="p-6 space-y-6"
112
+ variants={containerVariants}
113
+ initial="hidden"
114
+ animate="visible"
115
+ >
116
+ <motion.div variants={itemVariants}>
117
+ <h1 className="text-3xl font-bold">Projects</h1>
118
+ <p className="text-muted-foreground">Manage and track all your projects in one place</p>
119
+ </motion.div>
120
+
121
+ <motion.div
122
+ className="flex flex-col sm:flex-row gap-4 justify-between"
123
+ variants={itemVariants}
124
+ >
125
+ <Input
126
+ type="search"
127
+ placeholder="Search projects..."
128
+ value={searchQuery}
129
+ onChange={(e) => setSearchQuery(e.target.value)}
130
+ onClear={() => setSearchQuery('')}
131
+ className="max-w-md"
132
+ />
133
+
134
+ <div className="flex gap-2">
135
+ <div className="flex rounded-md border border-border">
136
+ <button
137
+ onClick={() => setViewMode('grid')}
138
+ className={cn(
139
+ 'p-2 rounded-l-md transition-colors',
140
+ viewMode === 'grid' ? 'bg-primary text-primary-foreground' : 'hover:bg-muted'
141
+ )}
142
+ aria-label="Grid view"
143
+ >
144
+ <Grid className="w-4 h-4" />
145
+ </button>
146
+ <button
147
+ onClick={() => setViewMode('list')}
148
+ className={cn(
149
+ 'p-2 rounded-r-md transition-colors',
150
+ viewMode === 'list' ? 'bg-primary text-primary-foreground' : 'hover:bg-muted'
151
+ )}
152
+ aria-label="List view"
153
+ >
154
+ <List className="w-4 h-4" />
155
+ </button>
156
+ </div>
157
+ <Button icon={<Plus className="w-4 h-4" />}>New Project</Button>
158
+ </div>
159
+ </motion.div>
160
+
161
+ <motion.div
162
+ className={cn(
163
+ 'grid gap-4',
164
+ viewMode === 'grid' ? 'grid-cols-1 md:grid-cols-2 lg:grid-cols-3' : 'grid-cols-1'
165
+ )}
166
+ variants={containerVariants}
167
+ >
168
+ {filteredProjects.map((project) => (
169
+ <motion.div key={project.id} variants={itemVariants}>
170
+ <Card interactive variant="bordered">
171
+ <CardHeader>
172
+ <div className="flex items-start justify-between">
173
+ <div className="flex items-center gap-3">
174
+ <div
175
+ className={cn(
176
+ 'w-10 h-10 rounded-lg flex items-center justify-center',
177
+ project.color
178
+ )}
179
+ >
180
+ <FolderOpen className="w-5 h-5 text-white" />
181
+ </div>
182
+ <div>
183
+ <CardTitle className="text-lg">{project.name}</CardTitle>
184
+ <span
185
+ className={cn(
186
+ 'text-xs px-2 py-1 rounded-full mt-1 inline-block',
187
+ project.status === 'In Progress' &&
188
+ 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300',
189
+ project.status === 'Planning' &&
190
+ 'bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300',
191
+ project.status === 'Review' &&
192
+ 'bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300'
193
+ )}
194
+ >
195
+ {project.status}
196
+ </span>
197
+ </div>
198
+ </div>
199
+ <button className="p-1 hover:bg-muted rounded">
200
+ <MoreVertical className="w-4 h-4 text-muted-foreground" />
201
+ </button>
202
+ </div>
203
+ </CardHeader>
204
+ <CardContent>
205
+ <CardDescription className="mb-4">{project.description}</CardDescription>
206
+
207
+ <div className="space-y-3">
208
+ <div>
209
+ <div className="flex justify-between text-sm mb-1">
210
+ <span className="text-muted-foreground">Progress</span>
211
+ <span className="font-medium">{project.progress}%</span>
212
+ </div>
213
+ <div className="w-full h-2 bg-muted rounded-full overflow-hidden">
214
+ <motion.div
215
+ className={project.color}
216
+ initial={{ width: 0 }}
217
+ animate={{ width: `${project.progress}%` }}
218
+ transition={{ duration: 0.5, delay: 0.2 }}
219
+ style={{ height: '100%' }}
220
+ />
221
+ </div>
222
+ </div>
223
+
224
+ <div className="flex items-center justify-between text-sm">
225
+ <div className="flex items-center gap-1 text-muted-foreground">
226
+ <Users className="w-3 h-3" />
227
+ <span>{project.team} members</span>
228
+ </div>
229
+ <div className="flex items-center gap-1 text-muted-foreground">
230
+ <Clock className="w-3 h-3" />
231
+ <span>{project.updated}</span>
232
+ </div>
233
+ </div>
234
+ </div>
235
+ </CardContent>
236
+ </Card>
237
+ </motion.div>
238
+ ))}
239
+ </motion.div>
240
+
241
+ {filteredProjects.length === 0 && (
242
+ <motion.div variants={itemVariants} className="text-center py-12">
243
+ <FolderOpen className="w-12 h-12 mx-auto text-muted-foreground mb-4" />
244
+ <h3 className="text-lg font-medium mb-2">No projects found</h3>
245
+ <p className="text-muted-foreground">Try adjusting your search or create a new project</p>
246
+ </motion.div>
247
+ )}
248
+ </motion.div>
249
+ );
250
+ }
@@ -0,0 +1,386 @@
1
+ import { useState, useMemo, memo } from 'react';
2
+ import { motion } from 'framer-motion';
3
+ import {
4
+ Mail,
5
+ Send,
6
+ Loader2,
7
+ Check,
8
+ CheckCircle,
9
+ AlertCircle,
10
+ FileText,
11
+ Bug,
12
+ ThumbsUp,
13
+ } from 'lucide-react';
14
+ import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/common/Card';
15
+ import { Button } from '@/components/common/Button';
16
+ import { useSession } from '@/contexts/SessionContext';
17
+ import { useToast } from '@/hooks/useToast';
18
+ import { Toaster } from '@/components/common/Toast';
19
+ import { cn } from '@/utils/cn';
20
+ import logger from '@/utils/logger';
21
+ import type { Document } from '@/types/session';
22
+
23
+ const containerVariants = {
24
+ hidden: { opacity: 0 },
25
+ visible: {
26
+ opacity: 1,
27
+ transition: {
28
+ staggerChildren: 0.1,
29
+ },
30
+ },
31
+ };
32
+
33
+ const itemVariants = {
34
+ hidden: { opacity: 0, y: 20 },
35
+ visible: {
36
+ opacity: 1,
37
+ y: 0,
38
+ transition: {
39
+ duration: 0.5,
40
+ },
41
+ },
42
+ };
43
+
44
+ interface DocumentWithSession extends Document {
45
+ sessionName: string;
46
+ sessionId: string;
47
+ backupPath?: string;
48
+ }
49
+
50
+ export const Reporting = memo(function Reporting() {
51
+ const { sessions } = useSession();
52
+ const { toasts, toast, dismiss } = useToast();
53
+ const [selectedDocs, setSelectedDocs] = useState<Set<string>>(new Set());
54
+ const [reportType, setReportType] = useState<'bug' | 'kudos'>('bug');
55
+ const [noDocument, setNoDocument] = useState(false);
56
+ const [isGenerating, setIsGenerating] = useState(false);
57
+ const [progress, setProgress] = useState(0);
58
+
59
+ // Get last 10 processed docs (completed or error) sorted by processedAt
60
+ const recentDocs = useMemo(() => {
61
+ const docs: DocumentWithSession[] = [];
62
+ sessions.forEach((session) => {
63
+ session.documents.forEach((doc) => {
64
+ if (doc.status === 'completed' || doc.status === 'error') {
65
+ docs.push({
66
+ ...doc,
67
+ sessionName: session.name,
68
+ sessionId: session.id,
69
+ backupPath: doc.processingResult?.backupPath,
70
+ });
71
+ }
72
+ });
73
+ });
74
+ return docs
75
+ .sort((a, b) => {
76
+ const aTime = a.processedAt ? new Date(a.processedAt).getTime() : 0;
77
+ const bTime = b.processedAt ? new Date(b.processedAt).getTime() : 0;
78
+ return bTime - aTime;
79
+ })
80
+ .slice(0, 10);
81
+ }, [sessions]);
82
+
83
+ const canGenerate = noDocument || selectedDocs.size > 0;
84
+
85
+ const toggleDoc = (docId: string) => {
86
+ if (noDocument) return; // Don't allow selecting docs when "no document" is checked
87
+ const newSet = new Set(selectedDocs);
88
+ if (newSet.has(docId)) {
89
+ newSet.delete(docId);
90
+ } else if (newSet.size < 3) {
91
+ newSet.add(docId);
92
+ }
93
+ setSelectedDocs(newSet);
94
+ };
95
+
96
+ const handleNoDocumentToggle = () => {
97
+ if (!noDocument) {
98
+ // Clearing document selection when enabling "no document"
99
+ setSelectedDocs(new Set());
100
+ }
101
+ setNoDocument(!noDocument);
102
+ };
103
+
104
+ const handleGenerateEmail = async () => {
105
+ setIsGenerating(true);
106
+ setProgress(0);
107
+ try {
108
+ const timestamp = Date.now();
109
+ const folderName = `DocHub_Report_${timestamp}`;
110
+ const downloadsPath = await window.electronAPI.getDownloadsPath();
111
+ const folderPath = `${downloadsPath}\\${folderName}`;
112
+
113
+ // Create folder
114
+ await window.electronAPI.createFolder(folderPath);
115
+ setProgress(10);
116
+
117
+ let zipPath = '';
118
+
119
+ if (!noDocument && selectedDocs.size > 0) {
120
+ // Copy files
121
+ const selectedDocsList = Array.from(selectedDocs);
122
+ for (let i = 0; i < selectedDocsList.length; i++) {
123
+ const doc = recentDocs.find((d) => d.id === selectedDocsList[i]);
124
+ if (doc?.path) {
125
+ // Copy processed file
126
+ await window.electronAPI.copyFileToFolder(doc.path, folderPath);
127
+ // Copy backup if exists
128
+ if (doc.backupPath) {
129
+ await window.electronAPI.copyFileToFolder(doc.backupPath, folderPath);
130
+ }
131
+ }
132
+ setProgress(10 + ((i + 1) * 60) / selectedDocsList.length);
133
+ }
134
+
135
+ // Create ZIP
136
+ zipPath = await window.electronAPI.createReportZip(folderPath, `${folderName}.zip`);
137
+ setProgress(85);
138
+ } else {
139
+ // No documents selected, just create an empty placeholder
140
+ setProgress(85);
141
+ }
142
+
143
+ // Open Outlook
144
+ const subject =
145
+ reportType === 'bug' ? 'Bug Report: Documentation Hub' : 'Kudos: Documentation Hub';
146
+
147
+ const result = await window.electronAPI.openOutlookEmail(subject, zipPath);
148
+ setProgress(100);
149
+
150
+ if (result.method === 'mailto' && zipPath) {
151
+ toast({
152
+ title: 'Email draft opened',
153
+ description: 'Please attach the ZIP file from the opened folder.',
154
+ variant: 'success',
155
+ duration: 6000,
156
+ });
157
+ } else {
158
+ toast({ title: 'Email draft opened', variant: 'success' });
159
+ }
160
+ } catch (error) {
161
+ logger.error('Failed to generate email:', error);
162
+ toast({ title: 'Failed to generate email', variant: 'destructive' });
163
+ } finally {
164
+ setIsGenerating(false);
165
+ // Clear selections after completion
166
+ setSelectedDocs(new Set());
167
+ setNoDocument(false);
168
+ }
169
+ };
170
+
171
+ return (
172
+ <motion.div
173
+ variants={containerVariants}
174
+ initial="hidden"
175
+ animate="visible"
176
+ className="p-6 max-w-[1000px] mx-auto space-y-6"
177
+ >
178
+ {/* Header */}
179
+ <motion.div variants={itemVariants} className="flex items-start justify-between gap-4">
180
+ <div>
181
+ <h1 className="text-3xl font-bold mb-2 flex items-center gap-2">
182
+ <Mail className="w-8 h-8" />
183
+ Reporting
184
+ </h1>
185
+ <p className="text-muted-foreground">Generate bug reports or kudos emails</p>
186
+ </div>
187
+ <div className="flex flex-col items-end gap-2">
188
+ <Button
189
+ onClick={handleGenerateEmail}
190
+ disabled={!canGenerate || isGenerating}
191
+ className={cn('gap-2', canGenerate && 'bg-primary hover:bg-primary/90')}
192
+ >
193
+ {isGenerating ? (
194
+ <>
195
+ <Loader2 className="w-5 h-5 animate-spin" />
196
+ Generating...
197
+ </>
198
+ ) : (
199
+ <>
200
+ <Send className="w-5 h-5" />
201
+ Generate Email
202
+ </>
203
+ )}
204
+ </Button>
205
+ {isGenerating && (
206
+ <div className="h-2 w-40 bg-muted rounded-full overflow-hidden">
207
+ <motion.div
208
+ className="h-full bg-primary"
209
+ initial={{ width: 0 }}
210
+ animate={{ width: `${progress}%` }}
211
+ transition={{ duration: 0.3 }}
212
+ />
213
+ </div>
214
+ )}
215
+ </div>
216
+ </motion.div>
217
+
218
+ {/* Report Type Selection */}
219
+ <motion.div variants={itemVariants}>
220
+ <Card>
221
+ <CardHeader>
222
+ <CardTitle className="flex items-center gap-2">
223
+ <FileText className="w-5 h-5" />
224
+ Report Type
225
+ </CardTitle>
226
+ <CardDescription>Select the type of report you want to generate</CardDescription>
227
+ </CardHeader>
228
+ <CardContent className="flex gap-4">
229
+ <label
230
+ className={cn(
231
+ 'flex items-center gap-3 px-4 py-3 rounded-lg cursor-pointer transition-colors flex-1',
232
+ reportType === 'bug'
233
+ ? 'bg-primary/10 border-2 border-primary'
234
+ : 'bg-muted/30 border-2 border-transparent hover:bg-muted/50'
235
+ )}
236
+ >
237
+ <input
238
+ type="radio"
239
+ name="reportType"
240
+ checked={reportType === 'bug'}
241
+ onChange={() => setReportType('bug')}
242
+ className="sr-only"
243
+ />
244
+ <div
245
+ className={cn(
246
+ 'w-5 h-5 rounded-full border-2 flex items-center justify-center',
247
+ reportType === 'bug' ? 'border-primary' : 'border-muted-foreground'
248
+ )}
249
+ >
250
+ {reportType === 'bug' && <div className="w-2.5 h-2.5 rounded-full bg-primary" />}
251
+ </div>
252
+ <Bug className={cn('w-5 h-5', reportType === 'bug' ? 'text-primary' : 'text-muted-foreground')} />
253
+ <span className={cn('font-medium', reportType === 'bug' ? 'text-foreground' : 'text-muted-foreground')}>
254
+ Bug Report
255
+ </span>
256
+ </label>
257
+ <label
258
+ className={cn(
259
+ 'flex items-center gap-3 px-4 py-3 rounded-lg cursor-pointer transition-colors flex-1',
260
+ reportType === 'kudos'
261
+ ? 'bg-primary/10 border-2 border-primary'
262
+ : 'bg-muted/30 border-2 border-transparent hover:bg-muted/50'
263
+ )}
264
+ >
265
+ <input
266
+ type="radio"
267
+ name="reportType"
268
+ checked={reportType === 'kudos'}
269
+ onChange={() => setReportType('kudos')}
270
+ className="sr-only"
271
+ />
272
+ <div
273
+ className={cn(
274
+ 'w-5 h-5 rounded-full border-2 flex items-center justify-center',
275
+ reportType === 'kudos' ? 'border-primary' : 'border-muted-foreground'
276
+ )}
277
+ >
278
+ {reportType === 'kudos' && <div className="w-2.5 h-2.5 rounded-full bg-primary" />}
279
+ </div>
280
+ <ThumbsUp className={cn('w-5 h-5', reportType === 'kudos' ? 'text-primary' : 'text-muted-foreground')} />
281
+ <span className={cn('font-medium', reportType === 'kudos' ? 'text-foreground' : 'text-muted-foreground')}>
282
+ Kudos
283
+ </span>
284
+ </label>
285
+ </CardContent>
286
+ </Card>
287
+ </motion.div>
288
+
289
+ {/* Description */}
290
+ <motion.div variants={itemVariants}>
291
+ <p className="text-muted-foreground text-sm">
292
+ This section will help you send documents quickly for troubleshooting or reviewing purposes. Select up to three documents in the list below. Only processed or errored documents are shown. Ensure the correct "Report Type" is selected: "Bug Report" or "Kudos". Then click on the "Generate Email" button. This application will make a copy of both the backup file and the processed file, create a new folder within your Downloads folder starting with "DocHub_Report_". It will then zip it up, bring up a blank email, and automatically attach this zip file. Thanks for the report or feedback!
293
+ </p>
294
+ </motion.div>
295
+
296
+ {/* Document Selection */}
297
+ <motion.div variants={itemVariants}>
298
+ <Card>
299
+ <CardHeader>
300
+ <CardTitle className="flex items-center gap-2">
301
+ <FileText className="w-5 h-5" />
302
+ Select Documents
303
+ </CardTitle>
304
+ </CardHeader>
305
+ <CardContent className="space-y-2">
306
+ {recentDocs.length === 0 ? (
307
+ <div className="text-center py-8 text-muted-foreground">
308
+ <FileText className="w-12 h-12 mx-auto mb-2 opacity-50" />
309
+ <p>No recently processed documents</p>
310
+ <p className="text-sm">Process some documents first to include them in reports</p>
311
+ </div>
312
+ ) : (
313
+ <>
314
+ {recentDocs.map((doc) => (
315
+ <div
316
+ key={doc.id}
317
+ onClick={() => toggleDoc(doc.id)}
318
+ className={cn(
319
+ 'flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors',
320
+ selectedDocs.has(doc.id)
321
+ ? 'bg-primary/10 border border-primary'
322
+ : 'bg-muted/30 hover:bg-muted/50 border border-transparent',
323
+ noDocument && 'opacity-50 cursor-not-allowed'
324
+ )}
325
+ >
326
+ <div
327
+ className={cn(
328
+ 'w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0',
329
+ selectedDocs.has(doc.id) ? 'bg-primary border-primary' : 'border-muted-foreground'
330
+ )}
331
+ >
332
+ {selectedDocs.has(doc.id) && <Check className="w-3 h-3 text-primary-foreground" />}
333
+ </div>
334
+ {doc.status === 'completed' ? (
335
+ <CheckCircle className="w-4 h-4 text-green-500 flex-shrink-0" />
336
+ ) : (
337
+ <AlertCircle className="w-4 h-4 text-destructive flex-shrink-0" />
338
+ )}
339
+ <div className="flex-1 min-w-0">
340
+ <span className="truncate block">{doc.name}</span>
341
+ <span className="text-xs text-muted-foreground truncate block">{doc.sessionName}</span>
342
+ </div>
343
+ </div>
344
+ ))}
345
+ </>
346
+ )}
347
+
348
+ {/* No Document option */}
349
+ <div className="pt-4 border-t border-border mt-4">
350
+ <div
351
+ onClick={handleNoDocumentToggle}
352
+ className={cn(
353
+ 'flex items-center gap-3 p-3 rounded-lg cursor-pointer transition-colors',
354
+ noDocument
355
+ ? 'bg-primary/10 border border-primary'
356
+ : 'bg-muted/30 hover:bg-muted/50 border border-transparent'
357
+ )}
358
+ >
359
+ <div
360
+ className={cn(
361
+ 'w-5 h-5 rounded border-2 flex items-center justify-center flex-shrink-0',
362
+ noDocument ? 'bg-primary border-primary' : 'border-muted-foreground'
363
+ )}
364
+ >
365
+ {noDocument && <Check className="w-3 h-3 text-primary-foreground" />}
366
+ </div>
367
+ <span className="font-medium">No Document (text-only report)</span>
368
+ </div>
369
+ </div>
370
+
371
+ {/* Selection info */}
372
+ {selectedDocs.size > 0 && (
373
+ <p className="text-sm text-muted-foreground pt-2">
374
+ {selectedDocs.size} of 3 documents selected
375
+ </p>
376
+ )}
377
+ </CardContent>
378
+ </Card>
379
+ </motion.div>
380
+
381
+
382
+ {/* Toast Notifications */}
383
+ <Toaster toasts={toasts} onDismiss={dismiss} />
384
+ </motion.div>
385
+ );
386
+ });