diff --git a/web/database/worker/db-worker.js b/web/database/worker/db-worker.js
--- a/web/database/worker/db-worker.js
+++ b/web/database/worker/db-worker.js
@@ -148,6 +148,17 @@
async function processAppRequest(
message: WorkerRequestMessage,
): Promise {
+ // testing
+ if (message.type === workerRequestMessageTypes.GET_DB_FILE) {
+ if (!dbModule) {
+ throw new Error(`Database not initialized, unable export database file`);
+ }
+ return {
+ type: workerResponseMessageTypes.GET_DB_FILE,
+ file: exportDatabaseContent(dbModule, COMM_SQLITE_DATABASE_PATH),
+ };
+ }
+
// non-database operations
if (message.type === workerRequestMessageTypes.PING) {
return {
diff --git a/web/settings/account-settings.react.js b/web/settings/account-settings.react.js
--- a/web/settings/account-settings.react.js
+++ b/web/settings/account-settings.react.js
@@ -20,7 +20,9 @@
import TunnelbrokerTestScreen from './tunnelbroker-test.react.js';
import EditUserAvatar from '../avatars/edit-user-avatar.react.js';
import Button from '../components/button.react.js';
+import { getDatabaseModule } from '../database/database-module-provider.js';
import { useSelector } from '../redux/redux-utils.js';
+import { workerRequestMessageTypes } from '../types/worker-types.js';
import { useStaffCanSee } from '../utils/staff-utils.js';
function AccountSettings(): React.Node {
@@ -82,6 +84,27 @@
[popModal, pushModal],
);
+ const downloadDatabaseFile = React.useCallback(async () => {
+ const databaseModule = await getDatabaseModule();
+ const response = await databaseModule.schedule({
+ type: workerRequestMessageTypes.GET_DB_FILE,
+ });
+ if (!response) {
+ return;
+ }
+ const { file } = response;
+ const blob = new Blob([file]);
+ const a = document.createElement('a');
+ const url = URL.createObjectURL(blob);
+ a.href = url;
+ a.download = 'web.sqlite';
+
+ document.body?.appendChild(a);
+ a.click();
+ document.body?.removeChild(a);
+ window.URL.revokeObjectURL(url);
+ }, []);
+
const showAppearanceModal = React.useCallback(
() => pushModal(