@buoy-gg/time-machine 7.0.40 → 7.0.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/lib/commonjs/components/HeaderActions.js +1 -91
- package/lib/commonjs/components/HeaderReloadButton.js +1 -58
- package/lib/commonjs/components/TimeMachineBody.js +1 -282
- package/lib/commonjs/components/TimeMachineModal.js +1 -74
- package/lib/commonjs/components/confirm.js +2 -38
- package/lib/commonjs/components/floating/NamePromptModal.js +1 -193
- package/lib/commonjs/components/floating/TimeMachineFloatingTool.js +1 -715
- package/lib/commonjs/components/floating/armedPoint.js +1 -92
- package/lib/commonjs/components/floating/barSettings.js +1 -66
- package/lib/commonjs/components/format.js +1 -24
- package/lib/commonjs/components/list/CaptureBar.js +1 -97
- package/lib/commonjs/components/list/RestoreOutcomeCard.js +1 -175
- package/lib/commonjs/components/list/SnapshotRow.js +1 -170
- package/lib/commonjs/components/list/SourcesStrip.js +1 -172
- package/lib/commonjs/components/list/UndoDeleteBar.js +1 -85
- package/lib/commonjs/components/list/WipeAllRow.js +1 -46
- package/lib/commonjs/components/preview/ItemDiffPanel.js +1 -79
- package/lib/commonjs/components/preview/PreviewFlow.js +1 -51
- package/lib/commonjs/components/preview/RestorePointNameRow.js +1 -83
- package/lib/commonjs/components/preview/RestorePreviewScreen.js +1 -1010
- package/lib/commonjs/components/preview/verdictMeta.js +1 -58
- package/lib/commonjs/components/sources.js +1 -83
- package/lib/commonjs/hooks/useTimeMachine.js +1 -24
- package/lib/commonjs/index.js +1 -161
- package/lib/commonjs/preset.js +1 -56
- package/lib/commonjs/store/routeRestore.js +1 -188
- package/lib/commonjs/store/snapshotVault.js +1 -186
- package/lib/commonjs/store/sourceIds.js +1 -9
- package/lib/commonjs/store/sourceSettings.js +1 -79
- package/lib/commonjs/store/timeMachineStore.js +1 -848
- package/lib/commonjs/sync/timeMachineSyncAdapter.js +1 -258
- package/lib/commonjs/ui/SwipeActionsRow.js +1 -178
- package/lib/commonjs/ui/primitives.js +1 -172
- package/lib/commonjs/ui/tmTheme.js +1 -118
- package/lib/module/components/HeaderActions.js +1 -85
- package/lib/module/components/HeaderReloadButton.js +1 -53
- package/lib/module/components/TimeMachineBody.js +1 -277
- package/lib/module/components/TimeMachineModal.js +1 -68
- package/lib/module/components/confirm.js +2 -33
- package/lib/module/components/floating/NamePromptModal.js +1 -188
- package/lib/module/components/floating/TimeMachineFloatingTool.js +1 -708
- package/lib/module/components/floating/armedPoint.js +1 -82
- package/lib/module/components/floating/barSettings.js +1 -57
- package/lib/module/components/format.js +1 -19
- package/lib/module/components/list/CaptureBar.js +1 -92
- package/lib/module/components/list/RestoreOutcomeCard.js +1 -169
- package/lib/module/components/list/SnapshotRow.js +1 -167
- package/lib/module/components/list/SourcesStrip.js +1 -169
- package/lib/module/components/list/UndoDeleteBar.js +1 -82
- package/lib/module/components/list/WipeAllRow.js +1 -41
- package/lib/module/components/preview/ItemDiffPanel.js +1 -74
- package/lib/module/components/preview/PreviewFlow.js +1 -46
- package/lib/module/components/preview/RestorePointNameRow.js +1 -78
- package/lib/module/components/preview/RestorePreviewScreen.js +1 -1005
- package/lib/module/components/preview/verdictMeta.js +1 -54
- package/lib/module/components/sources.js +1 -73
- package/lib/module/hooks/useTimeMachine.js +1 -19
- package/lib/module/index.js +1 -46
- package/lib/module/preset.js +1 -51
- package/lib/module/store/routeRestore.js +1 -176
- package/lib/module/store/snapshotVault.js +1 -170
- package/lib/module/store/sourceIds.js +1 -5
- package/lib/module/store/sourceSettings.js +1 -69
- package/lib/module/store/timeMachineStore.js +1 -839
- package/lib/module/sync/timeMachineSyncAdapter.js +1 -253
- package/lib/module/ui/SwipeActionsRow.js +1 -173
- package/lib/module/ui/primitives.js +1 -164
- package/lib/module/ui/tmTheme.js +1 -114
- package/lib/web/index.mjs +3 -0
- package/package.json +43 -10
- package/lib/commonjs/components/HeaderActions.js.map +0 -1
- package/lib/commonjs/components/HeaderReloadButton.js.map +0 -1
- package/lib/commonjs/components/TimeMachineBody.js.map +0 -1
- package/lib/commonjs/components/TimeMachineModal.js.map +0 -1
- package/lib/commonjs/components/confirm.js.map +0 -1
- package/lib/commonjs/components/floating/NamePromptModal.js.map +0 -1
- package/lib/commonjs/components/floating/TimeMachineFloatingTool.js.map +0 -1
- package/lib/commonjs/components/floating/armedPoint.js.map +0 -1
- package/lib/commonjs/components/floating/barSettings.js.map +0 -1
- package/lib/commonjs/components/format.js.map +0 -1
- package/lib/commonjs/components/list/CaptureBar.js.map +0 -1
- package/lib/commonjs/components/list/RestoreOutcomeCard.js.map +0 -1
- package/lib/commonjs/components/list/SnapshotRow.js.map +0 -1
- package/lib/commonjs/components/list/SourcesStrip.js.map +0 -1
- package/lib/commonjs/components/list/UndoDeleteBar.js.map +0 -1
- package/lib/commonjs/components/list/WipeAllRow.js.map +0 -1
- package/lib/commonjs/components/preview/ItemDiffPanel.js.map +0 -1
- package/lib/commonjs/components/preview/PreviewFlow.js.map +0 -1
- package/lib/commonjs/components/preview/RestorePointNameRow.js.map +0 -1
- package/lib/commonjs/components/preview/RestorePreviewScreen.js.map +0 -1
- package/lib/commonjs/components/preview/verdictMeta.js.map +0 -1
- package/lib/commonjs/components/sources.js.map +0 -1
- package/lib/commonjs/hooks/useTimeMachine.js.map +0 -1
- package/lib/commonjs/index.js.map +0 -1
- package/lib/commonjs/preset.js.map +0 -1
- package/lib/commonjs/store/routeRestore.js.map +0 -1
- package/lib/commonjs/store/snapshotVault.js.map +0 -1
- package/lib/commonjs/store/sourceIds.js.map +0 -1
- package/lib/commonjs/store/sourceSettings.js.map +0 -1
- package/lib/commonjs/store/timeMachineStore.js.map +0 -1
- package/lib/commonjs/sync/timeMachineSyncAdapter.js.map +0 -1
- package/lib/commonjs/ui/SwipeActionsRow.js.map +0 -1
- package/lib/commonjs/ui/primitives.js.map +0 -1
- package/lib/commonjs/ui/tmTheme.js.map +0 -1
- package/lib/module/components/HeaderActions.js.map +0 -1
- package/lib/module/components/HeaderReloadButton.js.map +0 -1
- package/lib/module/components/TimeMachineBody.js.map +0 -1
- package/lib/module/components/TimeMachineModal.js.map +0 -1
- package/lib/module/components/confirm.js.map +0 -1
- package/lib/module/components/floating/NamePromptModal.js.map +0 -1
- package/lib/module/components/floating/TimeMachineFloatingTool.js.map +0 -1
- package/lib/module/components/floating/armedPoint.js.map +0 -1
- package/lib/module/components/floating/barSettings.js.map +0 -1
- package/lib/module/components/format.js.map +0 -1
- package/lib/module/components/list/CaptureBar.js.map +0 -1
- package/lib/module/components/list/RestoreOutcomeCard.js.map +0 -1
- package/lib/module/components/list/SnapshotRow.js.map +0 -1
- package/lib/module/components/list/SourcesStrip.js.map +0 -1
- package/lib/module/components/list/UndoDeleteBar.js.map +0 -1
- package/lib/module/components/list/WipeAllRow.js.map +0 -1
- package/lib/module/components/preview/ItemDiffPanel.js.map +0 -1
- package/lib/module/components/preview/PreviewFlow.js.map +0 -1
- package/lib/module/components/preview/RestorePointNameRow.js.map +0 -1
- package/lib/module/components/preview/RestorePreviewScreen.js.map +0 -1
- package/lib/module/components/preview/verdictMeta.js.map +0 -1
- package/lib/module/components/sources.js.map +0 -1
- package/lib/module/hooks/useTimeMachine.js.map +0 -1
- package/lib/module/index.js.map +0 -1
- package/lib/module/preset.js.map +0 -1
- package/lib/module/store/routeRestore.js.map +0 -1
- package/lib/module/store/snapshotVault.js.map +0 -1
- package/lib/module/store/sourceIds.js.map +0 -1
- package/lib/module/store/sourceSettings.js.map +0 -1
- package/lib/module/store/timeMachineStore.js.map +0 -1
- package/lib/module/sync/timeMachineSyncAdapter.js.map +0 -1
- package/lib/module/ui/SwipeActionsRow.js.map +0 -1
- package/lib/module/ui/primitives.js.map +0 -1
- package/lib/module/ui/tmTheme.js.map +0 -1
- package/lib/typescript/components/HeaderActions.d.ts.map +0 -1
- package/lib/typescript/components/HeaderReloadButton.d.ts.map +0 -1
- package/lib/typescript/components/TimeMachineBody.d.ts.map +0 -1
- package/lib/typescript/components/TimeMachineModal.d.ts.map +0 -1
- package/lib/typescript/components/confirm.d.ts.map +0 -1
- package/lib/typescript/components/floating/NamePromptModal.d.ts.map +0 -1
- package/lib/typescript/components/floating/TimeMachineFloatingTool.d.ts.map +0 -1
- package/lib/typescript/components/floating/armedPoint.d.ts.map +0 -1
- package/lib/typescript/components/floating/barSettings.d.ts.map +0 -1
- package/lib/typescript/components/format.d.ts.map +0 -1
- package/lib/typescript/components/list/CaptureBar.d.ts.map +0 -1
- package/lib/typescript/components/list/RestoreOutcomeCard.d.ts.map +0 -1
- package/lib/typescript/components/list/SnapshotRow.d.ts.map +0 -1
- package/lib/typescript/components/list/SourcesStrip.d.ts.map +0 -1
- package/lib/typescript/components/list/UndoDeleteBar.d.ts.map +0 -1
- package/lib/typescript/components/list/WipeAllRow.d.ts.map +0 -1
- package/lib/typescript/components/preview/ItemDiffPanel.d.ts.map +0 -1
- package/lib/typescript/components/preview/PreviewFlow.d.ts.map +0 -1
- package/lib/typescript/components/preview/RestorePointNameRow.d.ts.map +0 -1
- package/lib/typescript/components/preview/RestorePreviewScreen.d.ts.map +0 -1
- package/lib/typescript/components/preview/verdictMeta.d.ts.map +0 -1
- package/lib/typescript/components/sources.d.ts.map +0 -1
- package/lib/typescript/hooks/useTimeMachine.d.ts.map +0 -1
- package/lib/typescript/index.d.ts.map +0 -1
- package/lib/typescript/preset.d.ts.map +0 -1
- package/lib/typescript/store/routeRestore.d.ts.map +0 -1
- package/lib/typescript/store/snapshotVault.d.ts.map +0 -1
- package/lib/typescript/store/sourceIds.d.ts.map +0 -1
- package/lib/typescript/store/sourceSettings.d.ts.map +0 -1
- package/lib/typescript/store/timeMachineStore.d.ts.map +0 -1
- package/lib/typescript/sync/timeMachineSyncAdapter.d.ts.map +0 -1
- package/lib/typescript/ui/SwipeActionsRow.d.ts.map +0 -1
- package/lib/typescript/ui/primitives.d.ts.map +0 -1
- package/lib/typescript/ui/tmTheme.d.ts.map +0 -1
|
@@ -1,82 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Which restore point the floating restore bar restores on tap.
|
|
5
|
-
*
|
|
6
|
-
* The bar needs an answer before the user picks anything, or its first tap is
|
|
7
|
-
* a picker instead of a restore. So the armed point is resolved, not just
|
|
8
|
-
* stored: an explicit pick wins, then the point restored most recently, then
|
|
9
|
-
* the newest capture. Baselines never resolve; restoring one wipes storage
|
|
10
|
-
* and reloads behind a confirm dialog, which is not a one-tap action. The
|
|
11
|
-
* safety slot never resolves either: Undo is its way in.
|
|
12
|
-
*
|
|
13
|
-
* The explicit pick is persisted so it survives the reloads the loop itself
|
|
14
|
-
* causes (RELOAD APP, reload-mode restores).
|
|
15
|
-
*/
|
|
16
|
-
import { devToolsStorageKeys, persistentStorage } from "@buoy-gg/shared-ui";
|
|
17
|
-
const KEY = devToolsStorageKeys.timeMachine.armedPoint();
|
|
18
|
-
let pickedId = null;
|
|
19
|
-
let loaded = false;
|
|
20
|
-
let loadPromise = null;
|
|
21
|
-
const listeners = new Set();
|
|
22
|
-
const notify = () => listeners.forEach(listener => listener());
|
|
23
|
-
export function getPickedPointId() {
|
|
24
|
-
return pickedId;
|
|
25
|
-
}
|
|
26
|
-
export function subscribePickedPoint(listener) {
|
|
27
|
-
listeners.add(listener);
|
|
28
|
-
return () => {
|
|
29
|
-
listeners.delete(listener);
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/** Read the saved pick once. Later calls return the same promise. */
|
|
34
|
-
export function ensurePickedPointLoaded() {
|
|
35
|
-
if (loaded) return Promise.resolve();
|
|
36
|
-
if (!loadPromise) {
|
|
37
|
-
loadPromise = persistentStorage.getItem(KEY).then(saved => {
|
|
38
|
-
// A pick made while the read was in flight wins over the disk copy.
|
|
39
|
-
if (pickedId === null && saved) {
|
|
40
|
-
pickedId = saved;
|
|
41
|
-
notify();
|
|
42
|
-
}
|
|
43
|
-
}).catch(() => {}).finally(() => {
|
|
44
|
-
loaded = true;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
return loadPromise;
|
|
48
|
-
}
|
|
49
|
-
export function setPickedPointId(id) {
|
|
50
|
-
if (pickedId === id) return;
|
|
51
|
-
pickedId = id;
|
|
52
|
-
notify();
|
|
53
|
-
void (id === null ? persistentStorage.removeItem(KEY) : persistentStorage.setItem(KEY, id)).catch(() => {});
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** Test seam: forget the pick and the load, without touching storage. */
|
|
57
|
-
export function resetPickedPointForTests() {
|
|
58
|
-
pickedId = null;
|
|
59
|
-
loaded = false;
|
|
60
|
-
loadPromise = null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* The point the bar restores: the saved pick if it still exists, else the
|
|
65
|
-
* most recently restored point, else the newest capture. Never a baseline.
|
|
66
|
-
*/
|
|
67
|
-
export function resolveArmedPoint(snapshots, pickedId) {
|
|
68
|
-
const candidates = snapshots.filter(meta => !meta.baseline && !meta.safety);
|
|
69
|
-
if (candidates.length === 0) return null;
|
|
70
|
-
if (pickedId) {
|
|
71
|
-
const picked = candidates.find(meta => meta.id === pickedId);
|
|
72
|
-
if (picked) return picked;
|
|
73
|
-
}
|
|
74
|
-
let best = null;
|
|
75
|
-
for (const meta of candidates) {
|
|
76
|
-
if (meta.lastRestoredAt === undefined) continue;
|
|
77
|
-
if (!best || meta.lastRestoredAt > (best.lastRestoredAt ?? 0)) best = meta;
|
|
78
|
-
}
|
|
79
|
-
if (best) return best;
|
|
80
|
-
return candidates.reduce((newest, meta) => meta.createdAt > newest.createdAt ? meta : newest);
|
|
81
|
-
}
|
|
82
|
-
//# sourceMappingURL=armedPoint.js.map
|
|
1
|
+
"use strict";import{devToolsStorageKeys as P,persistentStorage as s}from"@buoy-gg/shared-ui";const c=P.timeMachine.armedPoint();let n=null;let u=false;let l=null;const d=new Set;const a=()=>d.forEach(e=>e());export function getPickedPointId(){return n}export function subscribePickedPoint(e){d.add(e);return()=>{d.delete(e)}}export function ensurePickedPointLoaded(){if(u)return Promise.resolve();if(!l){l=s.getItem(c).then(e=>{if(n===null&&e){n=e;a()}}).catch(()=>{}).finally(()=>{u=true})}return l}export function setPickedPointId(e){if(n===e)return;n=e;a();void(e===null?s.removeItem(c):s.setItem(c,e)).catch(()=>{})}export function resetPickedPointForTests(){n=null;u=false;l=null}export function resolveArmedPoint(e,f){const o=e.filter(t=>!t.baseline&&!t.safety);if(o.length===0)return null;if(f){const t=o.find(i=>i.id===f);if(t)return t}let r=null;for(const t of o){if(t.lastRestoredAt===void 0)continue;if(!r||t.lastRestoredAt>(r.lastRestoredAt??0))r=t}if(r)return r;return o.reduce((t,i)=>i.createdAt>t.createdAt?i:t)}
|
|
@@ -1,57 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The action bar's one setting: restore live, or restore and reload.
|
|
5
|
-
*
|
|
6
|
-
* Live restore replaces stores in place and is right for state that lives in
|
|
7
|
-
* Redux, Zustand, Jotai or the query cache. It cannot reach a React context
|
|
8
|
-
* or `useState` that hydrates itself from storage once at mount: the
|
|
9
|
-
* storage key comes back, the screen keeps showing what it already had, and
|
|
10
|
-
* "restore did nothing" is the report. A restore that reloads the app makes
|
|
11
|
-
* those screens rebuild from the restored storage. Persisted, because the
|
|
12
|
-
* reload itself is what brings the bar back.
|
|
13
|
-
*/
|
|
14
|
-
import { devToolsStorageKeys, persistentStorage } from "@buoy-gg/shared-ui";
|
|
15
|
-
const KEY = devToolsStorageKeys.timeMachine.barReloadMode();
|
|
16
|
-
let reloadMode = false;
|
|
17
|
-
let loaded = false;
|
|
18
|
-
let loadPromise = null;
|
|
19
|
-
const listeners = new Set();
|
|
20
|
-
const notify = () => listeners.forEach(listener => listener());
|
|
21
|
-
export function getBarReloadMode() {
|
|
22
|
-
return reloadMode;
|
|
23
|
-
}
|
|
24
|
-
export function subscribeBarSettings(listener) {
|
|
25
|
-
listeners.add(listener);
|
|
26
|
-
return () => {
|
|
27
|
-
listeners.delete(listener);
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
export function ensureBarSettingsLoaded() {
|
|
31
|
-
if (loaded) return Promise.resolve();
|
|
32
|
-
if (!loadPromise) {
|
|
33
|
-
loadPromise = persistentStorage.getItem(KEY).then(saved => {
|
|
34
|
-
if (!reloadMode && saved === "1") {
|
|
35
|
-
reloadMode = true;
|
|
36
|
-
notify();
|
|
37
|
-
}
|
|
38
|
-
}).catch(() => {}).finally(() => {
|
|
39
|
-
loaded = true;
|
|
40
|
-
});
|
|
41
|
-
}
|
|
42
|
-
return loadPromise;
|
|
43
|
-
}
|
|
44
|
-
export function setBarReloadMode(on) {
|
|
45
|
-
if (on === reloadMode) return;
|
|
46
|
-
reloadMode = on;
|
|
47
|
-
notify();
|
|
48
|
-
void persistentStorage.setItem(KEY, on ? "1" : "0").catch(() => {});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
/** Test seam. */
|
|
52
|
-
export function resetBarSettingsForTests() {
|
|
53
|
-
reloadMode = false;
|
|
54
|
-
loaded = false;
|
|
55
|
-
loadPromise = null;
|
|
56
|
-
}
|
|
57
|
-
//# sourceMappingURL=barSettings.js.map
|
|
1
|
+
"use strict";import{devToolsStorageKeys as l,persistentStorage as s}from"@buoy-gg/shared-ui";const a=l.timeMachine.barReloadMode();let t=false;let o=false;let r=null;const n=new Set;const i=()=>n.forEach(e=>e());export function getBarReloadMode(){return t}export function subscribeBarSettings(e){n.add(e);return()=>{n.delete(e)}}export function ensureBarSettingsLoaded(){if(o)return Promise.resolve();if(!r){r=s.getItem(a).then(e=>{if(!t&&e==="1"){t=true;i()}}).catch(()=>{}).finally(()=>{o=true})}return r}export function setBarReloadMode(e){if(e===t)return;t=e;i();void s.setItem(a,e?"1":"0").catch(()=>{})}export function resetBarSettingsForTests(){t=false;o=false;r=null}
|
|
@@ -1,19 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/** Display formatting shared by the Time Machine screens. */
|
|
4
|
-
|
|
5
|
-
export function timeAgo(ts) {
|
|
6
|
-
const s = Math.max(0, Math.round((Date.now() - ts) / 1000));
|
|
7
|
-
if (s < 60) return `${s}s ago`;
|
|
8
|
-
const m = Math.round(s / 60);
|
|
9
|
-
if (m < 60) return `${m}m ago`;
|
|
10
|
-
const h = Math.round(m / 60);
|
|
11
|
-
if (h < 24) return `${h}h ago`;
|
|
12
|
-
return `${Math.round(h / 24)}d ago`;
|
|
13
|
-
}
|
|
14
|
-
export function formatBytes(bytes) {
|
|
15
|
-
if (bytes < 1024) return `${bytes} B`;
|
|
16
|
-
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
17
|
-
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
18
|
-
}
|
|
19
|
-
//# sourceMappingURL=format.js.map
|
|
1
|
+
"use strict";export function timeAgo(t){const r=Math.max(0,Math.round((Date.now()-t)/1e3));if(r<60)return`${r}s ago`;const o=Math.round(r/60);if(o<60)return`${o}m ago`;const n=Math.round(o/60);if(n<24)return`${n}h ago`;return`${Math.round(n/24)}d ago`}export function formatBytes(t){if(t<1024)return`${t} B`;if(t<1024*1024)return`${(t/1024).toFixed(1)} KB`;return`${(t/(1024*1024)).toFixed(1)} MB`}
|
|
@@ -1,92 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Capture bar — the single field-plus-pill control at the top of the list.
|
|
5
|
-
*
|
|
6
|
-
* Owns the draft name itself so keystrokes re-render this component and not
|
|
7
|
-
* the snapshot list underneath it. The parent only hears about a finished
|
|
8
|
-
* capture.
|
|
9
|
-
*/
|
|
10
|
-
import { useState } from "react";
|
|
11
|
-
import { StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
|
|
12
|
-
import { tm } from "../../ui/tmTheme";
|
|
13
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
14
|
-
export function CaptureBar({
|
|
15
|
-
disabled,
|
|
16
|
-
busy,
|
|
17
|
-
onCapture
|
|
18
|
-
}) {
|
|
19
|
-
const [name, setName] = useState("");
|
|
20
|
-
const capture = () => {
|
|
21
|
-
if (disabled) return;
|
|
22
|
-
onCapture(name);
|
|
23
|
-
setName("");
|
|
24
|
-
};
|
|
25
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
26
|
-
style: styles.bar,
|
|
27
|
-
children: [/*#__PURE__*/_jsx(TextInput, {
|
|
28
|
-
style: styles.input,
|
|
29
|
-
value: name,
|
|
30
|
-
onChangeText: setName,
|
|
31
|
-
placeholder: "Name this restore point\u2026",
|
|
32
|
-
placeholderTextColor: tm.color.labelTertiary,
|
|
33
|
-
editable: !disabled,
|
|
34
|
-
onSubmitEditing: capture,
|
|
35
|
-
returnKeyType: "done",
|
|
36
|
-
testID: "time-machine-name-input"
|
|
37
|
-
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
38
|
-
style: [styles.button, disabled ? styles.buttonDisabled : null],
|
|
39
|
-
onPress: capture,
|
|
40
|
-
disabled: disabled,
|
|
41
|
-
accessibilityRole: "button",
|
|
42
|
-
accessibilityLabel: "Capture restore point",
|
|
43
|
-
testID: "time-machine-capture",
|
|
44
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
45
|
-
style: styles.buttonText,
|
|
46
|
-
children: busy ? "Capturing…" : "Capture"
|
|
47
|
-
})
|
|
48
|
-
})]
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
const styles = StyleSheet.create({
|
|
52
|
-
bar: {
|
|
53
|
-
flexDirection: "row",
|
|
54
|
-
alignItems: "center",
|
|
55
|
-
gap: 8,
|
|
56
|
-
marginHorizontal: tm.gutter,
|
|
57
|
-
backgroundColor: tm.color.group,
|
|
58
|
-
borderRadius: tm.radius.group,
|
|
59
|
-
borderWidth: 1,
|
|
60
|
-
borderColor: tm.color.groupBorder,
|
|
61
|
-
paddingLeft: tm.textInset,
|
|
62
|
-
padding: 6
|
|
63
|
-
},
|
|
64
|
-
input: {
|
|
65
|
-
flex: 1,
|
|
66
|
-
minWidth: 0,
|
|
67
|
-
color: tm.color.label,
|
|
68
|
-
fontSize: tm.font.row,
|
|
69
|
-
letterSpacing: tm.tracking.row,
|
|
70
|
-
// Zero out the platform chrome so the field reads as part of the card.
|
|
71
|
-
padding: 0,
|
|
72
|
-
backgroundColor: "transparent"
|
|
73
|
-
},
|
|
74
|
-
button: {
|
|
75
|
-
height: 34,
|
|
76
|
-
paddingHorizontal: 16,
|
|
77
|
-
borderRadius: tm.radius.pill,
|
|
78
|
-
backgroundColor: tm.color.accent,
|
|
79
|
-
alignItems: "center",
|
|
80
|
-
justifyContent: "center"
|
|
81
|
-
},
|
|
82
|
-
buttonDisabled: {
|
|
83
|
-
opacity: 0.4
|
|
84
|
-
},
|
|
85
|
-
buttonText: {
|
|
86
|
-
color: tm.color.onAccent,
|
|
87
|
-
fontSize: tm.font.control,
|
|
88
|
-
fontWeight: "600",
|
|
89
|
-
letterSpacing: tm.tracking.control
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
//# sourceMappingURL=CaptureBar.js.map
|
|
1
|
+
"use strict";import{useState as s}from"react";import{StyleSheet as u,Text as p,TextInput as d,TouchableOpacity as b,View as g}from"react-native";import{tm as t}from"../../ui/tmTheme";import{jsx as r,jsxs as m}from"react/jsx-runtime";export function CaptureBar({disabled:o,busy:l,onCapture:c}){const[n,i]=s("");const a=()=>{if(o)return;c(n);i("")};return m(g,{style:e.bar,children:[r(d,{style:e.input,value:n,onChangeText:i,placeholder:"Name this restore point\u2026",placeholderTextColor:t.color.labelTertiary,editable:!o,onSubmitEditing:a,returnKeyType:"done",testID:"time-machine-name-input"}),r(b,{style:[e.button,o?e.buttonDisabled:null],onPress:a,disabled:o,accessibilityRole:"button",accessibilityLabel:"Capture restore point",testID:"time-machine-capture",children:r(p,{style:e.buttonText,children:l?"Capturing\u2026":"Capture"})})]})}const e=u.create({bar:{flexDirection:"row",alignItems:"center",gap:8,marginHorizontal:t.gutter,backgroundColor:t.color.group,borderRadius:t.radius.group,borderWidth:1,borderColor:t.color.groupBorder,paddingLeft:t.textInset,padding:6},input:{flex:1,minWidth:0,color:t.color.label,fontSize:t.font.row,letterSpacing:t.tracking.row,padding:0,backgroundColor:"transparent"},button:{height:34,paddingHorizontal:16,borderRadius:t.radius.pill,backgroundColor:t.color.accent,alignItems:"center",justifyContent:"center"},buttonDisabled:{opacity:.4},buttonText:{color:t.color.onAccent,fontSize:t.font.control,fontWeight:"600",letterSpacing:t.tracking.control}});
|
|
@@ -1,169 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* What the last restore did, shown ONLY when something went wrong.
|
|
5
|
-
*
|
|
6
|
-
* A clean restore says so with a toast and then gets out of the way — the
|
|
7
|
-
* restored app is the proof, and a wall of green ticks on top of the list
|
|
8
|
-
* every single time was noise. A restore that skipped or failed a source is
|
|
9
|
-
* the opposite: nothing else on screen would ever tell you, so it stays until
|
|
10
|
-
* dismissed.
|
|
11
|
-
*/
|
|
12
|
-
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
13
|
-
import { X } from "@buoy-gg/shared-ui";
|
|
14
|
-
import { tm } from "../../ui/tmTheme";
|
|
15
|
-
import { timeMachineStore } from "../../store/timeMachineStore";
|
|
16
|
-
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
17
|
-
const HIT = {
|
|
18
|
-
top: 10,
|
|
19
|
-
bottom: 10,
|
|
20
|
-
left: 10,
|
|
21
|
-
right: 10
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
* Did this restore do anything the app itself won't show you? Warnings alone
|
|
26
|
-
* don't count — "1 derived atom recomputes" is true of every restore and
|
|
27
|
-
* would put the card back on screen permanently.
|
|
28
|
-
*/
|
|
29
|
-
export function restoreNeedsAttention(outcome) {
|
|
30
|
-
if (Object.values(outcome.results).some(r => !r.ok || r.skipped.length > 0)) return true;
|
|
31
|
-
const route = outcome.route;
|
|
32
|
-
return route?.status === "failed" || route?.status === "unavailable";
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/** ✓ / ✕ / ↻ line — the glyph carries the meaning, the color reinforces it. */
|
|
36
|
-
function ResultLine({
|
|
37
|
-
glyph,
|
|
38
|
-
text,
|
|
39
|
-
ok,
|
|
40
|
-
testID
|
|
41
|
-
}) {
|
|
42
|
-
return /*#__PURE__*/_jsxs(Text, {
|
|
43
|
-
style: [styles.line, {
|
|
44
|
-
color: ok ? tm.color.accent : tm.color.warning
|
|
45
|
-
}],
|
|
46
|
-
numberOfLines: 2,
|
|
47
|
-
testID: testID,
|
|
48
|
-
children: [/*#__PURE__*/_jsxs(Text, {
|
|
49
|
-
style: styles.glyph,
|
|
50
|
-
children: [glyph, " "]
|
|
51
|
-
}), text]
|
|
52
|
-
});
|
|
53
|
-
}
|
|
54
|
-
const ROUTE_TEST_ID = "time-machine-outcome-route";
|
|
55
|
-
function RouteResult({
|
|
56
|
-
route
|
|
57
|
-
}) {
|
|
58
|
-
if (route.status === "navigated") return /*#__PURE__*/_jsx(ResultLine, {
|
|
59
|
-
glyph: "\u2713",
|
|
60
|
-
ok: true,
|
|
61
|
-
text: `route — ${route.href}`,
|
|
62
|
-
testID: ROUTE_TEST_ID
|
|
63
|
-
});
|
|
64
|
-
if (route.status === "deferred") return /*#__PURE__*/_jsx(ResultLine, {
|
|
65
|
-
glyph: "\u21BB",
|
|
66
|
-
ok: true,
|
|
67
|
-
text: `route — ${route.href} after reload`,
|
|
68
|
-
testID: ROUTE_TEST_ID
|
|
69
|
-
});
|
|
70
|
-
return /*#__PURE__*/_jsx(ResultLine, {
|
|
71
|
-
glyph: "\u2715",
|
|
72
|
-
ok: false,
|
|
73
|
-
text: `route — ${route.error ?? route.status}`,
|
|
74
|
-
testID: ROUTE_TEST_ID
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
export function RestoreOutcomeCard({
|
|
78
|
-
outcome
|
|
79
|
-
}) {
|
|
80
|
-
const entries = Object.entries(outcome.results);
|
|
81
|
-
const reloading = outcome.mode === "reload" || outcome.willReload;
|
|
82
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
83
|
-
style: styles.card,
|
|
84
|
-
testID: "time-machine-outcome",
|
|
85
|
-
children: [/*#__PURE__*/_jsxs(View, {
|
|
86
|
-
style: styles.headerRow,
|
|
87
|
-
children: [/*#__PURE__*/_jsxs(Text, {
|
|
88
|
-
style: styles.title,
|
|
89
|
-
numberOfLines: 1,
|
|
90
|
-
testID: "time-machine-outcome-title",
|
|
91
|
-
children: ["Restored \u201C", outcome.snapshotName, "\u201D", reloading ? " · reloading" : ""]
|
|
92
|
-
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
93
|
-
onPress: () => timeMachineStore.clearLastOutcome(),
|
|
94
|
-
hitSlop: HIT,
|
|
95
|
-
accessibilityRole: "button",
|
|
96
|
-
accessibilityLabel: "Dismiss restore result",
|
|
97
|
-
testID: "time-machine-outcome-dismiss",
|
|
98
|
-
children: /*#__PURE__*/_jsx(X, {
|
|
99
|
-
size: 13,
|
|
100
|
-
color: tm.color.labelSecondary
|
|
101
|
-
})
|
|
102
|
-
})]
|
|
103
|
-
}), entries.length === 0 && !outcome.route ? /*#__PURE__*/_jsx(Text, {
|
|
104
|
-
style: styles.empty,
|
|
105
|
-
testID: "time-machine-outcome-empty",
|
|
106
|
-
children: "No sources restored."
|
|
107
|
-
}) : null, outcome.route ? /*#__PURE__*/_jsx(RouteResult, {
|
|
108
|
-
route: outcome.route
|
|
109
|
-
}) : null, entries.map(([sourceId, result]) => /*#__PURE__*/_jsxs(View, {
|
|
110
|
-
children: [/*#__PURE__*/_jsx(ResultLine, {
|
|
111
|
-
testID: `time-machine-outcome-${sourceId}`,
|
|
112
|
-
glyph: result.ok ? "✓" : "✕",
|
|
113
|
-
ok: result.ok,
|
|
114
|
-
text: `${sourceId} — applied ${result.applied}${result.skipped.length > 0 ? `, skipped ${result.skipped.length}` : ""}`
|
|
115
|
-
}), result.skipped.slice(0, 3).map(skip => /*#__PURE__*/_jsxs(Text, {
|
|
116
|
-
style: styles.detail,
|
|
117
|
-
numberOfLines: 2,
|
|
118
|
-
children: [skip.id, ": ", skip.reason]
|
|
119
|
-
}, skip.id)), result.warnings.slice(0, 3).map(warning => /*#__PURE__*/_jsxs(Text, {
|
|
120
|
-
style: styles.detail,
|
|
121
|
-
numberOfLines: 2,
|
|
122
|
-
children: ["\u26A0 ", warning]
|
|
123
|
-
}, warning))]
|
|
124
|
-
}, sourceId))]
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
const styles = StyleSheet.create({
|
|
128
|
-
card: {
|
|
129
|
-
marginHorizontal: tm.gutter,
|
|
130
|
-
marginTop: 12,
|
|
131
|
-
backgroundColor: tm.color.group,
|
|
132
|
-
borderRadius: tm.radius.group,
|
|
133
|
-
borderWidth: 1,
|
|
134
|
-
borderColor: tm.color.groupBorder,
|
|
135
|
-
padding: 14,
|
|
136
|
-
gap: 4
|
|
137
|
-
},
|
|
138
|
-
headerRow: {
|
|
139
|
-
flexDirection: "row",
|
|
140
|
-
alignItems: "center",
|
|
141
|
-
gap: 10,
|
|
142
|
-
marginBottom: 2
|
|
143
|
-
},
|
|
144
|
-
title: {
|
|
145
|
-
flex: 1,
|
|
146
|
-
color: tm.color.label,
|
|
147
|
-
fontSize: 15,
|
|
148
|
-
fontWeight: "600",
|
|
149
|
-
letterSpacing: tm.tracking.control
|
|
150
|
-
},
|
|
151
|
-
line: {
|
|
152
|
-
fontSize: tm.font.footnote,
|
|
153
|
-
lineHeight: tm.font.footnote * 1.4
|
|
154
|
-
},
|
|
155
|
-
glyph: {
|
|
156
|
-
fontWeight: "700"
|
|
157
|
-
},
|
|
158
|
-
detail: {
|
|
159
|
-
color: tm.color.labelTertiary,
|
|
160
|
-
fontSize: tm.font.mono,
|
|
161
|
-
lineHeight: tm.font.mono * 1.4,
|
|
162
|
-
paddingLeft: 14
|
|
163
|
-
},
|
|
164
|
-
empty: {
|
|
165
|
-
color: tm.color.labelSecondary,
|
|
166
|
-
fontSize: tm.font.footnote
|
|
167
|
-
}
|
|
168
|
-
});
|
|
169
|
-
//# sourceMappingURL=RestoreOutcomeCard.js.map
|
|
1
|
+
"use strict";import{StyleSheet as h,Text as c,TouchableOpacity as f,View as u}from"react-native";import{X as g}from"@buoy-gg/shared-ui";import{tm as t}from"../../ui/tmTheme";import{timeMachineStore as y}from"../../store/timeMachineStore";import{jsxs as o,jsx as r}from"react/jsx-runtime";const b={top:10,bottom:10,left:10,right:10};export function restoreNeedsAttention(e){if(Object.values(e.results).some(s=>!s.ok||s.skipped.length>0))return true;const n=e.route;return n?.status==="failed"||n?.status==="unavailable"}function m({glyph:e,text:n,ok:s,testID:d}){return o(c,{style:[i.line,{color:s?t.color.accent:t.color.warning}],numberOfLines:2,testID:d,children:[o(c,{style:i.glyph,children:[e," "]}),n]})}const p="time-machine-outcome-route";function x({route:e}){if(e.status==="navigated")return r(m,{glyph:"\u2713",ok:true,text:`route \u2014 ${e.href}`,testID:p});if(e.status==="deferred")return r(m,{glyph:"\u21BB",ok:true,text:`route \u2014 ${e.href} after reload`,testID:p});return r(m,{glyph:"\u2715",ok:false,text:`route \u2014 ${e.error??e.status}`,testID:p})}export function RestoreOutcomeCard({outcome:e}){const n=Object.entries(e.results);const s=e.mode==="reload"||e.willReload;return o(u,{style:i.card,testID:"time-machine-outcome",children:[o(u,{style:i.headerRow,children:[o(c,{style:i.title,numberOfLines:1,testID:"time-machine-outcome-title",children:["Restored \u201C",e.snapshotName,"\u201D",s?" \xB7 reloading":""]}),r(f,{onPress:()=>y.clearLastOutcome(),hitSlop:b,accessibilityRole:"button",accessibilityLabel:"Dismiss restore result",testID:"time-machine-outcome-dismiss",children:r(g,{size:13,color:t.color.labelSecondary})})]}),n.length===0&&!e.route?r(c,{style:i.empty,testID:"time-machine-outcome-empty",children:"No sources restored."}):null,e.route?r(x,{route:e.route}):null,n.map(([d,l])=>o(u,{children:[r(m,{testID:`time-machine-outcome-${d}`,glyph:l.ok?"\u2713":"\u2715",ok:l.ok,text:`${d} \u2014 applied ${l.applied}${l.skipped.length>0?`, skipped ${l.skipped.length}`:""}`}),l.skipped.slice(0,3).map(a=>o(c,{style:i.detail,numberOfLines:2,children:[a.id,": ",a.reason]},a.id)),l.warnings.slice(0,3).map(a=>o(c,{style:i.detail,numberOfLines:2,children:["\u26A0 ",a]},a))]},d))]})}const i=h.create({card:{marginHorizontal:t.gutter,marginTop:12,backgroundColor:t.color.group,borderRadius:t.radius.group,borderWidth:1,borderColor:t.color.groupBorder,padding:14,gap:4},headerRow:{flexDirection:"row",alignItems:"center",gap:10,marginBottom:2},title:{flex:1,color:t.color.label,fontSize:15,fontWeight:"600",letterSpacing:t.tracking.control},line:{fontSize:t.font.footnote,lineHeight:t.font.footnote*1.4},glyph:{fontWeight:"700"},detail:{color:t.color.labelTertiary,fontSize:t.font.mono,lineHeight:t.font.mono*1.4,paddingLeft:14},empty:{color:t.color.labelSecondary,fontSize:t.font.footnote}});
|
|
@@ -1,167 +1 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* One restore point in the list: what it is, when it was taken, how big it
|
|
5
|
-
* is, where it was captured — and the single action worth having at arm's
|
|
6
|
-
* reach. Tapping the row opens the restore preview; the pill restores now.
|
|
7
|
-
*
|
|
8
|
-
* The route is shown as context — where this state was true. Whether a
|
|
9
|
-
* restore also navigates there is decided in the restore preview, beside the
|
|
10
|
-
* other changes it is about to make.
|
|
11
|
-
*
|
|
12
|
-
* Duplicate and delete live behind a swipe. A destructive target beside
|
|
13
|
-
* "Restore" is a mis-tap that costs a snapshot, and the two-step gesture is
|
|
14
|
-
* deliberate enough — recovery is the undo the list offers after, not a
|
|
15
|
-
* dialog before. Renaming is NOT here: it belongs with the restore point's
|
|
16
|
-
* other settings, on the preview screen.
|
|
17
|
-
*/
|
|
18
|
-
import { StyleSheet, Text, TouchableOpacity, View } from "react-native";
|
|
19
|
-
import { PillLabel } from "../../ui/primitives";
|
|
20
|
-
import { SwipeActionsRow } from "../../ui/SwipeActionsRow";
|
|
21
|
-
import { TM_MONO, tm } from "../../ui/tmTheme";
|
|
22
|
-
import { formatBytes, timeAgo } from "../format";
|
|
23
|
-
|
|
24
|
-
/** "15h ago · 9.5 KB · 5 sources · skips 2" */
|
|
25
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
26
|
-
function describe(meta) {
|
|
27
|
-
if (meta.baseline) return "Wipes to fresh install";
|
|
28
|
-
const parts = [timeAgo(meta.createdAt), formatBytes(meta.sizeBytes), `${Object.keys(meta.sources).length} sources`];
|
|
29
|
-
// A saved selection is worth stating on the row — this restore point no
|
|
30
|
-
// longer does the obvious thing, and one tap on RESTORE honors it.
|
|
31
|
-
if (meta.excludedKeys?.length) parts.push(`skips ${meta.excludedKeys.length}`);else if (meta.scope?.length) parts.push(`scoped (${meta.scope.length})`);
|
|
32
|
-
// The bar's own undo slot: kept for one restore, not a point you chose.
|
|
33
|
-
if (meta.safety) parts.unshift("safety copy");
|
|
34
|
-
return parts.join(" · ");
|
|
35
|
-
}
|
|
36
|
-
export function SnapshotRow({
|
|
37
|
-
meta,
|
|
38
|
-
busy,
|
|
39
|
-
armed = false,
|
|
40
|
-
onOpen,
|
|
41
|
-
onRestore,
|
|
42
|
-
onDelete,
|
|
43
|
-
onDuplicate,
|
|
44
|
-
onArm
|
|
45
|
-
}) {
|
|
46
|
-
const testID = `time-machine-snap-${meta.id}`;
|
|
47
|
-
return /*#__PURE__*/_jsx(SwipeActionsRow, {
|
|
48
|
-
testID: testID,
|
|
49
|
-
actions: [
|
|
50
|
-
// "Bar": put this point on the floating action bar.
|
|
51
|
-
{
|
|
52
|
-
label: "Bar",
|
|
53
|
-
onPress: onArm
|
|
54
|
-
},
|
|
55
|
-
// "Dup" over "Copy": on a row full of text, "Copy" reads as
|
|
56
|
-
// copy-to-clipboard.
|
|
57
|
-
{
|
|
58
|
-
label: "Dup",
|
|
59
|
-
onPress: onDuplicate
|
|
60
|
-
}, {
|
|
61
|
-
label: "Delete",
|
|
62
|
-
onPress: onDelete,
|
|
63
|
-
background: tm.color.danger,
|
|
64
|
-
color: tm.color.onDanger
|
|
65
|
-
}],
|
|
66
|
-
children: /*#__PURE__*/_jsxs(View, {
|
|
67
|
-
style: styles.row,
|
|
68
|
-
children: [/*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
69
|
-
style: styles.text,
|
|
70
|
-
onPress: onOpen,
|
|
71
|
-
activeOpacity: 0.7,
|
|
72
|
-
accessibilityRole: "button",
|
|
73
|
-
accessibilityLabel: `${meta.name}. ${describe(meta)}. Open restore preview`,
|
|
74
|
-
testID: testID,
|
|
75
|
-
children: [/*#__PURE__*/_jsx(Text, {
|
|
76
|
-
style: styles.name,
|
|
77
|
-
numberOfLines: 1,
|
|
78
|
-
testID: `${testID}-name`,
|
|
79
|
-
children: meta.name
|
|
80
|
-
}), armed ? /*#__PURE__*/_jsx(Text, {
|
|
81
|
-
style: styles.armed,
|
|
82
|
-
numberOfLines: 1,
|
|
83
|
-
testID: `${testID}-armed`,
|
|
84
|
-
children: "On the action bar"
|
|
85
|
-
}) : null, /*#__PURE__*/_jsx(Text, {
|
|
86
|
-
style: styles.meta,
|
|
87
|
-
numberOfLines: 1,
|
|
88
|
-
testID: `${testID}-meta`,
|
|
89
|
-
children: describe(meta)
|
|
90
|
-
}), meta.lastRestoredAt ? /*#__PURE__*/_jsxs(Text, {
|
|
91
|
-
style: styles.restored,
|
|
92
|
-
numberOfLines: 1,
|
|
93
|
-
testID: `${testID}-restored`,
|
|
94
|
-
children: ["Restored ", timeAgo(meta.lastRestoredAt)]
|
|
95
|
-
}) : null, meta.route ? /*#__PURE__*/_jsx(Text, {
|
|
96
|
-
style: styles.route,
|
|
97
|
-
numberOfLines: 1,
|
|
98
|
-
testID: `${testID}-route`,
|
|
99
|
-
children: meta.route.href
|
|
100
|
-
}) : null]
|
|
101
|
-
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
102
|
-
onPress: onRestore,
|
|
103
|
-
disabled: busy,
|
|
104
|
-
style: [styles.restore, busy ? styles.actionDisabled : null],
|
|
105
|
-
accessibilityRole: "button",
|
|
106
|
-
accessibilityLabel: meta.baseline ? "Wipe and reload" : "Restore",
|
|
107
|
-
testID: `${testID}-restore`,
|
|
108
|
-
children: /*#__PURE__*/_jsx(PillLabel, {
|
|
109
|
-
testID: `${testID}-restore-label`,
|
|
110
|
-
label: meta.baseline ? "Wipe" : "Restore",
|
|
111
|
-
color: meta.baseline ? tm.color.danger : tm.color.accent,
|
|
112
|
-
background: meta.baseline ? tm.color.dangerSoft : tm.color.accentSoft
|
|
113
|
-
})
|
|
114
|
-
})]
|
|
115
|
-
})
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
const styles = StyleSheet.create({
|
|
119
|
-
row: {
|
|
120
|
-
flexDirection: "row",
|
|
121
|
-
alignItems: "center",
|
|
122
|
-
gap: 10,
|
|
123
|
-
paddingHorizontal: tm.textInset
|
|
124
|
-
},
|
|
125
|
-
// The text block is the tallest child, so its padding sets the row height
|
|
126
|
-
// and the open target spans the full row.
|
|
127
|
-
text: {
|
|
128
|
-
flex: 1,
|
|
129
|
-
minWidth: 0,
|
|
130
|
-
paddingVertical: 11
|
|
131
|
-
},
|
|
132
|
-
restore: {
|
|
133
|
-
justifyContent: "center"
|
|
134
|
-
},
|
|
135
|
-
name: {
|
|
136
|
-
color: tm.color.label,
|
|
137
|
-
fontSize: tm.font.row,
|
|
138
|
-
fontWeight: "600",
|
|
139
|
-
letterSpacing: tm.tracking.row
|
|
140
|
-
},
|
|
141
|
-
meta: {
|
|
142
|
-
color: tm.color.labelSecondary,
|
|
143
|
-
fontSize: tm.font.footnote,
|
|
144
|
-
marginTop: 2,
|
|
145
|
-
fontVariant: ["tabular-nums"]
|
|
146
|
-
},
|
|
147
|
-
restored: {
|
|
148
|
-
color: tm.color.accent,
|
|
149
|
-
fontSize: tm.font.footnote,
|
|
150
|
-
marginTop: 2
|
|
151
|
-
},
|
|
152
|
-
armed: {
|
|
153
|
-
color: tm.color.accent,
|
|
154
|
-
fontSize: tm.font.footnote,
|
|
155
|
-
marginTop: 2
|
|
156
|
-
},
|
|
157
|
-
route: {
|
|
158
|
-
color: tm.color.labelTertiary,
|
|
159
|
-
fontFamily: TM_MONO,
|
|
160
|
-
fontSize: tm.font.mono,
|
|
161
|
-
marginTop: 4
|
|
162
|
-
},
|
|
163
|
-
actionDisabled: {
|
|
164
|
-
opacity: 0.4
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
//# sourceMappingURL=SnapshotRow.js.map
|
|
1
|
+
"use strict";import{StyleSheet as g,Text as l,TouchableOpacity as c,View as m}from"react-native";import{PillLabel as D}from"../../ui/primitives";import{SwipeActionsRow as x}from"../../ui/SwipeActionsRow";import{TM_MONO as S,tm as o}from"../../ui/tmTheme";import{formatBytes as $,timeAgo as a}from"../format";import{jsx as s,jsxs as i}from"react/jsx-runtime";function f(e){if(e.baseline)return"Wipes to fresh install";const n=[a(e.createdAt),$(e.sizeBytes),`${Object.keys(e.sources).length} sources`];if(e.excludedKeys?.length)n.push(`skips ${e.excludedKeys.length}`);else if(e.scope?.length)n.push(`scoped (${e.scope.length})`);if(e.safety)n.unshift("safety copy");return n.join(" \xB7 ")}export function SnapshotRow({meta:e,busy:n,armed:d=false,onOpen:b,onRestore:p,onDelete:u,onDuplicate:y,onArm:h}){const t=`time-machine-snap-${e.id}`;return s(x,{testID:t,actions:[{label:"Bar",onPress:h},{label:"Dup",onPress:y},{label:"Delete",onPress:u,background:o.color.danger,color:o.color.onDanger}],children:i(m,{style:r.row,children:[i(c,{style:r.text,onPress:b,activeOpacity:.7,accessibilityRole:"button",accessibilityLabel:`${e.name}. ${f(e)}. Open restore preview`,testID:t,children:[s(l,{style:r.name,numberOfLines:1,testID:`${t}-name`,children:e.name}),d?s(l,{style:r.armed,numberOfLines:1,testID:`${t}-armed`,children:"On the action bar"}):null,s(l,{style:r.meta,numberOfLines:1,testID:`${t}-meta`,children:f(e)}),e.lastRestoredAt?i(l,{style:r.restored,numberOfLines:1,testID:`${t}-restored`,children:["Restored ",a(e.lastRestoredAt)]}):null,e.route?s(l,{style:r.route,numberOfLines:1,testID:`${t}-route`,children:e.route.href}):null]}),s(c,{onPress:p,disabled:n,style:[r.restore,n?r.actionDisabled:null],accessibilityRole:"button",accessibilityLabel:e.baseline?"Wipe and reload":"Restore",testID:`${t}-restore`,children:s(D,{testID:`${t}-restore-label`,label:e.baseline?"Wipe":"Restore",color:e.baseline?o.color.danger:o.color.accent,background:e.baseline?o.color.dangerSoft:o.color.accentSoft})})]})})}const r=g.create({row:{flexDirection:"row",alignItems:"center",gap:10,paddingHorizontal:o.textInset},text:{flex:1,minWidth:0,paddingVertical:11},restore:{justifyContent:"center"},name:{color:o.color.label,fontSize:o.font.row,fontWeight:"600",letterSpacing:o.tracking.row},meta:{color:o.color.labelSecondary,fontSize:o.font.footnote,marginTop:2,fontVariant:["tabular-nums"]},restored:{color:o.color.accent,fontSize:o.font.footnote,marginTop:2},armed:{color:o.color.accent,fontSize:o.font.footnote,marginTop:2},route:{color:o.color.labelTertiary,fontFamily:S,fontSize:o.font.mono,marginTop:4},actionDisabled:{opacity:.4}});
|