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,410 @@
|
|
|
1
|
+
import { useState, useEffect, useRef } from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
} from '@/components/common/Card';
|
|
9
|
+
import { Button } from '@/components/common/Button';
|
|
10
|
+
import { Input } from '@/components/common/Input';
|
|
11
|
+
import { AlertCircle, CheckCircle2, Upload, Shield, Download, Info, Trash2 } from 'lucide-react';
|
|
12
|
+
import logger from '@/utils/logger';
|
|
13
|
+
|
|
14
|
+
interface Certificate {
|
|
15
|
+
path: string;
|
|
16
|
+
name: string;
|
|
17
|
+
issuer?: string;
|
|
18
|
+
subject?: string;
|
|
19
|
+
validUntil?: string;
|
|
20
|
+
isActive: boolean;
|
|
21
|
+
isZscaler?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function CertificateManager() {
|
|
25
|
+
const [certificates, setCertificates] = useState<Certificate[]>([]);
|
|
26
|
+
const [isZscalerDetected, setIsZscalerDetected] = useState(false);
|
|
27
|
+
const [certificateStatus, setCertificateStatus] = useState<
|
|
28
|
+
'checking' | 'configured' | 'not-configured' | 'error'
|
|
29
|
+
>('checking');
|
|
30
|
+
const [importStatus, setImportStatus] = useState<{
|
|
31
|
+
type: 'success' | 'error' | 'info' | null;
|
|
32
|
+
message: string;
|
|
33
|
+
}>({ type: null, message: '' });
|
|
34
|
+
const [currentCertPath, setCurrentCertPath] = useState<string>('');
|
|
35
|
+
|
|
36
|
+
// Timeout refs for cleanup
|
|
37
|
+
const importTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
38
|
+
const detectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
39
|
+
const testTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
checkCertificateStatus();
|
|
43
|
+
loadExistingCertificates();
|
|
44
|
+
|
|
45
|
+
// Listen for certificate configuration from main process
|
|
46
|
+
const handleCertificateConfigured = (_event: unknown, data: { certPath: string }) => {
|
|
47
|
+
setCertificateStatus('configured');
|
|
48
|
+
setCurrentCertPath(data.certPath);
|
|
49
|
+
loadExistingCertificates();
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
window.electronAPI.on('certificate-configured', handleCertificateConfigured);
|
|
53
|
+
|
|
54
|
+
return () => {
|
|
55
|
+
window.electronAPI.removeListener('certificate-configured', handleCertificateConfigured);
|
|
56
|
+
};
|
|
57
|
+
}, []);
|
|
58
|
+
|
|
59
|
+
// Cleanup all timeouts on unmount
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
return () => {
|
|
62
|
+
if (importTimeoutRef.current) {
|
|
63
|
+
clearTimeout(importTimeoutRef.current);
|
|
64
|
+
}
|
|
65
|
+
if (detectTimeoutRef.current) {
|
|
66
|
+
clearTimeout(detectTimeoutRef.current);
|
|
67
|
+
}
|
|
68
|
+
if (testTimeoutRef.current) {
|
|
69
|
+
clearTimeout(testTimeoutRef.current);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
}, []);
|
|
73
|
+
|
|
74
|
+
const checkCertificateStatus = async () => {
|
|
75
|
+
try {
|
|
76
|
+
// Check if Zscaler is detected
|
|
77
|
+
const zscalerStatus = await window.electronAPI.checkZscalerStatus();
|
|
78
|
+
setIsZscalerDetected(zscalerStatus.detected);
|
|
79
|
+
|
|
80
|
+
// Check current certificate configuration
|
|
81
|
+
const certPath = await window.electronAPI.getCertificatePath();
|
|
82
|
+
if (certPath) {
|
|
83
|
+
setCertificateStatus('configured');
|
|
84
|
+
setCurrentCertPath(certPath);
|
|
85
|
+
} else {
|
|
86
|
+
setCertificateStatus('not-configured');
|
|
87
|
+
}
|
|
88
|
+
} catch (_error) {
|
|
89
|
+
logger.error('Error checking certificate status:', _error);
|
|
90
|
+
setCertificateStatus('error');
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const loadExistingCertificates = async () => {
|
|
95
|
+
try {
|
|
96
|
+
const certPaths = await window.electronAPI.getInstalledCertificates();
|
|
97
|
+
const certs: Certificate[] = certPaths.map((path: string) => ({
|
|
98
|
+
path,
|
|
99
|
+
name: path.split('/').pop() || path,
|
|
100
|
+
isActive: path === currentCertPath,
|
|
101
|
+
}));
|
|
102
|
+
setCertificates(certs);
|
|
103
|
+
} catch (_error) {
|
|
104
|
+
logger.error('Error loading certificates:', _error);
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
|
|
108
|
+
const handleImportCertificate = async () => {
|
|
109
|
+
try {
|
|
110
|
+
const result = await window.electronAPI.importCertificate();
|
|
111
|
+
|
|
112
|
+
if (result.success) {
|
|
113
|
+
setImportStatus({
|
|
114
|
+
type: 'success',
|
|
115
|
+
message: `Certificate imported successfully: ${result.name}`,
|
|
116
|
+
});
|
|
117
|
+
setCertificateStatus('configured');
|
|
118
|
+
loadExistingCertificates();
|
|
119
|
+
} else {
|
|
120
|
+
setImportStatus({
|
|
121
|
+
type: 'error',
|
|
122
|
+
message: result.error || 'Failed to import certificate',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
} catch (_error) {
|
|
126
|
+
setImportStatus({
|
|
127
|
+
type: 'error',
|
|
128
|
+
message: 'Error importing certificate',
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Clear status after 5 seconds
|
|
133
|
+
if (importTimeoutRef.current) {
|
|
134
|
+
clearTimeout(importTimeoutRef.current);
|
|
135
|
+
}
|
|
136
|
+
importTimeoutRef.current = setTimeout(() => {
|
|
137
|
+
setImportStatus({ type: null, message: '' });
|
|
138
|
+
importTimeoutRef.current = null;
|
|
139
|
+
}, 5000);
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const handleExportFromBrowser = async () => {
|
|
143
|
+
try {
|
|
144
|
+
// Open instructions in browser
|
|
145
|
+
await window.electronAPI.openExternal(
|
|
146
|
+
'https://github.com/ItMeDiaTech/Documentation_Hub/wiki/Export-Certificate-From-Browser'
|
|
147
|
+
);
|
|
148
|
+
} catch (_error) {
|
|
149
|
+
logger.error('Error opening browser guide:', _error);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const handleAutoDetect = async () => {
|
|
154
|
+
setImportStatus({ type: 'info', message: 'Searching for certificates in Windows store...' });
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
const result = await window.electronAPI.autoDetectCertificates();
|
|
158
|
+
|
|
159
|
+
if (result.success) {
|
|
160
|
+
setImportStatus({
|
|
161
|
+
type: 'success',
|
|
162
|
+
message: `Found and configured ${result.count} certificate(s)`,
|
|
163
|
+
});
|
|
164
|
+
setCertificateStatus('configured');
|
|
165
|
+
loadExistingCertificates();
|
|
166
|
+
} else {
|
|
167
|
+
setImportStatus({
|
|
168
|
+
type: 'error',
|
|
169
|
+
message: 'No Zscaler certificates found. You may need to export manually.',
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
} catch (_error) {
|
|
173
|
+
setImportStatus({
|
|
174
|
+
type: 'error',
|
|
175
|
+
message: 'Error detecting certificates',
|
|
176
|
+
});
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (detectTimeoutRef.current) {
|
|
180
|
+
clearTimeout(detectTimeoutRef.current);
|
|
181
|
+
}
|
|
182
|
+
detectTimeoutRef.current = setTimeout(() => {
|
|
183
|
+
setImportStatus({ type: null, message: '' });
|
|
184
|
+
detectTimeoutRef.current = null;
|
|
185
|
+
}, 5000);
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
const handleRemoveCertificate = async (certPath: string) => {
|
|
189
|
+
try {
|
|
190
|
+
const result = await window.electronAPI.removeCertificate(certPath);
|
|
191
|
+
if (result.success) {
|
|
192
|
+
loadExistingCertificates();
|
|
193
|
+
}
|
|
194
|
+
} catch (_error) {
|
|
195
|
+
logger.error('Error removing certificate:', _error);
|
|
196
|
+
}
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
const handleTestConnection = async () => {
|
|
200
|
+
setImportStatus({ type: 'info', message: 'Testing connection to GitHub...' });
|
|
201
|
+
|
|
202
|
+
try {
|
|
203
|
+
const result = await window.electronAPI.testGitHubConnection();
|
|
204
|
+
|
|
205
|
+
if (result.success) {
|
|
206
|
+
setImportStatus({
|
|
207
|
+
type: 'success',
|
|
208
|
+
message: 'Connection successful! Updates should work now.',
|
|
209
|
+
});
|
|
210
|
+
} else {
|
|
211
|
+
setImportStatus({
|
|
212
|
+
type: 'error',
|
|
213
|
+
message: `Connection failed: ${result.error}`,
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
} catch (_error) {
|
|
217
|
+
setImportStatus({
|
|
218
|
+
type: 'error',
|
|
219
|
+
message: 'Error testing connection',
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
if (testTimeoutRef.current) {
|
|
224
|
+
clearTimeout(testTimeoutRef.current);
|
|
225
|
+
}
|
|
226
|
+
testTimeoutRef.current = setTimeout(() => {
|
|
227
|
+
setImportStatus({ type: null, message: '' });
|
|
228
|
+
testTimeoutRef.current = null;
|
|
229
|
+
}, 5000);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
return (
|
|
233
|
+
<div className="space-y-4">
|
|
234
|
+
{/* Status Banner */}
|
|
235
|
+
{isZscalerDetected && (
|
|
236
|
+
<Card className="border-yellow-500 bg-yellow-50 dark:bg-yellow-950/20">
|
|
237
|
+
<CardHeader>
|
|
238
|
+
<div className="flex items-center gap-2">
|
|
239
|
+
<Shield className="h-5 w-5 text-yellow-600" />
|
|
240
|
+
<CardTitle className="text-lg">Zscaler Detected</CardTitle>
|
|
241
|
+
</div>
|
|
242
|
+
<CardDescription>
|
|
243
|
+
Zscaler is performing SSL inspection on your network. Certificate configuration is
|
|
244
|
+
required for automatic updates.
|
|
245
|
+
</CardDescription>
|
|
246
|
+
</CardHeader>
|
|
247
|
+
</Card>
|
|
248
|
+
)}
|
|
249
|
+
|
|
250
|
+
{/* Certificate Status */}
|
|
251
|
+
<Card>
|
|
252
|
+
<CardHeader>
|
|
253
|
+
<CardTitle>Certificate Configuration</CardTitle>
|
|
254
|
+
<CardDescription>
|
|
255
|
+
Manage certificates for secure connections through corporate networks
|
|
256
|
+
</CardDescription>
|
|
257
|
+
</CardHeader>
|
|
258
|
+
<CardContent className="space-y-4">
|
|
259
|
+
{/* Current Status */}
|
|
260
|
+
<div className="flex items-center justify-between p-4 rounded-lg bg-muted">
|
|
261
|
+
<div className="flex items-center gap-3">
|
|
262
|
+
{certificateStatus === 'configured' ? (
|
|
263
|
+
<CheckCircle2 className="h-5 w-5 text-green-600" />
|
|
264
|
+
) : (
|
|
265
|
+
<AlertCircle className="h-5 w-5 text-yellow-600" />
|
|
266
|
+
)}
|
|
267
|
+
<div>
|
|
268
|
+
<p className="font-medium">
|
|
269
|
+
{certificateStatus === 'configured'
|
|
270
|
+
? 'Certificate Configured'
|
|
271
|
+
: 'Certificate Not Configured'}
|
|
272
|
+
</p>
|
|
273
|
+
{currentCertPath && (
|
|
274
|
+
<p className="text-sm text-muted-foreground">{currentCertPath}</p>
|
|
275
|
+
)}
|
|
276
|
+
</div>
|
|
277
|
+
</div>
|
|
278
|
+
<Button variant="outline" size="sm" onClick={handleTestConnection}>
|
|
279
|
+
Test Connection
|
|
280
|
+
</Button>
|
|
281
|
+
</div>
|
|
282
|
+
|
|
283
|
+
{/* Import Status Message */}
|
|
284
|
+
{importStatus.type && (
|
|
285
|
+
<div
|
|
286
|
+
className={`p-3 rounded-lg flex items-center gap-2 ${
|
|
287
|
+
importStatus.type === 'success'
|
|
288
|
+
? 'bg-green-50 text-green-700 dark:bg-green-950/20'
|
|
289
|
+
: importStatus.type === 'error'
|
|
290
|
+
? 'bg-red-50 text-red-700 dark:bg-red-950/20'
|
|
291
|
+
: 'bg-blue-50 text-blue-700 dark:bg-blue-950/20'
|
|
292
|
+
}`}
|
|
293
|
+
>
|
|
294
|
+
<Info className="h-4 w-4" />
|
|
295
|
+
<span className="text-sm">{importStatus.message}</span>
|
|
296
|
+
</div>
|
|
297
|
+
)}
|
|
298
|
+
|
|
299
|
+
{/* Actions */}
|
|
300
|
+
<div className="flex gap-2">
|
|
301
|
+
<Button onClick={handleAutoDetect} variant="default" className="flex-1">
|
|
302
|
+
<Shield className="mr-2 h-4 w-4" />
|
|
303
|
+
Auto-Detect Certificates
|
|
304
|
+
</Button>
|
|
305
|
+
<Button onClick={handleImportCertificate} variant="outline" className="flex-1">
|
|
306
|
+
<Upload className="mr-2 h-4 w-4" />
|
|
307
|
+
Import Certificate
|
|
308
|
+
</Button>
|
|
309
|
+
</div>
|
|
310
|
+
|
|
311
|
+
<Button onClick={handleExportFromBrowser} variant="ghost" className="w-full">
|
|
312
|
+
<Download className="mr-2 h-4 w-4" />
|
|
313
|
+
How to Export Certificate from Browser
|
|
314
|
+
</Button>
|
|
315
|
+
</CardContent>
|
|
316
|
+
</Card>
|
|
317
|
+
|
|
318
|
+
{/* Installed Certificates */}
|
|
319
|
+
{certificates.length > 0 && (
|
|
320
|
+
<Card>
|
|
321
|
+
<CardHeader>
|
|
322
|
+
<CardTitle>Installed Certificates</CardTitle>
|
|
323
|
+
<CardDescription>Certificates currently available to the application</CardDescription>
|
|
324
|
+
</CardHeader>
|
|
325
|
+
<CardContent>
|
|
326
|
+
<div className="space-y-2">
|
|
327
|
+
{certificates.map((cert, index) => (
|
|
328
|
+
<div
|
|
329
|
+
key={index}
|
|
330
|
+
className="flex items-center justify-between p-3 rounded-lg border"
|
|
331
|
+
>
|
|
332
|
+
<div className="flex-1">
|
|
333
|
+
<div className="flex items-center gap-2">
|
|
334
|
+
<p className="font-medium">{cert.name}</p>
|
|
335
|
+
{cert.isZscaler && (
|
|
336
|
+
<span className="text-xs px-2 py-0.5 rounded bg-yellow-100 text-yellow-700 dark:bg-yellow-900 dark:text-yellow-300">
|
|
337
|
+
Zscaler
|
|
338
|
+
</span>
|
|
339
|
+
)}
|
|
340
|
+
{cert.isActive && (
|
|
341
|
+
<span className="text-xs px-2 py-0.5 rounded bg-green-100 text-green-700 dark:bg-green-900 dark:text-green-300">
|
|
342
|
+
Active
|
|
343
|
+
</span>
|
|
344
|
+
)}
|
|
345
|
+
</div>
|
|
346
|
+
{cert.issuer && (
|
|
347
|
+
<p className="text-sm text-muted-foreground">Issuer: {cert.issuer}</p>
|
|
348
|
+
)}
|
|
349
|
+
{cert.validUntil && (
|
|
350
|
+
<p className="text-sm text-muted-foreground">
|
|
351
|
+
Valid until: {cert.validUntil}
|
|
352
|
+
</p>
|
|
353
|
+
)}
|
|
354
|
+
</div>
|
|
355
|
+
<Button
|
|
356
|
+
onClick={() => handleRemoveCertificate(cert.path)}
|
|
357
|
+
variant="ghost"
|
|
358
|
+
size="icon"
|
|
359
|
+
>
|
|
360
|
+
<Trash2 className="h-4 w-4" />
|
|
361
|
+
</Button>
|
|
362
|
+
</div>
|
|
363
|
+
))}
|
|
364
|
+
</div>
|
|
365
|
+
</CardContent>
|
|
366
|
+
</Card>
|
|
367
|
+
)}
|
|
368
|
+
|
|
369
|
+
{/* Help Section */}
|
|
370
|
+
<Card>
|
|
371
|
+
<CardHeader>
|
|
372
|
+
<CardTitle>Troubleshooting Guide</CardTitle>
|
|
373
|
+
</CardHeader>
|
|
374
|
+
<CardContent>
|
|
375
|
+
<div className="space-y-3 text-sm">
|
|
376
|
+
<div>
|
|
377
|
+
<p className="font-medium mb-1">If auto-detect doesn't work:</p>
|
|
378
|
+
<ol className="list-decimal list-inside space-y-1 text-muted-foreground ml-2">
|
|
379
|
+
<li>Open Chrome or Edge and navigate to https://github.com</li>
|
|
380
|
+
<li>Click the padlock icon in the address bar</li>
|
|
381
|
+
<li>Select "Connection is secure" → "Certificate is valid"</li>
|
|
382
|
+
<li>Go to the "Details" tab and select the root certificate</li>
|
|
383
|
+
<li>Export as Base64 encoded .CER or .PEM file</li>
|
|
384
|
+
<li>Use the "Import Certificate" button to import the file</li>
|
|
385
|
+
</ol>
|
|
386
|
+
</div>
|
|
387
|
+
|
|
388
|
+
<div>
|
|
389
|
+
<p className="font-medium mb-1">Common certificate names:</p>
|
|
390
|
+
<ul className="list-disc list-inside space-y-1 text-muted-foreground ml-2">
|
|
391
|
+
<li>Zscaler Root CA</li>
|
|
392
|
+
<li>Zscaler Intermediate Root CA</li>
|
|
393
|
+
<li>Your Company Root CA</li>
|
|
394
|
+
<li>Corporate Proxy Certificate</li>
|
|
395
|
+
</ul>
|
|
396
|
+
</div>
|
|
397
|
+
|
|
398
|
+
<div className="mt-4 p-3 rounded-lg bg-muted">
|
|
399
|
+
<p className="text-xs text-muted-foreground">
|
|
400
|
+
<strong>Note:</strong> If you continue to have issues, contact your IT department
|
|
401
|
+
and request that *.github.com and *.githubusercontent.com be bypassed from SSL
|
|
402
|
+
inspection.
|
|
403
|
+
</p>
|
|
404
|
+
</div>
|
|
405
|
+
</div>
|
|
406
|
+
</CardContent>
|
|
407
|
+
</Card>
|
|
408
|
+
</div>
|
|
409
|
+
);
|
|
410
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { motion } from 'framer-motion';
|
|
2
|
+
import { cn } from '@/utils/cn';
|
|
3
|
+
import type { LucideIcon } from 'lucide-react';
|
|
4
|
+
|
|
5
|
+
interface SegmentedControlOption<T extends string> {
|
|
6
|
+
value: T;
|
|
7
|
+
label: string;
|
|
8
|
+
icon?: LucideIcon;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface SegmentedControlProps<T extends string> {
|
|
12
|
+
value: T;
|
|
13
|
+
onValueChange: (value: T) => void;
|
|
14
|
+
options: SegmentedControlOption<T>[];
|
|
15
|
+
className?: string;
|
|
16
|
+
size?: 'sm' | 'md' | 'lg';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function SegmentedControl<T extends string>({
|
|
20
|
+
value,
|
|
21
|
+
onValueChange,
|
|
22
|
+
options,
|
|
23
|
+
className,
|
|
24
|
+
size = 'md',
|
|
25
|
+
}: SegmentedControlProps<T>) {
|
|
26
|
+
const sizeStyles = {
|
|
27
|
+
sm: 'p-0.5 text-xs',
|
|
28
|
+
md: 'p-1 text-sm',
|
|
29
|
+
lg: 'p-1.5 text-base',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const buttonSizeStyles = {
|
|
33
|
+
sm: 'px-2.5 py-1',
|
|
34
|
+
md: 'px-4 py-2',
|
|
35
|
+
lg: 'px-5 py-2.5',
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const iconSizeStyles = {
|
|
39
|
+
sm: 'w-3.5 h-3.5',
|
|
40
|
+
md: 'w-4 h-4',
|
|
41
|
+
lg: 'w-5 h-5',
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<div
|
|
46
|
+
role="radiogroup"
|
|
47
|
+
className={cn(
|
|
48
|
+
'inline-flex items-center rounded-lg bg-muted/50 border border-border',
|
|
49
|
+
sizeStyles[size],
|
|
50
|
+
className
|
|
51
|
+
)}
|
|
52
|
+
>
|
|
53
|
+
{options.map((option) => {
|
|
54
|
+
const isSelected = value === option.value;
|
|
55
|
+
const Icon = option.icon;
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<button
|
|
59
|
+
key={option.value}
|
|
60
|
+
type="button"
|
|
61
|
+
role="radio"
|
|
62
|
+
aria-checked={isSelected}
|
|
63
|
+
onClick={() => onValueChange(option.value)}
|
|
64
|
+
className={cn(
|
|
65
|
+
'relative flex items-center justify-center gap-2 rounded-md font-medium transition-colors',
|
|
66
|
+
buttonSizeStyles[size],
|
|
67
|
+
isSelected
|
|
68
|
+
? 'text-foreground'
|
|
69
|
+
: 'text-muted-foreground hover:text-foreground'
|
|
70
|
+
)}
|
|
71
|
+
>
|
|
72
|
+
{isSelected && (
|
|
73
|
+
<motion.div
|
|
74
|
+
layoutId="segmented-indicator"
|
|
75
|
+
className="absolute inset-0 bg-background rounded-md shadow-sm border border-border/50"
|
|
76
|
+
transition={{ type: 'spring', stiffness: 400, damping: 30 }}
|
|
77
|
+
/>
|
|
78
|
+
)}
|
|
79
|
+
<span className="relative flex items-center gap-2">
|
|
80
|
+
{Icon && <Icon className={iconSizeStyles[size]} />}
|
|
81
|
+
<span>{option.label}</span>
|
|
82
|
+
</span>
|
|
83
|
+
</button>
|
|
84
|
+
);
|
|
85
|
+
})}
|
|
86
|
+
</div>
|
|
87
|
+
);
|
|
88
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { cn } from '@/utils/cn';
|
|
2
|
+
import type { LucideIcon } from 'lucide-react';
|
|
3
|
+
import type { ReactNode } from 'react';
|
|
4
|
+
|
|
5
|
+
interface SettingRowProps {
|
|
6
|
+
icon?: LucideIcon;
|
|
7
|
+
title: string;
|
|
8
|
+
description?: string;
|
|
9
|
+
badge?: string;
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function SettingRow({
|
|
15
|
+
icon: Icon,
|
|
16
|
+
title,
|
|
17
|
+
description,
|
|
18
|
+
badge,
|
|
19
|
+
children,
|
|
20
|
+
className,
|
|
21
|
+
}: SettingRowProps) {
|
|
22
|
+
return (
|
|
23
|
+
<div
|
|
24
|
+
className={cn(
|
|
25
|
+
'flex items-center justify-between gap-4 py-3',
|
|
26
|
+
className
|
|
27
|
+
)}
|
|
28
|
+
>
|
|
29
|
+
<div className="flex items-start gap-3 flex-1 min-w-0">
|
|
30
|
+
{Icon && (
|
|
31
|
+
<div className="p-2 rounded-lg bg-muted shrink-0 mt-0.5">
|
|
32
|
+
<Icon className="w-4 h-4 text-muted-foreground" />
|
|
33
|
+
</div>
|
|
34
|
+
)}
|
|
35
|
+
<div className="flex-1 min-w-0">
|
|
36
|
+
<div className="flex items-center gap-2">
|
|
37
|
+
<span className="text-sm font-medium">{title}</span>
|
|
38
|
+
{badge && (
|
|
39
|
+
<span className="px-1.5 py-0.5 text-[10px] font-medium rounded bg-muted text-muted-foreground uppercase tracking-wide">
|
|
40
|
+
{badge}
|
|
41
|
+
</span>
|
|
42
|
+
)}
|
|
43
|
+
</div>
|
|
44
|
+
{description && (
|
|
45
|
+
<p className="text-xs text-muted-foreground mt-0.5">{description}</p>
|
|
46
|
+
)}
|
|
47
|
+
</div>
|
|
48
|
+
</div>
|
|
49
|
+
<div className="shrink-0">{children}</div>
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|