mirror of
https://github.com/Dvorinka/Containr.git
synced 2026-10-28 07:41:27 +00:00
* feat(offline): persisted query cache + unreachable banner (web + mobile) - Web: PersistQueryClientProvider on localStorage (24h maxAge); mobile: AsyncStorage persister (7d). Both exclude high-churn keys (logs, notifications, metrics) — stale tails are worse than none. - networkMode 'offlineFirst' so cached data serves while the refetch attempt fails. - Web: ConnectivityBanner in PlatformShell pings public /health every 15s + listens to online/offline events — slim "last-known data" bar so persisted state can't masquerade as live. - Mobile: same banner in the tabs layout — /health ping plus expo-network's local signal distinguishes "no connection" from "instance down". Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * feat(mobile): cron jobs screen — schedules, run-now, execution history - /service/cron lists the service's jobs with schedule, timezone, last/next run, and last status; "Run now" triggers via the existing POST /cron-jobs/:id/trigger and "History" expands recent executions with status + output/error. - Manage row on the service detail + Stack registration. Verified live: created */5 job on a running service, triggered it — execution recorded with status success and captured stdout. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
63 lines
1.6 KiB
TypeScript
63 lines
1.6 KiB
TypeScript
import { StrictMode } from 'react';
|
|
import { createRoot } from 'react-dom/client';
|
|
import { QueryClient } from '@tanstack/react-query';
|
|
import { PersistQueryClientProvider } from '@tanstack/react-query-persist-client';
|
|
import { createSyncStoragePersister } from '@tanstack/query-sync-storage-persister';
|
|
import { BrowserRouter } from 'react-router-dom';
|
|
import App from './app/App';
|
|
import { ToastProvider } from './shared/components';
|
|
import './index.css';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
staleTime: 30_000,
|
|
retry: 1,
|
|
refetchOnWindowFocus: false,
|
|
// Serve the persisted snapshot while offline instead of erroring.
|
|
networkMode: 'offlineFirst',
|
|
},
|
|
},
|
|
});
|
|
|
|
// High-churn or bulky keys never hit localStorage — a stale log tail is
|
|
// worse than none.
|
|
const NEVER_PERSIST = new Set([
|
|
'shell-notifications',
|
|
'notifications',
|
|
'service-logs',
|
|
'logs',
|
|
'activity',
|
|
'audit-logs',
|
|
'audit',
|
|
'metrics',
|
|
'connectivity',
|
|
]);
|
|
|
|
const persister = createSyncStoragePersister({
|
|
storage: window.localStorage,
|
|
key: 'containr-query-cache-v1',
|
|
});
|
|
|
|
createRoot(document.getElementById('root')!).render(
|
|
<StrictMode>
|
|
<PersistQueryClientProvider
|
|
client={queryClient}
|
|
persistOptions={{
|
|
persister,
|
|
maxAge: 24 * 60 * 60 * 1000,
|
|
dehydrateOptions: {
|
|
shouldDehydrateQuery: (q) =>
|
|
q.state.status === 'success' && !NEVER_PERSIST.has(String(q.queryKey[0])),
|
|
},
|
|
}}
|
|
>
|
|
<BrowserRouter>
|
|
<ToastProvider>
|
|
<App />
|
|
</ToastProvider>
|
|
</BrowserRouter>
|
|
</PersistQueryClientProvider>
|
|
</StrictMode>,
|
|
);
|