openvibers/openvibe.network Commits

Needs you: Review opens an approval, the text never hides under the button (#650)

OP OpenVibers committed 6 days ago · eff2cba97c · 3 files, +22 −6

On a phone (openvibe.my, production, the probe) the Approve button covered the item's title (the body's grid items
kept min-width auto), the meta line showed an agent id (agt01M6…), and a one-tap Approve sat on "Run rm -rf …".
- An approval's button is Review, a link to the approval itself (what runs, Approve or Decline); Try again stays one
  tap (it repeats what already ran).
- The body's column is minmax(0, 1fr) with min-width 0 children; at 600 px and below the button goes under the text
  (44 px tall), lined up with it.
- An agent known only by its id is not shown by it.
Test: my-today (Review link, no Approve button, the raw id left out, Try again kept).

Changes

ddiff --git a/public/css/my.css b/public/css/my.css
iindex 174da66a..304342e1 100644
---- a/public/css/my.css
++++ b/public/css/my.css
@@@ -254,7 +254,8 @@ a.linked-item:hover{background:var(--bg-hover,var(--bg-card));transform:translat
.ny-list { display: grid; gap: 8px; }
.ny-item { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: 12px; background: var(--bg-secondary); border: 1px solid var(--border); }
.ny-ic { flex: none; width: 34px; height: 34px; display: grid; place-items: center; border-radius: 10px; background: color-mix(in srgb, var(--accent) 14%, var(--bg-input)); color: var(--accent-light); font-size: 14px; }
--.ny-body { flex: 1; min-width: 0; display: grid; gap: 2px; }
++.ny-body { flex: 1; min-width: 0; display: grid; grid-template-columns: minmax(0, 1fr); gap: 2px; }
++.ny-body > * { min-width: 0; }
.ny-body h3 { font-size: 14px; font-weight: 750; overflow-wrap: anywhere; }
.ny-body p { font-size: 12.5px; color: var(--text-secondary); line-height: 1.4; overflow-wrap: anywhere; }
.ny-meta { font-size: 11.5px; color: var(--text-muted); }
@@@ -262,7 +263,8 @@ a.linked-item:hover{background:var(--bg-hover,var(--bg-card));transform:translat
.ny-btn:hover, .ny-btn:focus-visible { filter: brightness(1.08); outline: none; }
.ny-btn:focus-visible { box-shadow: 0 0 0 3px color-mix(in srgb, var(--accent) 45%, transparent); }
.ny-btn[disabled] { opacity: .65; cursor: progress; }
--@media (max-width: 600px) { .ny { padding: 16px; } .ny-item { align-items: flex-start; flex-wrap: wrap; } .ny-btn { margin-left: 46px; } }
++/* A phone: the text takes the row and the button goes under it, lined up with the text (it covered the title). */
++@media (max-width: 600px) { .ny { padding: 16px; } .ny-item { align-items: flex-start; flex-wrap: wrap; } .ny-body { flex: 1 1 calc(100% - 46px); } .ny-btn { margin-left: 46px; min-height: 44px; } }
.td { display: grid; gap: 22px; margin: -8px 0 36px; }
.td-sec { display: grid; gap: 10px; min-width: 0; }
ddiff --git a/public/js/my/today.js b/public/js/my/today.js
iindex 9fc85a75..923c8ee9 100644
---- a/public/js/my/today.js
++++ b/public/js/my/today.js
@@@ -262,9 +262,11 @@ function nyHref(item) {
return /^https:\/\//.test(href) ? href : '#approvals';
}
++// An approval is never one tap from here: the hub shows a line, and a step may delete, spend or send. Review opens the
++// approval itself (what exactly runs, Approve or Decline). Try again stays one tap: it only repeats what already ran.
function nyButton(item, action) {
-- const label = action === 'approve' ? 'Approve' : action === 'retry' ? 'Try again' : 'Open';
-- if (action !== 'approve' && action !== 'retry') {
++ const label = action === 'approve' ? 'Review' : action === 'retry' ? 'Try again' : 'Open';
++ if (action !== 'retry') {
const href = nyHref(item);
const a = document.createElement('a');
a.className = 'ny-btn';
@@@ -336,7 +338,8 @@ function renderNeedsYou(doc) {
summary.textContent = item.summary;
body.append(summary);
}
-- if (item.agent) {
++ // The agent by its name; a raw id (agt_…, app_…) says nothing to a person, so it is left out.
++ if (item.agent && !/^(agt|app|svc|usr)[_0-9A-HJKMNP-TV-Z]{20,}$/i.test(String(item.agent))) {
const meta = document.createElement('span');
meta.className = 'ny-meta';
meta.textContent = item.agent;
ddiff --git a/test/my-today.test.js b/test/my-today.test.js
iindex d211e8b6..5cdddfb4 100644
---- a/test/my-today.test.js
++++ b/test/my-today.test.js
@@@ -155,10 +155,21 @@ assert.match(CSS, /@media \(min-width:1000px\)\{[\s\S]*\.settings\{display:grid;
assert.strictEqual(p.ids['needs-you-sub'].textContent, '2 things waiting');
const rows = p.ids['needs-you-list'].children;
assert.strictEqual(rows.length, 2);
-- assert.strictEqual(rows[0].all((c) => c.tagName === 'BUTTON')[0].textContent, 'Approve', 'an approval has its one button');
++ const review = rows[0].all((c) => c.tagName === 'A')[0];
++ assert.strictEqual(review.textContent, 'Review', 'an approval opens itself: never one tap from the hub');
++ assert.strictEqual(rows[0].all((c) => c.tagName === 'BUTTON').length, 0, 'no Approve button here');
assert.strictEqual(rows[0].all((c) => c.tagName === 'H3')[0].textContent, 'Send one email to the venue');
assert.strictEqual(rows[0].all((c) => c.tagName === 'P')[0].textContent, 'Trip planner asks to use mail.send');
assert.strictEqual(rows[1].all((c) => c.tagName === 'A')[0].href, 'https://openvibe.actor/tasks/tsk_1', 'an open item links its page');
++ // An agent known only by its id is not shown by it; Try again stays one tap.
++ p.sandbox.renderNeedsYou({ buckets: { waiting: [
++ { service: 'actor', id: 'apr_1', kind: 'approval', title: 'Run a command', agent: 'agt01M6VEKFK36XWYB3CSY1RE60YN', href: 'https://openvibe.actor/me/approvals/apr_1', actions: ['approve', 'open'] },
++ { service: 'actor', id: 'tsk_2', kind: 'agent_task', title: 'Summarise the inbox', href: 'https://openvibe.actor/tasks/tsk_2', actions: ['retry', 'open'] },
++ ] } });
++ const two = p.ids['needs-you-list'].children;
++ assert.ok(!/agt01M6/.test(two[0].textContent), 'a raw agent id is left out');
++ assert.strictEqual(two[0].all((c) => c.tagName === 'A')[0].href, 'https://openvibe.actor/me/approvals/apr_1', 'Review opens the approval');
++ assert.strictEqual(two[1].all((c) => c.tagName === 'BUTTON')[0].textContent, 'Try again');
p.sandbox.renderNeedsYou({ buckets: { waiting: [] } });
assert.strictEqual(p.ids['needs-you'].hidden, true, 'an empty queue leaves the section out');