@decentnetwork/beagle-ui 0.2.28 → 0.2.30
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/beagle-ui.js +224 -111
- package/package.json +1 -1
package/dist/beagle-ui.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const BEAGLE_UI_VERSION = "0.2.
|
|
1
|
+
export const BEAGLE_UI_VERSION = "0.2.30";
|
|
2
2
|
// src/icons.jsx
|
|
3
3
|
var ICON_PATHS = {
|
|
4
4
|
// ---- tab bar (the four must feel like one set) ----
|
|
@@ -166,6 +166,142 @@ function DkBrowserNotice(props) {
|
|
|
166
166
|
return H.DkBrowserNotice ? /* @__PURE__ */ React.createElement(H.DkBrowserNotice, { ...props }) : null;
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
// src/host-messages.js
|
|
170
|
+
function protocolTest(rule) {
|
|
171
|
+
if (typeof rule !== "function")
|
|
172
|
+
return () => false;
|
|
173
|
+
return (msg) => {
|
|
174
|
+
if (!msg)
|
|
175
|
+
return false;
|
|
176
|
+
try {
|
|
177
|
+
const v = rule(msg);
|
|
178
|
+
return typeof v === "string" ? v || true : !!v;
|
|
179
|
+
} catch (e) {
|
|
180
|
+
return false;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
function stripOwnPrefix(text) {
|
|
185
|
+
return String(text == null ? "" : text).replace(/^you:\s*/i, "");
|
|
186
|
+
}
|
|
187
|
+
function lastMessageOf(peer) {
|
|
188
|
+
const raw = String(peer && peer.lastMsg || "");
|
|
189
|
+
return {
|
|
190
|
+
text: stripOwnPrefix(raw),
|
|
191
|
+
dir: peer && peer.lastDir || (/^you:\s*/i.test(raw) ? "out" : "in"),
|
|
192
|
+
ts: peer && peer.lastTs || 0
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
function lastIsProtocol(peer, isProto) {
|
|
196
|
+
const last = lastMessageOf(peer);
|
|
197
|
+
if (!last.text)
|
|
198
|
+
return false;
|
|
199
|
+
return isProto(last);
|
|
200
|
+
}
|
|
201
|
+
function newestHumanMessage(msgs, isProto) {
|
|
202
|
+
const arr = msgs || [];
|
|
203
|
+
for (let i = arr.length - 1; i >= 0; i--) {
|
|
204
|
+
const m = arr[i];
|
|
205
|
+
if (!m)
|
|
206
|
+
continue;
|
|
207
|
+
if (m.file)
|
|
208
|
+
return m;
|
|
209
|
+
if (!m.text)
|
|
210
|
+
continue;
|
|
211
|
+
if (isProto({ text: m.text, dir: m.dir, ts: m.ts }))
|
|
212
|
+
continue;
|
|
213
|
+
return m;
|
|
214
|
+
}
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
function humanUnread(msgs, unread, isProto) {
|
|
218
|
+
const want = Number(unread) || 0;
|
|
219
|
+
if (want <= 0)
|
|
220
|
+
return { count: 0, exact: true };
|
|
221
|
+
const arr = msgs || [];
|
|
222
|
+
const window2 = arr.slice(Math.max(0, arr.length - want));
|
|
223
|
+
let n = 0;
|
|
224
|
+
for (const m of window2) {
|
|
225
|
+
if (!m || m.dir !== "in")
|
|
226
|
+
continue;
|
|
227
|
+
if (m.text && !m.file && isProto({ text: m.text, dir: m.dir, ts: m.ts }))
|
|
228
|
+
continue;
|
|
229
|
+
n++;
|
|
230
|
+
}
|
|
231
|
+
return { count: n, exact: window2.length >= want };
|
|
232
|
+
}
|
|
233
|
+
function rosterRow(peer, isProto, fix) {
|
|
234
|
+
const hidden = lastIsProtocol(peer, isProto);
|
|
235
|
+
if (!hidden) {
|
|
236
|
+
return {
|
|
237
|
+
preview: peer && peer.lastMsg || "",
|
|
238
|
+
lastTime: peer && peer.lastTime || "",
|
|
239
|
+
unread: Number(peer && peer.unread || 0),
|
|
240
|
+
activityTs: Number(peer && peer.lastTs || 0),
|
|
241
|
+
hidden: false
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
return {
|
|
245
|
+
preview: fix && fix.preview || "",
|
|
246
|
+
lastTime: fix && fix.lastTime || "",
|
|
247
|
+
unread: fix && fix.unreadExact ? fix.unread : 0,
|
|
248
|
+
activityTs: fix && fix.ts || 0,
|
|
249
|
+
hidden: true,
|
|
250
|
+
pending: !fix
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
function rosterUnreadTotal(peers, isProto, fixes) {
|
|
254
|
+
return (peers || []).reduce((n, p) => n + rosterRow(p, isProto, fixes && fixes[p.id]).unread, 0);
|
|
255
|
+
}
|
|
256
|
+
function collapseProtocol(thread, isProto, lang) {
|
|
257
|
+
const out = [];
|
|
258
|
+
let run = null;
|
|
259
|
+
const flush = () => {
|
|
260
|
+
if (!run)
|
|
261
|
+
return;
|
|
262
|
+
out.push({
|
|
263
|
+
protocol: true,
|
|
264
|
+
id: `proto-${run.first.id || run.startIndex}`,
|
|
265
|
+
count: run.items.length,
|
|
266
|
+
label: run.label,
|
|
267
|
+
dir: run.first.from === "me" ? "out" : "in",
|
|
268
|
+
text: run.items.map((m) => m.text).join("\n"),
|
|
269
|
+
line: protocolLine(run, lang)
|
|
270
|
+
});
|
|
271
|
+
run = null;
|
|
272
|
+
};
|
|
273
|
+
(thread || []).forEach((m, i) => {
|
|
274
|
+
const hit = m && !m.day ? isProto({ text: m.text, dir: m && m.from === "me" ? "out" : "in", ts: m && m.ts }) : false;
|
|
275
|
+
if (!hit || m && m.file) {
|
|
276
|
+
flush();
|
|
277
|
+
out.push(m);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (!run)
|
|
281
|
+
run = { first: m, startIndex: i, items: [], label: typeof hit === "string" ? hit : "" };
|
|
282
|
+
if (!run.label && typeof hit === "string")
|
|
283
|
+
run.label = hit;
|
|
284
|
+
run.items.push(m);
|
|
285
|
+
});
|
|
286
|
+
flush();
|
|
287
|
+
return out;
|
|
288
|
+
}
|
|
289
|
+
function protocolLine(run, lang) {
|
|
290
|
+
const arrow = run.first.from === "me" ? "\u2192" : "\u2190";
|
|
291
|
+
const n = run.items.length;
|
|
292
|
+
if (run.label) {
|
|
293
|
+
return `\u2699 ${arrow} ${run.label}${n > 1 ? ` \xB7 ${n}` : ""}`;
|
|
294
|
+
}
|
|
295
|
+
if (n > 1) {
|
|
296
|
+
return lang === "zh" ? `\u2699 ${arrow} ${n} \u6761\u534F\u8BAE\u6D88\u606F` : `\u2699 ${arrow} ${n} protocol messages`;
|
|
297
|
+
}
|
|
298
|
+
return `\u2699 ${arrow} ${protocolSummary(run.first.text)}`;
|
|
299
|
+
}
|
|
300
|
+
function protocolSummary(text, max = 72) {
|
|
301
|
+
const s = String(text == null ? "" : text).replace(/\s+/g, " ").trim();
|
|
302
|
+
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
303
|
+
}
|
|
304
|
+
|
|
169
305
|
// src/data-ipc.jsx
|
|
170
306
|
function dkHash(s) {
|
|
171
307
|
let h = 2166136261;
|
|
@@ -398,6 +534,48 @@ function dkThreadMsg(m) {
|
|
|
398
534
|
components: m.components
|
|
399
535
|
};
|
|
400
536
|
}
|
|
537
|
+
var DK_TAIL_MIN = 30;
|
|
538
|
+
var DK_TAIL_MAX = 200;
|
|
539
|
+
function useProtocolTails(peers, isProtocol, enabled) {
|
|
540
|
+
const [fixes, setFixes] = React.useState({});
|
|
541
|
+
const cache = React.useRef(/* @__PURE__ */ new Map());
|
|
542
|
+
const inFlight = React.useRef(/* @__PURE__ */ new Set());
|
|
543
|
+
React.useEffect(() => {
|
|
544
|
+
if (!enabled)
|
|
545
|
+
return;
|
|
546
|
+
for (const p of peers || []) {
|
|
547
|
+
if (!p || !lastIsProtocol(p, isProtocol))
|
|
548
|
+
continue;
|
|
549
|
+
const unread = Number(p.unread) || 0;
|
|
550
|
+
const key = `${p.lastTs || 0}:${unread}`;
|
|
551
|
+
const had = cache.current.get(p.id);
|
|
552
|
+
if (had && had.key === key)
|
|
553
|
+
continue;
|
|
554
|
+
if (inFlight.current.has(p.id))
|
|
555
|
+
continue;
|
|
556
|
+
const limit = Math.min(DK_TAIL_MAX, Math.max(DK_TAIL_MIN, unread + 5));
|
|
557
|
+
inFlight.current.add(p.id);
|
|
558
|
+
dkGet("/api/chat-history?peer=" + encodeURIComponent(p.id) + "&limit=" + limit).then((d) => {
|
|
559
|
+
const msgs = d && d.chats && d.chats[p.id] || [];
|
|
560
|
+
const human = newestHumanMessage(msgs, isProtocol);
|
|
561
|
+
const count = humanUnread(msgs, unread, isProtocol);
|
|
562
|
+
const fix = {
|
|
563
|
+
preview: human ? (human.dir === "out" ? "you: " : "") + (human.file ? human.file.name : human.text || "") : "",
|
|
564
|
+
lastTime: human ? dkClock(human.ts) : "",
|
|
565
|
+
ts: human ? human.ts : 0,
|
|
566
|
+
unread: count.count,
|
|
567
|
+
unreadExact: count.exact
|
|
568
|
+
};
|
|
569
|
+
cache.current.set(p.id, { key, fix });
|
|
570
|
+
setFixes((f) => Object.assign({}, f, { [p.id]: fix }));
|
|
571
|
+
}).catch(() => {
|
|
572
|
+
}).finally(() => {
|
|
573
|
+
inFlight.current.delete(p.id);
|
|
574
|
+
});
|
|
575
|
+
}
|
|
576
|
+
}, [peers, isProtocol, enabled]);
|
|
577
|
+
return fixes;
|
|
578
|
+
}
|
|
401
579
|
function useDaemonData() {
|
|
402
580
|
const [snap, setSnap] = React.useState({
|
|
403
581
|
me: DK_ME_FALLBACK,
|
|
@@ -1157,6 +1335,20 @@ async function loadServicePeers() {
|
|
|
1157
1335
|
return service_peers_default;
|
|
1158
1336
|
}
|
|
1159
1337
|
}
|
|
1338
|
+
var ASSISTANT_TS_KEY = "beagle.assistant.lastTs";
|
|
1339
|
+
function loadAssistantTs() {
|
|
1340
|
+
try {
|
|
1341
|
+
return Number(localStorage.getItem(ASSISTANT_TS_KEY)) || 0;
|
|
1342
|
+
} catch (e) {
|
|
1343
|
+
return 0;
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
function saveAssistantTs(ts) {
|
|
1347
|
+
try {
|
|
1348
|
+
localStorage.setItem(ASSISTANT_TS_KEY, String(ts));
|
|
1349
|
+
} catch (e) {
|
|
1350
|
+
}
|
|
1351
|
+
}
|
|
1160
1352
|
var ASSISTANT_PEER = {
|
|
1161
1353
|
id: ASSISTANT_ID,
|
|
1162
1354
|
userId: ASSISTANT_ID,
|
|
@@ -1164,7 +1356,6 @@ var ASSISTANT_PEER = {
|
|
|
1164
1356
|
address: "",
|
|
1165
1357
|
online: true,
|
|
1166
1358
|
app: true,
|
|
1167
|
-
pinned: true,
|
|
1168
1359
|
agent: false,
|
|
1169
1360
|
pending: false,
|
|
1170
1361
|
via: null,
|
|
@@ -1269,9 +1460,18 @@ function AssistantPanel({ m, T, lang, onRemove, onAdopt }) {
|
|
|
1269
1460
|
}).finally(() => setBusy(false));
|
|
1270
1461
|
} }, busy ? T.working || "Working\u2026" : label), /* @__PURE__ */ React.createElement("span", { style: { fontSize: 12, color: "var(--faint)" } }, adopt ? lang === "zh" ? "\u53D6\u6D88\u52FE\u9009\u5373\u4FDD\u6301\u4E3A\u597D\u53CB" : "Untick any you want to keep as a friend" : lang === "zh" ? "\u53D6\u6D88\u52FE\u9009\u53EF\u4FDD\u7559" : "Untick anyone you want to keep"))));
|
|
1271
1462
|
}
|
|
1272
|
-
function useAssistant({ lang, T, muted, onToggleMute, sound, flash, setAlert, onReloadFriends }) {
|
|
1463
|
+
function useAssistant({ lang, T, muted, onToggleMute, sound, flash, setAlert, onReloadFriends, onActivity }) {
|
|
1273
1464
|
const [thread, setThread] = React.useState(() => [{ day: (/* @__PURE__ */ new Date()).toLocaleDateString() }, asMsg("them", helpText(lang))]);
|
|
1274
|
-
const
|
|
1465
|
+
const bump = React.useCallback(() => {
|
|
1466
|
+
const ts = Date.now();
|
|
1467
|
+
saveAssistantTs(ts);
|
|
1468
|
+
if (onActivity)
|
|
1469
|
+
onActivity(ts);
|
|
1470
|
+
}, [onActivity]);
|
|
1471
|
+
const append = React.useCallback((...ms) => {
|
|
1472
|
+
bump();
|
|
1473
|
+
setThread((t) => t.concat(ms));
|
|
1474
|
+
}, [bump]);
|
|
1275
1475
|
React.useEffect(() => {
|
|
1276
1476
|
setThread((t) => t.length === 2 ? [t[0], asMsg("them", helpText(lang))] : t);
|
|
1277
1477
|
}, [lang]);
|
|
@@ -1506,100 +1706,6 @@ ${lines}`, { assistant: { kind: "adopt", rows: fresh } }));
|
|
|
1506
1706
|
return { thread, handle, removeFriends, adoptServicePeers };
|
|
1507
1707
|
}
|
|
1508
1708
|
|
|
1509
|
-
// src/host-messages.js
|
|
1510
|
-
function protocolTest(rule) {
|
|
1511
|
-
if (typeof rule !== "function")
|
|
1512
|
-
return () => false;
|
|
1513
|
-
return (msg) => {
|
|
1514
|
-
if (!msg)
|
|
1515
|
-
return false;
|
|
1516
|
-
try {
|
|
1517
|
-
const v = rule(msg);
|
|
1518
|
-
return typeof v === "string" ? v || true : !!v;
|
|
1519
|
-
} catch (e) {
|
|
1520
|
-
return false;
|
|
1521
|
-
}
|
|
1522
|
-
};
|
|
1523
|
-
}
|
|
1524
|
-
function stripOwnPrefix(text) {
|
|
1525
|
-
return String(text == null ? "" : text).replace(/^you:\s*/i, "");
|
|
1526
|
-
}
|
|
1527
|
-
function lastMessageOf(peer) {
|
|
1528
|
-
const raw = String(peer && peer.lastMsg || "");
|
|
1529
|
-
return {
|
|
1530
|
-
text: stripOwnPrefix(raw),
|
|
1531
|
-
dir: peer && peer.lastDir || (/^you:\s*/i.test(raw) ? "out" : "in"),
|
|
1532
|
-
ts: peer && peer.lastTs || 0
|
|
1533
|
-
};
|
|
1534
|
-
}
|
|
1535
|
-
function lastIsProtocol(peer, isProto) {
|
|
1536
|
-
const last = lastMessageOf(peer);
|
|
1537
|
-
if (!last.text)
|
|
1538
|
-
return false;
|
|
1539
|
-
return isProto(last);
|
|
1540
|
-
}
|
|
1541
|
-
function rosterRow(peer, isProto) {
|
|
1542
|
-
const hidden = lastIsProtocol(peer, isProto);
|
|
1543
|
-
return {
|
|
1544
|
-
preview: hidden ? "" : peer && peer.lastMsg || "",
|
|
1545
|
-
lastTime: hidden ? "" : peer && peer.lastTime || "",
|
|
1546
|
-
unread: hidden ? 0 : Number(peer && peer.unread || 0),
|
|
1547
|
-
activityTs: hidden ? 0 : Number(peer && peer.lastTs || 0),
|
|
1548
|
-
hidden
|
|
1549
|
-
};
|
|
1550
|
-
}
|
|
1551
|
-
function rosterUnreadTotal(peers, isProto) {
|
|
1552
|
-
return (peers || []).reduce((n, p) => n + rosterRow(p, isProto).unread, 0);
|
|
1553
|
-
}
|
|
1554
|
-
function collapseProtocol(thread, isProto, lang) {
|
|
1555
|
-
const out = [];
|
|
1556
|
-
let run = null;
|
|
1557
|
-
const flush = () => {
|
|
1558
|
-
if (!run)
|
|
1559
|
-
return;
|
|
1560
|
-
out.push({
|
|
1561
|
-
protocol: true,
|
|
1562
|
-
id: `proto-${run.first.id || run.startIndex}`,
|
|
1563
|
-
count: run.items.length,
|
|
1564
|
-
label: run.label,
|
|
1565
|
-
dir: run.first.from === "me" ? "out" : "in",
|
|
1566
|
-
text: run.items.map((m) => m.text).join("\n"),
|
|
1567
|
-
line: protocolLine(run, lang)
|
|
1568
|
-
});
|
|
1569
|
-
run = null;
|
|
1570
|
-
};
|
|
1571
|
-
(thread || []).forEach((m, i) => {
|
|
1572
|
-
const hit = m && !m.day ? isProto({ text: m.text, dir: m && m.from === "me" ? "out" : "in", ts: m && m.ts }) : false;
|
|
1573
|
-
if (!hit || m && m.file) {
|
|
1574
|
-
flush();
|
|
1575
|
-
out.push(m);
|
|
1576
|
-
return;
|
|
1577
|
-
}
|
|
1578
|
-
if (!run)
|
|
1579
|
-
run = { first: m, startIndex: i, items: [], label: typeof hit === "string" ? hit : "" };
|
|
1580
|
-
if (!run.label && typeof hit === "string")
|
|
1581
|
-
run.label = hit;
|
|
1582
|
-
run.items.push(m);
|
|
1583
|
-
});
|
|
1584
|
-
flush();
|
|
1585
|
-
return out;
|
|
1586
|
-
}
|
|
1587
|
-
function protocolLine(run, lang) {
|
|
1588
|
-
const arrow = run.first.from === "me" ? "\u2192" : "\u2190";
|
|
1589
|
-
const n = run.items.length;
|
|
1590
|
-
if (run.label) {
|
|
1591
|
-
return `\u2699 ${arrow} ${run.label}${n > 1 ? ` \xB7 ${n}` : ""}`;
|
|
1592
|
-
}
|
|
1593
|
-
if (n > 1) {
|
|
1594
|
-
return lang === "zh" ? `\u2699 ${arrow} ${n} \u6761\u534F\u8BAE\u6D88\u606F` : `\u2699 ${arrow} ${n} protocol messages`;
|
|
1595
|
-
}
|
|
1596
|
-
return `\u2699 ${arrow} ${protocolSummary(run.first.text)}`;
|
|
1597
|
-
}
|
|
1598
|
-
function protocolSummary(text, max = 72) {
|
|
1599
|
-
const s = String(text == null ? "" : text).replace(/\s+/g, " ").trim();
|
|
1600
|
-
return s.length > max ? s.slice(0, max - 1) + "\u2026" : s;
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
1709
|
// src/chat.jsx
|
|
1604
1710
|
var DK_CMD_HIST_KEY = "beagle.assistant.history";
|
|
1605
1711
|
var DK_CMD_HIST_MAX = 50;
|
|
@@ -1661,9 +1767,9 @@ function RequestsBlock({ T, requests, onAct }) {
|
|
|
1661
1767
|
paddingLeft: 8
|
|
1662
1768
|
} }, r.descr), failed[r.id] && /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--ui)", fontSize: 11, color: "var(--danger)" } }, failed[r.id]), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", gap: 6 } }, /* @__PURE__ */ React.createElement(Btn, { tone: "ok", icon: "check", size: "sm", onClick: () => act(r, "accept"), style: { flex: 1 } }, T.accept), /* @__PURE__ */ React.createElement(Btn, { tone: "danger", icon: "x", size: "sm", onClick: () => act(r, "reject"), style: { flex: 1 } }, T.reject))))));
|
|
1663
1769
|
}
|
|
1664
|
-
function PeerRow({ peer, T, active, onClick, muted, isProtocol }) {
|
|
1770
|
+
function PeerRow({ peer, T, active, onClick, muted, isProtocol, fix }) {
|
|
1665
1771
|
const name = peer.alias || peer.userId;
|
|
1666
|
-
const row = rosterRow(peer, isProtocol || (() => false));
|
|
1772
|
+
const row = rosterRow(peer, isProtocol || (() => false), fix);
|
|
1667
1773
|
return /* @__PURE__ */ React.createElement("button", { onClick, style: {
|
|
1668
1774
|
display: "flex",
|
|
1669
1775
|
alignItems: "center",
|
|
@@ -1694,11 +1800,11 @@ function PeerRow({ peer, T, active, onClick, muted, isProtocol }) {
|
|
|
1694
1800
|
minWidth: 0
|
|
1695
1801
|
} }, dkRowPreview(row.preview)))), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", alignItems: "flex-end", gap: 4, flexShrink: 0 } }, /* @__PURE__ */ React.createElement("span", { style: { fontFamily: "var(--mono)", fontSize: 10.5, color: "var(--faint)" } }, row.lastTime), row.unread ? /* @__PURE__ */ React.createElement(Unread, { n: row.unread }) : peer.pending ? /* @__PURE__ */ React.createElement(Icon, { name: "clock", size: 11, stroke: 2.2, color: "var(--warn, #d29922)", title: "friend request pending" }) : /* @__PURE__ */ React.createElement(StatusDot, { online: peer.online })));
|
|
1696
1802
|
}
|
|
1697
|
-
function dkActivityTs(p, isProtocol) {
|
|
1698
|
-
const row = rosterRow(p, isProtocol || (() => false));
|
|
1803
|
+
function dkActivityTs(p, isProtocol, fix) {
|
|
1804
|
+
const row = rosterRow(p, isProtocol || (() => false), fix);
|
|
1699
1805
|
return Math.max(row.activityTs, p.acceptedAt || 0, p.requestedAt || 0);
|
|
1700
1806
|
}
|
|
1701
|
-
function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, wide, isProtocol }) {
|
|
1807
|
+
function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, wide, isProtocol, protocolFix }) {
|
|
1702
1808
|
const [q, setQ] = React.useState("");
|
|
1703
1809
|
const [addr, setAddr] = React.useState("");
|
|
1704
1810
|
const [addState, setAddState] = React.useState(null);
|
|
@@ -1743,7 +1849,8 @@ function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, pre
|
|
|
1743
1849
|
}).slice().sort((a, b) => {
|
|
1744
1850
|
if (!!a.pinned !== !!b.pinned)
|
|
1745
1851
|
return a.pinned ? -1 : 1;
|
|
1746
|
-
const ta = dkActivityTs(a, isProtocol
|
|
1852
|
+
const ta = dkActivityTs(a, isProtocol, protocolFix && protocolFix[a.id]);
|
|
1853
|
+
const tb = dkActivityTs(b, isProtocol, protocolFix && protocolFix[b.id]);
|
|
1747
1854
|
if (ta !== tb)
|
|
1748
1855
|
return tb - ta;
|
|
1749
1856
|
return String(a.alias || a.userId || "").localeCompare(String(b.alias || b.userId || ""));
|
|
@@ -1782,7 +1889,7 @@ function PeerSidebar({ T, peers, requests, activeId, onSelect, onAct, onAdd, pre
|
|
|
1782
1889
|
fontSize: 11.5,
|
|
1783
1890
|
lineHeight: 1.35,
|
|
1784
1891
|
color: addState.kind === "err" ? "var(--bad, #e5484d)" : addState.kind === "ok" ? "var(--good, #46a758)" : "var(--faint)"
|
|
1785
|
-
} }, addState.msg), /* @__PURE__ */ React.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "search", size: 15, color: "var(--faint)", stroke: 2, style: { position: "absolute", left: 9 } }), /* @__PURE__ */ React.createElement("input", { value: q, onChange: (e) => setQ(e.target.value), placeholder: T.search, style: { ...inputStyle, paddingLeft: 30 } }))), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", padding: "10px 8px 16px" } }, /* @__PURE__ */ React.createElement(RequestsBlock, { T, requests, onAct }), /* @__PURE__ */ React.createElement(Section, { label: T.peers, count: `${online}/${peers.length}`, style: { margin: "6px 4px 8px" } }), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((p) => /* @__PURE__ */ React.createElement(PeerRow, { key: p.id, peer: p, T, active: p.id === activeId, onClick: () => onSelect(p.id), muted: !!muted && muted.includes(p.id), isProtocol })), !filtered.length && /* @__PURE__ */ React.createElement("div", { style: { padding: 16, textAlign: "center", fontFamily: "var(--mono)", fontSize: 12, color: "var(--faint)" } }, "no matches"))));
|
|
1892
|
+
} }, addState.msg), /* @__PURE__ */ React.createElement("div", { style: { position: "relative", display: "flex", alignItems: "center" } }, /* @__PURE__ */ React.createElement(Icon, { name: "search", size: 15, color: "var(--faint)", stroke: 2, style: { position: "absolute", left: 9 } }), /* @__PURE__ */ React.createElement("input", { value: q, onChange: (e) => setQ(e.target.value), placeholder: T.search, style: { ...inputStyle, paddingLeft: 30 } }))), /* @__PURE__ */ React.createElement("div", { style: { flex: 1, overflow: "auto", padding: "10px 8px 16px" } }, /* @__PURE__ */ React.createElement(RequestsBlock, { T, requests, onAct }), /* @__PURE__ */ React.createElement(Section, { label: T.peers, count: `${online}/${peers.length}`, style: { margin: "6px 4px 8px" } }), /* @__PURE__ */ React.createElement("div", { style: { display: "flex", flexDirection: "column", gap: 2 } }, filtered.map((p) => /* @__PURE__ */ React.createElement(PeerRow, { key: p.id, peer: p, T, active: p.id === activeId, onClick: () => onSelect(p.id), muted: !!muted && muted.includes(p.id), isProtocol, fix: protocolFix && protocolFix[p.id] })), !filtered.length && /* @__PURE__ */ React.createElement("div", { style: { padding: 16, textAlign: "center", fontFamily: "var(--mono)", fontSize: 12, color: "var(--faint)" } }, "no matches"))));
|
|
1786
1893
|
}
|
|
1787
1894
|
var inputStyle = {
|
|
1788
1895
|
flex: 1,
|
|
@@ -3383,12 +3490,12 @@ function MenuItem({ icon, label, onClick, danger }) {
|
|
|
3383
3490
|
function ChatEmpty({ T }) {
|
|
3384
3491
|
return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 12, color: "var(--faint)", background: "var(--bg)" } }, /* @__PURE__ */ React.createElement(Icon, { name: "message", size: 40, stroke: 1.4, color: "var(--line)" }), /* @__PURE__ */ React.createElement("div", { style: { fontFamily: "var(--mono)", fontSize: 13 } }, T.pickPeer));
|
|
3385
3492
|
}
|
|
3386
|
-
function ChatTab({ T, lang, peers, requests, activeId, thread, isProtocol, onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, prefillAddr, onPrefillConsumed, muted, onToggleMute, phone, onBack }) {
|
|
3493
|
+
function ChatTab({ T, lang, peers, requests, activeId, thread, isProtocol, protocolFix, onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, prefillAddr, onPrefillConsumed, muted, onToggleMute, phone, onBack }) {
|
|
3387
3494
|
const peer = peers.find((p) => p.id === activeId);
|
|
3388
3495
|
if (phone) {
|
|
3389
|
-
return peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute, phone: true, onBack }) : /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol, wide: true });
|
|
3496
|
+
return peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute, phone: true, onBack }) : /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol, protocolFix, wide: true });
|
|
3390
3497
|
}
|
|
3391
|
-
return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", minWidth: 0, minHeight: 0 } }, /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol }), peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute }) : /* @__PURE__ */ React.createElement(ChatEmpty, { T }));
|
|
3498
|
+
return /* @__PURE__ */ React.createElement("div", { style: { flex: 1, display: "flex", minWidth: 0, minHeight: 0 } }, /* @__PURE__ */ React.createElement(PeerSidebar, { T, peers, requests, activeId, onSelect, onAct, onAdd, prefillAddr, onPrefillConsumed, muted, isProtocol, protocolFix }), peer ? /* @__PURE__ */ React.createElement(Conversation, { T, peer, lang, peers, onOpenChat: onSelect, thread, isProtocol, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread, hasEarlier, onLoadEarlier, onAssistantRemove, onAssistantAdopt, muted: !!muted && muted.includes(peer.id), onToggleMute }) : /* @__PURE__ */ React.createElement(ChatEmpty, { T }));
|
|
3392
3499
|
}
|
|
3393
3500
|
Object.assign(window, { ChatTab });
|
|
3394
3501
|
|
|
@@ -6869,7 +6976,11 @@ function DkApp() {
|
|
|
6869
6976
|
sessionStorage.setItem(key, "1");
|
|
6870
6977
|
window.location.reload();
|
|
6871
6978
|
}, [me && me.beagleVer]);
|
|
6872
|
-
const
|
|
6979
|
+
const [assistantTs, setAssistantTs] = React.useState(loadAssistantTs);
|
|
6980
|
+
const peers = React.useMemo(() => (data.peers || []).concat([Object.assign({}, ASSISTANT_PEER, {
|
|
6981
|
+
lastTs: assistantTs,
|
|
6982
|
+
lastTime: assistantTs ? dkClock(assistantTs) : ""
|
|
6983
|
+
})]), [data.peers, assistantTs]);
|
|
6873
6984
|
const [pendingAddr, setPendingAddr] = React.useState(() => dkParseDeepLinkAddress());
|
|
6874
6985
|
React.useEffect(() => {
|
|
6875
6986
|
const onHash = () => {
|
|
@@ -6924,6 +7035,7 @@ function DkApp() {
|
|
|
6924
7035
|
const mutedIds = Array.isArray(t.alertMuted) ? t.alertMuted : [];
|
|
6925
7036
|
const onToggleMute = (id) => setTweak("alertMuted", mutedIds.includes(id) ? mutedIds.filter((x) => x !== id) : mutedIds.concat(id));
|
|
6926
7037
|
const isProtocol = React.useMemo(() => protocolTest(hostIsProtocolMessage), []);
|
|
7038
|
+
const protocolFix = useProtocolTails(peers, isProtocol, !!hostIsProtocolMessage);
|
|
6927
7039
|
useIncomingAlerts({
|
|
6928
7040
|
T,
|
|
6929
7041
|
peers,
|
|
@@ -6940,6 +7052,7 @@ function DkApp() {
|
|
|
6940
7052
|
T,
|
|
6941
7053
|
muted: mutedIds,
|
|
6942
7054
|
onToggleMute,
|
|
7055
|
+
onActivity: setAssistantTs,
|
|
6943
7056
|
sound: t.alertSound !== false,
|
|
6944
7057
|
flash: t.alertFlash !== false,
|
|
6945
7058
|
setAlert: (which, on) => setTweak(which === "sound" ? "alertSound" : "alertFlash", on),
|
|
@@ -7185,7 +7298,7 @@ function DkApp() {
|
|
|
7185
7298
|
const lastPeople = React.useRef("here");
|
|
7186
7299
|
if (peopleTab)
|
|
7187
7300
|
lastPeople.current = tab;
|
|
7188
|
-
const unreadTotal = rosterUnreadTotal(peers, isProtocol) + (requests || []).length;
|
|
7301
|
+
const unreadTotal = rosterUnreadTotal(peers, isProtocol, protocolFix) + (requests || []).length;
|
|
7189
7302
|
const NAV_FOR = {
|
|
7190
7303
|
chat: { icon: "message", label: T.chat, active: tab === "chat", badge: unreadTotal, go: () => setTab("chat") },
|
|
7191
7304
|
people: { icon: "users", label: T.people, active: peopleTab, go: () => setTab(lastPeople.current) },
|
|
@@ -7243,7 +7356,7 @@ function DkApp() {
|
|
|
7243
7356
|
fontWeight: 600,
|
|
7244
7357
|
background: tab === n.id ? "var(--accent)" : "transparent",
|
|
7245
7358
|
color: tab === n.id ? "#fff" : "var(--dim)"
|
|
7246
|
-
} }, /* @__PURE__ */ React.createElement(Icon, { name: n.icon, size: 14, stroke: 2, color: tab === n.id ? "#fff" : "var(--dim)" }), n.label))), tab === "chat" && /* @__PURE__ */ React.createElement(ChatTab, { T, lang: t.lang, phone, isProtocol, onBack: closeConversation, peers, requests, activeId, thread: activeId === ASSISTANT_ID ? assistant.thread : data.threads[activeId], onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread: () => activeId && data.loadThread(activeId), hasEarlier: !!(activeId && activeId !== ASSISTANT_ID && data.earlier[activeId]), onAssistantRemove: activeId === ASSISTANT_ID ? assistant.removeFriends : null, onAssistantAdopt: activeId === ASSISTANT_ID ? assistant.adoptServicePeers : null, onLoadEarlier: () => activeId && data.loadEarlier(activeId), prefillAddr: pendingAddr, onPrefillConsumed: () => setPendingAddr(""), muted: mutedIds, onToggleMute }), tab === "here" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "bridge", peers, meId: me.userId, onAdd, onOpenChat }), tab === "recommended" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "recommended", peers, meId: me.userId, onAdd, onOpenChat }), tab === "registered" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "registered", peers, meId: me.userId, onAdd, onOpenChat }), tab === "network" && /* @__PURE__ */ React.createElement(NetworkTab, { T, me, peers, exits, activeExit, reqCount: requests.length, onSetExit, onOpenChat, backend, onArmLan: armLan, onCancelLan: cancelLan }), tab === "apps" && /* @__PURE__ */ React.createElement(AppsTab, { T, t, me, peers, phone, setTab }), tabs.map((x) => x.kind === "host" && tab === x.id ? /* @__PURE__ */ React.createElement(HostTabPane, { key: x.id, tab: x, props: { T, t, me, peers, phone, setTab }, lang: t.lang }) : null), tab === "profile" && /* @__PURE__ */ React.createElement(
|
|
7359
|
+
} }, /* @__PURE__ */ React.createElement(Icon, { name: n.icon, size: 14, stroke: 2, color: tab === n.id ? "#fff" : "var(--dim)" }), n.label))), tab === "chat" && /* @__PURE__ */ React.createElement(ChatTab, { T, lang: t.lang, phone, isProtocol, protocolFix, onBack: closeConversation, peers, requests, activeId, thread: activeId === ASSISTANT_ID ? assistant.thread : data.threads[activeId], onSelect, onAct, onAdd, onSend, onSendFile, onSendRtcFile, onAlias, onRemove, onOpenNet, onCall, onReloadThread: () => activeId && data.loadThread(activeId), hasEarlier: !!(activeId && activeId !== ASSISTANT_ID && data.earlier[activeId]), onAssistantRemove: activeId === ASSISTANT_ID ? assistant.removeFriends : null, onAssistantAdopt: activeId === ASSISTANT_ID ? assistant.adoptServicePeers : null, onLoadEarlier: () => activeId && data.loadEarlier(activeId), prefillAddr: pendingAddr, onPrefillConsumed: () => setPendingAddr(""), muted: mutedIds, onToggleMute }), tab === "here" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "bridge", peers, meId: me.userId, onAdd, onOpenChat }), tab === "recommended" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "recommended", peers, meId: me.userId, onAdd, onOpenChat }), tab === "registered" && /* @__PURE__ */ React.createElement(DiscoverTab, { T, kind: "registered", peers, meId: me.userId, onAdd, onOpenChat }), tab === "network" && /* @__PURE__ */ React.createElement(NetworkTab, { T, me, peers, exits, activeExit, reqCount: requests.length, onSetExit, onOpenChat, backend, onArmLan: armLan, onCancelLan: cancelLan }), tab === "apps" && /* @__PURE__ */ React.createElement(AppsTab, { T, t, me, peers, phone, setTab }), tabs.map((x) => x.kind === "host" && tab === x.id ? /* @__PURE__ */ React.createElement(HostTabPane, { key: x.id, tab: x, props: { T, t, me, peers, phone, setTab }, lang: t.lang }) : null), tab === "profile" && /* @__PURE__ */ React.createElement(
|
|
7247
7360
|
ProfileTab,
|
|
7248
7361
|
{
|
|
7249
7362
|
T,
|
package/package.json
CHANGED