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.
- package/.eslintrc.json +43 -0
- package/.github/workflows/build.yml +64 -0
- package/.github/workflows/ci.yml +39 -0
- package/.vscode/extensions.json +3 -0
- package/Current.md +97 -0
- package/DocHub_Image.png +0 -0
- package/README.md +666 -0
- package/USER_GUIDE.md +1173 -0
- package/Updater.md +311 -0
- package/build/256x256.png +0 -0
- package/build/512x512.png +0 -0
- package/build/app-update.yml +4 -0
- package/build/create-icon.js +208 -0
- package/build/icon.ico +0 -0
- package/build/icon.png +0 -0
- package/build/icon_1024x1024.png +0 -0
- package/dist/assets/Analytics-BpsG9895.js +1 -0
- package/dist/assets/Card-IAZin8kp.js +1 -0
- package/dist/assets/CurrentSession-B-rFkHvf.js +12 -0
- package/dist/assets/Dashboard-C_5gMb0q.js +1 -0
- package/dist/assets/Documents-CqZ25axS.js +1 -0
- package/dist/assets/Input-l89xwXBi.js +1 -0
- package/dist/assets/Reporting-DqdHJY_a.js +1 -0
- package/dist/assets/Search-XNbu5z_3.js +1 -0
- package/dist/assets/SessionManager-lH9hZfzH.js +1 -0
- package/dist/assets/Sessions-ClZOPYNc.js +1 -0
- package/dist/assets/Settings-DUEHGURa.js +11 -0
- package/dist/assets/index-8xUe8ptc.js +24 -0
- package/dist/assets/index-RYyJqF7O.css +1 -0
- package/dist/assets/path-BkOl0AGO.js +1 -0
- package/dist/assets/promises-ID_B9S-h.js +1 -0
- package/dist/assets/urlHelpers-TvgahX0r.js +1 -0
- package/dist/assets/useToast-yRSO1dkm.js +1 -0
- package/dist/assets/vendor-charts-RkGK5ROP.js +36 -0
- package/dist/assets/vendor-db-l0sNRNKZ.js +1 -0
- package/dist/assets/vendor-react-BVZ_anCF.js +4 -0
- package/dist/assets/vendor-search-Dw8P0qyA.js +1 -0
- package/dist/assets/vendor-ui-BU7NfluV.js +53 -0
- package/dist/electron/PowerAutomateApiService-LfW09ZGr.js +147 -0
- package/dist/electron/main-CXkNtyv-.js +19789 -0
- package/dist/electron/main.js +5 -0
- package/dist/electron/preload.js +1 -0
- package/dist/icon.png +0 -0
- package/dist/index.html +27 -0
- package/docs/CODEBASE_ANALYSIS_REPORT.md +309 -0
- package/docs/DEBUG_LOGGING_GUIDE.md +244 -0
- package/docs/README.md +115 -0
- package/docs/TOC_WIRING_GUIDE.md +344 -0
- package/docs/analysis/Bullet_Symbol_Bug_Analysis.md +136 -0
- package/docs/analysis/DOCXMLATER_ANALYSIS_SUMMARY.txt +169 -0
- package/docs/analysis/Document_Processing_Issues_Analysis.md +704 -0
- package/docs/analysis/FIELD_PRESERVATION_ANALYSIS.md +1200 -0
- package/docs/analysis/INDENTATION_PRESERVE_ANALYSIS.md +181 -0
- package/docs/analysis/INDENTATION_PRESERVE_IMPLEMENTATION.md +207 -0
- package/docs/analysis/List_Implementation.md +206 -0
- package/docs/analysis/List_Implementation_Accuracy_Report.md +366 -0
- package/docs/analysis/PROCESSING_OPTIONS_UI_UPDATES.md +220 -0
- package/docs/analysis/RefactorStyles.md +852 -0
- package/docs/analysis/STYLE_PARAMETER_ENHANCEMENT.md +143 -0
- package/docs/analysis/docxmlater-comparison-todo-2025-11-13.md +636 -0
- package/docs/analysis/docxmlater-implementation-analysis-2025-11-13.md +340 -0
- package/docs/analysis/docxmlater-template_ui-integration-analysis.md +263 -0
- package/docs/analysis/github-issues-to-create.md +237 -0
- package/docs/api/API_README.md +538 -0
- package/docs/api/API_REFERENCE.md +751 -0
- package/docs/api/TYPE_DEFINITIONS.md +869 -0
- package/docs/architecture/FONT_EMBEDDING_GUIDE.md +318 -0
- package/docs/architecture/docxmlater-functions-and-structure.md +726 -0
- package/docs/docxmlater-readme.md +1341 -0
- package/docs/fixes/EXECUTION_LOG_TEST_BASE.md +573 -0
- package/docs/fixes/HYPERLINK_TEXT_SANITIZATION.md +253 -0
- package/docs/fixes/README.md +37 -0
- package/docs/github-issues/issue-1-body.md +125 -0
- package/docs/github-issues/issue-10-body.md +850 -0
- package/docs/github-issues/issue-2-body.md +200 -0
- package/docs/github-issues/issue-3-body.md +270 -0
- package/docs/github-issues/issue-4-body.md +169 -0
- package/docs/github-issues/issue-5-body.md +173 -0
- package/docs/github-issues/issue-6-body.md +158 -0
- package/docs/github-issues/issue-7-body.md +171 -0
- package/docs/github-issues/issue-8-body.md +407 -0
- package/docs/github-issues/issue-9-body.md +515 -0
- package/docs/github-issues/issue-tracker.md +274 -0
- package/docs/github-issues/predictive-analysis-2025-10-18.md +2131 -0
- package/docs/implementation/List_Framework_Refactor_Plan.md +336 -0
- package/docs/implementation/PRIMARY_TEXT_COLOR_FEATURE.md +217 -0
- package/docs/implementation/RELEASE_PLAN_v2.1.0.md +362 -0
- package/docs/implementation/RefactorStyles.md +588 -0
- package/docs/implementation/implement-plan.md +489 -0
- package/docs/implementation/missing-helpers-implementation.md +391 -0
- package/docs/implementation/refactor-plan.md +520 -0
- package/docs/implementation/session-implementation-complete.md +233 -0
- package/docs/implementation/session-management-plan.md +250 -0
- package/docs/setup-checklist.md +77 -0
- package/docs/versions/changelog.md +345 -0
- package/electron/customUpdater.ts +656 -0
- package/electron/main.ts +2441 -0
- package/electron/memoryConfig.ts +187 -0
- package/electron/preload.ts +394 -0
- package/electron/proxyConfig.ts +340 -0
- package/electron/services/BackupService.ts +452 -0
- package/electron/services/DictionaryService.ts +402 -0
- package/electron/services/LocalDictionaryLookupService.ts +147 -0
- package/electron/services/PowerAutomateApiService.ts +231 -0
- package/electron/services/SharePointSyncService.ts +474 -0
- package/electron/windowsCertStore.ts +427 -0
- package/electron/zscalerConfig.ts +381 -0
- package/eslint.config.js +92 -0
- package/jest.config.js +52 -0
- package/package.json +214 -0
- package/postcss.config.mjs +6 -0
- package/public/icon.png +0 -0
- package/publish-release.ps1 +5 -0
- package/renovate.json +30 -0
- package/src/App.tsx +216 -0
- package/src/__mocks__/p-limit.js +12 -0
- package/src/__mocks__/styleMock.js +1 -0
- package/src/components/common/BugReportButton.tsx +44 -0
- package/src/components/common/BugReportDialog.tsx +193 -0
- package/src/components/common/Button.tsx +153 -0
- package/src/components/common/Card.tsx +86 -0
- package/src/components/common/ColorPickerDialog.tsx +177 -0
- package/src/components/common/ConfirmDialog.tsx +96 -0
- package/src/components/common/DebugConsole.tsx +275 -0
- package/src/components/common/EmptyState.tsx +183 -0
- package/src/components/common/ErrorBoundary.tsx +98 -0
- package/src/components/common/ErrorDetailsDialog.tsx +153 -0
- package/src/components/common/ErrorFallback.tsx +218 -0
- package/src/components/common/Input.tsx +109 -0
- package/src/components/common/Skeleton.tsx +184 -0
- package/src/components/common/SplashScreen.tsx +81 -0
- package/src/components/common/Toast.tsx +155 -0
- package/src/components/common/Tooltip.tsx +79 -0
- package/src/components/common/UpdateNotification.tsx +320 -0
- package/src/components/comparison/ComparisonWindow.tsx +374 -0
- package/src/components/comparison/SideBySideDiff.tsx +486 -0
- package/src/components/comparison/index.ts +8 -0
- package/src/components/document/DocumentUploader.tsx +288 -0
- package/src/components/document/HyperlinkPreview.tsx +430 -0
- package/src/components/document/HyperlinkService.md +1484 -0
- package/src/components/document/Hyperlink_Technical_Documentation.md +496 -0
- package/src/components/document/InlineChangesView.tsx +707 -0
- package/src/components/document/ProcessingProgress.tsx +303 -0
- package/src/components/document/ProcessingResults.tsx +256 -0
- package/src/components/document/TrackedChangesDetail.tsx +530 -0
- package/src/components/document/TrackedChangesPanel.tsx +546 -0
- package/src/components/document/VirtualDocumentList.tsx +240 -0
- package/src/components/editor/DocumentEditor.tsx +723 -0
- package/src/components/editor/DocumentEditorModal.tsx +640 -0
- package/src/components/editor/EditorQuickActions.tsx +502 -0
- package/src/components/editor/EditorToolbar.tsx +312 -0
- package/src/components/editor/TableEditor.tsx +926 -0
- package/src/components/editor/index.ts +18 -0
- package/src/components/layout/Header.tsx +190 -0
- package/src/components/layout/Sidebar.tsx +313 -0
- package/src/components/layout/TitleBar.tsx +190 -0
- package/src/components/navigation/CommandPalette.tsx +233 -0
- package/src/components/navigation/KeyboardShortcutsModal.tsx +173 -0
- package/src/components/sessions/ChangeItem.tsx +408 -0
- package/src/components/sessions/ChangeViewer.tsx +1155 -0
- package/src/components/sessions/DocumentComparisonModal.tsx +314 -0
- package/src/components/sessions/ProcessingOptions.tsx +297 -0
- package/src/components/sessions/ReplacementsTab.tsx +438 -0
- package/src/components/sessions/RevisionHandlingOptions.tsx +87 -0
- package/src/components/sessions/SessionManager.tsx +188 -0
- package/src/components/sessions/StylesEditor.tsx +1335 -0
- package/src/components/sessions/TabContainer.tsx +151 -0
- package/src/components/sessions/VirtualSessionList.tsx +157 -0
- package/src/components/sessions/sessionToProcessorManager.tsx +420 -0
- package/src/components/settings/CertificateManager.tsx +410 -0
- package/src/components/settings/SegmentedControl.tsx +88 -0
- package/src/components/settings/SettingRow.tsx +52 -0
- package/src/contexts/GlobalStatsContext.tsx +396 -0
- package/src/contexts/SessionContext.tsx +2129 -0
- package/src/contexts/ThemeContext.tsx +428 -0
- package/src/contexts/UserSettingsContext.tsx +290 -0
- package/src/contexts/__tests__/GlobalStatsContext.test.tsx +390 -0
- package/src/global.d.ts +273 -0
- package/src/hooks/useDocumentQueue.tsx +210 -0
- package/src/hooks/useToast.tsx +55 -0
- package/src/main.tsx +10 -0
- package/src/pages/Analytics.tsx +386 -0
- package/src/pages/CurrentSession.tsx +1174 -0
- package/src/pages/Dashboard.tsx +319 -0
- package/src/pages/Documents.tsx +317 -0
- package/src/pages/Projects.tsx +250 -0
- package/src/pages/Reporting.tsx +386 -0
- package/src/pages/Search.tsx +349 -0
- package/src/pages/Sessions.tsx +285 -0
- package/src/pages/Settings.tsx +2662 -0
- package/src/services/HyperlinkService.ts +1085 -0
- package/src/services/document/DocXMLaterProcessor.ts +617 -0
- package/src/services/document/DocumentProcessingComparison.ts +856 -0
- package/src/services/document/DocumentSnapshotService.ts +575 -0
- package/src/services/document/WordDocumentProcessor.ts +10509 -0
- package/src/services/document/__tests__/DocXMLaterProcessor.hyperlinks.test.md +311 -0
- package/src/services/document/__tests__/WordDocumentProcessor.integration.test.ts +515 -0
- package/src/services/document/__tests__/WordDocumentProcessor.test.ts +812 -0
- package/src/services/document/blanklines/BlankLineManager.ts +658 -0
- package/src/services/document/blanklines/__tests__/paragraphChecks.test.ts +281 -0
- package/src/services/document/blanklines/helpers/blankLineInsertion.ts +87 -0
- package/src/services/document/blanklines/helpers/blankLineSnapshot.ts +251 -0
- package/src/services/document/blanklines/helpers/clearCustom.ts +121 -0
- package/src/services/document/blanklines/helpers/contextChecks.ts +117 -0
- package/src/services/document/blanklines/helpers/imageChecks.ts +51 -0
- package/src/services/document/blanklines/helpers/paragraphChecks.ts +236 -0
- package/src/services/document/blanklines/helpers/removeBlanksBetweenListItems.ts +91 -0
- package/src/services/document/blanklines/helpers/removeTrailingBlanks.ts +35 -0
- package/src/services/document/blanklines/helpers/tableGuards.ts +21 -0
- package/src/services/document/blanklines/index.ts +67 -0
- package/src/services/document/blanklines/rules/additionRules.ts +337 -0
- package/src/services/document/blanklines/rules/indentationRules.ts +317 -0
- package/src/services/document/blanklines/rules/removalRules.ts +362 -0
- package/src/services/document/blanklines/rules/ruleTypes.ts +92 -0
- package/src/services/document/blanklines/types.ts +29 -0
- package/src/services/document/helpers/ImageBorderCropper.ts +377 -0
- package/src/services/document/helpers/__tests__/whitespace.test.ts +272 -0
- package/src/services/document/helpers/whitespace.ts +117 -0
- package/src/services/document/list/ListNormalizer.ts +947 -0
- package/src/services/document/list/index.ts +45 -0
- package/src/services/document/list/list-detection.ts +275 -0
- package/src/services/document/list/list-types.ts +162 -0
- package/src/services/document/processors/HyperlinkProcessor.ts +370 -0
- package/src/services/document/processors/ListProcessor.ts +257 -0
- package/src/services/document/processors/StructureProcessor.ts +176 -0
- package/src/services/document/processors/StyleProcessor.ts +389 -0
- package/src/services/document/processors/TableProcessor.ts +2238 -0
- package/src/services/document/processors/__tests__/HyperlinkProcessor.test.ts +314 -0
- package/src/services/document/processors/__tests__/ListProcessor.test.ts +291 -0
- package/src/services/document/processors/__tests__/StructureProcessor.test.ts +257 -0
- package/src/services/document/processors/__tests__/TableProcessor.hlp-tips-bullets.test.ts +459 -0
- package/src/services/document/processors/__tests__/TableProcessor.test.ts +1604 -0
- package/src/services/document/processors/index.ts +28 -0
- package/src/services/document/types/docx-processing.ts +310 -0
- package/src/services/editor/EditorActionHandlers.ts +901 -0
- package/src/services/editor/index.ts +13 -0
- package/src/setupTests.ts +47 -0
- package/src/styles/global.css +782 -0
- package/src/types/backup.ts +132 -0
- package/src/types/dictionary.ts +125 -0
- package/src/types/document-processing.ts +331 -0
- package/src/types/docxmlater-augments.d.ts +142 -0
- package/src/types/editor.ts +280 -0
- package/src/types/electron.ts +340 -0
- package/src/types/globalStats.ts +155 -0
- package/src/types/hyperlink.ts +471 -0
- package/src/types/operations.ts +354 -0
- package/src/types/session.ts +427 -0
- package/src/types/settings.ts +112 -0
- package/src/utils/MemoryMonitor.ts +248 -0
- package/src/utils/cn.ts +6 -0
- package/src/utils/colorConvert.ts +306 -0
- package/src/utils/diffUtils.ts +347 -0
- package/src/utils/documentUtils.ts +202 -0
- package/src/utils/electronGuard.ts +62 -0
- package/src/utils/indexedDB.ts +915 -0
- package/src/utils/logger.ts +717 -0
- package/src/utils/pathSecurity.ts +232 -0
- package/src/utils/pathValidator.ts +236 -0
- package/src/utils/processingTimeEstimator.ts +153 -0
- package/src/utils/safeJsonParse.ts +62 -0
- package/src/utils/textSanitizer.ts +162 -0
- package/src/utils/urlHelpers.ts +304 -0
- package/src/utils/urlPatterns.ts +198 -0
- package/src/utils/urlSanitizer.ts +152 -0
- package/src/vite-env.d.ts +11 -0
- package/tsconfig.electron.json +19 -0
- package/tsconfig.json +36 -0
- package/tsconfig.node.json +12 -0
- package/typedoc.json +45 -0
- 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
|
+
});
|