openvibers/openvibe.bot Commits
Bot: Arrange shows only to the robot's owner (#411)
Changes
@@@ -755,7 +755,7 @@ function renderPanel({ robot, profile, role, allowed_commands = [], holdResendMsconst estop = ESTOP_ROLES.has(role) ? `<button type="button" class="estop" data-estop>${icon('stop')}<span>E-stop</span></button>`: (embed && role === 'watcher' ? `<button type="button" class="estop" data-estop hidden>${icon('stop')}<span>E-stop</span></button>` : '');const clear = role === 'owner' ? `<button type="button" class="estop-clear" data-estop-clear${latched ? '' : ' hidden'}>Clear e-stop</button>` : '';-- const arrangeButton = arrange && arrange.src++ const arrangeButton = arrange && arrange.src && role === 'owner'? `<button type="button" class="arrange-btn" data-arrange data-arrange-src="${esc(arrange.src || '')}" title="Arrange the controls">${icon('sliders')}<span>Arrange</span></button>` : '';const body = `<header class="estop-banner" data-estop-banner data-latched="${latched}">${embed ? '' : tryIt ? topbar('<span class="crumb">Try the panel</span>', '/') : topbar(`<span class="crumb">${esc(robot.name)}</span>`)}@@@ -972,7 +972,7 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limihasStick: !!overlayStickMarkup(profile, role === 'watcher' ? [] : domain.control.allowedFor(robot, role, profile)),canDrive,});-- const storedRaw = signedIn && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;++ const storedRaw = role === 'owner' && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;const fallbackLayout = surface.overlayDefaultLayout(catalog, device);const stored = usable(catalog, storedRaw, fallbackLayout);arrange = {@@@ -983,7 +983,7 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi};} else {const catalog = surface.controlsCatalog(profile);-- const storedRaw = signedIn && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;++ const storedRaw = role === 'owner' && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;const fallbackLayout = surface.defaultLayout(catalog, device);const stored = usable(catalog, storedRaw, fallbackLayout);let src = null;@@@ -41,6 +41,14 @@ assert.ok(/data-ov-arranged="true"/.test(withLayout), 'a stored layout draws theassert.ok(/grid-column:1 \/ span 2/.test(withLayout), 'the stick is drawn in its cells');assert.ok(/data-ov-part="battery"[^>]*hidden/.test(withLayout) || /hidden[^>]*data-ov-part="battery"/.test(withLayout), 'a hidden readout is hidden before first paint');++// Only the owner gets Arrange: a framed, signed-out watcher of a public robot sees the controls, not the editor.++const watched = render.renderPanel({++ robot, profile, role: 'watcher', allowed_commands: [], mode: 'embed', view: 'panel', signedIn: false,++ arrange: { catalog, parts: surface.partsOf(profile), layout: defaults, device: 'phone', signedIn: false, layoutSource: 'default', src: '/shared/ov-arrange.js' },++});++assert.ok(!watched.includes('data-arrange'), 'a watcher has no Arrange button');++assert.ok(watched.includes('data-ov-part="stop"'), 'but the parts are still there');++const overlayCatalog = surface.overlayCatalog(profile, { slider: { name: 'head' }, hasStick: true, canDrive: false });const overlay = render.renderPanel({robot, profile, role: 'watcher', allowed_commands: [], mode: 'embed', view: 'overlay', signedIn: false,
@@ -755,7 +755,7 @@ function renderPanel({ robot, profile, role, allowed_commands = [], holdResendMs
@@ -755,7 +755,7 @@ function renderPanel({ robot, profile, role, allowed_commands = [], holdResendMs
const estop = ESTOP_ROLES.has(role) ? `<button type="button" class="estop" data-estop>${icon('stop')}<span>E-stop</span></button>`
const estop = ESTOP_ROLES.has(role) ? `<button type="button" class="estop" data-estop>${icon('stop')}<span>E-stop</span></button>`
: (embed && role === 'watcher' ? `<button type="button" class="estop" data-estop hidden>${icon('stop')}<span>E-stop</span></button>` : '');
: (embed && role === 'watcher' ? `<button type="button" class="estop" data-estop hidden>${icon('stop')}<span>E-stop</span></button>` : '');
const clear = role === 'owner' ? `<button type="button" class="estop-clear" data-estop-clear${latched ? '' : ' hidden'}>Clear e-stop</button>` : '';
const clear = role === 'owner' ? `<button type="button" class="estop-clear" data-estop-clear${latched ? '' : ' hidden'}>Clear e-stop</button>` : '';
- const arrangeButton = arrange && arrange.src
+ const arrangeButton = arrange && arrange.src && role === 'owner'
? `<button type="button" class="arrange-btn" data-arrange data-arrange-src="${esc(arrange.src || '')}" title="Arrange the controls">${icon('sliders')}<span>Arrange</span></button>` : '';
? `<button type="button" class="arrange-btn" data-arrange data-arrange-src="${esc(arrange.src || '')}" title="Arrange the controls">${icon('sliders')}<span>Arrange</span></button>` : '';
const body = `<header class="estop-banner" data-estop-banner data-latched="${latched}">
const body = `<header class="estop-banner" data-estop-banner data-latched="${latched}">
${embed ? '' : tryIt ? topbar('<span class="crumb">Try the panel</span>', '/') : topbar(`<span class="crumb">${esc(robot.name)}</span>`)}
${embed ? '' : tryIt ? topbar('<span class="crumb">Try the panel</span>', '/') : topbar(`<span class="crumb">${esc(robot.name)}</span>`)}
@@ -972,7 +972,7 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi
@@ -972,7 +972,7 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi
hasStick: !!overlayStickMarkup(profile, role === 'watcher' ? [] : domain.control.allowedFor(robot, role, profile)),
hasStick: !!overlayStickMarkup(profile, role === 'watcher' ? [] : domain.control.allowedFor(robot, role, profile)),
canDrive,
canDrive,
});
});
- const storedRaw = signedIn && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;
+ const storedRaw = role === 'owner' && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;
const fallbackLayout = surface.overlayDefaultLayout(catalog, device);
const fallbackLayout = surface.overlayDefaultLayout(catalog, device);
const stored = usable(catalog, storedRaw, fallbackLayout);
const stored = usable(catalog, storedRaw, fallbackLayout);
arrange = {
arrange = {
@@ -983,7 +983,7 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi
@@ -983,7 +983,7 @@ function createWebRoutes(config, { domain = null, sim = null, onvif = null, limi
};
};
} else {
} else {
const catalog = surface.controlsCatalog(profile);
const catalog = surface.controlsCatalog(profile);
- const storedRaw = signedIn && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;
+ const storedRaw = role === 'owner' && token ? await layoutStore.activeLayout({ config, token, surface: catalog.id, device }) : null;
const fallbackLayout = surface.defaultLayout(catalog, device);
const fallbackLayout = surface.defaultLayout(catalog, device);
const stored = usable(catalog, storedRaw, fallbackLayout);
const stored = usable(catalog, storedRaw, fallbackLayout);
let src = null;
let src = null;
@@ -41,6 +41,14 @@ assert.ok(/data-ov-arranged="true"/.test(withLayout), 'a stored layout draws the
@@ -41,6 +41,14 @@ assert.ok(/data-ov-arranged="true"/.test(withLayout), 'a stored layout draws the
assert.ok(/grid-column:1 \/ span 2/.test(withLayout), 'the stick is drawn in its cells');
assert.ok(/grid-column:1 \/ span 2/.test(withLayout), 'the stick is drawn in its cells');
assert.ok(/data-ov-part="battery"[^>]*hidden/.test(withLayout) || /hidden[^>]*data-ov-part="battery"/.test(withLayout), 'a hidden readout is hidden before first paint');
assert.ok(/data-ov-part="battery"[^>]*hidden/.test(withLayout) || /hidden[^>]*data-ov-part="battery"/.test(withLayout), 'a hidden readout is hidden before first paint');
+// Only the owner gets Arrange: a framed, signed-out watcher of a public robot sees the controls, not the editor.
+const watched = render.renderPanel({
+ robot, profile, role: 'watcher', allowed_commands: [], mode: 'embed', view: 'panel', signedIn: false,
+ arrange: { catalog, parts: surface.partsOf(profile), layout: defaults, device: 'phone', signedIn: false, layoutSource: 'default', src: '/shared/ov-arrange.js' },
+});
+assert.ok(!watched.includes('data-arrange'), 'a watcher has no Arrange button');
+assert.ok(watched.includes('data-ov-part="stop"'), 'but the parts are still there');
+
const overlayCatalog = surface.overlayCatalog(profile, { slider: { name: 'head' }, hasStick: true, canDrive: false });
const overlayCatalog = surface.overlayCatalog(profile, { slider: { name: 'head' }, hasStick: true, canDrive: false });
const overlay = render.renderPanel({
const overlay = render.renderPanel({
robot, profile, role: 'watcher', allowed_commands: [], mode: 'embed', view: 'overlay', signedIn: false,
robot, profile, role: 'watcher', allowed_commands: [], mode: 'embed', view: 'overlay', signedIn: false,