(slicer = { name: '', path: '' })
| 4 | let slicerEntries = []; |
| 5 | |
| 6 | function suggestSlicerNameFromPath(slicerPath) { |
| 7 | const base = String(slicerPath || '').split(/[/\\]/).pop() || ''; |
| 8 | const withoutExt = base.replace(/\.(exe|app|appimage|dmg)$/i, ''); |
| 9 | const spaced = withoutExt.replace(/[-_]+/g, ' ').replace(/\s+/g, ' ').trim(); |
| 10 | if (!spaced) return ''; |
| 11 | return spaced.replace(/\b[a-z]/g, (c) => c.toUpperCase()); |
| 12 | } |
| 13 | |
| 14 | function applySlicerPathToEntry(entryEl, filePath) { |
| 15 | if (!entryEl || !filePath) return; |
| 16 | const pathInput = entryEl.querySelector('.slicer-path'); |
| 17 | const nameInput = entryEl.querySelector('.slicer-name'); |
| 18 | if (pathInput) pathInput.value = filePath; |
| 19 | if (nameInput && !nameInput.value.trim()) { |
| 20 | nameInput.value = suggestSlicerNameFromPath(filePath); |
| 21 | } |
| 22 | } |
| 23 | |
| 24 | async function createSlicerEntry(slicer = { name: '', path: '' }) { |
| 25 | const template = document.getElementById('slicer-entry-template'); |
| 26 | if (!template) { |
| 27 | console.error('Slicer entry template not found'); |
| 28 | return null; |
| 29 | } |
| 30 | |
| 31 | const entry = template.content.cloneNode(true); |
| 32 | const container = entry.querySelector('.slicer-entry'); |
| 33 | const nameInput = entry.querySelector('.slicer-name'); |
| 34 | const pathInput = entry.querySelector('.slicer-path'); |
| 35 | |
| 36 | // Generate unique IDs for the inputs to avoid conflicts |
| 37 | const uniqueId = Date.now().toString() + Math.random().toString(36).substr(2, 9); |
| 38 | nameInput.id = `slicer-name-${uniqueId}`; |
| 39 | pathInput.id = `slicer-path-${uniqueId}`; |
| 40 | |
| 41 | // Set initial values and store them in data attributes |
| 42 | nameInput.value = slicer.name || ''; |
| 43 | pathInput.value = slicer.path || ''; |
| 44 | nameInput.dataset.originalValue = slicer.name || ''; |
| 45 | pathInput.dataset.originalValue = slicer.path || ''; |
| 46 | |
| 47 | // Always make both fields editable (never readonly) - users should be able to type name before path |
| 48 | nameInput.removeAttribute('readonly'); |
| 49 | nameInput.disabled = false; |
| 50 | pathInput.removeAttribute('readonly'); |
| 51 | pathInput.disabled = false; |
| 52 | |
| 53 | // Check if we're in server mode |
| 54 | const serverMode = await window.electron.isServerMode().catch(() => false); |
| 55 | |
| 56 | // Update placeholder for path field in server mode |
| 57 | if (serverMode) { |
| 58 | pathInput.placeholder = 'Enter slicer path on your workstation'; |
| 59 | } |
| 60 | |
| 61 | // If user pastes/types a path first, fill an empty name from the executable |
| 62 | pathInput.addEventListener('change', () => { |
| 63 | if (!nameInput.value.trim() && pathInput.value.trim()) { |
no outgoing calls
no test coverage detected