Skip to content

Commit 2f1b5a3

Browse files
authored
Merge pull request #59 from beNative/codex/add-plantuml-rendering-configuration-option
Add offline PlantUML renderer option
2 parents 1d2440f + 703e0ab commit 2f1b5a3

27 files changed

Lines changed: 575 additions & 74 deletions

App.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,7 +1090,7 @@ const MainApp: React.FC = () => {
10901090
}
10911091

10921092
const renderMainContent = () => {
1093-
if (view === 'info') return <InfoView />;
1093+
if (view === 'info') return <InfoView settings={settings} />;
10941094
if (view === 'settings') return <SettingsView settings={settings} onSave={saveSettings} discoveredServices={discoveredServices} onDetectServices={handleDetectServices} isDetecting={isDetecting} commands={enrichedCommands} />;
10951095

10961096
if (activeTemplate) {

FUNCTIONAL_MANUAL.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,25 @@ Accessed via the gear icon in the title bar. The settings are organized into cat
133133
- **LLM Provider:** Configure your connection to a local AI service. You can detect running services and select a model.
134134
- **Appearance:** Change the UI scale and choose from different icon sets.
135135
- **Keyboard Shortcuts:** View and customize keyboard shortcuts for all major application actions. You can record a new key combination for any command.
136-
- **General:** Configure application behavior, like auto-saving logs and opting into pre-release updates.
136+
- **General:** Configure application behavior, like auto-saving logs, opting into pre-release updates, and choosing how PlantUML diagrams are rendered.
137137
- **Database:** View detailed statistics about your local database file, and perform maintenance tasks such as creating a compressed backup, checking file integrity, and optimizing the database size (`VACUUM`).
138138
- **Advanced:** View and edit the raw JSON configuration file using an interactive tree or a raw text editor, and import/export your settings.
139139

140140
### Info View
141141

142142
Accessed via the info icon in the title bar. This view contains tabs for reading the application's `README.md`, this `FUNCTIONAL_MANUAL.md`, the `TECHNICAL_MANUAL.md`, and the `VERSION_LOG.md`.
143143

144+
#### PlantUML Rendering Modes
145+
146+
The **General** settings category includes a **PlantUML Rendering** selector. Choose between:
147+
148+
- **Remote (plantuml.com):** Encodes the diagram and requests the SVG from the public PlantUML server.
149+
- **Offline (local renderer):** Invokes the bundled PlantUML engine inside the desktop application. This mode requires a local Java Runtime Environment and access to Graphviz (or the bundled `viz.js` assets) so the renderer can generate diagrams without contacting plantuml.com.
150+
151+
If the Java runtime is unavailable, DocForge will report the error in the preview and you can switch back to remote rendering at any time.
152+
153+
The chosen rendering mode is used for PlantUML code blocks inside Markdown documents *and* for standalone `.puml` documents rendered through the dedicated PlantUML previewer.
154+
144155
### Logger Panel
145156

146157
Accessed via the terminal icon in the title bar, this panel is your primary tool for debugging and monitoring application activity.

TECHNICAL_MANUAL.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This document provides a technical overview of the DocForge application's archit
1414
- **Bundler:** [esbuild](https://esbuild.github.io/) for fast and efficient bundling of the application's source code.
1515
- **Styling:** [Tailwind CSS](https://tailwindcss.com/) for a utility-first CSS framework.
1616
- **Packaging:** [electron-builder](https://www.electron.build/) for creating distributable application packages.
17+
- **Diagram Rendering:** [PlantUML](https://plantuml.com/) via either the public plantuml.com service or the bundled [`node-plantuml`](https://www.npmjs.com/package/node-plantuml) renderer. Offline rendering requires a locally installed Java Runtime Environment and access to Graphviz (or the cached `viz.js` binary) so that diagrams can be rendered without network access.
1718

1819
---
1920

@@ -93,7 +94,8 @@ This system provides a consistent and extensible editing experience for all docu
9394
- **`CodeEditor.tsx`:** A React component that wraps and configures the Monaco Editor instance. It's responsible for managing the editor's content, theme, and language for syntax highlighting based on props.
9495
- **`PreviewPane.tsx`:** This component is responsible for displaying the rendered output of a document. It debounces content updates for performance and uses the `PreviewService` to get the correct output.
9596
- **`services/previewService.ts`:** This service acts as a registry for all available renderer "plugins." It exposes a method, `getRendererForLanguage()`, which finds and returns the appropriate renderer for a given language ID (e.g., 'markdown').
96-
- **Renderer Plugins (`services/preview/`):** Each file format with a preview is supported by a dedicated renderer class that implements the `IRenderer` interface. This makes the system highly extensible: to support a new format, one only needs to create a new renderer class and add it to the `previewService` registry. Currently, renderers for Markdown, HTML, and plaintext (fallback) are implemented.
97+
- **Renderer Plugins (`services/preview/`):** Each file format with a preview is supported by a dedicated renderer class that implements the `IRenderer` interface. This makes the system highly extensible: to support a new format, one only needs to create a new renderer class and add it to the `previewService` registry. The bundled plugins cover Markdown (with Mermaid + PlantUML support), standalone PlantUML documents, HTML, PDFs, common image formats, and a plaintext fallback renderer.
98+
- Both the Markdown renderer and the standalone PlantUML renderer share the `PlantUMLDiagram` component, which routes diagrams through either the remote plantuml.com server or the offline `node-plantuml` IPC bridge depending on the active setting.
9799

98100
### LLM Service (`services/llmService.ts`)
99101

components/InfoView.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from 'react';
22
import PreviewPane from './PreviewPane';
33
import Spinner from './Spinner';
44
import { useLogger } from '../hooks/useLogger';
5+
import type { Settings } from '../types';
56

67
type DocTab = 'Readme' | 'Functional Manual' | 'Technical Manual' | 'Version Log';
78

@@ -12,7 +13,11 @@ const docFiles: Record<DocTab, string> = {
1213
'Version Log': 'VERSION_LOG.md',
1314
};
1415

15-
const InfoView: React.FC = () => {
16+
interface InfoViewProps {
17+
settings: Settings;
18+
}
19+
20+
const InfoView: React.FC<InfoViewProps> = ({ settings }) => {
1621
const [activeTab, setActiveTab] = useState<DocTab>('Readme');
1722
const [documents, setDocuments] = useState<Record<DocTab, string>>({
1823
'Readme': 'Loading...',
@@ -100,7 +105,7 @@ const InfoView: React.FC = () => {
100105
<span>Loading documentation...</span>
101106
</div>
102107
) : (
103-
<PreviewPane content={documents[activeTab]} language="markdown" addLog={addLog} />
108+
<PreviewPane content={documents[activeTab]} language="markdown" addLog={addLog} settings={settings} />
104109
)}
105110
</div>
106111
</div>

components/PreviewPane.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,17 @@ import React, { useState, useEffect } from 'react';
22
import { previewService } from '../services/previewService';
33
import Spinner from './Spinner';
44
import { useTheme } from '../hooks/useTheme';
5-
import type { LogLevel } from '../types';
5+
import type { LogLevel, Settings } from '../types';
66

77
interface PreviewPaneProps {
88
content: string;
99
language: string | null;
1010
onScroll?: (event: React.UIEvent<HTMLDivElement>) => void;
1111
addLog: (level: LogLevel, message: string) => void;
12+
settings: Settings;
1213
}
1314

14-
const PreviewPane = React.forwardRef<HTMLDivElement, PreviewPaneProps>(({ content, language, onScroll, addLog }, ref) => {
15+
const PreviewPane = React.forwardRef<HTMLDivElement, PreviewPaneProps>(({ content, language, onScroll, addLog, settings }, ref) => {
1516
const [renderedOutput, setRenderedOutput] = useState<React.ReactElement | null>(null);
1617
const [error, setError] = useState<string | null>(null);
1718
const [isLoading, setIsLoading] = useState(true);
@@ -28,7 +29,7 @@ const PreviewPane = React.forwardRef<HTMLDivElement, PreviewPaneProps>(({ conten
2829

2930
setError(null);
3031
const renderer = previewService.getRendererForLanguage(language);
31-
const result = await renderer.render(content, addLog, language);
32+
const result = await renderer.render(content, addLog, language, settings);
3233

3334
clearTimeout(loadingTimer);
3435
if (!isCancelled) {
@@ -57,7 +58,7 @@ const PreviewPane = React.forwardRef<HTMLDivElement, PreviewPaneProps>(({ conten
5758
isCancelled = true;
5859
clearTimeout(debounceTimer);
5960
};
60-
}, [content, language, addLog, ref, onScroll]);
61+
}, [content, language, addLog, ref, onScroll, settings]);
6162

6263
return (
6364
<div className="w-full h-full bg-secondary">

components/PromptEditor.tsx

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,9 @@ interface DocumentEditorProps {
2929
const PREVIEWABLE_LANGUAGES = new Set<string>([
3030
'markdown',
3131
'html',
32+
'plantuml',
33+
'puml',
34+
'uml',
3235
'pdf',
3336
'application/pdf',
3437
'image',
@@ -62,6 +65,9 @@ const resolveDefaultViewMode = (mode: ViewMode | null | undefined, languageHint:
6265
if (normalizedHint === 'image' || normalizedHint.startsWith('image/')) {
6366
return 'preview';
6467
}
68+
if (normalizedHint === 'plantuml' || normalizedHint === 'puml' || normalizedHint === 'uml') {
69+
return 'preview';
70+
}
6571
return 'edit';
6672
};
6773

@@ -482,7 +488,7 @@ const DocumentEditor: React.FC<DocumentEditorProps> = ({ documentNode, onSave, o
482488
fontSize={settings.editorFontSize}
483489
/>
484490
);
485-
const preview = <PreviewPane ref={previewScrollRef} content={content} language={language} onScroll={handlePreviewScroll} addLog={addLog} />;
491+
const preview = <PreviewPane ref={previewScrollRef} content={content} language={language} onScroll={handlePreviewScroll} addLog={addLog} settings={settings} />;
486492

487493
switch(viewMode) {
488494
case 'edit': return editor;

components/SettingsView.tsx

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1369,8 +1369,10 @@ requests"
13691369
};
13701370

13711371
const GeneralSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCurrentSettings' | 'sectionRef'>> = ({ settings, setCurrentSettings, sectionRef }) => {
1372+
const isOfflineRendererAvailable = typeof window !== 'undefined' && !!window.electronAPI?.renderPlantUML;
1373+
const offlineRendererMessage = 'Offline rendering requires the desktop application with a local Java runtime.';
13721374
return (
1373-
<div id="general" ref={sectionRef} className="py-6">
1375+
<div id="general" ref={sectionRef} className="py-6">
13741376
<h2 className="text-lg font-semibold text-text-main mb-4">General</h2>
13751377
<div className="space-y-6">
13761378
<SettingRow htmlFor="allowPrerelease" label="Receive Pre-releases" description="Get notified about new beta versions and test features early.">
@@ -1379,6 +1381,31 @@ const GeneralSettingsSection: React.FC<Pick<SectionProps, 'settings' | 'setCurre
13791381
<SettingRow htmlFor="autoSaveLogs" label="Auto-save Logs" description="Automatically save all logs to a daily file on your computer for debugging.">
13801382
<ToggleSwitch id="autoSaveLogs" checked={settings.autoSaveLogs} onChange={(val) => setCurrentSettings(s => ({...s, autoSaveLogs: val}))} />
13811383
</SettingRow>
1384+
<SettingRow
1385+
htmlFor="plantumlRendererMode"
1386+
label="PlantUML Rendering"
1387+
description="Choose whether PlantUML diagrams are rendered via the public server or the local renderer."
1388+
>
1389+
<div className="flex flex-col items-end w-full md:items-end">
1390+
<select
1391+
id="plantumlRendererMode"
1392+
value={settings.plantumlRendererMode}
1393+
onChange={(event) => setCurrentSettings(prev => ({
1394+
...prev,
1395+
plantumlRendererMode: event.target.value as Settings['plantumlRendererMode'],
1396+
}))}
1397+
className="w-full md:w-64 px-3 py-2 text-sm rounded-md border border-border-color bg-background text-text-main focus:outline-none focus:ring-2 focus:ring-primary/50"
1398+
>
1399+
<option value="remote">Remote (plantuml.com)</option>
1400+
<option value="offline">Offline (local renderer)</option>
1401+
</select>
1402+
{!isOfflineRendererAvailable && (
1403+
<p className={`mt-2 text-xs ${settings.plantumlRendererMode === 'offline' ? 'text-destructive-text' : 'text-text-secondary'} text-right md:text-left md:w-full`}>
1404+
{offlineRendererMessage}
1405+
</p>
1406+
)}
1407+
</div>
1408+
</SettingRow>
13821409
</div>
13831410
</div>
13841411
);

constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ export const DEFAULT_SETTINGS: Settings = {
2424
iconSet: 'heroicons',
2525
autoSaveLogs: false,
2626
allowPrerelease: false,
27+
plantumlRendererMode: 'remote',
2728
uiScale: 100,
2829
documentTreeIndent: 16,
2930
documentTreeVerticalSpacing: 4,

docs/FUNCTIONAL_MANUAL.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,14 +133,25 @@ Accessed via the gear icon in the title bar. The settings are organized into cat
133133
- **LLM Provider:** Configure your connection to a local AI service. You can detect running services and select a model.
134134
- **Appearance:** Change the UI scale and choose from different icon sets.
135135
- **Keyboard Shortcuts:** View and customize keyboard shortcuts for all major application actions. You can record a new key combination for any command.
136-
- **General:** Configure application behavior, like auto-saving logs and opting into pre-release updates.
136+
- **General:** Configure application behavior, like auto-saving logs, opting into pre-release updates, and choosing how PlantUML diagrams are rendered.
137137
- **Database:** View detailed statistics about your local database file, and perform maintenance tasks such as creating a compressed backup, checking file integrity, and optimizing the database size (`VACUUM`).
138138
- **Advanced:** View and edit the raw JSON configuration file using an interactive tree or a raw text editor, and import/export your settings.
139139

140140
### Info View
141141

142142
Accessed via the info icon in the title bar. This view contains tabs for reading the application's `README.md`, this `FUNCTIONAL_MANUAL.md`, the `TECHNICAL_MANUAL.md`, and the `VERSION_LOG.md`.
143143

144+
#### PlantUML Rendering Modes
145+
146+
The **General** settings category includes a **PlantUML Rendering** selector. Choose between:
147+
148+
- **Remote (plantuml.com):** Encodes the diagram and requests the SVG from the public PlantUML server.
149+
- **Offline (local renderer):** Invokes the bundled PlantUML engine inside the desktop application. This mode requires a local Java Runtime Environment and access to Graphviz (or the bundled `viz.js` assets) so the renderer can generate diagrams without contacting plantuml.com.
150+
151+
If the Java runtime is unavailable, DocForge will report the error in the preview and you can switch back to remote rendering at any time.
152+
153+
The chosen rendering mode is used for PlantUML code blocks inside Markdown documents *and* for standalone `.puml` documents rendered through the dedicated PlantUML previewer.
154+
144155
### Logger Panel
145156

146157
Accessed via the terminal icon in the title bar, this panel is your primary tool for debugging and monitoring application activity.

docs/TECHNICAL_MANUAL.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ This document provides a technical overview of the DocForge application's archit
1414
- **Bundler:** [esbuild](https://esbuild.github.io/) for fast and efficient bundling of the application's source code.
1515
- **Styling:** [Tailwind CSS](https://tailwindcss.com/) for a utility-first CSS framework.
1616
- **Packaging:** [electron-builder](https://www.electron.build/) for creating distributable application packages.
17+
- **Diagram Rendering:** [PlantUML](https://plantuml.com/) via either the public plantuml.com service or the bundled [`node-plantuml`](https://www.npmjs.com/package/node-plantuml) renderer. Offline rendering requires a locally installed Java Runtime Environment and access to Graphviz (or the cached `viz.js` binary) so that diagrams can be rendered without network access.
1718

1819
---
1920

@@ -93,7 +94,8 @@ This system provides a consistent and extensible editing experience for all docu
9394
- **`CodeEditor.tsx`:** A React component that wraps and configures the Monaco Editor instance. It's responsible for managing the editor's content, theme, and language for syntax highlighting based on props.
9495
- **`PreviewPane.tsx`:** This component is responsible for displaying the rendered output of a document. It debounces content updates for performance and uses the `PreviewService` to get the correct output.
9596
- **`services/previewService.ts`:** This service acts as a registry for all available renderer "plugins." It exposes a method, `getRendererForLanguage()`, which finds and returns the appropriate renderer for a given language ID (e.g., 'markdown').
96-
- **Renderer Plugins (`services/preview/`):** Each file format with a preview is supported by a dedicated renderer class that implements the `IRenderer` interface. This makes the system highly extensible: to support a new format, one only needs to create a new renderer class and add it to the `previewService` registry. Currently, renderers for Markdown, HTML, and plaintext (fallback) are implemented.
97+
- **Renderer Plugins (`services/preview/`):** Each file format with a preview is supported by a dedicated renderer class that implements the `IRenderer` interface. This makes the system highly extensible: to support a new format, one only needs to create a new renderer class and add it to the `previewService` registry. The bundled plugins cover Markdown (with Mermaid + PlantUML support), standalone PlantUML documents, HTML, PDFs, common image formats, and a plaintext fallback renderer.
98+
- Both the Markdown renderer and the standalone PlantUML renderer share the `PlantUMLDiagram` component, which routes diagrams through either the remote plantuml.com server or the offline `node-plantuml` IPC bridge depending on the active setting.
9799

98100
### LLM Service (`services/llmService.ts`)
99101

0 commit comments

Comments
 (0)