Add message schema version section to internal settings
This commit is contained in:
parent
115b79e4ac
commit
46bf933e72
7 changed files with 197 additions and 9 deletions
|
@ -625,21 +625,41 @@ $secondary-text-color: light-dark(
|
|||
margin-inline: 4px;
|
||||
}
|
||||
}
|
||||
pre {
|
||||
max-height: 128px;
|
||||
}
|
||||
}
|
||||
|
||||
.Preferences--internal--validate-backup--result {
|
||||
.Preferences--internal--result {
|
||||
padding-inline: 48px 24px;
|
||||
max-width: 100%;
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
th,
|
||||
td {
|
||||
padding-inline: 16px;
|
||||
padding-block: 4px;
|
||||
text-align: start;
|
||||
max-width: 600px;
|
||||
}
|
||||
.Preferences--internal--subresult {
|
||||
background-color: variables.$color-white-alpha-06;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
}
|
||||
|
||||
.Preferences--internal--validate-backup--error {
|
||||
.Preferences--internal--error {
|
||||
padding-inline: 48px 24px;
|
||||
color: variables.$color-accent-red;
|
||||
}
|
||||
|
||||
.Preferences--internal--validate-backup--result pre,
|
||||
.Preferences--internal--validate-backup--error pre {
|
||||
max-height: 128px;
|
||||
.Preferences--internal pre,
|
||||
.Preferences--internal pre {
|
||||
max-height: 400px;
|
||||
max-width: 100%;
|
||||
white-space: pre-wrap;
|
||||
user-select: text;
|
||||
overflow-x: scroll;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import { DialogType } from '../types/Dialogs';
|
|||
|
||||
import type { PropsType } from './Preferences';
|
||||
import type { WidthBreakpoint } from './_util';
|
||||
import type { MessageAttributesType } from '../model-types';
|
||||
|
||||
const { i18n } = window.SignalContext;
|
||||
|
||||
|
@ -200,6 +201,13 @@ export default {
|
|||
result: exportLocalBackupResult,
|
||||
};
|
||||
},
|
||||
getMessageCountBySchemaVersion: async () => [
|
||||
{ schemaVersion: 10, count: 1024 },
|
||||
{ schemaVersion: 8, count: 256 },
|
||||
],
|
||||
getMessageSampleForSchemaVersion: async () => [
|
||||
{ id: 'messageId' } as MessageAttributesType,
|
||||
],
|
||||
makeSyncRequest: action('makeSyncRequest'),
|
||||
onAudioNotificationsChange: action('onAudioNotificationsChange'),
|
||||
onAutoConvertEmojiChange: action('onAutoConvertEmojiChange'),
|
||||
|
|
|
@ -75,6 +75,8 @@ import { PreferencesInternal } from './PreferencesInternal';
|
|||
import { FunEmojiLocalizationProvider } from './fun/FunEmojiLocalizationProvider';
|
||||
import { NavTabsToggle } from './NavTabs';
|
||||
import type { UnreadStats } from '../util/countUnreadStats';
|
||||
import type { MessageCountBySchemaVersionType } from '../sql/Interface';
|
||||
import type { MessageAttributesType } from '../model-types';
|
||||
|
||||
type CheckboxChangeHandlerType = (value: boolean) => unknown;
|
||||
type SelectChangeHandlerType<T = string | number> = (value: T) => unknown;
|
||||
|
@ -171,6 +173,10 @@ type PropsFunctionType = {
|
|||
doDeleteAllData: () => unknown;
|
||||
editCustomColor: (colorId: string, color: CustomColorType) => unknown;
|
||||
exportLocalBackup: () => Promise<BackupValidationResultType>;
|
||||
getMessageCountBySchemaVersion: () => Promise<MessageCountBySchemaVersionType>;
|
||||
getMessageSampleForSchemaVersion: (
|
||||
version: number
|
||||
) => Promise<Array<MessageAttributesType>>;
|
||||
getConversationsWithCustomColor: (colorId: string) => Array<ConversationType>;
|
||||
makeSyncRequest: () => unknown;
|
||||
onStartUpdate: () => unknown;
|
||||
|
@ -301,6 +307,8 @@ export function Preferences({
|
|||
emojiSkinToneDefault,
|
||||
exportLocalBackup,
|
||||
getConversationsWithCustomColor,
|
||||
getMessageCountBySchemaVersion,
|
||||
getMessageSampleForSchemaVersion,
|
||||
hasAudioNotifications,
|
||||
hasAutoConvertEmoji,
|
||||
hasAutoDownloadUpdate,
|
||||
|
@ -1800,6 +1808,8 @@ export function Preferences({
|
|||
i18n={i18n}
|
||||
exportLocalBackup={exportLocalBackup}
|
||||
validateBackup={validateBackup}
|
||||
getMessageCountBySchemaVersion={getMessageCountBySchemaVersion}
|
||||
getMessageSampleForSchemaVersion={getMessageSampleForSchemaVersion}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,21 +10,35 @@ import type { ValidationResultType as BackupValidationResultType } from '../serv
|
|||
import { SettingsRow, SettingsControl } from './PreferencesUtil';
|
||||
import { Button, ButtonVariant } from './Button';
|
||||
import { Spinner } from './Spinner';
|
||||
import type { MessageCountBySchemaVersionType } from '../sql/Interface';
|
||||
import type { MessageAttributesType } from '../model-types';
|
||||
|
||||
export function PreferencesInternal({
|
||||
i18n,
|
||||
exportLocalBackup: doExportLocalBackup,
|
||||
validateBackup: doValidateBackup,
|
||||
getMessageCountBySchemaVersion,
|
||||
getMessageSampleForSchemaVersion,
|
||||
}: {
|
||||
i18n: LocalizerType;
|
||||
exportLocalBackup: () => Promise<BackupValidationResultType>;
|
||||
validateBackup: () => Promise<BackupValidationResultType>;
|
||||
getMessageCountBySchemaVersion: () => Promise<MessageCountBySchemaVersionType>;
|
||||
getMessageSampleForSchemaVersion: (
|
||||
version: number
|
||||
) => Promise<Array<MessageAttributesType>>;
|
||||
}): JSX.Element {
|
||||
const [isExportPending, setIsExportPending] = useState(false);
|
||||
const [exportResult, setExportResult] = useState<
|
||||
BackupValidationResultType | undefined
|
||||
>();
|
||||
|
||||
const [messageCountBySchemaVersion, setMessageCountBySchemaVersion] =
|
||||
useState<MessageCountBySchemaVersionType>();
|
||||
const [messageSampleForVersions, setMessageSampleForVersions] = useState<{
|
||||
[schemaVersion: number]: Array<MessageAttributesType>;
|
||||
}>();
|
||||
|
||||
const [isValidationPending, setIsValidationPending] = useState(false);
|
||||
const [validationResult, setValidationResult] = useState<
|
||||
BackupValidationResultType | undefined
|
||||
|
@ -68,7 +82,7 @@ export function PreferencesInternal({
|
|||
}
|
||||
|
||||
return (
|
||||
<div className="Preferences--internal--validate-backup--result">
|
||||
<div className="Preferences--internal--result">
|
||||
{snapshotDirEl}
|
||||
<p>Main file size: {formatFileSize(totalBytes)}</p>
|
||||
<p>Duration: {Math.round(duration / SECOND)}s</p>
|
||||
|
@ -82,7 +96,7 @@ export function PreferencesInternal({
|
|||
const { error } = backupResult;
|
||||
|
||||
return (
|
||||
<div className="Preferences--internal--validate-backup--error">
|
||||
<div className="Preferences--internal--error">
|
||||
<pre>
|
||||
<code>{error}</code>
|
||||
</pre>
|
||||
|
@ -105,7 +119,7 @@ export function PreferencesInternal({
|
|||
}, [doExportLocalBackup]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="Preferences--internal">
|
||||
<SettingsRow
|
||||
className="Preferences--internal--backups"
|
||||
title={i18n('icu:Preferences__button--backups')}
|
||||
|
@ -155,6 +169,91 @@ export function PreferencesInternal({
|
|||
|
||||
{renderValidationResult(exportResult)}
|
||||
</SettingsRow>
|
||||
</>
|
||||
|
||||
<SettingsRow
|
||||
className="Preferences--internal--message-schemas"
|
||||
title="Message schema versions"
|
||||
>
|
||||
<SettingsControl
|
||||
left="Check message schema versions"
|
||||
right={
|
||||
<Button
|
||||
variant={ButtonVariant.Secondary}
|
||||
onClick={async () => {
|
||||
setMessageCountBySchemaVersion(
|
||||
await getMessageCountBySchemaVersion()
|
||||
);
|
||||
setMessageSampleForVersions({});
|
||||
}}
|
||||
disabled={isExportPending}
|
||||
>
|
||||
Fetch data
|
||||
</Button>
|
||||
}
|
||||
/>
|
||||
|
||||
{messageCountBySchemaVersion ? (
|
||||
<div className="Preferences--internal--result">
|
||||
<pre>
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Schema version</th>
|
||||
<th># Messages</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{messageCountBySchemaVersion.map(
|
||||
({ schemaVersion, count }) => {
|
||||
return (
|
||||
<React.Fragment key={schemaVersion}>
|
||||
<tr>
|
||||
<td>{schemaVersion}</td>
|
||||
<td>{count}</td>
|
||||
<td>
|
||||
<button
|
||||
type="button"
|
||||
onClick={async () => {
|
||||
const sampleMessages =
|
||||
await getMessageSampleForSchemaVersion(
|
||||
schemaVersion
|
||||
);
|
||||
setMessageSampleForVersions({
|
||||
[schemaVersion]: sampleMessages,
|
||||
});
|
||||
}}
|
||||
disabled={isExportPending}
|
||||
>
|
||||
Sample
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
{messageSampleForVersions?.[schemaVersion] ? (
|
||||
<tr
|
||||
key={`${schemaVersion}_samples`}
|
||||
className="Preferences--internal--subresult"
|
||||
>
|
||||
<td colSpan={3}>
|
||||
<code>
|
||||
{JSON.stringify(
|
||||
messageSampleForVersions[schemaVersion],
|
||||
null,
|
||||
2
|
||||
)}
|
||||
</code>
|
||||
</td>
|
||||
</tr>
|
||||
) : null}
|
||||
</React.Fragment>
|
||||
);
|
||||
}
|
||||
)}
|
||||
</tbody>
|
||||
</table>
|
||||
</pre>
|
||||
</div>
|
||||
) : null}
|
||||
</SettingsRow>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -548,6 +548,11 @@ export enum AttachmentDownloadSource {
|
|||
BACKFILL = 'backfill',
|
||||
}
|
||||
|
||||
export type MessageCountBySchemaVersionType = Array<{
|
||||
schemaVersion: number;
|
||||
count: number;
|
||||
}>;
|
||||
|
||||
export const MESSAGE_ATTACHMENT_COLUMNS = [
|
||||
'messageId',
|
||||
'conversationId',
|
||||
|
@ -888,6 +893,11 @@ type ReadableInterface = {
|
|||
getAttachmentReferencesForMessages: (
|
||||
messageIds: Array<string>
|
||||
) => Array<MessageAttachmentDBType>;
|
||||
|
||||
getMessageCountBySchemaVersion: () => MessageCountBySchemaVersionType;
|
||||
getMessageSampleForSchemaVersion: (
|
||||
version: number
|
||||
) => Array<MessageAttributesType>;
|
||||
};
|
||||
|
||||
type WritableInterface = {
|
||||
|
|
|
@ -186,6 +186,7 @@ import type {
|
|||
MessageAttachmentDBType,
|
||||
MessageTypeUnhydrated,
|
||||
ServerMessageSearchResultType,
|
||||
MessageCountBySchemaVersionType,
|
||||
} from './Interface';
|
||||
import {
|
||||
AttachmentDownloadSource,
|
||||
|
@ -436,6 +437,8 @@ export const DataReader: ServerReadableInterface = {
|
|||
getBackupCdnObjectMetadata,
|
||||
getSizeOfPendingBackupAttachmentDownloadJobs,
|
||||
getAttachmentReferencesForMessages,
|
||||
getMessageCountBySchemaVersion,
|
||||
getMessageSampleForSchemaVersion,
|
||||
|
||||
// Server-only
|
||||
getKnownMessageAttachments,
|
||||
|
@ -8463,6 +8466,37 @@ function getUnreadEditedMessagesAndMarkRead(
|
|||
})();
|
||||
}
|
||||
|
||||
function getMessageCountBySchemaVersion(
|
||||
db: ReadableDB
|
||||
): MessageCountBySchemaVersionType {
|
||||
const [query, params] = sql`
|
||||
SELECT schemaVersion, COUNT(1) as count from messages
|
||||
GROUP BY schemaVersion;
|
||||
`;
|
||||
const rows = db
|
||||
.prepare(query)
|
||||
.all<{ schemaVersion: number; count: number }>(params);
|
||||
|
||||
return rows.sort((a, b) => a.schemaVersion - b.schemaVersion);
|
||||
}
|
||||
|
||||
function getMessageSampleForSchemaVersion(
|
||||
db: ReadableDB,
|
||||
version: number
|
||||
): Array<MessageAttributesType> {
|
||||
return db.transaction(() => {
|
||||
const [query, params] = sql`
|
||||
SELECT * from messages
|
||||
WHERE schemaVersion = ${version}
|
||||
ORDER BY RANDOM()
|
||||
LIMIT 2;
|
||||
`;
|
||||
const rows = db.prepare(query).all<MessageTypeUnhydrated>(params);
|
||||
|
||||
return hydrateMessages(db, rows);
|
||||
})();
|
||||
}
|
||||
|
||||
function disableMessageInsertTriggers(db: WritableDB): void {
|
||||
db.transaction(() => {
|
||||
createOrUpdateItem(db, {
|
||||
|
|
|
@ -55,6 +55,7 @@ import {
|
|||
} from '../selectors/updates';
|
||||
import { getHasAnyFailedStorySends } from '../selectors/stories';
|
||||
import { getOtherTabsUnreadStats } from '../selectors/nav';
|
||||
import { DataReader } from '../../sql/Client';
|
||||
|
||||
const DEFAULT_NOTIFICATION_SETTING = 'message';
|
||||
|
||||
|
@ -604,6 +605,12 @@ export function SmartPreferences(): JSX.Element {
|
|||
doDeleteAllData={doDeleteAllData}
|
||||
editCustomColor={editCustomColor}
|
||||
getConversationsWithCustomColor={getConversationsWithCustomColor}
|
||||
getMessageCountBySchemaVersion={
|
||||
DataReader.getMessageCountBySchemaVersion
|
||||
}
|
||||
getMessageSampleForSchemaVersion={
|
||||
DataReader.getMessageSampleForSchemaVersion
|
||||
}
|
||||
hasAudioNotifications={hasAudioNotifications}
|
||||
hasAutoConvertEmoji={hasAutoConvertEmoji}
|
||||
hasAutoDownloadUpdate={hasAutoDownloadUpdate}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue