Skip to content

Commit 60f81f2

Browse files
committed
feat(webui): complete Phase 4 - frontend implementation
Copy all WebUI frontend files from FlashForgeUI-Electron reference: Static Files (4): - index.html - Main HTML structure with login and main UI - webui.css - 31KB stylesheet with dark theme and GridStack customizations - gridstack-extra.min.css - Additional GridStack styles - tsconfig.json - Frontend TypeScript configuration Core Modules (2): - AppState.ts - Central state management for context, serial, connection state - Transport.ts - HTTP/WebSocket client with auto-reconnection Feature Modules (7): - authentication.ts - Login, token storage, remember-me, auto-login - camera.ts - MJPEG/RTSP stream initialization with JSMpeg - context-switching.ts - Multi-printer context switching and UI updates - job-control.ts - Pause/resume/cancel, file selection, job start - layout-theme.ts - GridStack editor, theme application, settings modal - material-matching.ts - AD5X material station slot mapping - spoolman.ts - Spoolman integration, spool selection, search UI Modules (3): - dialogs.ts - Modal management, toast notifications, temperature dialog - header.ts - Edit mode toggle, settings button, connection indicator - panels.ts - Update all 9 dashboard component panels from polling data Grid Modules (5): - WebUIGridManager.ts - GridStack wrapper for layout management - WebUILayoutPersistence.ts - Save/load layouts to localStorage - WebUIComponentRegistry.ts - Define all 9 dashboard components - WebUIMobileLayoutManager.ts - Mobile responsive layout (768px breakpoint) - types.ts - Grid type definitions Shared Modules (3): - dom.ts - DOM query and event listener helpers - formatting.ts - Format numbers, time, file sizes - icons.ts - Lucide icon hydration and initialization Build Configuration: - scripts/copy-webui-assets.js - Copy HTML/CSS and vendor libraries to dist - src/types/jsmpeg.d.ts - Type definitions for JSMpeg video player Build successfully compiles all 24 TypeScript files to JavaScript and copies 4 vendor libraries (GridStack, Lucide, JSMpeg, CSS) to dist/webui/static. Type check: 0 errors Lint: 9 warnings (from reference code) Phase 4 Frontend: Complete
1 parent d5e7436 commit 60f81f2

27 files changed

Lines changed: 7248 additions & 0 deletions

scripts/copy-webui-assets.js

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#!/usr/bin/env node
2+
3+
/**
4+
* Copy WebUI static assets from source to build output directory.
5+
*
6+
* This script copies HTML, CSS, and other static files from src/webui/static/
7+
* to dist/webui/static/ as part of the webui build process.
8+
*/
9+
10+
const fs = require('fs');
11+
const path = require('path');
12+
13+
// Configuration
14+
const srcDir = 'src/webui/static';
15+
const destDir = 'dist/webui/static';
16+
const filesToCopy = ['index.html', 'webui.css', 'gridstack-extra.min.css'];
17+
18+
// Vendor library to copy from node_modules
19+
const vendorLibraries = [
20+
{
21+
src: 'node_modules/@cycjimmy/jsmpeg-player/dist/jsmpeg-player.umd.min.js',
22+
dest: 'jsmpeg.min.js'
23+
},
24+
{
25+
src: 'node_modules/gridstack/dist/gridstack-all.js',
26+
dest: 'gridstack-all.js'
27+
},
28+
{
29+
src: 'node_modules/gridstack/dist/gridstack.min.css',
30+
dest: 'gridstack.min.css'
31+
},
32+
{
33+
src: 'node_modules/lucide/dist/umd/lucide.min.js',
34+
dest: 'lucide.min.js'
35+
}
36+
];
37+
38+
const GREEN = '\u001B[32m';
39+
const YELLOW = '\u001B[33m';
40+
const RED = '\u001B[31m';
41+
const RESET = '\u001B[0m';
42+
const GREEN_DOT = `${GREEN}${RESET}`;
43+
const YELLOW_DOT = `${YELLOW}${RESET}`;
44+
const RED_CROSS = `${RED}${RESET}`;
45+
46+
function logInfo(message) {
47+
console.log(` ${GREEN_DOT} ${message}`);
48+
}
49+
50+
function logWarn(message) {
51+
console.warn(` ${YELLOW_DOT} ${message}`);
52+
}
53+
54+
function logError(message) {
55+
console.error(` ${RED_CROSS} ${message}`);
56+
}
57+
58+
// Main function
59+
function copyWebUIAssets() {
60+
try {
61+
// Ensure destination directory exists
62+
fs.mkdirSync(destDir, { recursive: true });
63+
logInfo(`created directory ${destDir}`);
64+
65+
// Copy each file
66+
let copiedCount = 0;
67+
for (const fileName of filesToCopy) {
68+
const srcPath = path.join(srcDir, fileName);
69+
const destPath = path.join(destDir, fileName);
70+
71+
// Check if source file exists
72+
if (!fs.existsSync(srcPath)) {
73+
logWarn(`source file missing ${srcPath}`);
74+
continue;
75+
}
76+
77+
// Copy the file
78+
fs.copyFileSync(srcPath, destPath);
79+
logInfo(`copied ${fileName}`);
80+
copiedCount++;
81+
}
82+
83+
logInfo(`webui asset copy complete ${copiedCount}/${filesToCopy.length}`);
84+
85+
// Copy vendor libraries
86+
let vendorCount = 0;
87+
for (const vendor of vendorLibraries) {
88+
const srcPath = vendor.src;
89+
const destPath = path.join(destDir, vendor.dest);
90+
91+
// Check if source file exists
92+
if (!fs.existsSync(srcPath)) {
93+
logWarn(`vendor library missing ${srcPath}`);
94+
continue;
95+
}
96+
97+
// Copy the vendor library
98+
fs.copyFileSync(srcPath, destPath);
99+
logInfo(`copied vendor library ${vendor.dest}`);
100+
vendorCount++;
101+
}
102+
103+
logInfo(`vendor library copy complete ${vendorCount}/${vendorLibraries.length}`);
104+
105+
} catch (error) {
106+
logError(`error copying WebUI assets: ${error.message}`);
107+
process.exit(1);
108+
}
109+
}
110+
111+
// Run the script
112+
if (require.main === module) {
113+
copyWebUIAssets();
114+
}
115+
116+
module.exports = { copyWebUIAssets };

