feat(pose_3d): save/load/delete named poses
This commit is contained in:
1 parent
a81fc9acf9
commit
bb6796bfe3
1 file changed
+79
@@ -496,6 +496,84 @@ function bindJogAutoApply() {
|
||||
});
|
||||
}
|
||||
|
||||
// ----- named poses -----
|
||||
async function onSavePose() {
|
||||
const name = ($('p3PoseName').value || '').trim();
|
||||
if (!name) { alert('Inserisci un nome'); return; }
|
||||
if (!/^[A-Za-z0-9_-]{1,40}$/.test(name)) {
|
||||
alert('Nome: solo [A-Za-z0-9_-], 1-40 caratteri');
|
||||
return;
|
||||
}
|
||||
const side = state.active_side;
|
||||
const pose = state.target[side] || state.current[side];
|
||||
if (!pose) { alert('Nessuna posa da salvare'); return; }
|
||||
if (state.saved_poses[name]) {
|
||||
if (!confirm(`Posa "${name}" esiste già — sovrascrivere?`)) return;
|
||||
}
|
||||
try {
|
||||
await jsonFetch(`/api/pose_3d/poses/${encodeURIComponent(name)}`, {
|
||||
method: 'PUT', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({
|
||||
side, position: pose.position, quaternion: pose.quaternion,
|
||||
}),
|
||||
});
|
||||
$('p3PoseName').value = '';
|
||||
await pollState(); // refresh dropdown
|
||||
$('p3PoseSelect').value = name;
|
||||
} catch (e) {
|
||||
showError(`Salvataggio fallito: ${e.message}`);
|
||||
}
|
||||
}
|
||||
|
||||
async function onGoPose() {
|
||||
const name = $('p3PoseSelect').value;
|
||||
if (!name) { alert('Seleziona una posa dal dropdown'); return; }
|
||||
if (state.mode === 'jog') {
|
||||
if (!confirm(`Eseguire posa "${name}" SUL ROBOT REALE? (Jog mode)`)) return;
|
||||
}
|
||||
const dry_run = (state.mode === 'editor');
|
||||
clearError();
|
||||
try {
|
||||
const res = await jsonFetch(
|
||||
`/api/pose_3d/poses/${encodeURIComponent(name)}/go`,
|
||||
{
|
||||
method: 'POST', headers: { 'Content-Type': 'application/json' },
|
||||
body: JSON.stringify({ dry_run, precise: state.precise }),
|
||||
},
|
||||
);
|
||||
const r = res.result || {};
|
||||
if (r.reached_target === false || r.stalled === true) {
|
||||
showError(`Vai a "${name}": residual ${(r.position_error_mm||0).toFixed(1)} mm`);
|
||||
} else {
|
||||
$('p3Status').textContent = `✓ Posa "${name}" applicata` +
|
||||
(dry_run ? ' (simulato)' : '');
|
||||
$('p3Status').className = 'p3-status ok';
|
||||
}
|
||||
} catch (e) {
|
||||
showError(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
async function onDeletePose() {
|
||||
const name = $('p3PoseSelect').value;
|
||||
if (!name) { alert('Seleziona una posa dal dropdown'); return; }
|
||||
if (!confirm(`Cancellare definitivamente la posa "${name}"?`)) return;
|
||||
try {
|
||||
await jsonFetch(`/api/pose_3d/poses/${encodeURIComponent(name)}`, {
|
||||
method: 'DELETE',
|
||||
});
|
||||
await pollState();
|
||||
} catch (e) {
|
||||
showError(e.message);
|
||||
}
|
||||
}
|
||||
|
||||
function bindPoseButtons() {
|
||||
$('p3PoseSaveBtn').addEventListener('click', onSavePose);
|
||||
$('p3PoseGoBtn').addEventListener('click', onGoPose);
|
||||
$('p3PoseDelBtn').addEventListener('click', onDeletePose);
|
||||
}
|
||||
|
||||
// ----- init triggered on first activation -----
|
||||
let inited = false;
|
||||
function ensureInit() {
|
||||
@@ -511,6 +589,7 @@ function ensureInit() {
|
||||
bindModeControls();
|
||||
bindPreciseControl();
|
||||
bindJogAutoApply();
|
||||
bindPoseButtons();
|
||||
pollState();
|
||||
pollTimer = setInterval(pollState, POLL_MS);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user