feat: landing page + logo, dev-mode banner + sync cap, non-blocking sync with progress splash
This commit is contained in:
@@ -1,8 +1,9 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import GridLayout from 'react-grid-layout';
|
||||
import 'react-grid-layout/css/styles.css';
|
||||
import 'react-resizable/css/styles.css';
|
||||
import { AnalyticsApi, LayoutApi, ExportApi } from '../api/client.js';
|
||||
import { AnalyticsApi, LayoutApi, ExportApi, SyncApi } from '../api/client.js';
|
||||
import SyncSplash from '../components/SyncSplash.jsx';
|
||||
import {
|
||||
HealthWidget, StatCard, TopSendersWidget, VolumeWidget,
|
||||
HeatmapWidget, AttachmentsWidget, StorageWidget
|
||||
@@ -26,16 +27,37 @@ export default function Dashboard() {
|
||||
const [data, setData] = useState(null);
|
||||
const [layout, setLayout] = useState(DEFAULT_LAYOUT);
|
||||
const [hidden, setHidden] = useState([]);
|
||||
const [syncing, setSyncing] = useState(false);
|
||||
|
||||
const loadData = useCallback(() => {
|
||||
AnalyticsApi.dashboard().then(setData).catch(() => {});
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
AnalyticsApi.dashboard().then(setData).catch(() => {});
|
||||
LayoutApi.get().then((saved) => {
|
||||
if (saved?.length) {
|
||||
setLayout(saved.map((w) => ({ i: w.widgetKey, x: w.x, y: w.y, w: w.w, h: w.h })));
|
||||
setHidden(saved.filter((w) => !w.visible).map((w) => w.widgetKey));
|
||||
}
|
||||
}).catch(() => {});
|
||||
}, []);
|
||||
|
||||
// Decide whether to show the loading splash: if a sync is running, watch it;
|
||||
// if the inbox has never been synced, kick one off automatically.
|
||||
SyncApi.status().then((s) => {
|
||||
if (s.isRunning) {
|
||||
setSyncing(true);
|
||||
} else if (!s.lastSuccessfulSyncUtc) {
|
||||
SyncApi.incremental().then(() => setSyncing(true)).catch(loadData);
|
||||
} else {
|
||||
loadData();
|
||||
}
|
||||
}).catch(loadData);
|
||||
}, [loadData]);
|
||||
|
||||
const onSyncDone = useCallback(() => {
|
||||
setSyncing(false);
|
||||
loadData();
|
||||
}, [loadData]);
|
||||
|
||||
const persist = (nextLayout, nextHidden) => {
|
||||
const dto = nextLayout.map((l, idx) => ({
|
||||
@@ -69,6 +91,7 @@ export default function Dashboard() {
|
||||
|
||||
return (
|
||||
<div className="dashboard">
|
||||
{syncing && <SyncSplash onDone={onSyncDone} />}
|
||||
<div className="toolbar">
|
||||
<div className="widget-toggles">
|
||||
{ALL_WIDGETS.map((k) => (
|
||||
|
||||
Reference in New Issue
Block a user