fixes: timeAgo utc parse, reload clears unread, sync-event debug
- detail banner timeAgo: SQLite timestamps are UTC without tz marker, JS was parsing them as local. Fixed by appending Z when absent — same pattern chat uses. "2h ago" for a 30s-old update is gone. - banner Reload button now re-fires detail.opened so the collab-buckets plugin clears the red dot on the board card and calls mark-card-seen. Dismiss (×) still leaves the dot — that's the acknowledgement that nothing was actually read. - instrument /api/relay/poll with a sync_debug field so the JS can console.debug what happened on the sync-events sub-request (status, count, error body). Helps diagnose "no toast" reports. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
1 parent
1966f8f4c0
commit
4a668b7fc4
5 files changed
+26
-4
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
define('APP_NAME', 'hyprcrd');
|
define('APP_NAME', 'hyprcrd');
|
||||||
define('APP_VERSION', '1.8.0');
|
define('APP_VERSION', '1.8.1');
|
||||||
|
|
||||||
// Database path — writable directory, outside webroot
|
// Database path — writable directory, outside webroot
|
||||||
// DB_PATH / UPLOAD_DIR can be pre-defined by the Electron router for app isolation
|
// DB_PATH / UPLOAD_DIR can be pre-defined by the Electron router for app isolation
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "hyprcrd",
|
"name": "hyprcrd",
|
||||||
"version": "1.8.0",
|
"version": "1.8.1",
|
||||||
"description": "hyprcrd — self-hosted card manager",
|
"description": "hyprcrd — self-hosted card manager",
|
||||||
"main": "main.js",
|
"main": "main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
+8
-1
@@ -961,6 +961,7 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
// them. GET /api/sync-events on the relay auto-marks fetched events.
|
// them. GET /api/sync-events on the relay auto-marks fetched events.
|
||||||
// Best-effort — older relays won't have the endpoint.
|
// Best-effort — older relays won't have the endpoint.
|
||||||
$syncEvents = [];
|
$syncEvents = [];
|
||||||
|
$syncDebug = ['requested' => true];
|
||||||
$sch = curl_init(rtrim($relayUrl, '/') . '/api/sync-events');
|
$sch = curl_init(rtrim($relayUrl, '/') . '/api/sync-events');
|
||||||
curl_setopt_array($sch, [
|
curl_setopt_array($sch, [
|
||||||
CURLOPT_RETURNTRANSFER => true,
|
CURLOPT_RETURNTRANSFER => true,
|
||||||
@@ -970,14 +971,20 @@ if (str_starts_with($route, '/api/')) {
|
|||||||
$sResp = curl_exec($sch);
|
$sResp = curl_exec($sch);
|
||||||
$sStatus = curl_getinfo($sch, CURLINFO_HTTP_CODE);
|
$sStatus = curl_getinfo($sch, CURLINFO_HTTP_CODE);
|
||||||
curl_close($sch);
|
curl_close($sch);
|
||||||
|
$syncDebug['status'] = $sStatus;
|
||||||
if ($sStatus === 200) {
|
if ($sStatus === 200) {
|
||||||
$decoded = json_decode($sResp, true);
|
$decoded = json_decode($sResp, true);
|
||||||
if (is_array($decoded) && isset($decoded['events'])) {
|
if (is_array($decoded) && isset($decoded['events'])) {
|
||||||
$syncEvents = $decoded['events'];
|
$syncEvents = $decoded['events'];
|
||||||
|
$syncDebug['count'] = count($syncEvents);
|
||||||
|
} else {
|
||||||
|
$syncDebug['parse_error'] = substr((string)$sResp, 0, 200);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
$syncDebug['body'] = substr((string)$sResp, 0, 200);
|
||||||
}
|
}
|
||||||
|
|
||||||
echo json_encode(['ok' => true, 'pulled' => $pulled, 'sync_events' => $syncEvents]); exit;
|
echo json_encode(['ok' => true, 'pulled' => $pulled, 'sync_events' => $syncEvents, 'sync_debug' => $syncDebug]); exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
// List relay tenants (for the recipient picker)
|
// List relay tenants (for the recipient picker)
|
||||||
|
|||||||
@@ -340,6 +340,9 @@ function showSyncEventToast(ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function drainSyncEvents(relayRes) {
|
function drainSyncEvents(relayRes) {
|
||||||
|
if (relayRes?.sync_debug) {
|
||||||
|
console.debug('[sync-events]', relayRes.sync_debug);
|
||||||
|
}
|
||||||
const events = Array.isArray(relayRes?.sync_events) ? relayRes.sync_events : [];
|
const events = Array.isArray(relayRes?.sync_events) ? relayRes.sync_events : [];
|
||||||
for (const ev of events) showSyncEventToast(ev);
|
for (const ev of events) showSyncEventToast(ev);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,6 +116,10 @@ function showStaleBanner(fresh) {
|
|||||||
state.viewingCard = current;
|
state.viewingCard = current;
|
||||||
renderSidebar(current);
|
renderSidebar(current);
|
||||||
showContent(current);
|
showContent(current);
|
||||||
|
// Treat the reload as an explicit "I've now seen the new version"
|
||||||
|
// — re-fire detail.opened so collab-buckets clears the red dot
|
||||||
|
// on the board card and persists mark-card-seen to the backend.
|
||||||
|
window.hyprcrd?.hooks?.emit?.('detail.opened', { id: current.id });
|
||||||
}
|
}
|
||||||
dismissStaleBanner();
|
dismissStaleBanner();
|
||||||
});
|
});
|
||||||
@@ -123,7 +127,15 @@ function showStaleBanner(fresh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function timeAgo(iso) {
|
function timeAgo(iso) {
|
||||||
const t = new Date(iso).getTime();
|
if (!iso) return '';
|
||||||
|
// SQLite stores CURRENT_TIMESTAMP as UTC without a tz marker
|
||||||
|
// ("2026-04-14 12:34:56"). Without an explicit Z, JS parses it as
|
||||||
|
// local time — off by the tz offset (2h on CEST, hence "2h ago"
|
||||||
|
// for a 30-second-old update).
|
||||||
|
const normalized = String(iso).includes('T') || /[Zz]|[+-]\d\d:?\d\d$/.test(iso)
|
||||||
|
? iso
|
||||||
|
: iso.replace(' ', 'T') + 'Z';
|
||||||
|
const t = new Date(normalized).getTime();
|
||||||
if (!isFinite(t)) return '';
|
if (!isFinite(t)) return '';
|
||||||
const s = Math.max(0, (Date.now() - t) / 1000);
|
const s = Math.max(0, (Date.now() - t) / 1000);
|
||||||
if (s < 60) return `${Math.floor(s)}s ago`;
|
if (s < 60) return `${Math.floor(s)}s ago`;
|
||||||
|
|||||||
Reference in new issue
Block a user