Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d08ba0a55 |
Generated
+4
-4
@@ -81,7 +81,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "4.13.0",
|
||||
"@lotusguild/element-call-embedded": "0.25.0-lotus.23",
|
||||
"@lotusguild/element-call-embedded": "0.25.0-lotus.22",
|
||||
"@playwright/test": "1.63.0",
|
||||
"@rollup/plugin-inject": "5.0.5",
|
||||
"@rollup/plugin-wasm": "6.2.2",
|
||||
@@ -2695,9 +2695,9 @@
|
||||
"integrity": "sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA=="
|
||||
},
|
||||
"node_modules/@lotusguild/element-call-embedded": {
|
||||
"version": "0.25.0-lotus.23",
|
||||
"resolved": "https://code.lotusguild.org/api/packages/LotusGuild/npm/%40lotusguild%2Felement-call-embedded/-/0.25.0-lotus.23/element-call-embedded-0.25.0-lotus.23.tgz",
|
||||
"integrity": "sha512-vRmcWeJcU0Accyl2x3mqNEzrIe8djE5BekyYbYOSCsMflC98rZgD1mO7KOe7bA1cX7gparRf6sAt1fotHoU+bA==",
|
||||
"version": "0.25.0-lotus.22",
|
||||
"resolved": "https://code.lotusguild.org/api/packages/LotusGuild/npm/%40lotusguild%2Felement-call-embedded/-/0.25.0-lotus.22/element-call-embedded-0.25.0-lotus.22.tgz",
|
||||
"integrity": "sha512-AimDKZA4xUKEEyl2XUFUSUDl03tBKFv88T/3igKyH2VqNSPMGnqcQJC5HXIkHLTWrOmg8kLcJ//FFbqlUZiLcA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@matrix-org/matrix-sdk-crypto-wasm": {
|
||||
|
||||
+1
-1
@@ -108,7 +108,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "4.13.0",
|
||||
"@lotusguild/element-call-embedded": "0.25.0-lotus.23",
|
||||
"@lotusguild/element-call-embedded": "0.25.0-lotus.22",
|
||||
"@playwright/test": "1.63.0",
|
||||
"@rollup/plugin-inject": "5.0.5",
|
||||
"@rollup/plugin-wasm": "6.2.2",
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { test } from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import {
|
||||
foldEdits,
|
||||
filterGroupsByDateRange,
|
||||
filterGroupsByMsgType,
|
||||
filterGroupsByPinned,
|
||||
@@ -109,3 +110,47 @@ test('filterGroupsByPinned: keeps pinned items and drops empty groups', () => {
|
||||
['$2'],
|
||||
);
|
||||
});
|
||||
|
||||
const sr = (eventId: string, ts: number, content: Record<string, unknown>) =>
|
||||
({
|
||||
rank: 1,
|
||||
result: {
|
||||
event_id: eventId,
|
||||
room_id: '!r:x',
|
||||
origin_server_ts: ts,
|
||||
type: 'm.room.message',
|
||||
content,
|
||||
},
|
||||
}) as unknown as Parameters<typeof foldEdits>[0][number];
|
||||
|
||||
test('foldEdits: one row per message, showing the latest edit (#288)', () => {
|
||||
const edit = (id: string, ts: number, body: string) =>
|
||||
sr(id, ts, {
|
||||
body: `* ${body}`,
|
||||
'm.new_content': { body },
|
||||
'm.relates_to': { rel_type: 'm.replace', event_id: '$orig' },
|
||||
});
|
||||
const out = foldEdits([
|
||||
edit('$e2', 30, 'Tuesday 11am room B'),
|
||||
sr('$orig', 10, { body: 'Monday 10am room A' }),
|
||||
edit('$e1', 20, 'Tuesday 10am room A'),
|
||||
sr('$other', 5, { body: 'meeting notes' }),
|
||||
]);
|
||||
assert.deepEqual(
|
||||
out.map((r) => r.result.event_id),
|
||||
['$orig', '$other'],
|
||||
);
|
||||
assert.deepEqual(out[0].result.content['m.new_content'], { body: 'Tuesday 11am room B' });
|
||||
assert.equal(out[0].result.content.body, 'Monday 10am room A');
|
||||
});
|
||||
|
||||
test('foldEdits: an edit whose original did not match stands in for it', () => {
|
||||
const out = foldEdits([
|
||||
sr('$e1', 20, {
|
||||
'm.new_content': { body: 'x' },
|
||||
'm.relates_to': { rel_type: 'm.replace', event_id: '$orig' },
|
||||
}),
|
||||
]);
|
||||
assert.equal(out.length, 1);
|
||||
assert.equal(out[0].result.event_id, '$orig');
|
||||
});
|
||||
|
||||
@@ -96,10 +96,58 @@ export const filterGroupsByDateRange = (
|
||||
.filter((group) => group.items.length > 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* [Gitea #288] Server search also returns `m.replace` events, so an edited
|
||||
* message showed once per version. Fold each edit into its message: one row,
|
||||
* at the first position any version ranked, showing the latest text and
|
||||
* pointing at the original event (so "jump" lands on the real message).
|
||||
*/
|
||||
export const foldEdits = (results: ISearchResult[]): ISearchResult[] => {
|
||||
const targetOf = (r: ISearchResult): string => {
|
||||
const rel = r.result.content?.['m.relates_to'];
|
||||
return rel?.rel_type === 'm.replace' && typeof rel.event_id === 'string'
|
||||
? rel.event_id
|
||||
: r.result.event_id;
|
||||
};
|
||||
const isEdit = (r: ISearchResult) => targetOf(r) !== r.result.event_id;
|
||||
const order: string[] = [];
|
||||
const originals = new Map<string, ISearchResult>();
|
||||
const latestEdit = new Map<string, ISearchResult>();
|
||||
results.forEach((r) => {
|
||||
const target = targetOf(r);
|
||||
if (!originals.has(target) && !latestEdit.has(target)) order.push(target);
|
||||
if (!isEdit(r)) {
|
||||
originals.set(target, r);
|
||||
return;
|
||||
}
|
||||
const prev = latestEdit.get(target);
|
||||
if (!prev || r.result.origin_server_ts > prev.result.origin_server_ts)
|
||||
latestEdit.set(target, r);
|
||||
});
|
||||
return order.map((target) => {
|
||||
const original = originals.get(target);
|
||||
const edit = latestEdit.get(target);
|
||||
const newContent = edit?.result.content?.['m.new_content'];
|
||||
if (original && !newContent) return original;
|
||||
if (original) {
|
||||
return {
|
||||
...original,
|
||||
result: {
|
||||
...original.result,
|
||||
content: { ...original.result.content, 'm.new_content': newContent },
|
||||
},
|
||||
};
|
||||
}
|
||||
// Only an edit matched: show it as its message.
|
||||
const only = edit as ISearchResult;
|
||||
return { ...only, result: { ...only.result, event_id: target } };
|
||||
});
|
||||
};
|
||||
|
||||
const groupSearchResult = (results: ISearchResult[]): ResultGroup[] => {
|
||||
const groups: ResultGroup[] = [];
|
||||
|
||||
results.forEach((item) => {
|
||||
foldEdits(results).forEach((item) => {
|
||||
const roomId = item.result.room_id;
|
||||
const resultItem: ResultItem = {
|
||||
rank: item.rank,
|
||||
|
||||
@@ -31,7 +31,6 @@ import { verifyDenoiseAssets } from './denoiseSmokeCheck';
|
||||
import { canDelegateCapability } from './utils';
|
||||
import { getCallPageUrl } from './callPageUrl';
|
||||
import { restrictWidgetMessages } from '../widgetTransport';
|
||||
import { isRingableRoom } from '../../utils/callRing';
|
||||
|
||||
// Maximum time to wait for the embedded Element Call iframe to progress from
|
||||
// initial load to a ready/joined state. If it hasn't by then, we assume the
|
||||
@@ -252,18 +251,8 @@ export class CallEmbed {
|
||||
verifyDenoiseAssets(denoiseModel).catch(() => undefined);
|
||||
}
|
||||
|
||||
// [Gitea #295] Only ask Element Call to notify where a call can ring at all
|
||||
// (DMs, invite-only groups outside a space). In a voice channel or space
|
||||
// room the notification carries an @room mention, so every member got a
|
||||
// highlighted ping (and phone push) whenever a moderator hopped in, and
|
||||
// other clients showed it as a missed call.
|
||||
// `none` needs element-call-embedded ≥ 0.25.0-lotus.23 (older builds ignore it).
|
||||
if (CallEmbed.startingCall(intent)) {
|
||||
let notify = 'none';
|
||||
if (isRingableRoom(room, CallEmbed.dmCall(intent))) {
|
||||
notify = CallEmbed.dmCall(intent) ? 'ring' : 'notification';
|
||||
}
|
||||
params.append('sendNotificationType', notify);
|
||||
params.append('sendNotificationType', CallEmbed.dmCall(intent) ? 'ring' : 'notification');
|
||||
}
|
||||
|
||||
// [Gitea #43] On its own origin when config.json sets elementCallUrl.
|
||||
|
||||
Reference in New Issue
Block a user