Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
a38d06d
Rework camera view with consistent navbar and offline message
Q1WP Dec 4, 2025
7cf748e
Modernize files view with consistent navbar and improved styling
Q1WP Dec 4, 2025
5f23b5b
Modernize camera and files views with consistent UI
Q1WP Dec 4, 2025
82f4d56
Modernize UI with consistent dark navbar across all views
Q1WP Dec 4, 2025
98eee49
Modernize UI with consistent dark navbar, fix files breadcrumbs and d…
Q1WP Dec 4, 2025
6fb7b32
Fix files breadcrumbs and restore upload button in dialog
Q1WP Dec 4, 2025
8c4915a
Remove duplicate Upload/New Folder buttons from Files view navbar
Q1WP Dec 4, 2025
68cc571
Polish control page UI: axis table, macros, info tables, tabs
Q1WP Dec 4, 2025
d10e81e
Refine control page: MDI buttons, I/O Pins layout, Power styling
Q1WP Dec 4, 2025
258acd3
Fix axis buttons, power faults layout, I/O pins compact styling
Q1WP Dec 4, 2025
858d4a9
Fix axis buttons, I/O pins layout, page padding, camera visibility
Q1WP Dec 4, 2025
e622ca9
Fix axis button icons, I/O pins layout, camera default
Q1WP Dec 4, 2025
a79469c
Fix I/O pins table divider centering
Q1WP Dec 4, 2025
43e69e2
Update axis button icons
Q1WP Dec 4, 2025
0aacf35
Fix I/O pins table layout and axis button icons
Q1WP Dec 4, 2025
1c5b0ea
Table style update
Q1WP Dec 4, 2025
e9e7647
Axis button improvements
Q1WP Dec 4, 2025
3b2c723
Add logout button to Service and Macros navbars
Q1WP Dec 5, 2025
5f6f3f0
Consistent navbar pattern across Settings, Service, and Macros
Q1WP Dec 5, 2025
a8d04c6
Consistent navbar pattern across Settings, Service, and Macros
Q1WP Dec 5, 2025
0e3d71c
Mobile responsive improvements
Q1WP Dec 5, 2025
da36530
Mobile responsive improvements
Q1WP Dec 5, 2025
17dadae
Power tab table improvements: transpose layout and streamline motor r…
Q1WP Dec 5, 2025
bdceb35
Responsive UI improvements: settings pages, console, WiFi dialogs, an…
Q1WP Dec 6, 2025
68fab7c
I/O settings table width and dropdown sizing
Q1WP Dec 6, 2025
920e7cc
feat(ui): console card layout, settings polish, editor height
Q1WP Dec 6, 2025
c0bf6df
fix: Editor height and Messages tab card clipping
Q1WP Dec 7, 2025
66c0e34
fix: increase CodeMirror editor height
Q1WP Dec 7, 2025
33b8228
Fix CodeMirror height
Q1WP Dec 7, 2025
c203b5d
Fix CodeMirror editor height - use fixed pixel values
Q1WP Dec 7, 2025
b488e38
Fixed duplicate listeners
Q1WP Dec 7, 2025
ef7b471
fix(ui): restore USB drive access, fix layout on small screens, fix e…
Q1WP Dec 18, 2025
c764439
Fix dropdown hover and CodeMirror height
Q1WP Dec 18, 2025
6fd1202
Fix editor height, settings navbar, and files location UI
Q1WP Dec 18, 2025
5021d3b
Fix CodeMirror height and settings mobile issues
Q1WP Dec 18, 2025
90eb631
Fix CodeMirror height and settings mobile dots position
Q1WP Dec 18, 2025
d559a95
Fix settings mobile navbar - dots position and horizontal scroll
Q1WP Dec 18, 2025
e4e8cfd
Control page redesign: User panel, column selector, fullscreen
Q1WP Dec 23, 2025
8e48c4f
Refine control page UI: icon buttons, jog modal, layout fixes
Q1WP Dec 23, 2025
9cfc52f
UI polish: fullscreen icons, action order, jog layout, panel height
Q1WP Dec 23, 2025
c3db2d9
Fix header icon sizes, panel height, jog modal width
Q1WP Dec 23, 2025
b257406
UI fixes: MDI sizing, panel height, state column, messages clear
Q1WP Dec 24, 2025
0c5e49c
UI polish: sidebar cursor, MDI scroll, tab-level Clear
Q1WP Dec 24, 2025
dddf0bf
UI polish: MDI history scroll fix, Clear button styling
Q1WP Dec 24, 2025
ce3f55e
UI polish: MDI history scroll, Clear/Macros button styling
Q1WP Dec 24, 2025
c444e60
Mobile responsive fixes
Q1WP Dec 25, 2025
2919f01
Mobile responsive tweaks.
Q1WP Dec 25, 2025
3f65a92
Mobile responsive tweaks
Q1WP Dec 25, 2025
36b4f2a
fix: mobile responsive issues - overflow, jog modal, JS error
Q1WP Dec 25, 2025
df48698
Jog modal tweaks
Q1WP Dec 25, 2025
88f783a
Css selector changes.
Q1WP Dec 30, 2025
13a0b21
Css tweaks for jog controls
Q1WP Dec 30, 2025
21f5fdd
Fix, jogging bug
Q1WP Dec 30, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 162 additions & 14 deletions src/js/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,22 @@ module.exports = new Vue({
config: {
settings: {units: 'METRIC'},
motors: [{}, {}, {}, {}],
tool: {}, // FIX: Initialize tool config for reactivity
version: '<loading>'
},
state: {messages: []},
// FIX: Initialize state properties for Vue 1.x reactivity
// Properties must exist before Vue processes the component
state: {
messages: [],
service_due_count: 0,
s: 0, // Spindle speed - needed for popupMessagesHeader reactivity
xx: '', // Machine state
line: 0, // Current line
v: 0, // Velocity
feed: 0, // Feed rate
speed: 0, // Programmed speed
tool: 0 // Current tool
},
crosshair: cookie.get_bool('crosshair', false),
selected_program: new Program(this.$api, cookie.get('selected-path')),
active_program: undefined,
Expand All @@ -56,7 +69,15 @@ module.exports = new Vue({
errorMessage: '',
checkedUpgrade: false,
latestVersion: '',
webGLSupported: util.webgl_supported()
webGLSupported: util.webgl_supported(),
// Track if we've initialized after connect
initialized: false,
// Alert dismissal state (session-based, resets on browser close)
upgrade_dismissed: sessionStorage.getItem('upgrade_dismissed') === 'true',
service_dismissed: sessionStorage.getItem('service_dismissed') === 'true',
// Fullscreen state
is_fullscreen: false

}
},

Expand All @@ -69,6 +90,8 @@ module.exports = new Vue({
'view-editor': require('./view-editor'),
'view-settings': require('./view-settings'),
'view-files': require('./view-files'),
'view-macros': require('./view-macros'),
'view-service': require('./view-service'),
'view-camera': {template: '#view-camera-template'},
'view-docs': require('./view-docs')
},
Expand All @@ -78,15 +101,50 @@ module.exports = new Vue({
crosshair() {cookie.set_bool('crosshair', this.crosshair)},


'state.active_program'() {
let path = this.state.active_program
if (!path || path == '<mdi>') this.active_program = undefined
else new Program(this.$api, path)
// Watch for active_program changes from server
// Only update the active_program object - don't clear selected_program here
// (selected_program should persist through macro runs)
'state.active_program'(path) {
if (!path || path == '<mdi>') {
this.active_program = undefined
} else {
this.active_program = new Program(this.$api, path)
}
},


// Watch for e-stop state to clear programs
'state.xx'(state) {
if (state == 'ESTOPPED') {
// Clear programs on e-stop for safety
this.clear_selected_program()
}
},


'state.first_file'(value) {
if (!this.selected_program.path) this.select_path(value)
// Only auto-select first file if we have no selection
if (!this.selected_program.path && value) {
this.select_path(value)
}
},


// Reset upgrade dismissal when version changes
latestVersion(newVersion, oldVersion) {
if (oldVersion && newVersion !== oldVersion) {
this.upgrade_dismissed = false
sessionStorage.removeItem('upgrade_dismissed')
}
},


// Reset service dismissal when due count changes (new items become due)
'state.service_due_count'(newCount, oldCount) {
if (oldCount !== undefined && newCount > oldCount) {
this.service_dismissed = false
sessionStorage.removeItem('service_dismissed')
}
}
},

Expand Down Expand Up @@ -120,12 +178,6 @@ module.exports = new Vue({
},


async update() {
await this.update()
this.parse_hash()
},


error(msg) {
// Honor user error blocking
if (Date.now() - this.errorTimeoutStart < this.errorTimeout * 1000)
Expand Down Expand Up @@ -160,9 +212,45 @@ module.exports = new Vue({
},


// Dynamic header for GCode messages modal showing spindle speed
// Shows real-time spindle speed during M0 pause when tool is configured
popupMessagesHeader() {
let header = 'GCode Messages'

// Show spindle speed when tool is configured (not Disabled)
// NOTE: Access state.s unconditionally for Vue 1.x reactivity tracking
let toolType = this.config.tool && this.config.tool['tool-type']
let speed = parseFloat(this.state.s)

if (toolType && toolType !== 'Disabled' && !isNaN(speed)) {
header += ' - ' + Math.round(speed) + ' RPM'
}

return header
},


show_upgrade() {
if (!this.latestVersion) return false
return util.compare_versions(this.config.version, this.latestVersion) < 0
},


show_upgrade_alert() {
return this.show_upgrade && !this.upgrade_dismissed
},


show_service_alert() {
let count = this.state.service_due_count || 0
return count > 0 && !this.service_dismissed
},


camera_available() {
// Use state from backend, default to true if not yet received
return this.state.camera_available !== false

}
},

Expand Down Expand Up @@ -193,10 +281,27 @@ module.exports = new Vue({
}

this.check_login()

// Listen for fullscreen changes (e.g., user presses Escape)
document.addEventListener('fullscreenchange', () => {
this.is_fullscreen = !!document.fullscreenElement
})
},


methods: {
dismiss_upgrade() {
this.upgrade_dismissed = true
sessionStorage.setItem('upgrade_dismissed', 'true')
},


dismiss_service() {
this.service_dismissed = true
sessionStorage.setItem('service_dismissed', 'true')
},


async check_login() {
this.authorized = await this.$api.get('auth/login')
},
Expand Down Expand Up @@ -370,14 +475,40 @@ module.exports = new Vue({
},


select_path(path) {
// Clear selected program and cookie
clear_selected_program() {
cookie.set('selected-path', '')
this.selected_program = new Program(this.$api, '')
// Broadcast that program was cleared so views can update
this.$broadcast('program-cleared')
},


// Handle re-selecting same path to ensure fresh file content
select_path(path, force) {
if (path && this.selected_program.path != path) {
cookie.set('selected-path', path)
this.selected_program = new Program(this.$api, path)
} else if (path && force) {
// Same path but force refresh - invalidate cached data
this.selected_program.invalidate()
}

return this.selected_program
},


// Reload current program - creates new instance to force fresh fetch
// Used after file upload to ensure new content is displayed
reload_selected_program() {
if (this.selected_program && this.selected_program.path) {
let path = this.selected_program.path
// Create new Program instance - guarantees fresh data fetch
this.selected_program = new Program(this.$api, path)
// Broadcast to trigger reload in view-control
this.$broadcast('program-reloaded')
}
},


edit(path) {
Expand All @@ -389,6 +520,23 @@ module.exports = new Vue({
view(path) {
this.select_path(path)
location.hash = 'viewer'
},


toggle_fullscreen() {
if (!document.fullscreenElement) {
document.documentElement.requestFullscreen().then(() => {
this.is_fullscreen = true
}).catch(err => {
console.warn('Fullscreen request failed:', err)
})
} else {
document.exitFullscreen().then(() => {
this.is_fullscreen = false
}).catch(err => {
console.warn('Exit fullscreen failed:', err)
})
}
}
}
})
8 changes: 7 additions & 1 deletion src/js/axis-control.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,23 @@

module.exports = {
template: '#axis-control-template',
props: ['axes', 'colors', 'enabled', 'adjust', 'step'],
props: ['axes', 'colors', 'enabled', 'adjust', 'step', 'disabled'],


methods: {
jog(axis, ring, direction) {
// Prevent jogging when disabled (e.g., program is running)
if (this.disabled) return

let value = direction * this.value(ring)
this.$dispatch(this.step ? 'step' : 'jog', this.axes[axis], value)
},


release(axis) {
// NOTE: Do NOT check this.disabled here!
// When jog starts, machine state changes to JOGGING, which sets disabled=true.
// If we check disabled here, the stop command (jog 0) never gets sent.
if (!this.step) this.$dispatch('jog', this.axes[axis], 0)
},

Expand Down
2 changes: 1 addition & 1 deletion src/js/axis-row.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
module.exports = {
template: '#axis-row-template',
replace: true,
props: ['axis'],
props: ['axis', 'showOffset', 'showAbsolute', 'showState'],


data() {
Expand Down
36 changes: 36 additions & 0 deletions src/js/console.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,14 @@ module.exports = {
template: '#console-template',


props: {
showToolbar: {
type: Boolean,
default: true
}
},


data() {
return {messages: messages}
},
Expand Down Expand Up @@ -76,11 +84,39 @@ module.exports = {
// Event on errors
if (msg.level == 'error' || msg.level == 'critical')
this.$dispatch('error', msg)
},


// Allow parent to trigger clear via event
'clear-console'() {
this.clear()
}
},


methods: {
clear() {messages.splice(0, messages.length)},


copyMessage(msg) {
// Format message for clipboard
let text = '[' + (msg.level || 'info').toUpperCase() + ']'
if (msg.source) text += ' ' + msg.source
if (msg.where) text += ' @ ' + msg.where
text += ': ' + msg.msg

// Copy to clipboard
if (navigator.clipboard && navigator.clipboard.writeText) {
navigator.clipboard.writeText(text)
} else {
// Fallback for older browsers
let textarea = document.createElement('textarea')
textarea.value = text
document.body.appendChild(textarea)
textarea.select()
document.execCommand('copy')
document.body.removeChild(textarea)
}
}
}
}
Loading