src/types/jsmpeg.d.ts

Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/**
2+
* @fileoverview Type definitions for @cycjimmy/jsmpeg-player
3+
*
4+
* Since the @cycjimmy/jsmpeg-player library doesn't provide official TypeScript
5+
* type definitions, this file provides type safety for the JSMpeg player used
6+
* for RTSP stream rendering via WebSocket.
7+
*
8+
* Based on JSMpeg.js library documentation and actual usage in the application.
9+
*
10+
* Also provides global type declarations for JSMpeg vendored locally in WebUI.
11+
*/
12+
13+
/**
14+
* Options for configuring the JSMpeg player
15+
*/
16+
export interface JSMpegPlayerOptions {
17+
/** Canvas element to render video to */
18+
canvas?: HTMLCanvasElement;
19+
/** Whether to start playing automatically */
20+
autoplay?: boolean;
21+
/** Whether to enable audio playback */
22+
audio?: boolean;
23+
/** Whether to loop playback */
24+
loop?: boolean;
25+
/** Whether to show controls */
26+
controls?: boolean;
27+
/** Callback when stream is established */
28+
onSourceEstablished?: () => void;
29+
/** Callback when stream completes */
30+
onSourceCompleted?: () => void;
31+
/** Callback on play event */
32+
onPlay?: () => void;
33+
/** Callback on pause event */
34+
onPause?: () => void;
35+
/** Callback on stalled event */
36+
onStalled?: () => void;
37+
/** Callback on video decode */
38+
onVideoDecode?: (decoder: unknown, time: number) => void;
39+
/** Callback on audio decode */
40+
onAudioDecode?: (decoder: unknown, time: number) => void;
41+
}
42+
43+
/**
44+
* JSMpeg Player instance for MPEG1 video playback
45+
*/
46+
export interface JSMpegPlayerInstance {
47+
/** Play the video stream */
48+
play(): void;
49+
/** Pause the video stream */
50+
pause(): void;
51+
/** Stop the video stream */
52+
stop(): void;
53+
/** Destroy the player and clean up resources */
54+
destroy(): void;
55+
/** Get the canvas element being used for rendering */
56+
readonly canvas: HTMLCanvasElement | null;
57+
/** Whether the player is currently playing */
58+
readonly isPlaying: boolean;
59+
}
60+
61+
/**
62+
* JSMpeg namespace containing Player constructor
63+
*/
64+
export interface JSMpegStatic {
65+
/**
66+
* Create a new JSMpeg player instance
67+
* @param url - WebSocket URL for MPEG1 stream
68+
* @param options - Player configuration options
69+
*/
70+
Player: new (url: string, options?: JSMpegPlayerOptions) => JSMpegPlayerInstance;
71+
}
72+
73+
declare module '@cycjimmy/jsmpeg-player' {
74+
/**
75+
* Default export is the JSMpeg static object
76+
*/
77+
const JSMpeg: JSMpegStatic;
78+
export default JSMpeg;
79+
}
80+
81+
/**
82+
* Global declaration for JSMpeg when vendored locally (e.g., in WebUI)
83+
*/
84+
declare global {
85+
const JSMpeg: {
86+
Player: new (url: string, options?: {
87+
canvas?: HTMLCanvasElement;
88+
autoplay?: boolean;
89+
audio?: boolean;
90+
loop?: boolean;
91+
controls?: boolean;
92+
onSourceEstablished?: () => void;
93+
onSourceCompleted?: () => void;
94+
onPlay?: () => void;
95+
onPause?: () => void;
96+
onStalled?: () => void;
97+
}) => {
98+
play(): void;
99+
pause(): void;
100+
stop(): void;
101+
destroy(): void;
102+
};
103+
};
104+
}
105+
106+
export {};
107+

0 commit comments

Comments
 (0)