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,303 @@
|
|
|
1
|
+
import { cn } from '@/utils/cn';
|
|
2
|
+
import { motion } from 'framer-motion';
|
|
3
|
+
import {
|
|
4
|
+
Activity,
|
|
5
|
+
AlertCircle,
|
|
6
|
+
CheckCircle,
|
|
7
|
+
Clock,
|
|
8
|
+
Database,
|
|
9
|
+
FileText,
|
|
10
|
+
Link,
|
|
11
|
+
Shield,
|
|
12
|
+
} from 'lucide-react';
|
|
13
|
+
import { useEffect, useState } from 'react';
|
|
14
|
+
|
|
15
|
+
interface ProcessingStep {
|
|
16
|
+
id: string;
|
|
17
|
+
name: string;
|
|
18
|
+
description: string;
|
|
19
|
+
status: 'pending' | 'processing' | 'completed' | 'error' | 'skipped';
|
|
20
|
+
progress?: number;
|
|
21
|
+
duration?: number;
|
|
22
|
+
error?: string;
|
|
23
|
+
icon: React.ReactNode;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ProcessingProgressProps {
|
|
27
|
+
documentName: string;
|
|
28
|
+
currentStep?: string;
|
|
29
|
+
progress: number;
|
|
30
|
+
steps?: ProcessingStep[];
|
|
31
|
+
statistics?: {
|
|
32
|
+
totalElements: number;
|
|
33
|
+
processedElements: number;
|
|
34
|
+
modifiedElements: number;
|
|
35
|
+
hyperlinksProcessed?: number;
|
|
36
|
+
errors?: number;
|
|
37
|
+
warnings?: number;
|
|
38
|
+
};
|
|
39
|
+
estimatedTimeRemaining?: number;
|
|
40
|
+
onCancel?: () => void;
|
|
41
|
+
className?: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const defaultSteps: ProcessingStep[] = [
|
|
45
|
+
{
|
|
46
|
+
id: 'backup',
|
|
47
|
+
name: 'Creating Backup',
|
|
48
|
+
description: 'Saving original document',
|
|
49
|
+
status: 'pending',
|
|
50
|
+
icon: <Database className="w-4 h-4" />,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
id: 'validation',
|
|
54
|
+
name: 'Validating Document',
|
|
55
|
+
description: 'Checking document structure',
|
|
56
|
+
status: 'pending',
|
|
57
|
+
icon: <Shield className="w-4 h-4" />,
|
|
58
|
+
},
|
|
59
|
+
{
|
|
60
|
+
id: 'scanning',
|
|
61
|
+
name: 'Scanning Hyperlinks',
|
|
62
|
+
description: 'Finding all hyperlinks',
|
|
63
|
+
status: 'pending',
|
|
64
|
+
icon: <Activity className="w-4 h-4" />,
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'processing',
|
|
68
|
+
name: 'Processing Hyperlinks',
|
|
69
|
+
description: 'Applying modifications',
|
|
70
|
+
status: 'pending',
|
|
71
|
+
icon: <Link className="w-4 h-4" />,
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
id: 'saving',
|
|
75
|
+
name: 'Saving Document',
|
|
76
|
+
description: 'Writing changes to file',
|
|
77
|
+
status: 'pending',
|
|
78
|
+
icon: <FileText className="w-4 h-4" />,
|
|
79
|
+
},
|
|
80
|
+
];
|
|
81
|
+
|
|
82
|
+
export function ProcessingProgress({
|
|
83
|
+
documentName,
|
|
84
|
+
currentStep,
|
|
85
|
+
progress,
|
|
86
|
+
steps = defaultSteps,
|
|
87
|
+
statistics,
|
|
88
|
+
estimatedTimeRemaining,
|
|
89
|
+
onCancel,
|
|
90
|
+
className,
|
|
91
|
+
}: ProcessingProgressProps) {
|
|
92
|
+
const [animatedProgress, setAnimatedProgress] = useState(0);
|
|
93
|
+
const [elapsedTime, setElapsedTime] = useState(0);
|
|
94
|
+
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
setAnimatedProgress(progress);
|
|
97
|
+
}, [progress]);
|
|
98
|
+
|
|
99
|
+
useEffect(() => {
|
|
100
|
+
const interval = setInterval(() => {
|
|
101
|
+
setElapsedTime((prev) => prev + 1);
|
|
102
|
+
}, 1000);
|
|
103
|
+
|
|
104
|
+
return () => clearInterval(interval);
|
|
105
|
+
}, []);
|
|
106
|
+
|
|
107
|
+
const formatTime = (seconds: number): string => {
|
|
108
|
+
if (seconds < 60) return `${seconds}s`;
|
|
109
|
+
const minutes = Math.floor(seconds / 60);
|
|
110
|
+
const remainingSeconds = seconds % 60;
|
|
111
|
+
return `${minutes}m ${remainingSeconds}s`;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const getStepStatus = (step: ProcessingStep) => {
|
|
115
|
+
if (currentStep === step.id) return 'processing';
|
|
116
|
+
const currentIndex = steps.findIndex((s) => s.id === currentStep);
|
|
117
|
+
const stepIndex = steps.findIndex((s) => s.id === step.id);
|
|
118
|
+
if (currentIndex > stepIndex) return 'completed';
|
|
119
|
+
return step.status;
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const getStepIcon = (status: ProcessingStep['status']) => {
|
|
123
|
+
switch (status) {
|
|
124
|
+
case 'completed':
|
|
125
|
+
return <CheckCircle className="w-5 h-5 text-green-500" />;
|
|
126
|
+
case 'error':
|
|
127
|
+
return <AlertCircle className="w-5 h-5 text-red-500" />;
|
|
128
|
+
case 'processing':
|
|
129
|
+
return (
|
|
130
|
+
<motion.div
|
|
131
|
+
animate={{ rotate: 360 }}
|
|
132
|
+
transition={{ duration: 2, repeat: Infinity, ease: 'linear' }}
|
|
133
|
+
className="w-5 h-5 border-2 border-primary border-t-transparent rounded-full"
|
|
134
|
+
/>
|
|
135
|
+
);
|
|
136
|
+
case 'skipped':
|
|
137
|
+
return <div className="w-5 h-5 rounded-full bg-muted" />;
|
|
138
|
+
default:
|
|
139
|
+
return <Clock className="w-5 h-5 text-muted-foreground" />;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
return (
|
|
144
|
+
<div className={cn('space-y-6', className)}>
|
|
145
|
+
{/* Header */}
|
|
146
|
+
<div className="space-y-2">
|
|
147
|
+
<div className="flex items-center justify-between">
|
|
148
|
+
<div>
|
|
149
|
+
<h3 className="font-semibold text-lg">Processing Document</h3>
|
|
150
|
+
<p className="text-sm text-muted-foreground truncate max-w-md">{documentName}</p>
|
|
151
|
+
</div>
|
|
152
|
+
{onCancel && (
|
|
153
|
+
<button
|
|
154
|
+
onClick={onCancel}
|
|
155
|
+
className="px-3 py-1 text-sm border border-border rounded-lg hover:bg-destructive/10 hover:border-destructive transition-colors"
|
|
156
|
+
>
|
|
157
|
+
Cancel
|
|
158
|
+
</button>
|
|
159
|
+
)}
|
|
160
|
+
</div>
|
|
161
|
+
</div>
|
|
162
|
+
|
|
163
|
+
{/* Main Progress Bar */}
|
|
164
|
+
<div className="space-y-2">
|
|
165
|
+
<div className="flex justify-between text-sm">
|
|
166
|
+
<span className="text-muted-foreground">Overall Progress</span>
|
|
167
|
+
<span className="font-medium">{Math.round(animatedProgress)}%</span>
|
|
168
|
+
</div>
|
|
169
|
+
<div className="relative h-3 bg-muted rounded-full overflow-hidden">
|
|
170
|
+
<motion.div
|
|
171
|
+
className="absolute inset-y-0 left-0 bg-linear-to-r from-primary via-primary to-primary/80"
|
|
172
|
+
initial={{ width: '0%' }}
|
|
173
|
+
animate={{ width: `${animatedProgress}%` }}
|
|
174
|
+
transition={{ duration: 0.5, ease: 'easeOut' }}
|
|
175
|
+
>
|
|
176
|
+
{/* Shimmer effect */}
|
|
177
|
+
<motion.div
|
|
178
|
+
className="absolute inset-0 bg-linear-to-r from-transparent via-white/20 to-transparent"
|
|
179
|
+
animate={{ x: ['0%', '200%'] }}
|
|
180
|
+
transition={{ duration: 1.5, repeat: Infinity, ease: 'linear' }}
|
|
181
|
+
/>
|
|
182
|
+
</motion.div>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
|
|
186
|
+
{/* Processing Steps */}
|
|
187
|
+
<div className="space-y-3">
|
|
188
|
+
{steps.map((step, index) => {
|
|
189
|
+
const status = getStepStatus(step);
|
|
190
|
+
const isActive = currentStep === step.id;
|
|
191
|
+
|
|
192
|
+
return (
|
|
193
|
+
<motion.div
|
|
194
|
+
key={step.id}
|
|
195
|
+
initial={{ opacity: 0, x: -20 }}
|
|
196
|
+
animate={{ opacity: 1, x: 0 }}
|
|
197
|
+
transition={{ delay: index * 0.1 }}
|
|
198
|
+
className={cn(
|
|
199
|
+
'flex items-start gap-3 p-3 rounded-lg transition-all',
|
|
200
|
+
isActive && 'bg-primary/5 border border-primary/20',
|
|
201
|
+
status === 'completed' && 'opacity-70',
|
|
202
|
+
status === 'error' && 'bg-destructive/5 border border-destructive/20'
|
|
203
|
+
)}
|
|
204
|
+
>
|
|
205
|
+
<div className="mt-0.5">{getStepIcon(status)}</div>
|
|
206
|
+
|
|
207
|
+
<div className="flex-1 space-y-1">
|
|
208
|
+
<div className="flex items-center gap-2">
|
|
209
|
+
<span className="font-medium">{step.name}</span>
|
|
210
|
+
{isActive && (
|
|
211
|
+
<motion.span
|
|
212
|
+
initial={{ opacity: 0 }}
|
|
213
|
+
animate={{ opacity: [0.5, 1, 0.5] }}
|
|
214
|
+
transition={{ duration: 2, repeat: Infinity }}
|
|
215
|
+
className="text-xs text-primary px-2 py-0.5 bg-primary/10 rounded-full"
|
|
216
|
+
>
|
|
217
|
+
Processing...
|
|
218
|
+
</motion.span>
|
|
219
|
+
)}
|
|
220
|
+
</div>
|
|
221
|
+
<p className="text-sm text-muted-foreground">{step.description}</p>
|
|
222
|
+
{step.error && <p className="text-sm text-destructive">{step.error}</p>}
|
|
223
|
+
{isActive && step.progress !== undefined && (
|
|
224
|
+
<div className="mt-2">
|
|
225
|
+
<div className="h-1 bg-muted rounded-full overflow-hidden">
|
|
226
|
+
<motion.div
|
|
227
|
+
className="h-full bg-primary"
|
|
228
|
+
initial={{ width: '0%' }}
|
|
229
|
+
animate={{ width: `${step.progress}%` }}
|
|
230
|
+
transition={{ duration: 0.3 }}
|
|
231
|
+
/>
|
|
232
|
+
</div>
|
|
233
|
+
</div>
|
|
234
|
+
)}
|
|
235
|
+
</div>
|
|
236
|
+
|
|
237
|
+
<div className="flex items-center gap-2 text-muted-foreground">
|
|
238
|
+
{step.icon}
|
|
239
|
+
{status === 'completed' && step.duration && (
|
|
240
|
+
<span className="text-xs">{formatTime(step.duration)}</span>
|
|
241
|
+
)}
|
|
242
|
+
</div>
|
|
243
|
+
</motion.div>
|
|
244
|
+
);
|
|
245
|
+
})}
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
{/* Statistics */}
|
|
249
|
+
{statistics && (
|
|
250
|
+
<div className="grid grid-cols-2 sm:grid-cols-4 gap-3">
|
|
251
|
+
<div className="text-center p-3 bg-muted/30 rounded-lg">
|
|
252
|
+
<p className="text-lg font-bold">{statistics.totalElements}</p>
|
|
253
|
+
<p className="text-xs text-muted-foreground">Total Elements</p>
|
|
254
|
+
</div>
|
|
255
|
+
<div className="text-center p-3 bg-muted/30 rounded-lg">
|
|
256
|
+
<p className="text-lg font-bold text-primary">{statistics.processedElements}</p>
|
|
257
|
+
<p className="text-xs text-muted-foreground">Processed</p>
|
|
258
|
+
</div>
|
|
259
|
+
<div className="text-center p-3 bg-muted/30 rounded-lg">
|
|
260
|
+
<p className="text-lg font-bold text-green-500">{statistics.modifiedElements}</p>
|
|
261
|
+
<p className="text-xs text-muted-foreground">Modified</p>
|
|
262
|
+
</div>
|
|
263
|
+
<div className="text-center p-3 bg-muted/30 rounded-lg">
|
|
264
|
+
<p className="text-lg font-bold text-blue-500">{statistics.hyperlinksProcessed || 0}</p>
|
|
265
|
+
<p className="text-xs text-muted-foreground">Hyperlinks</p>
|
|
266
|
+
</div>
|
|
267
|
+
</div>
|
|
268
|
+
)}
|
|
269
|
+
|
|
270
|
+
{/* Time Information */}
|
|
271
|
+
<div className="flex justify-between items-center text-sm text-muted-foreground">
|
|
272
|
+
<div className="flex items-center gap-4">
|
|
273
|
+
<span>Elapsed: {formatTime(elapsedTime)}</span>
|
|
274
|
+
{estimatedTimeRemaining !== undefined && (
|
|
275
|
+
<span>Remaining: ~{formatTime(estimatedTimeRemaining)}</span>
|
|
276
|
+
)}
|
|
277
|
+
</div>
|
|
278
|
+
{statistics?.warnings !== undefined && statistics.warnings > 0 && (
|
|
279
|
+
<span className="text-yellow-500">
|
|
280
|
+
{statistics.warnings} warning{statistics.warnings !== 1 ? 's' : ''}
|
|
281
|
+
</span>
|
|
282
|
+
)}
|
|
283
|
+
</div>
|
|
284
|
+
|
|
285
|
+
{/* Animated background effect */}
|
|
286
|
+
<div className="absolute inset-0 pointer-events-none overflow-hidden rounded-lg">
|
|
287
|
+
<motion.div
|
|
288
|
+
className="absolute -inset-40 opacity-5"
|
|
289
|
+
animate={{
|
|
290
|
+
rotate: [0, 360],
|
|
291
|
+
}}
|
|
292
|
+
transition={{
|
|
293
|
+
duration: 20,
|
|
294
|
+
repeat: Infinity,
|
|
295
|
+
ease: 'linear',
|
|
296
|
+
}}
|
|
297
|
+
>
|
|
298
|
+
<div className="w-full h-full bg-linear-to-r from-primary to-transparent" />
|
|
299
|
+
</motion.div>
|
|
300
|
+
</div>
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { Button } from '@/components/common/Button';
|
|
2
|
+
import type { Document, DocumentChange } from '@/types/session';
|
|
3
|
+
import { cn } from '@/utils/cn';
|
|
4
|
+
import { motion } from 'framer-motion';
|
|
5
|
+
import {
|
|
6
|
+
AlertCircle,
|
|
7
|
+
Archive,
|
|
8
|
+
ArrowRight,
|
|
9
|
+
CheckCircle,
|
|
10
|
+
Clock,
|
|
11
|
+
Download,
|
|
12
|
+
FileText,
|
|
13
|
+
Hash,
|
|
14
|
+
Link,
|
|
15
|
+
RotateCcw,
|
|
16
|
+
Share2,
|
|
17
|
+
TrendingUp,
|
|
18
|
+
} from 'lucide-react';
|
|
19
|
+
import { TrackedChangesDetail } from './TrackedChangesDetail';
|
|
20
|
+
|
|
21
|
+
interface ProcessingResultsProps {
|
|
22
|
+
document: Document;
|
|
23
|
+
onDownload?: () => void;
|
|
24
|
+
onReprocess?: () => void;
|
|
25
|
+
onShare?: () => void;
|
|
26
|
+
onViewBackup?: () => void;
|
|
27
|
+
className?: string;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function ProcessingResults({
|
|
31
|
+
document,
|
|
32
|
+
onDownload,
|
|
33
|
+
onReprocess,
|
|
34
|
+
onShare,
|
|
35
|
+
onViewBackup,
|
|
36
|
+
className,
|
|
37
|
+
}: ProcessingResultsProps) {
|
|
38
|
+
const { processingResult } = document;
|
|
39
|
+
|
|
40
|
+
if (!processingResult) {
|
|
41
|
+
return (
|
|
42
|
+
<div className={cn('text-center py-8', className)}>
|
|
43
|
+
<AlertCircle className="w-12 h-12 text-muted-foreground mx-auto mb-3" />
|
|
44
|
+
<p className="text-muted-foreground">No processing results available</p>
|
|
45
|
+
</div>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const isSuccess = document.status === 'completed';
|
|
50
|
+
const hasErrors = document.status === 'error';
|
|
51
|
+
|
|
52
|
+
const formatDuration = (ms: number): string => {
|
|
53
|
+
if (ms < 1000) return `${ms}ms`;
|
|
54
|
+
if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;
|
|
55
|
+
const minutes = Math.floor(ms / 60000);
|
|
56
|
+
const seconds = ((ms % 60000) / 1000).toFixed(0);
|
|
57
|
+
return `${minutes}m ${seconds}s`;
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const getChangeIcon = (type: DocumentChange['type']) => {
|
|
61
|
+
switch (type) {
|
|
62
|
+
case 'hyperlink':
|
|
63
|
+
return <Link className="w-4 h-4 text-blue-500" />;
|
|
64
|
+
case 'text':
|
|
65
|
+
return <FileText className="w-4 h-4 text-green-500" />;
|
|
66
|
+
case 'style':
|
|
67
|
+
return <TrendingUp className="w-4 h-4 text-purple-500" />;
|
|
68
|
+
case 'structure':
|
|
69
|
+
return <Archive className="w-4 h-4 text-orange-500" />;
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<div className={cn('space-y-6', className)}>
|
|
75
|
+
{/* Status Header */}
|
|
76
|
+
<motion.div
|
|
77
|
+
initial={{ opacity: 0, y: 20 }}
|
|
78
|
+
animate={{ opacity: 1, y: 0 }}
|
|
79
|
+
className={cn(
|
|
80
|
+
'p-6 rounded-xl border-2',
|
|
81
|
+
isSuccess
|
|
82
|
+
? 'bg-green-500/5 border-green-500/20'
|
|
83
|
+
: hasErrors
|
|
84
|
+
? 'bg-red-500/5 border-red-500/20'
|
|
85
|
+
: 'bg-muted/30 border-border'
|
|
86
|
+
)}
|
|
87
|
+
>
|
|
88
|
+
<div className="flex items-start gap-4">
|
|
89
|
+
{isSuccess ? (
|
|
90
|
+
<CheckCircle className="w-8 h-8 text-green-500 mt-1" />
|
|
91
|
+
) : hasErrors ? (
|
|
92
|
+
<AlertCircle className="w-8 h-8 text-red-500 mt-1" />
|
|
93
|
+
) : (
|
|
94
|
+
<FileText className="w-8 h-8 text-muted-foreground mt-1" />
|
|
95
|
+
)}
|
|
96
|
+
|
|
97
|
+
<div className="flex-1">
|
|
98
|
+
<h3 className="text-xl font-semibold mb-1">
|
|
99
|
+
{isSuccess
|
|
100
|
+
? 'Processing Completed Successfully'
|
|
101
|
+
: hasErrors
|
|
102
|
+
? 'Processing Failed'
|
|
103
|
+
: 'Processing Results'}
|
|
104
|
+
</h3>
|
|
105
|
+
<p className="text-muted-foreground">{document.name}</p>
|
|
106
|
+
|
|
107
|
+
{processingResult.duration && (
|
|
108
|
+
<div className="flex items-center gap-2 mt-3 text-sm text-muted-foreground">
|
|
109
|
+
<Clock className="w-4 h-4" />
|
|
110
|
+
<span>Completed in {formatDuration(processingResult.duration)}</span>
|
|
111
|
+
</div>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
{hasErrors && document.errors && document.errors.length > 0 && (
|
|
115
|
+
<div className="mt-3 p-3 bg-red-500/10 rounded-lg">
|
|
116
|
+
<p className="text-sm text-red-600 font-medium mb-1">Errors:</p>
|
|
117
|
+
<ul className="text-sm text-red-600 space-y-1">
|
|
118
|
+
{document.errors.map((error, index) => (
|
|
119
|
+
<li key={index}>• {error}</li>
|
|
120
|
+
))}
|
|
121
|
+
</ul>
|
|
122
|
+
</div>
|
|
123
|
+
)}
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<div className="flex flex-col gap-2">
|
|
127
|
+
{onDownload && (
|
|
128
|
+
<Button variant="outline" size="sm" onClick={onDownload} className="gap-2">
|
|
129
|
+
<Download className="w-4 h-4" />
|
|
130
|
+
Download
|
|
131
|
+
</Button>
|
|
132
|
+
)}
|
|
133
|
+
{onShare && (
|
|
134
|
+
<Button variant="outline" size="sm" onClick={onShare} className="gap-2">
|
|
135
|
+
<Share2 className="w-4 h-4" />
|
|
136
|
+
Share
|
|
137
|
+
</Button>
|
|
138
|
+
)}
|
|
139
|
+
</div>
|
|
140
|
+
</div>
|
|
141
|
+
</motion.div>
|
|
142
|
+
|
|
143
|
+
{/* Statistics Grid */}
|
|
144
|
+
<div className="grid grid-cols-2 md:grid-cols-4 gap-4">
|
|
145
|
+
<motion.div
|
|
146
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
147
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
148
|
+
transition={{ delay: 0.1 }}
|
|
149
|
+
className="bg-muted/30 rounded-lg p-4 text-center"
|
|
150
|
+
>
|
|
151
|
+
<Link className="w-6 h-6 text-blue-500 mx-auto mb-2" />
|
|
152
|
+
<p className="text-2xl font-bold">{processingResult.hyperlinksProcessed || 0}</p>
|
|
153
|
+
<p className="text-xs text-muted-foreground">Hyperlinks Processed</p>
|
|
154
|
+
</motion.div>
|
|
155
|
+
|
|
156
|
+
<motion.div
|
|
157
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
158
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
159
|
+
transition={{ delay: 0.2 }}
|
|
160
|
+
className="bg-muted/30 rounded-lg p-4 text-center"
|
|
161
|
+
>
|
|
162
|
+
<ArrowRight className="w-6 h-6 text-green-500 mx-auto mb-2" />
|
|
163
|
+
<p className="text-2xl font-bold text-green-500">
|
|
164
|
+
{processingResult.hyperlinksModified || 0}
|
|
165
|
+
</p>
|
|
166
|
+
<p className="text-xs text-muted-foreground">Links Modified</p>
|
|
167
|
+
</motion.div>
|
|
168
|
+
|
|
169
|
+
<motion.div
|
|
170
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
171
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
172
|
+
transition={{ delay: 0.3 }}
|
|
173
|
+
className="bg-muted/30 rounded-lg p-4 text-center"
|
|
174
|
+
>
|
|
175
|
+
<Hash className="w-6 h-6 text-purple-500 mx-auto mb-2" />
|
|
176
|
+
<p className="text-2xl font-bold text-purple-500">
|
|
177
|
+
{processingResult.contentIdsAppended || 0}
|
|
178
|
+
</p>
|
|
179
|
+
<p className="text-xs text-muted-foreground">Content IDs Added</p>
|
|
180
|
+
</motion.div>
|
|
181
|
+
|
|
182
|
+
<motion.div
|
|
183
|
+
initial={{ opacity: 0, scale: 0.9 }}
|
|
184
|
+
animate={{ opacity: 1, scale: 1 }}
|
|
185
|
+
transition={{ delay: 0.4 }}
|
|
186
|
+
className="bg-muted/30 rounded-lg p-4 text-center"
|
|
187
|
+
>
|
|
188
|
+
<Clock className="w-6 h-6 text-orange-500 mx-auto mb-2" />
|
|
189
|
+
<p className="text-2xl font-bold text-orange-500">
|
|
190
|
+
{processingResult.duration ? formatDuration(processingResult.duration) : 'N/A'}
|
|
191
|
+
</p>
|
|
192
|
+
<p className="text-xs text-muted-foreground">Processing Time</p>
|
|
193
|
+
</motion.div>
|
|
194
|
+
</div>
|
|
195
|
+
|
|
196
|
+
{/* Enhanced Tracked Changes */}
|
|
197
|
+
{processingResult.changes && processingResult.changes.length > 0 && (
|
|
198
|
+
<TrackedChangesDetail changes={processingResult.changes} />
|
|
199
|
+
)}
|
|
200
|
+
|
|
201
|
+
{/* Backup Information */}
|
|
202
|
+
{processingResult.backupPath && (
|
|
203
|
+
<div className="p-4 bg-muted/20 rounded-lg">
|
|
204
|
+
<div className="flex items-center justify-between">
|
|
205
|
+
<div className="flex items-center gap-3">
|
|
206
|
+
<Archive className="w-5 h-5 text-muted-foreground" />
|
|
207
|
+
<div>
|
|
208
|
+
<p className="font-medium text-sm">Backup Created</p>
|
|
209
|
+
<p className="text-xs text-muted-foreground">
|
|
210
|
+
Original document saved before processing
|
|
211
|
+
</p>
|
|
212
|
+
</div>
|
|
213
|
+
</div>
|
|
214
|
+
{onViewBackup && (
|
|
215
|
+
<Button variant="ghost" size="sm" onClick={onViewBackup}>
|
|
216
|
+
View Backup
|
|
217
|
+
</Button>
|
|
218
|
+
)}
|
|
219
|
+
</div>
|
|
220
|
+
</div>
|
|
221
|
+
)}
|
|
222
|
+
|
|
223
|
+
{/* Action Buttons */}
|
|
224
|
+
<div className="flex justify-between items-center pt-4 border-t">
|
|
225
|
+
<div>
|
|
226
|
+
{isSuccess && (
|
|
227
|
+
<p className="text-sm text-green-600 flex items-center gap-2">
|
|
228
|
+
<CheckCircle className="w-4 h-4" />
|
|
229
|
+
All changes applied successfully
|
|
230
|
+
</p>
|
|
231
|
+
)}
|
|
232
|
+
</div>
|
|
233
|
+
<div className="flex items-center gap-2">
|
|
234
|
+
{onReprocess && (
|
|
235
|
+
<Button variant="outline" onClick={onReprocess} className="gap-2">
|
|
236
|
+
<RotateCcw className="w-4 h-4" />
|
|
237
|
+
Reprocess
|
|
238
|
+
</Button>
|
|
239
|
+
)}
|
|
240
|
+
</div>
|
|
241
|
+
</div>
|
|
242
|
+
|
|
243
|
+
{/* Success Animation Overlay */}
|
|
244
|
+
{isSuccess && (
|
|
245
|
+
<motion.div
|
|
246
|
+
initial={{ scale: 0, opacity: 0 }}
|
|
247
|
+
animate={{ scale: [0, 1.2, 1], opacity: [0, 0.2, 0] }}
|
|
248
|
+
transition={{ duration: 1 }}
|
|
249
|
+
className="absolute inset-0 pointer-events-none"
|
|
250
|
+
>
|
|
251
|
+
<div className="w-full h-full bg-green-500 rounded-xl" />
|
|
252
|
+
</motion.div>
|
|
253
|
+
)}
|
|
254
|
+
</div>
|
|
255
|
+
);
|
|
256
|
+
}
|