Integrate pinned messages bar/panel

This commit is contained in:
Jamie
2025-12-15 10:14:20 -08:00
committed by GitHub
parent 8edbe6ac78
commit acc9fd604f
26 changed files with 768 additions and 338 deletions

View File

@@ -69,12 +69,14 @@ import type {
PinnedMessage,
PinnedMessageId,
PinnedMessageParams,
PinnedMessageRenderData,
} from '../types/PinnedMessage.std.js';
import type { AppendPinnedMessageResult } from './server/pinnedMessages.std.js';
import type {
RemoteMegaphoneId,
RemoteMegaphoneType,
} from '../types/Megaphone.std.js';
import { QueryFragment, sqlJoin } from './util.std.js';
export type ReadableDB = Database & { __readable_db: never };
export type WritableDB = ReadableDB & { __writable_db: never };
@@ -191,6 +193,12 @@ export const MESSAGE_COLUMNS = [
...MESSAGE_NON_PRIMARY_KEY_COLUMNS,
] as const;
export const MESSAGE_COLUMNS_FRAGMENTS = MESSAGE_COLUMNS.map(
column => new QueryFragment(column, [])
);
export const MESSAGE_COLUMNS_SELECT = sqlJoin(MESSAGE_COLUMNS_FRAGMENTS);
export type MessageTypeUnhydrated = {
json: string;
@@ -980,7 +988,7 @@ type ReadableInterface = {
getPinnedMessagesForConversation: (
conversationId: string
) => ReadonlyArray<PinnedMessage>;
) => ReadonlyArray<PinnedMessageRenderData>;
getNextExpiringPinnedMessageAcrossConversations: () => PinnedMessage | null;
getMessagesNeedingUpgrade: (

View File

@@ -49,7 +49,7 @@ import { isNormalNumber } from '../util/isNormalNumber.std.js';
import { isNotNil } from '../util/isNotNil.std.js';
import { parseIntOrThrow } from '../util/parseIntOrThrow.std.js';
import { updateSchema } from './migrations/index.node.js';
import type { JSONRows } from './util.std.js';
import type { JSONRows, QueryFragment } from './util.std.js';
import {
batchMultiVarQuery,
bulkAdd,
@@ -68,7 +68,6 @@ import {
sqlConstant,
sqlFragment,
sqlJoin,
QueryFragment,
convertOptionalBooleanToInteger,
} from './util.std.js';
import {
@@ -199,6 +198,8 @@ import type {
import {
AttachmentDownloadSource,
MESSAGE_COLUMNS,
MESSAGE_COLUMNS_FRAGMENTS,
MESSAGE_COLUMNS_SELECT,
MESSAGE_ATTACHMENT_COLUMNS,
MESSAGE_NON_PRIMARY_KEY_COLUMNS,
} from './Interface.std.js';
@@ -783,10 +784,6 @@ export const DataWriter: ServerWritableInterface = {
runCorruptionChecks,
};
const MESSAGE_COLUMNS_FRAGMENTS = MESSAGE_COLUMNS.map(
column => new QueryFragment(column, [])
);
function rowToConversation(row: ConversationRow): ConversationType {
const { expireTimerVersion } = row;
const parsedJson = JSON.parse(row.json);
@@ -3534,7 +3531,7 @@ function getUnreadReactionsAndMarkRead(
return db
.prepare(
`
UPDATE reactions
UPDATE reactions
INDEXED BY reactions_unread
SET unread = 0
WHERE
@@ -3782,7 +3779,7 @@ function getRecentStoryReplies(
const createQuery = (timeFilter: QueryFragment): QueryFragment => sqlFragment`
SELECT
${sqlJoin(MESSAGE_COLUMNS_FRAGMENTS)}
${MESSAGE_COLUMNS_SELECT}
FROM messages
WHERE
(${messageId ?? null} IS NULL OR id IS NOT ${messageId ?? null}) AND

View File

@@ -5,21 +5,65 @@ import type {
PinnedMessage,
PinnedMessageId,
PinnedMessageParams,
PinnedMessageRenderData,
} from '../../types/PinnedMessage.std.js';
import { strictAssert } from '../../util/assert.std.js';
import type { ReadableDB, WritableDB } from '../Interface.std.js';
import { hydrateMessage } from '../hydration.std.js';
import type {
MessageTypeUnhydrated,
MessageType,
ReadableDB,
WritableDB,
} from '../Interface.std.js';
import { sql } from '../util.std.js';
function _getMessageById(
db: ReadableDB,
messageId: string
): MessageType | null {
const [query, params] = sql`
SELECT * FROM messages
WHERE id = ${messageId}
`;
const row = db.prepare(query).get<MessageTypeUnhydrated>(params);
if (row == null) {
return null;
}
return hydrateMessage(db, row);
}
function _getPinnedMessageRenderData(
db: ReadableDB,
pinnedMessage: PinnedMessage
): PinnedMessageRenderData {
const message = _getMessageById(db, pinnedMessage.messageId);
strictAssert(
message != null,
`Missing message ${pinnedMessage.messageId} for pinned message ${pinnedMessage.id}`
);
return { pinnedMessage, message };
}
export function getPinnedMessagesForConversation(
db: ReadableDB,
conversationId: string
): ReadonlyArray<PinnedMessage> {
const [query, params] = sql`
SELECT * FROM pinnedMessages
WHERE conversationId = ${conversationId}
ORDER BY pinnedAt DESC
`;
return db.prepare(query).all<PinnedMessage>(params);
): ReadonlyArray<PinnedMessageRenderData> {
return db.transaction(() => {
const [query, params] = sql`
SELECT * FROM pinnedMessages
WHERE conversationId = ${conversationId}
ORDER BY pinnedAt DESC
`;
return db
.prepare(query)
.all<PinnedMessage>(params)
.map(pinnedMessage => {
return _getPinnedMessageRenderData(db, pinnedMessage);
});
})();
}
function _getPinnedMessageByMessageId(