diff --git a/src/settings/SettingsModal.jsx b/src/settings/SettingsModal.jsx
index 964973e9..3d82000b 100644
--- a/src/settings/SettingsModal.jsx
+++ b/src/settings/SettingsModal.jsx
@@ -1,4 +1,4 @@
-import React from "react";
+import React, { useState } from "react";
import { Modal } from "../Modal";
import styles from "./SettingsModal.module.css";
import { TabContainer, TabItem } from "../tabs/Tabs";
@@ -8,7 +8,7 @@ import { ReactComponent as DeveloperIcon } from "../icons/Developer.svg";
import { SelectInput } from "../input/SelectInput";
import { Item } from "@react-stately/collections";
import { useMediaHandler } from "./useMediaHandler";
-import { FieldRow, InputField } from "../input/Input";
+import { FieldRow, InputField, ErrorMessage } from "../input/Input";
import { Button } from "../button";
import { useSubmitRageshake } from "./useSubmitRageshake";
@@ -27,7 +27,8 @@ export function SettingsModal({
setVideoInput,
} = useMediaHandler(client);
- const { submitRageshake, downloadDebugLog } = useSubmitRageshake();
+ const { submitRageshake, sending, sent, error, downloadDebugLog } =
+ useSubmitRageshake();
return (
-
+
+ {error && (
+
+ {error.message}
+
+ )}
diff --git a/src/settings/useSubmitRageshake.js b/src/settings/useSubmitRageshake.js
index 2507e900..0c32b8b2 100644
--- a/src/settings/useSubmitRageshake.js
+++ b/src/settings/useSubmitRageshake.js
@@ -1,4 +1,4 @@
-import { useCallback, useContext } from "react";
+import { useCallback, useContext, useState } from "react";
import * as rageshake from "matrix-react-sdk/src/rageshake/rageshake";
import pako from "pako";
import { useClient } from "../ClientContext";
@@ -6,186 +6,205 @@ import { InspectorContext } from "../room/GroupCallInspector";
export function useSubmitRageshake() {
const { client } = useClient();
- const [{ json, svg }] = useContext(InspectorContext);
+ const [{ json }] = useContext(InspectorContext);
+
+ const [{ sending, sent, error }, setState] = useState({
+ sending: false,
+ sent: false,
+ error: null,
+ });
const submitRageshake = useCallback(
async (opts) => {
- let userAgent = "UNKNOWN";
- if (window.navigator && window.navigator.userAgent) {
- userAgent = window.navigator.userAgent;
+ if (sending) {
+ return;
}
- let touchInput = "UNKNOWN";
try {
- // MDN claims broad support across browsers
- touchInput = String(window.matchMedia("(pointer: coarse)").matches);
- } catch (e) {}
+ setState({ sending: true, sent: false, error: null });
- const body = new FormData();
- body.append(
- "text",
- opts.description || "User did not supply any additional text."
- );
- body.append("app", "matrix-video-chat");
- body.append("version", "dev");
- body.append("user_agent", userAgent);
- body.append("installed_pwa", false);
- body.append("touch_input", touchInput);
-
- if (client) {
- body.append("user_id", client.credentials.userId);
- body.append("device_id", client.deviceId);
-
- if (client.isCryptoEnabled()) {
- const keys = [`ed25519:${client.getDeviceEd25519Key()}`];
- if (client.getDeviceCurve25519Key) {
- keys.push(`curve25519:${client.getDeviceCurve25519Key()}`);
- }
- body.append("device_keys", keys.join(", "));
- body.append("cross_signing_key", client.getCrossSigningId());
-
- // add cross-signing status information
- const crossSigning = client.crypto.crossSigningInfo;
- const secretStorage = client.crypto.secretStorage;
-
- body.append(
- "cross_signing_ready",
- String(await client.isCrossSigningReady())
- );
- body.append(
- "cross_signing_supported_by_hs",
- String(
- await client.doesServerSupportUnstableFeature(
- "org.matrix.e2e_cross_signing"
- )
- )
- );
- body.append("cross_signing_key", crossSigning.getId());
- body.append(
- "cross_signing_privkey_in_secret_storage",
- String(
- !!(await crossSigning.isStoredInSecretStorage(secretStorage))
- )
- );
-
- const pkCache = client.getCrossSigningCacheCallbacks();
- body.append(
- "cross_signing_master_privkey_cached",
- String(
- !!(pkCache && (await pkCache.getCrossSigningKeyCache("master")))
- )
- );
- body.append(
- "cross_signing_self_signing_privkey_cached",
- String(
- !!(
- pkCache &&
- (await pkCache.getCrossSigningKeyCache("self_signing"))
- )
- )
- );
- body.append(
- "cross_signing_user_signing_privkey_cached",
- String(
- !!(
- pkCache &&
- (await pkCache.getCrossSigningKeyCache("user_signing"))
- )
- )
- );
-
- body.append(
- "secret_storage_ready",
- String(await client.isSecretStorageReady())
- );
- body.append(
- "secret_storage_key_in_account",
- String(!!(await secretStorage.hasKey()))
- );
-
- body.append(
- "session_backup_key_in_secret_storage",
- String(!!(await client.isKeyBackupKeyStored()))
- );
- const sessionBackupKeyFromCache =
- await client.crypto.getSessionBackupPrivateKey();
- body.append(
- "session_backup_key_cached",
- String(!!sessionBackupKeyFromCache)
- );
- body.append(
- "session_backup_key_well_formed",
- String(sessionBackupKeyFromCache instanceof Uint8Array)
- );
+ let userAgent = "UNKNOWN";
+ if (window.navigator && window.navigator.userAgent) {
+ userAgent = window.navigator.userAgent;
}
- }
- if (opts.label) {
- body.append("label", opts.label);
- }
-
- // add storage persistence/quota information
- if (navigator.storage && navigator.storage.persisted) {
+ let touchInput = "UNKNOWN";
try {
- body.append(
- "storageManager_persisted",
- String(await navigator.storage.persisted())
- );
+ // MDN claims broad support across browsers
+ touchInput = String(window.matchMedia("(pointer: coarse)").matches);
} catch (e) {}
- } else if (document.hasStorageAccess) {
- // Safari
- try {
- body.append(
- "storageManager_persisted",
- String(await document.hasStorageAccess())
- );
- } catch (e) {}
- }
- if (navigator.storage && navigator.storage.estimate) {
- try {
- const estimate = await navigator.storage.estimate();
- body.append("storageManager_quota", String(estimate.quota));
- body.append("storageManager_usage", String(estimate.usage));
- if (estimate.usageDetails) {
- Object.keys(estimate.usageDetails).forEach((k) => {
- body.append(
- `storageManager_usage_${k}`,
- String(estimate.usageDetails[k])
- );
- });
- }
- } catch (e) {}
- }
-
- const logs = await rageshake.getLogsForReport();
-
- for (const entry of logs) {
- // encode as UTF-8
- let buf = new TextEncoder().encode(entry.lines);
-
- // compress
- buf = pako.gzip(buf);
-
- body.append("compressed-log", new Blob([buf]), entry.id);
- }
-
- if (json) {
+ const body = new FormData();
body.append(
- "file",
- new Blob([JSON.stringify(json)], { type: "text/plain" }),
- "groupcall.txt"
+ "text",
+ opts.description || "User did not supply any additional text."
);
- }
+ body.append("app", "matrix-video-chat");
+ body.append("version", "dev");
+ body.append("user_agent", userAgent);
+ body.append("installed_pwa", false);
+ body.append("touch_input", touchInput);
- await fetch(
- import.meta.env.VITE_RAGESHAKE_SUBMIT_URL ||
- "https://element.io/bugreports/submit",
- {
- method: "POST",
- body,
+ if (client) {
+ body.append("user_id", client.credentials.userId);
+ body.append("device_id", client.deviceId);
+
+ if (client.isCryptoEnabled()) {
+ const keys = [`ed25519:${client.getDeviceEd25519Key()}`];
+ if (client.getDeviceCurve25519Key) {
+ keys.push(`curve25519:${client.getDeviceCurve25519Key()}`);
+ }
+ body.append("device_keys", keys.join(", "));
+ body.append("cross_signing_key", client.getCrossSigningId());
+
+ // add cross-signing status information
+ const crossSigning = client.crypto.crossSigningInfo;
+ const secretStorage = client.crypto.secretStorage;
+
+ body.append(
+ "cross_signing_ready",
+ String(await client.isCrossSigningReady())
+ );
+ body.append(
+ "cross_signing_supported_by_hs",
+ String(
+ await client.doesServerSupportUnstableFeature(
+ "org.matrix.e2e_cross_signing"
+ )
+ )
+ );
+ body.append("cross_signing_key", crossSigning.getId());
+ body.append(
+ "cross_signing_privkey_in_secret_storage",
+ String(
+ !!(await crossSigning.isStoredInSecretStorage(secretStorage))
+ )
+ );
+
+ const pkCache = client.getCrossSigningCacheCallbacks();
+ body.append(
+ "cross_signing_master_privkey_cached",
+ String(
+ !!(pkCache && (await pkCache.getCrossSigningKeyCache("master")))
+ )
+ );
+ body.append(
+ "cross_signing_self_signing_privkey_cached",
+ String(
+ !!(
+ pkCache &&
+ (await pkCache.getCrossSigningKeyCache("self_signing"))
+ )
+ )
+ );
+ body.append(
+ "cross_signing_user_signing_privkey_cached",
+ String(
+ !!(
+ pkCache &&
+ (await pkCache.getCrossSigningKeyCache("user_signing"))
+ )
+ )
+ );
+
+ body.append(
+ "secret_storage_ready",
+ String(await client.isSecretStorageReady())
+ );
+ body.append(
+ "secret_storage_key_in_account",
+ String(!!(await secretStorage.hasKey()))
+ );
+
+ body.append(
+ "session_backup_key_in_secret_storage",
+ String(!!(await client.isKeyBackupKeyStored()))
+ );
+ const sessionBackupKeyFromCache =
+ await client.crypto.getSessionBackupPrivateKey();
+ body.append(
+ "session_backup_key_cached",
+ String(!!sessionBackupKeyFromCache)
+ );
+ body.append(
+ "session_backup_key_well_formed",
+ String(sessionBackupKeyFromCache instanceof Uint8Array)
+ );
+ }
}
- );
+
+ if (opts.label) {
+ body.append("label", opts.label);
+ }
+
+ // add storage persistence/quota information
+ if (navigator.storage && navigator.storage.persisted) {
+ try {
+ body.append(
+ "storageManager_persisted",
+ String(await navigator.storage.persisted())
+ );
+ } catch (e) {}
+ } else if (document.hasStorageAccess) {
+ // Safari
+ try {
+ body.append(
+ "storageManager_persisted",
+ String(await document.hasStorageAccess())
+ );
+ } catch (e) {}
+ }
+
+ if (navigator.storage && navigator.storage.estimate) {
+ try {
+ const estimate = await navigator.storage.estimate();
+ body.append("storageManager_quota", String(estimate.quota));
+ body.append("storageManager_usage", String(estimate.usage));
+ if (estimate.usageDetails) {
+ Object.keys(estimate.usageDetails).forEach((k) => {
+ body.append(
+ `storageManager_usage_${k}`,
+ String(estimate.usageDetails[k])
+ );
+ });
+ }
+ } catch (e) {}
+ }
+
+ const logs = await rageshake.getLogsForReport();
+
+ for (const entry of logs) {
+ // encode as UTF-8
+ let buf = new TextEncoder().encode(entry.lines);
+
+ // compress
+ buf = pako.gzip(buf);
+
+ body.append("compressed-log", new Blob([buf]), entry.id);
+ }
+
+ if (json) {
+ body.append(
+ "file",
+ new Blob([JSON.stringify(json)], { type: "text/plain" }),
+ "groupcall.txt"
+ );
+ }
+
+ await fetch(
+ import.meta.env.VITE_RAGESHAKE_SUBMIT_URL ||
+ "https://element.io/bugreports/submit",
+ {
+ method: "POST",
+ body,
+ }
+ );
+
+ setState({ sending: false, sent: true, error: null });
+ } catch (error) {
+ setState({ sending: false, sent: false, error });
+ console.error(error);
+ }
},
[client]
);
@@ -205,5 +224,5 @@ export function useSubmitRageshake() {
}, 0);
});
- return { submitRageshake, downloadDebugLog };
+ return { submitRageshake, sending, sent, error, downloadDebugLog };
}