Changeset a29c8c8 in Klonkt for src/assets/js/guardian.js


Ignore:
Timestamp:
08/07/2026 01:51:38 PM (5 weeks ago)
Author:
roboburr <roboburr@…>
Branches:
main
Children:
7cfe35a
Parents:
792af53
git-author:
Robin <roboburr@…> (08/07/2026 01:51:36 PM)
git-committer:
roboburr <roboburr@…> (08/07/2026 01:51:38 PM)
Message:

Een hulpvraag oppikken en afsluiten, zichtbaar voor alle guardians (shaer-lgo)

Een hulpvraag (5.2.1) gaat naar ALLE guardians van een kind, op verschillende
servers. Zonder gedeelde staat denken er twee dat de ander het oppakt -- precies
het scenario waar de reddingsboei voor bestaat. Tot nu toe droeg een hulpvraag
geen enkele staat: een vlag op ap_mentions, verder niets.

DE FAALSTAND IS HIER NIET VEILIG, en dat stuurt het hele ontwerp. Bij een gate is
"dicht" het veilige antwoord. Hier is de faalstand "iedereen denkt dat het
geregeld is", en dat is gevaarlijker dan geen markering. Daarom staat een
hulpvraag bij twijfel OPEN: een lege lijst, een rij die we niet kunnen lezen, een
soort die we niet kennen -- alles wat geen expliciete afsluiting is telt als
"er wacht nog iemand".

Twee besluiten van Bart zitten in de vorm.

OPGEPIKT mag stapelen en vervalt niet, maar veroudert zichtbaar. Twee mensen die
tegelijk reageren op een kind is geen probleem; twee die allebei niets doen omdat
de ander het "geclaimd" had, wel. En een signaal dat vanzelf verdwijnt laat een
hulpvraag er onaangeroerd uitzien terwijl er iemand mee bezig is -- dus het blijft
staan en toont hoe oud het is.

AFGEHANDELD kent GEEN terugdraai. Sluiten gaat met een stevige bevestiging (geen
window.confirm, zelfde lijn als het loslaten van een ward), en leeft de vraag
daarna nog, dan wordt hij opnieuw gesteld -- een nieuwe hulpvraag. Er wordt niets
herschreven, er wordt toegevoegd. Een test bewaakt dat er geen undo() of
reopen() bestaat.

Geen nieuw protocol: de markering is een gewone directe note met een
shaer:-eigenschap, net als de zwaai en de afwezigheidsmelding. Daardoor reist hij
over de bestaande bezorging, ziet de WARD hem als bericht ("er komt iemand") en
houden de mede-guardians er staat aan over. Naar de ward en naar de andere
guardians tegelijk.

De eigen kopie wordt meteen weggeschreven, voordat er bezorgd is: het scherm van
degene die klikt hoort niet te liegen omdat een andere server traag is.

11 tests op het pure stuk. Gecontroleerd dat ze bijten: laat helpStatus altijd
"afgehandeld" zeggen en er vallen er vijf om. nl/en/de. Suite 576/576.

Niet gedekt: de weergave zelf (client-JS), en er is geen guardianship op dev om
het end-to-end te zien lopen.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • src/assets/js/guardian.js

    r792af53 ra29c8c8  
    7272      card.appendChild(a);
    7373    }
     74    card.appendChild(helpState(h));
    7475    return card;
     76  }
     77
     78  /** Hoe lang geleden, grof. Een oppik vervalt niet maar hoort wel te verouderen. */
     79  function ago(ms) {
     80    var u = Math.floor(ms / 3600000);
     81    if (u < 1) return T.help_just_now || 'just now';
     82    if (u < 24) return (T.help_hours || '{n}h ago').replace('{n}', u);
     83    return (T.help_days || '{n}d ago').replace('{n}', Math.floor(u / 24));
     84  }
     85
     86  /**
     87   * De gedeelde staat van een hulpvraag (shaer-lgo): wie er al op af is, of het
     88   * is afgesloten, en de twee knoppen.
     89   *
     90   * De faalstand hier is NIET veilig: 'iedereen denkt dat het geregeld is' is
     91   * gevaarlijker dan geen markering. Dus bij twijfel toont dit OPEN, en een oude
     92   * oppik verkleurt in plaats van te verdwijnen -- anders ziet een hulpvraag er
     93   * onaangeroerd uit terwijl er iemand mee bezig is.
     94   */
     95  function helpState(h) {
     96    var st = h.state || { open: true, pickedUpBy: [], handled: null, ageMs: null };
     97    var box = el('div', 'g-help-state');
     98
     99    if (st.handled) {
     100      var wie = st.handled.handle || handleOf(st.handled.uri);
     101      box.appendChild(el('div', 'g-help-done', (T.help_handled_by || 'Handled by {who}').replace('{who}', wie)));
     102      // Geen terugdraaiknop: leeft de vraag nog, dan wordt hij opnieuw gesteld.
     103      box.appendChild(el('p', 'small g-empty', T.help_handled_note || ''));
     104      return box;
     105    }
     106
     107    (st.pickedUpBy || []).forEach(function (p) {
     108      var line = (T.help_picked_by || '{who} is looking into this').replace('{who}', p.handle || handleOf(p.uri));
     109      box.appendChild(el('div', 'g-help-pick', line));
     110    });
     111    // Oud, maar niet weg. Dit is het verschil tussen 'er is iemand mee bezig' en
     112    // 'er was ooit iemand mee bezig'.
     113    if (st.ageMs != null && st.ageMs > 3600000) {
     114      box.appendChild(el('div', 'g-help-age small', ago(st.ageMs)));
     115    }
     116
     117    var row = el('div', 'row');
     118    var mij = (st.pickedUpBy || []).some(function (p) { return p.uri === S.me; });
     119    if (!mij) {
     120      var pick = el('button', 'small', T.help_pick || 'I am on it');
     121      pick.addEventListener('click', function () { markHelp(h, 'pickup', pick); });
     122      row.appendChild(pick);
     123    }
     124    var done = el('button', 'quiet small', T.help_close || 'Mark handled');
     125    // Een stevige bevestiging, en nooit een window.confirm: dat verstopt een
     126    // uitleg achter een OK die mensen wegklikken. Zelfde lijn als het loslaten
     127    // van een ward.
     128    done.addEventListener('click', function () {
     129      done.hidden = true;
     130      var ask = el('div', 'g-confirm');
     131      ask.appendChild(el('p', 'small', T.help_close_ask || ''));
     132      var ja = el('button', 'small', T.help_close_yes || 'Yes, handled');
     133      ja.addEventListener('click', function () { markHelp(h, 'handled', ja); });
     134      var nee = el('button', 'quiet small', T.release_no || 'No');
     135      nee.addEventListener('click', function () { ask.remove(); done.hidden = false; });
     136      ask.appendChild(ja); ask.appendChild(nee);
     137      box.appendChild(ask);
     138    });
     139    row.appendChild(done);
     140    box.appendChild(row);
     141    return box;
     142  }
     143
     144  function markHelp(h, kind, btn) {
     145    if (btn) btn.disabled = true;
     146    fetch('/guardian/api/help/' + kind, {
     147      method: 'POST', headers: { 'Content-Type': 'application/json' },
     148      body: JSON.stringify({ note: h.object_uri, ward: h.actor_uri, site: S.site }),
     149    }).then(refresh).catch(function () { if (btn) btn.disabled = false; });
    75150  }
    76151
Note: See TracChangeset for help on using the changeset viewer.