feat: Add vision controls, function menu, and custom alert dialogs
- Add Vision menu with Camera (QRCode) and Barcode (Keyence) controls - Add Function menu with Manage, Log Viewer, and folder navigation - Add quick action buttons (Manual, Light, Print, Cancel) to header - Replace browser alert() with custom AlertDialog component - Add MachineBridge methods for vision, lighting, folders, and manual operations - Add WebSocketServer handlers for all new commands - Add communication layer methods for frontend-backend integration 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -431,6 +431,259 @@ class CommunicationLayer {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// ===== VISION CONTROL METHODS =====
|
||||
|
||||
private async sendVisionCommand(command: string, responseType: string): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
// WebView2 mode - direct call to C# methods
|
||||
return { success: false, message: 'Vision commands not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
if (!this.isConnected) {
|
||||
setTimeout(() => {
|
||||
if (!this.isConnected) reject({ success: false, message: "WebSocket connection timeout" });
|
||||
}, 2000);
|
||||
}
|
||||
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject({ success: false, message: "Vision command timeout" });
|
||||
}, 10000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === responseType) {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: command }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async cameraConnect(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('CAMERA_CONNECT', 'CAMERA_RESULT');
|
||||
}
|
||||
|
||||
public async cameraDisconnect(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('CAMERA_DISCONNECT', 'CAMERA_RESULT');
|
||||
}
|
||||
|
||||
public async cameraGetImage(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('CAMERA_GET_IMAGE', 'CAMERA_RESULT');
|
||||
}
|
||||
|
||||
public async cameraLiveView(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('CAMERA_LIVE_VIEW', 'CAMERA_RESULT');
|
||||
}
|
||||
|
||||
public async cameraReadTest(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('CAMERA_READ_TEST', 'CAMERA_RESULT');
|
||||
}
|
||||
|
||||
public async keyenceTriggerOn(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('KEYENCE_TRIGGER_ON', 'KEYENCE_RESULT');
|
||||
}
|
||||
|
||||
public async keyenceTriggerOff(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('KEYENCE_TRIGGER_OFF', 'KEYENCE_RESULT');
|
||||
}
|
||||
|
||||
public async keyenceGetImage(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('KEYENCE_GET_IMAGE', 'KEYENCE_RESULT');
|
||||
}
|
||||
|
||||
public async keyenceSaveImage(): Promise<{ success: boolean; message: string }> {
|
||||
return this.sendVisionCommand('KEYENCE_SAVE_IMAGE', 'KEYENCE_RESULT');
|
||||
}
|
||||
|
||||
// Light, Manual Print, Cancel Job commands
|
||||
public async toggleLight(): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Light control not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Light toggle timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'LIGHT_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: 'TOGGLE_LIGHT' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async openManualPrint(): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Manual print not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Manual print timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'MANUAL_PRINT_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: 'OPEN_MANUAL_PRINT' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async cancelJob(): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Cancel job not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Cancel job timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'CANCEL_JOB_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: 'CANCEL_JOB' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async openManage(): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Manage not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Open manage timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'MANAGE_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: 'OPEN_MANAGE' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async openManual(): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Manual not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Open manual timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'MANUAL_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: 'OPEN_MANUAL' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async openLogViewer(): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Log viewer not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Open log viewer timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'LOG_VIEWER_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: 'OPEN_LOG_VIEWER' }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async openFolder(command: string): Promise<{ success: boolean; message: string }> {
|
||||
if (isWebView && machine) {
|
||||
return { success: false, message: 'Folder open not yet implemented in WebView2 mode' };
|
||||
} else {
|
||||
return new Promise((resolve, reject) => {
|
||||
const timeoutId = setTimeout(() => {
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
reject(new Error('Open folder timeout'));
|
||||
}, 5000);
|
||||
|
||||
const handler = (data: any) => {
|
||||
if (data.type === 'FOLDER_RESULT') {
|
||||
clearTimeout(timeoutId);
|
||||
this.listeners = this.listeners.filter(cb => cb !== handler);
|
||||
resolve(data.data);
|
||||
}
|
||||
};
|
||||
|
||||
this.listeners.push(handler);
|
||||
this.ws?.send(JSON.stringify({ type: command }));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public async openProgramFolder(): Promise<{ success: boolean; message: string }> {
|
||||
return this.openFolder('OPEN_PROGRAM_FOLDER');
|
||||
}
|
||||
|
||||
public async openLogFolder(): Promise<{ success: boolean; message: string }> {
|
||||
return this.openFolder('OPEN_LOG_FOLDER');
|
||||
}
|
||||
|
||||
public async openScreenshotFolder(): Promise<{ success: boolean; message: string }> {
|
||||
return this.openFolder('OPEN_SCREENSHOT_FOLDER');
|
||||
}
|
||||
|
||||
public async openSavedDataFolder(): Promise<{ success: boolean; message: string }> {
|
||||
return this.openFolder('OPEN_SAVED_DATA_FOLDER');
|
||||
}
|
||||
}
|
||||
|
||||
export const comms = new CommunicationLayer();
|
||||
|
||||
Reference in New Issue
Block a user