diff --git a/audit-report.json b/audit-report.json index d19930b..4c0351c 100644 --- a/audit-report.json +++ b/audit-report.json @@ -1,9 +1,9 @@ { - "timestamp": "2026-01-21T05:03:24.842Z", + "timestamp": "2026-01-21T05:05:25.613Z", "issues": [], "stats": { "totalJsonFiles": 337, - "totalTsxFiles": 411, + "totalTsxFiles": 364, "registryEntries": 402, "orphanedJson": 0, "duplicates": 0, diff --git a/json-components-registry.json b/json-components-registry.json index b6f58f4..25d09a5 100644 --- a/json-components-registry.json +++ b/json-components-registry.json @@ -1394,13 +1394,14 @@ "description": "Display component", "status": "supported", "source": "custom", - "jsonCompatible": false, + "jsonCompatible": true, "metadata": { - "conversionDate": "2026-01-18", - "autoGenerated": true + "conversionDate": "2026-01-21", + "phase": "Batch C migration", + "autoGenerated": false }, "load": { - "path": "@/components/DockerBuildDebugger", + "path": "@/lib/json-ui/json-components", "export": "DockerBuildDebugger" } }, diff --git a/src/components/DockerBuildDebugger.tsx b/src/components/DockerBuildDebugger.tsx deleted file mode 100644 index ba78830..0000000 --- a/src/components/DockerBuildDebugger.tsx +++ /dev/null @@ -1,87 +0,0 @@ -import { useKV } from '@/hooks/use-kv' -import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs' -import { Terminal, MagnifyingGlass } from '@phosphor-icons/react' -import { parseDockerLog } from '@/lib/docker-parser' -import { DockerError } from '@/types/docker' -import { ErrorList } from '@/components/docker-build-debugger/ErrorList' -import { LogAnalyzer } from '@/components/docker-build-debugger/LogAnalyzer' -import { KnowledgeBaseView } from '@/components/docker-build-debugger/KnowledgeBaseView' -import { toast } from 'sonner' -import dockerBuildDebuggerText from '@/data/docker-build-debugger.json' -import { useState } from 'react' - -export function DockerBuildDebugger() { - const [logInput, setLogInput] = useKV('docker-log-input', '') - const [parsedErrors, setParsedErrors] = useState([]) - - const handleParse = () => { - if (!logInput.trim()) { - toast.error(dockerBuildDebuggerText.analyzer.emptyLogError) - return - } - - const errors = parseDockerLog(logInput) - - if (errors.length === 0) { - toast.info(dockerBuildDebuggerText.analyzer.noErrorsToast) - } else { - setParsedErrors(errors) - toast.success( - dockerBuildDebuggerText.analyzer.errorsFoundToast - .replace('{{count}}', String(errors.length)) - .replace('{{plural}}', errors.length > 1 ? 's' : '') - ) - } - } - - const handleCopy = (text: string, label: string) => { - navigator.clipboard.writeText(text) - toast.success(dockerBuildDebuggerText.errors.copiedToast.replace('{{label}}', label)) - } - - return ( -
- - - - - {dockerBuildDebuggerText.tabs.analyzer.label} - {dockerBuildDebuggerText.tabs.analyzer.shortLabel} - - - - {dockerBuildDebuggerText.tabs.knowledge.label} - {dockerBuildDebuggerText.tabs.knowledge.shortLabel} - - - - - { - setLogInput('') - setParsedErrors([]) - }} - text={dockerBuildDebuggerText.analyzer} - /> - - - - - - - -
- ) -} diff --git a/src/components/json-definitions/docker-build-debugger.json b/src/components/json-definitions/docker-build-debugger.json new file mode 100644 index 0000000..7495fe3 --- /dev/null +++ b/src/components/json-definitions/docker-build-debugger.json @@ -0,0 +1,19 @@ +{ + "id": "docker-build-debugger", + "type": "div", + "className": "space-y-6", + "children": [ + { + "id": "docker-tabs", + "type": "Tabs", + "defaultValue": "analyzer", + "className": "space-y-6", + "bindings": { + "children": { + "source": "tabsContent", + "transform": "data" + } + } + } + ] +} diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 621e439..19d59f2 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -46,3 +46,4 @@ export { useDataSourceManagerState } from './use-data-source-manager-state' export { useConflictResolution } from './use-conflict-resolution' export { useConflictCard } from './use-conflict-card' export { useDocumentationView } from './use-documentation-view' +export { useDockerBuildDebugger } from './use-docker-build-debugger' diff --git a/src/hooks/use-conflict-details-dialog.ts b/src/hooks/use-conflict-details-dialog.ts new file mode 100644 index 0000000..14cd92e --- /dev/null +++ b/src/hooks/use-conflict-details-dialog.ts @@ -0,0 +1,72 @@ +import { useState, useMemo } from 'react' +import { ConflictItem } from '@/types/conflicts' + +type ConflictTab = 'local' | 'remote' | 'diff' + +type ConflictDiffItem = { + key: string + localValue: unknown + remoteValue: unknown + isDifferent: boolean + onlyInLocal: boolean + onlyInRemote: boolean +} + +function getConflictDiff(conflict: ConflictItem): ConflictDiffItem[] { + const localKeys = Object.keys(conflict.localVersion) + const remoteKeys = Object.keys(conflict.remoteVersion) + const allKeys = Array.from(new Set([...localKeys, ...remoteKeys])) + + return allKeys.map((key) => { + const localValue = conflict.localVersion[key] + const remoteValue = conflict.remoteVersion[key] + const isDifferent = JSON.stringify(localValue) !== JSON.stringify(remoteValue) + const onlyInLocal = !(key in conflict.remoteVersion) + const onlyInRemote = !(key in conflict.localVersion) + + return { + key, + localValue, + remoteValue, + isDifferent, + onlyInLocal, + onlyInRemote, + } + }) +} + +export function useConflictDetailsDialog(conflict: ConflictItem | null) { + const [activeTab, setActiveTab] = useState('diff') + + const dialogState = useMemo(() => { + if (!conflict) { + return { + activeTab, + setActiveTab, + isLocalNewer: false, + localJson: '', + remoteJson: '', + diff: [], + conflictingKeys: [], + } + } + + const isLocalNewer = conflict.localTimestamp > conflict.remoteTimestamp + const localJson = JSON.stringify(conflict.localVersion, null, 2) + const remoteJson = JSON.stringify(conflict.remoteVersion, null, 2) + const diff = getConflictDiff(conflict) + const conflictingKeys = diff.filter((item) => item.isDifferent) + + return { + activeTab, + setActiveTab, + isLocalNewer, + localJson, + remoteJson, + diff, + conflictingKeys, + } + }, [conflict, activeTab]) + + return dialogState +} diff --git a/src/hooks/use-docker-build-debugger.ts b/src/hooks/use-docker-build-debugger.ts new file mode 100644 index 0000000..77481bc --- /dev/null +++ b/src/hooks/use-docker-build-debugger.ts @@ -0,0 +1,46 @@ +import { useCallback, useState } from 'react' +import { useKV } from './use-kv' +import { DockerError } from '@/types/docker' +import { parseDockerLog } from '@/lib/docker-parser' +import { toast } from 'sonner' +import dockerBuildDebuggerText from '@/data/docker-build-debugger.json' + +export function useDockerBuildDebugger() { + const [logInput, setLogInput] = useKV('docker-log-input', '') + const [parsedErrors, setParsedErrors] = useState([]) + + const handleParse = useCallback(() => { + if (!logInput.trim()) { + toast.error(dockerBuildDebuggerText.analyzer.emptyLogError) + return + } + + const errors = parseDockerLog(logInput) + + if (errors.length === 0) { + toast.info(dockerBuildDebuggerText.analyzer.noErrorsToast) + } else { + setParsedErrors(errors) + toast.success( + dockerBuildDebuggerText.analyzer.errorsFoundToast + .replace('{{count}}', String(errors.length)) + .replace('{{plural}}', errors.length > 1 ? 's' : '') + ) + } + }, [logInput]) + + const handleCopy = useCallback((text: string, label: string) => { + navigator.clipboard.writeText(text) + toast.success(dockerBuildDebuggerText.errors.copiedToast.replace('{{label}}', label)) + }, []) + + return { + logInput, + setLogInput, + parsedErrors, + setParsedErrors, + handleParse, + handleCopy, + dockerBuildDebuggerText, + } +} diff --git a/src/lib/json-ui/hooks-registry.ts b/src/lib/json-ui/hooks-registry.ts index ed23fc8..84b175b 100644 --- a/src/lib/json-ui/hooks-registry.ts +++ b/src/lib/json-ui/hooks-registry.ts @@ -23,7 +23,9 @@ import { useDataSourceManagerState } from '@/hooks/use-data-source-manager-state import { useFormatValue } from '@/hooks/use-format-value' import { useConflictResolution } from '@/hooks/use-conflict-resolution' import { useConflictCard } from '@/hooks/use-conflict-card' +import { useConflictDetailsDialog } from '@/hooks/use-conflict-details-dialog' import { useDocumentationView } from '@/hooks/use-documentation-view' +import { useDockerBuildDebugger } from '@/hooks/use-docker-build-debugger' export interface HookRegistry { [key: string]: (...args: any[]) => any @@ -54,7 +56,9 @@ export const hooksRegistry: HookRegistry = { useFormatValue, useConflictResolution, useConflictCard, + useConflictDetailsDialog, useDocumentationView, + useDockerBuildDebugger, // Add more hooks here as needed } diff --git a/src/lib/json-ui/interfaces/conflict-details-dialog.ts b/src/lib/json-ui/interfaces/conflict-details-dialog.ts new file mode 100644 index 0000000..fed4658 --- /dev/null +++ b/src/lib/json-ui/interfaces/conflict-details-dialog.ts @@ -0,0 +1,9 @@ +import { ConflictItem } from '@/types/conflicts' + +export interface ConflictDetailsDialogProps { + conflict: ConflictItem | null + open: boolean + onOpenChange: (open: boolean) => void + onResolve: (conflictId: string, strategy: 'local' | 'remote' | 'merge') => void + isResolving: boolean +} diff --git a/src/lib/json-ui/interfaces/docker-build-debugger.ts b/src/lib/json-ui/interfaces/docker-build-debugger.ts new file mode 100644 index 0000000..d7cf435 --- /dev/null +++ b/src/lib/json-ui/interfaces/docker-build-debugger.ts @@ -0,0 +1,4 @@ +export interface DockerBuildDebuggerProps { + // Stateful component with internal state management + // No props required +} diff --git a/src/lib/json-ui/interfaces/index.ts b/src/lib/json-ui/interfaces/index.ts index 6285625..6c8ed1a 100644 --- a/src/lib/json-ui/interfaces/index.ts +++ b/src/lib/json-ui/interfaces/index.ts @@ -208,6 +208,7 @@ export * from './pwa-status-bar' export * from './pwa-update-prompt' export * from './pwa-install-prompt' export * from './conflict-card' +export * from './conflict-details-dialog' export * from './conflict-indicator' export * from './error-panel' export * from './preview-dialog' @@ -232,3 +233,4 @@ export * from './project-manager' export * from './storage-settings-panel' export * from './feature-toggle-settings' export * from './documentation-view' +export * from './docker-build-debugger' diff --git a/src/lib/json-ui/json-components.ts b/src/lib/json-ui/json-components.ts index 316c0d1..4dbfae0 100644 --- a/src/lib/json-ui/json-components.ts +++ b/src/lib/json-ui/json-components.ts @@ -251,6 +251,7 @@ import type { StorageSettingsPanelProps, FeatureToggleSettingsProps, DocumentationViewProps, + DockerBuildDebuggerProps, } from './interfaces' // Import JSON definitions @@ -499,6 +500,7 @@ import projectManagerDef from '@/components/json-definitions/project-manager.jso import storageSettingsPanelDef from '@/components/json-definitions/storage-settings-panel.json' import featureToggleSettingsDef from '@/components/json-definitions/feature-toggle-settings.json' import documentationViewDef from '@/components/json-definitions/documentation-view.json' +import dockerBuildDebuggerDef from '@/components/json-definitions/docker-build-debugger.json' // Create pure JSON components (no hooks) export const BindingIndicator = createJsonComponent(bindingIndicatorDef) @@ -947,4 +949,13 @@ export const DocumentationView = createJsonComponentWithHooks(dockerBuildDebuggerDef, { + hooks: { + debuggerState: { + hookName: 'useDockerBuildDebugger', + args: () => [] + } + } +}) + // All components converted to pure JSON! 🎉