@buoy-gg/time-machine 7.0.17 → 7.0.18
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/lib/commonjs/components/HeaderReloadButton.js +61 -0
- package/lib/commonjs/components/HeaderReloadButton.js.map +1 -0
- package/lib/commonjs/components/TimeMachineBody.js +343 -127
- package/lib/commonjs/components/TimeMachineBody.js.map +1 -1
- package/lib/commonjs/components/TimeMachineModal.js +1 -0
- package/lib/commonjs/components/TimeMachineModal.js.map +1 -1
- package/lib/commonjs/components/preview/ItemDetailScreen.js +189 -0
- package/lib/commonjs/components/preview/ItemDetailScreen.js.map +1 -0
- package/lib/commonjs/components/preview/RestorePreviewScreen.js +1056 -0
- package/lib/commonjs/components/preview/RestorePreviewScreen.js.map +1 -0
- package/lib/commonjs/components/preview/verdictMeta.js +58 -0
- package/lib/commonjs/components/preview/verdictMeta.js.map +1 -0
- package/lib/commonjs/preset.js +11 -2
- package/lib/commonjs/preset.js.map +1 -1
- package/lib/commonjs/store/snapshotVault.js +19 -0
- package/lib/commonjs/store/snapshotVault.js.map +1 -1
- package/lib/commonjs/store/timeMachineStore.js +298 -7
- package/lib/commonjs/store/timeMachineStore.js.map +1 -1
- package/lib/commonjs/sync/timeMachineSyncAdapter.js +62 -2
- package/lib/commonjs/sync/timeMachineSyncAdapter.js.map +1 -1
- package/lib/module/components/HeaderReloadButton.js +56 -0
- package/lib/module/components/HeaderReloadButton.js.map +1 -0
- package/lib/module/components/TimeMachineBody.js +345 -129
- package/lib/module/components/TimeMachineBody.js.map +1 -1
- package/lib/module/components/TimeMachineModal.js +1 -0
- package/lib/module/components/TimeMachineModal.js.map +1 -1
- package/lib/module/components/preview/ItemDetailScreen.js +184 -0
- package/lib/module/components/preview/ItemDetailScreen.js.map +1 -0
- package/lib/module/components/preview/RestorePreviewScreen.js +1051 -0
- package/lib/module/components/preview/RestorePreviewScreen.js.map +1 -0
- package/lib/module/components/preview/verdictMeta.js +53 -0
- package/lib/module/components/preview/verdictMeta.js.map +1 -0
- package/lib/module/preset.js +11 -2
- package/lib/module/preset.js.map +1 -1
- package/lib/module/store/snapshotVault.js +18 -0
- package/lib/module/store/snapshotVault.js.map +1 -1
- package/lib/module/store/timeMachineStore.js +299 -8
- package/lib/module/store/timeMachineStore.js.map +1 -1
- package/lib/module/sync/timeMachineSyncAdapter.js +62 -2
- package/lib/module/sync/timeMachineSyncAdapter.js.map +1 -1
- package/lib/typescript/components/HeaderReloadButton.d.ts +2 -0
- package/lib/typescript/components/HeaderReloadButton.d.ts.map +1 -0
- package/lib/typescript/components/TimeMachineBody.d.ts.map +1 -1
- package/lib/typescript/components/TimeMachineModal.d.ts.map +1 -1
- package/lib/typescript/components/preview/ItemDetailScreen.d.ts +11 -0
- package/lib/typescript/components/preview/ItemDetailScreen.d.ts.map +1 -0
- package/lib/typescript/components/preview/RestorePreviewScreen.d.ts +15 -0
- package/lib/typescript/components/preview/RestorePreviewScreen.d.ts.map +1 -0
- package/lib/typescript/components/preview/verdictMeta.d.ts +10 -0
- package/lib/typescript/components/preview/verdictMeta.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts +15 -3
- package/lib/typescript/preset.d.ts.map +1 -1
- package/lib/typescript/store/snapshotVault.d.ts +7 -0
- package/lib/typescript/store/snapshotVault.d.ts.map +1 -1
- package/lib/typescript/store/timeMachineStore.d.ts +49 -2
- package/lib/typescript/store/timeMachineStore.d.ts.map +1 -1
- package/lib/typescript/sync/timeMachineSyncAdapter.d.ts +36 -0
- package/lib/typescript/sync/timeMachineSyncAdapter.d.ts.map +1 -1
- package/package.json +13 -6
- package/src/components/HeaderReloadButton.tsx +45 -0
- package/src/components/TimeMachineBody.tsx +416 -137
- package/src/components/TimeMachineModal.tsx +1 -0
- package/src/components/preview/ItemDetailScreen.tsx +172 -0
- package/src/components/preview/RestorePreviewScreen.tsx +1089 -0
- package/src/components/preview/verdictMeta.ts +40 -0
- package/src/preset.tsx +11 -2
- package/src/store/snapshotVault.ts +28 -0
- package/src/store/timeMachineStore.ts +330 -7
- package/src/sync/timeMachineSyncAdapter.ts +63 -3
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Time Machine body — capture bar, provider status strip
|
|
5
|
-
* the
|
|
6
|
-
*
|
|
4
|
+
* Time Machine body — snapshot list, capture bar, provider status strip and
|
|
5
|
+
* the Restore Preview flow (tap a snapshot row → item-level diff of what a
|
|
6
|
+
* restore would change; tap an item → tree/split detail).
|
|
7
|
+
*
|
|
8
|
+
* Shared by the RN modal and the inline (desktop) tool view. The host must
|
|
9
|
+
* NOT wrap this in a scroll view — each screen owns its scrolling (the
|
|
10
|
+
* preview is a virtualized FlatList; wrapping it would defeat that).
|
|
7
11
|
*/
|
|
8
12
|
import { useState } from "react";
|
|
9
|
-
import { Alert, Platform, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
|
|
10
|
-
import { buoyColors } from "@buoy-gg/shared-ui";
|
|
13
|
+
import { Alert, Platform, ScrollView, StyleSheet, Text, TextInput, TouchableOpacity, View } from "react-native";
|
|
14
|
+
import { Plus, EventPickerModal, Home, Trash2, buoyColors } from "@buoy-gg/shared-ui";
|
|
15
|
+
import { JotaiIcon, QueryIcon, ReduxIcon, StorageIcon, TimeMachineIcon, ZustandIcon } from "@buoy-gg/floating-tools-core";
|
|
16
|
+
import { useToolHost } from "@buoy-gg/core";
|
|
11
17
|
import { useIsPro } from "@buoy-gg/license";
|
|
12
18
|
import { useSnapshotProviders, useTimeMachineState } from "../hooks/useTimeMachine";
|
|
13
19
|
import { timeMachineStore } from "../store/timeMachineStore";
|
|
20
|
+
import { RestorePreviewScreen } from "./preview/RestorePreviewScreen";
|
|
21
|
+
import { ItemDetailScreen } from "./preview/ItemDetailScreen";
|
|
14
22
|
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
15
23
|
const FREE_SNAPSHOT_LIMIT = 2;
|
|
24
|
+
const SOURCE_ICONS = {
|
|
25
|
+
storage: StorageIcon,
|
|
26
|
+
redux: ReduxIcon,
|
|
27
|
+
zustand: ZustandIcon,
|
|
28
|
+
jotai: JotaiIcon,
|
|
29
|
+
query: QueryIcon
|
|
30
|
+
};
|
|
16
31
|
function timeAgo(ts) {
|
|
17
32
|
const s = Math.max(0, Math.round((Date.now() - ts) / 1000));
|
|
18
33
|
if (s < 60) return `${s}s ago`;
|
|
@@ -95,11 +110,21 @@ export function TimeMachineBody() {
|
|
|
95
110
|
hasLoaded,
|
|
96
111
|
busy,
|
|
97
112
|
lastOutcome,
|
|
113
|
+
preview,
|
|
98
114
|
remoteProviders
|
|
99
115
|
} = useTimeMachineState();
|
|
100
116
|
const localProviders = useSnapshotProviders();
|
|
101
117
|
const isPro = useIsPro();
|
|
118
|
+
const host = useToolHost();
|
|
102
119
|
const [name, setName] = useState("");
|
|
120
|
+
const [screen, setScreen] = useState({
|
|
121
|
+
kind: "list"
|
|
122
|
+
});
|
|
123
|
+
const [picker, setPicker] = useState(null);
|
|
124
|
+
|
|
125
|
+
// Header search (when hosted by the core shell) filters the snapshot list.
|
|
126
|
+
const listQuery = host.search.trim().toLowerCase();
|
|
127
|
+
const visibleSnapshots = listQuery ? snapshots.filter(s => s.name.toLowerCase().includes(listQuery)) : snapshots;
|
|
103
128
|
|
|
104
129
|
// On-device: live registry probes. Buoy Desktop: statuses mirrored from
|
|
105
130
|
// the device's sync payload.
|
|
@@ -115,38 +140,159 @@ export function TimeMachineBody() {
|
|
|
115
140
|
void timeMachineStore.capture(name);
|
|
116
141
|
setName("");
|
|
117
142
|
};
|
|
118
|
-
const
|
|
119
|
-
if (captureDisabled) return;
|
|
120
|
-
void timeMachineStore.captureBaseline();
|
|
121
|
-
};
|
|
122
|
-
const restore = (meta, mode) => {
|
|
143
|
+
const restore = (meta, mode, excludeKeys) => {
|
|
123
144
|
if (busy) return;
|
|
124
145
|
if (meta.baseline) {
|
|
125
146
|
confirmDestructive("Restore fresh install?", "This wipes all app storage and reloads the app.", "Wipe & reload", () => void timeMachineStore.restore(meta.id, "reload"));
|
|
126
147
|
return;
|
|
127
148
|
}
|
|
128
|
-
void timeMachineStore.restore(meta.id, mode);
|
|
149
|
+
void timeMachineStore.restore(meta.id, mode, excludeKeys);
|
|
129
150
|
};
|
|
130
151
|
const remove = meta => {
|
|
131
152
|
confirmDestructive("Delete snapshot?", `“${meta.name}” cannot be recovered.`, "Delete", () => void timeMachineStore.delete(meta.id));
|
|
132
153
|
};
|
|
154
|
+
const wipeAll = () => {
|
|
155
|
+
if (busy) return;
|
|
156
|
+
confirmDestructive("Wipe all app state?", "This deletes all app storage and reloads the app — like a fresh install.", "Wipe & reload", () => void timeMachineStore.wipeAll());
|
|
157
|
+
};
|
|
158
|
+
const openPreview = meta => {
|
|
159
|
+
void timeMachineStore.buildPreview({
|
|
160
|
+
snapshotId: meta.id
|
|
161
|
+
});
|
|
162
|
+
setScreen({
|
|
163
|
+
kind: "preview"
|
|
164
|
+
});
|
|
165
|
+
};
|
|
166
|
+
const closePreview = () => {
|
|
167
|
+
timeMachineStore.clearPreview();
|
|
168
|
+
setScreen({
|
|
169
|
+
kind: "list"
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
// ── Preview / item screens ──
|
|
174
|
+
if (screen.kind === "item" && preview) {
|
|
175
|
+
return /*#__PURE__*/_jsx(ItemDetailScreen, {
|
|
176
|
+
sourceLabel: screen.sourceLabel,
|
|
177
|
+
item: screen.item,
|
|
178
|
+
leftLabel: preview.left === "current" ? "CURRENT" : snapshots.find(s => s.id === preview.left.snapshotId)?.name ?? "snapshot",
|
|
179
|
+
rightLabel: preview.right === "current" ? "CURRENT" : snapshots.find(s => s.id === preview.right.snapshotId)?.name ?? "snapshot",
|
|
180
|
+
onBack: () => setScreen({
|
|
181
|
+
kind: "preview"
|
|
182
|
+
})
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (screen.kind === "preview" && preview) {
|
|
186
|
+
const rightMeta = preview.right === "current" ? undefined : snapshots.find(s => s.id === preview.right.snapshotId);
|
|
187
|
+
const pickerItems = [];
|
|
188
|
+
if (picker) {
|
|
189
|
+
const otherRef = picker === "left" ? preview.right : preview.left;
|
|
190
|
+
const otherId = otherRef === "current" ? null : otherRef.snapshotId;
|
|
191
|
+
if (picker === "left") {
|
|
192
|
+
pickerItems.push({
|
|
193
|
+
index: 0,
|
|
194
|
+
label: "Current state",
|
|
195
|
+
timestamp: "live",
|
|
196
|
+
relativeTime: "now",
|
|
197
|
+
selected: preview.left === "current"
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
snapshots.forEach((s, i) => {
|
|
201
|
+
const ref = {
|
|
202
|
+
snapshotId: s.id
|
|
203
|
+
};
|
|
204
|
+
const current = picker === "left" ? preview.left : preview.right;
|
|
205
|
+
pickerItems.push({
|
|
206
|
+
index: picker === "left" ? i + 1 : i,
|
|
207
|
+
label: s.baseline ? `⌂ ${s.name}` : s.name,
|
|
208
|
+
timestamp: new Date(s.createdAt).toLocaleTimeString(),
|
|
209
|
+
relativeTime: timeAgo(s.createdAt),
|
|
210
|
+
disabled: s.id === otherId || picker === "right" && s.baseline,
|
|
211
|
+
selected: current !== "current" && current.snapshotId === s.id
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
}
|
|
215
|
+
const onPickerSelect = index => {
|
|
216
|
+
const side = picker;
|
|
217
|
+
setPicker(null);
|
|
218
|
+
if (!side) return;
|
|
219
|
+
let ref;
|
|
220
|
+
if (side === "left") {
|
|
221
|
+
ref = index === 0 ? "current" : {
|
|
222
|
+
snapshotId: snapshots[index - 1].id
|
|
223
|
+
};
|
|
224
|
+
void timeMachineStore.buildPreview(preview.right, ref);
|
|
225
|
+
} else {
|
|
226
|
+
ref = {
|
|
227
|
+
snapshotId: snapshots[index].id
|
|
228
|
+
};
|
|
229
|
+
void timeMachineStore.buildPreview(ref, preview.left);
|
|
230
|
+
}
|
|
231
|
+
};
|
|
232
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
233
|
+
style: styles.screenFill,
|
|
234
|
+
children: [/*#__PURE__*/_jsx(RestorePreviewScreen, {
|
|
235
|
+
preview: preview,
|
|
236
|
+
snapshots: snapshots,
|
|
237
|
+
busy: busy !== null,
|
|
238
|
+
onBack: closePreview,
|
|
239
|
+
onOpenItem: (sourceId, item) => {
|
|
240
|
+
const source = preview.sources.find(s => s.id === sourceId);
|
|
241
|
+
setScreen({
|
|
242
|
+
kind: "item",
|
|
243
|
+
sourceId,
|
|
244
|
+
sourceLabel: source?.label ?? sourceId,
|
|
245
|
+
item
|
|
246
|
+
});
|
|
247
|
+
},
|
|
248
|
+
onRestore: (mode, excludeKeys) => {
|
|
249
|
+
if (!rightMeta || busy) return;
|
|
250
|
+
if (rightMeta.baseline) {
|
|
251
|
+
confirmDestructive("Restore fresh install?", "This wipes all app storage and reloads the app.", "Wipe & reload", () => void timeMachineStore.restore(rightMeta.id, "reload"));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
// Land back on the list, where the outcome panel reports the
|
|
255
|
+
// results — the preview's diff is stale the moment restore runs.
|
|
256
|
+
void timeMachineStore.restore(rightMeta.id, mode, excludeKeys).then(() => closePreview());
|
|
257
|
+
},
|
|
258
|
+
onPickSide: setPicker,
|
|
259
|
+
onRefresh: () => void timeMachineStore.buildPreview(preview.right, preview.left)
|
|
260
|
+
}), picker && /*#__PURE__*/_jsx(EventPickerModal, {
|
|
261
|
+
isOpen: true,
|
|
262
|
+
onClose: () => setPicker(null),
|
|
263
|
+
title: picker === "left" ? "Compare from" : "Compare to",
|
|
264
|
+
position: picker,
|
|
265
|
+
items: pickerItems,
|
|
266
|
+
onSelect: onPickerSelect
|
|
267
|
+
})]
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// ── List screen ──
|
|
133
272
|
const unavailable = providers.filter(p => p.detail && (!p.canCapture || !p.canRestore));
|
|
134
|
-
return /*#__PURE__*/_jsxs(
|
|
135
|
-
style: styles.
|
|
273
|
+
return /*#__PURE__*/_jsxs(ScrollView, {
|
|
274
|
+
style: styles.screenFill,
|
|
275
|
+
contentContainerStyle: styles.container,
|
|
136
276
|
children: [lastOutcome && /*#__PURE__*/_jsx(OutcomePanel, {
|
|
137
277
|
outcome: lastOutcome
|
|
138
278
|
}), /*#__PURE__*/_jsxs(View, {
|
|
139
|
-
style: styles.
|
|
140
|
-
children: [/*#__PURE__*/
|
|
141
|
-
style: styles.
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
279
|
+
style: styles.captureCard,
|
|
280
|
+
children: [/*#__PURE__*/_jsxs(View, {
|
|
281
|
+
style: styles.captureField,
|
|
282
|
+
children: [/*#__PURE__*/_jsx(Plus, {
|
|
283
|
+
size: 14,
|
|
284
|
+
color: buoyColors.textMuted
|
|
285
|
+
}), /*#__PURE__*/_jsx(TextInput, {
|
|
286
|
+
style: styles.captureInput,
|
|
287
|
+
value: name,
|
|
288
|
+
onChangeText: setName,
|
|
289
|
+
placeholder: "Name this restore point\u2026",
|
|
290
|
+
placeholderTextColor: buoyColors.textMuted,
|
|
291
|
+
editable: !captureDisabled,
|
|
292
|
+
onSubmitEditing: capture,
|
|
293
|
+
returnKeyType: "done",
|
|
294
|
+
testID: "time-machine-name-input"
|
|
295
|
+
})]
|
|
150
296
|
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
151
297
|
style: [styles.captureButton, captureDisabled && styles.buttonDisabled],
|
|
152
298
|
onPress: capture,
|
|
@@ -157,76 +303,88 @@ export function TimeMachineBody() {
|
|
|
157
303
|
children: busy === "capture" ? "…" : "CAPTURE"
|
|
158
304
|
})
|
|
159
305
|
})]
|
|
160
|
-
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
161
|
-
style: [styles.baselineButton, captureDisabled && styles.buttonDisabled],
|
|
162
|
-
onPress: captureBaseline,
|
|
163
|
-
disabled: captureDisabled,
|
|
164
|
-
testID: "time-machine-capture-baseline",
|
|
165
|
-
children: /*#__PURE__*/_jsx(Text, {
|
|
166
|
-
style: styles.baselineButtonText,
|
|
167
|
-
children: "\u2302 CAPTURE FRESH-INSTALL BASELINE"
|
|
168
|
-
})
|
|
169
306
|
}), atFreeLimit && /*#__PURE__*/_jsxs(Text, {
|
|
170
307
|
style: styles.freeLimitNote,
|
|
171
308
|
children: ["Free plan: ", FREE_SNAPSHOT_LIMIT, " restore points. Upgrade to Pro for unlimited snapshots."]
|
|
172
309
|
}), /*#__PURE__*/_jsxs(View, {
|
|
173
|
-
style: styles.
|
|
174
|
-
children: [
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
style: styles.
|
|
184
|
-
children:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
310
|
+
style: styles.sectionRow,
|
|
311
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
312
|
+
style: styles.sectionTitle,
|
|
313
|
+
children: "Sources"
|
|
314
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
315
|
+
style: styles.sourceTiles,
|
|
316
|
+
children: [providers.map(p => {
|
|
317
|
+
const IconComp = SOURCE_ICONS[p.id] ?? TimeMachineIcon;
|
|
318
|
+
const dotColor = !p.canCapture ? buoyColors.textMuted : p.canRestore ? buoyColors.success : buoyColors.warning;
|
|
319
|
+
return /*#__PURE__*/_jsxs(View, {
|
|
320
|
+
style: styles.sourceTile,
|
|
321
|
+
children: [/*#__PURE__*/_jsx(IconComp, {
|
|
322
|
+
size: 16
|
|
323
|
+
}), /*#__PURE__*/_jsx(View, {
|
|
324
|
+
style: [styles.sourceTileDot, {
|
|
325
|
+
backgroundColor: dotColor
|
|
326
|
+
}]
|
|
327
|
+
})]
|
|
328
|
+
}, p.id);
|
|
329
|
+
}), providers.length === 0 && /*#__PURE__*/_jsx(Text, {
|
|
330
|
+
style: styles.emptyText,
|
|
331
|
+
children: "none registered"
|
|
332
|
+
})]
|
|
190
333
|
})]
|
|
191
334
|
}), unavailable.map(p => /*#__PURE__*/_jsxs(Text, {
|
|
192
335
|
style: styles.providerDetail,
|
|
193
336
|
children: [p.label, ": ", p.detail]
|
|
194
|
-
}, p.id)),
|
|
337
|
+
}, p.id)), /*#__PURE__*/_jsx(Text, {
|
|
338
|
+
style: [styles.sectionTitle, styles.sectionSpacing],
|
|
339
|
+
children: "Restore points"
|
|
340
|
+
}), hasLoaded && snapshots.length === 0 && /*#__PURE__*/_jsx(Text, {
|
|
195
341
|
style: styles.emptyText,
|
|
196
|
-
children: "No
|
|
197
|
-
}),
|
|
342
|
+
children: "No restore points yet. Set up the state you want to return to, then capture it."
|
|
343
|
+
}), visibleSnapshots.map(meta => {
|
|
198
344
|
const warnings = warningCount(meta);
|
|
199
|
-
return /*#__PURE__*/_jsxs(
|
|
200
|
-
style: styles.
|
|
345
|
+
return /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
346
|
+
style: styles.snapshotCard,
|
|
347
|
+
onPress: () => openPreview(meta),
|
|
201
348
|
testID: `time-machine-snap-${meta.id}`,
|
|
202
|
-
children: [/*#__PURE__*/
|
|
349
|
+
children: [/*#__PURE__*/_jsx(View, {
|
|
350
|
+
style: styles.snapshotIconTile,
|
|
351
|
+
children: meta.baseline ? /*#__PURE__*/_jsx(Home, {
|
|
352
|
+
size: 17,
|
|
353
|
+
color: buoyColors.textSecondary
|
|
354
|
+
}) : /*#__PURE__*/_jsx(TimeMachineIcon, {
|
|
355
|
+
size: 18
|
|
356
|
+
})
|
|
357
|
+
}), /*#__PURE__*/_jsxs(View, {
|
|
203
358
|
style: styles.snapshotInfo,
|
|
204
|
-
children: [/*#__PURE__*/
|
|
359
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
205
360
|
style: styles.snapshotName,
|
|
206
361
|
numberOfLines: 1,
|
|
207
|
-
children:
|
|
362
|
+
children: meta.name
|
|
208
363
|
}), /*#__PURE__*/_jsxs(Text, {
|
|
209
364
|
style: styles.snapshotMeta,
|
|
210
|
-
|
|
365
|
+
numberOfLines: 1,
|
|
366
|
+
children: [meta.baseline ? "wipes to fresh install" : `${timeAgo(meta.createdAt)} · ${formatBytes(meta.sizeBytes)} · ${Object.keys(meta.sources).length} sources`, meta.scope?.length ? ` · scoped (${meta.scope.length})` : "", warnings > 0 ? ` · ⚠ ${warnings}` : ""]
|
|
211
367
|
})]
|
|
212
|
-
}), !meta.baseline
|
|
213
|
-
style: [styles.
|
|
368
|
+
}), !meta.baseline ? /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
369
|
+
style: [styles.rowAction, busy && styles.buttonDisabled],
|
|
214
370
|
onPress: () => restore(meta, "live"),
|
|
215
371
|
disabled: busy !== null,
|
|
372
|
+
accessibilityLabel: "Restore",
|
|
216
373
|
children: /*#__PURE__*/_jsx(Text, {
|
|
217
|
-
style: styles.
|
|
374
|
+
style: styles.rowActionLabel,
|
|
218
375
|
children: "RESTORE"
|
|
219
376
|
})
|
|
220
|
-
})
|
|
221
|
-
style: [styles.
|
|
377
|
+
}) : /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
378
|
+
style: [styles.rowAction, busy && styles.buttonDisabled],
|
|
222
379
|
onPress: () => restore(meta, "reload"),
|
|
223
380
|
disabled: busy !== null,
|
|
381
|
+
accessibilityLabel: "Wipe and reload",
|
|
224
382
|
children: /*#__PURE__*/_jsx(Text, {
|
|
225
|
-
style: styles.
|
|
226
|
-
children:
|
|
383
|
+
style: styles.rowActionLabelDanger,
|
|
384
|
+
children: "WIPE"
|
|
227
385
|
})
|
|
228
386
|
}), /*#__PURE__*/_jsx(TouchableOpacity, {
|
|
229
|
-
style: styles.
|
|
387
|
+
style: styles.rowAction,
|
|
230
388
|
onPress: () => remove(meta),
|
|
231
389
|
hitSlop: {
|
|
232
390
|
top: 8,
|
|
@@ -234,39 +392,66 @@ export function TimeMachineBody() {
|
|
|
234
392
|
left: 4,
|
|
235
393
|
right: 8
|
|
236
394
|
},
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
395
|
+
accessibilityLabel: "Delete",
|
|
396
|
+
children: /*#__PURE__*/_jsx(Trash2, {
|
|
397
|
+
size: 14,
|
|
398
|
+
color: buoyColors.error
|
|
240
399
|
})
|
|
241
400
|
})]
|
|
242
401
|
}, meta.id);
|
|
402
|
+
}), /*#__PURE__*/_jsxs(TouchableOpacity, {
|
|
403
|
+
style: [styles.wipeAllButton, busy && styles.buttonDisabled],
|
|
404
|
+
onPress: wipeAll,
|
|
405
|
+
disabled: busy !== null,
|
|
406
|
+
testID: "time-machine-wipe-all",
|
|
407
|
+
children: [/*#__PURE__*/_jsx(Trash2, {
|
|
408
|
+
size: 13,
|
|
409
|
+
color: buoyColors.error
|
|
410
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
411
|
+
style: styles.wipeAllText,
|
|
412
|
+
children: "Wipe all app state\u2026"
|
|
413
|
+
})]
|
|
414
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
415
|
+
style: styles.wipeAllCaption,
|
|
416
|
+
children: "Deletes all app storage and reloads \u2014 like a fresh install."
|
|
243
417
|
})]
|
|
244
418
|
});
|
|
245
419
|
}
|
|
246
420
|
const styles = StyleSheet.create({
|
|
421
|
+
screenFill: {
|
|
422
|
+
flex: 1
|
|
423
|
+
},
|
|
247
424
|
container: {
|
|
248
425
|
padding: 12,
|
|
249
426
|
gap: 8
|
|
250
427
|
},
|
|
251
|
-
|
|
428
|
+
captureCard: {
|
|
252
429
|
flexDirection: "row",
|
|
430
|
+
alignItems: "center",
|
|
253
431
|
gap: 8
|
|
254
432
|
},
|
|
255
|
-
|
|
433
|
+
captureField: {
|
|
256
434
|
flex: 1,
|
|
257
|
-
|
|
435
|
+
flexDirection: "row",
|
|
436
|
+
alignItems: "center",
|
|
437
|
+
gap: 8,
|
|
438
|
+
backgroundColor: buoyColors.card,
|
|
258
439
|
borderColor: buoyColors.border,
|
|
259
440
|
borderWidth: 1,
|
|
260
|
-
borderRadius:
|
|
441
|
+
borderRadius: 10,
|
|
442
|
+
paddingHorizontal: 10
|
|
443
|
+
},
|
|
444
|
+
captureInput: {
|
|
445
|
+
flex: 1,
|
|
261
446
|
color: buoyColors.text,
|
|
262
|
-
|
|
263
|
-
paddingVertical:
|
|
264
|
-
fontSize: 13
|
|
447
|
+
fontSize: 13,
|
|
448
|
+
paddingVertical: 9
|
|
265
449
|
},
|
|
266
450
|
captureButton: {
|
|
267
451
|
backgroundColor: buoyColors.primary,
|
|
268
|
-
borderRadius:
|
|
269
|
-
paddingHorizontal:
|
|
452
|
+
borderRadius: 10,
|
|
453
|
+
paddingHorizontal: 16,
|
|
454
|
+
paddingVertical: 10,
|
|
270
455
|
justifyContent: "center"
|
|
271
456
|
},
|
|
272
457
|
captureButtonText: {
|
|
@@ -275,19 +460,6 @@ const styles = StyleSheet.create({
|
|
|
275
460
|
fontWeight: "700",
|
|
276
461
|
letterSpacing: 0.5
|
|
277
462
|
},
|
|
278
|
-
baselineButton: {
|
|
279
|
-
borderColor: buoyColors.border,
|
|
280
|
-
borderWidth: 1,
|
|
281
|
-
borderRadius: 6,
|
|
282
|
-
paddingVertical: 8,
|
|
283
|
-
alignItems: "center"
|
|
284
|
-
},
|
|
285
|
-
baselineButtonText: {
|
|
286
|
-
color: buoyColors.textSecondary,
|
|
287
|
-
fontSize: 11,
|
|
288
|
-
fontWeight: "600",
|
|
289
|
-
letterSpacing: 0.5
|
|
290
|
-
},
|
|
291
463
|
buttonDisabled: {
|
|
292
464
|
opacity: 0.4
|
|
293
465
|
},
|
|
@@ -295,83 +467,127 @@ const styles = StyleSheet.create({
|
|
|
295
467
|
color: buoyColors.warning,
|
|
296
468
|
fontSize: 11
|
|
297
469
|
},
|
|
298
|
-
|
|
470
|
+
sectionRow: {
|
|
299
471
|
flexDirection: "row",
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
marginTop:
|
|
472
|
+
alignItems: "center",
|
|
473
|
+
justifyContent: "space-between",
|
|
474
|
+
marginTop: 12,
|
|
475
|
+
gap: 10
|
|
476
|
+
},
|
|
477
|
+
sectionTitle: {
|
|
478
|
+
color: buoyColors.text,
|
|
479
|
+
fontSize: 14,
|
|
480
|
+
fontWeight: "700"
|
|
481
|
+
},
|
|
482
|
+
sectionSpacing: {
|
|
483
|
+
marginTop: 14
|
|
303
484
|
},
|
|
304
|
-
|
|
485
|
+
sourceTiles: {
|
|
305
486
|
flexDirection: "row",
|
|
306
|
-
|
|
307
|
-
|
|
487
|
+
gap: 6,
|
|
488
|
+
flexWrap: "wrap",
|
|
489
|
+
justifyContent: "flex-end",
|
|
490
|
+
flex: 1
|
|
491
|
+
},
|
|
492
|
+
sourceTile: {
|
|
493
|
+
width: 32,
|
|
494
|
+
height: 32,
|
|
495
|
+
borderRadius: 9,
|
|
308
496
|
backgroundColor: buoyColors.card,
|
|
309
497
|
borderColor: buoyColors.border,
|
|
310
498
|
borderWidth: 1,
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
paddingVertical: 3
|
|
499
|
+
alignItems: "center",
|
|
500
|
+
justifyContent: "center"
|
|
314
501
|
},
|
|
315
|
-
|
|
502
|
+
sourceTileDot: {
|
|
503
|
+
position: "absolute",
|
|
504
|
+
top: 3,
|
|
505
|
+
right: 3,
|
|
316
506
|
width: 6,
|
|
317
507
|
height: 6,
|
|
318
508
|
borderRadius: 3
|
|
319
509
|
},
|
|
320
|
-
providerLabel: {
|
|
321
|
-
color: buoyColors.textSecondary,
|
|
322
|
-
fontSize: 11
|
|
323
|
-
},
|
|
324
510
|
providerDetail: {
|
|
325
511
|
color: buoyColors.textMuted,
|
|
326
|
-
fontSize: 10
|
|
512
|
+
fontSize: 10,
|
|
513
|
+
marginTop: 4
|
|
327
514
|
},
|
|
328
515
|
emptyText: {
|
|
329
516
|
color: buoyColors.textMuted,
|
|
330
517
|
fontSize: 12,
|
|
331
518
|
marginTop: 8
|
|
332
519
|
},
|
|
333
|
-
|
|
520
|
+
snapshotCard: {
|
|
334
521
|
flexDirection: "row",
|
|
335
522
|
alignItems: "center",
|
|
336
523
|
backgroundColor: buoyColors.card,
|
|
337
524
|
borderColor: buoyColors.border,
|
|
338
525
|
borderWidth: 1,
|
|
339
|
-
borderRadius:
|
|
340
|
-
|
|
341
|
-
|
|
526
|
+
borderRadius: 12,
|
|
527
|
+
paddingHorizontal: 12,
|
|
528
|
+
paddingVertical: 10,
|
|
529
|
+
marginTop: 8,
|
|
530
|
+
gap: 10
|
|
531
|
+
},
|
|
532
|
+
snapshotIconTile: {
|
|
533
|
+
width: 36,
|
|
534
|
+
height: 36,
|
|
535
|
+
borderRadius: 10,
|
|
536
|
+
backgroundColor: buoyColors.hover,
|
|
537
|
+
alignItems: "center",
|
|
538
|
+
justifyContent: "center"
|
|
342
539
|
},
|
|
343
540
|
snapshotInfo: {
|
|
344
541
|
flex: 1,
|
|
345
|
-
minWidth: 0
|
|
542
|
+
minWidth: 0,
|
|
543
|
+
gap: 2
|
|
346
544
|
},
|
|
347
545
|
snapshotName: {
|
|
348
546
|
color: buoyColors.text,
|
|
349
|
-
fontSize:
|
|
350
|
-
fontWeight: "
|
|
547
|
+
fontSize: 14,
|
|
548
|
+
fontWeight: "700"
|
|
351
549
|
},
|
|
352
550
|
snapshotMeta: {
|
|
353
551
|
color: buoyColors.textMuted,
|
|
354
552
|
fontSize: 10,
|
|
355
|
-
|
|
553
|
+
fontVariant: ["tabular-nums"]
|
|
356
554
|
},
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
paddingHorizontal: 8,
|
|
362
|
-
paddingVertical: 6
|
|
555
|
+
rowAction: {
|
|
556
|
+
padding: 4,
|
|
557
|
+
justifyContent: "center",
|
|
558
|
+
alignItems: "center"
|
|
363
559
|
},
|
|
364
|
-
|
|
560
|
+
rowActionLabel: {
|
|
365
561
|
color: buoyColors.primary,
|
|
366
|
-
fontSize:
|
|
367
|
-
fontWeight: "
|
|
562
|
+
fontSize: 12,
|
|
563
|
+
fontWeight: "600"
|
|
368
564
|
},
|
|
369
|
-
|
|
370
|
-
|
|
565
|
+
rowActionLabelDanger: {
|
|
566
|
+
color: buoyColors.error,
|
|
567
|
+
fontSize: 12,
|
|
568
|
+
fontWeight: "600"
|
|
371
569
|
},
|
|
372
|
-
|
|
570
|
+
wipeAllButton: {
|
|
571
|
+
flexDirection: "row",
|
|
572
|
+
alignItems: "center",
|
|
573
|
+
justifyContent: "center",
|
|
574
|
+
gap: 7,
|
|
575
|
+
borderColor: `${buoyColors.error}55`,
|
|
576
|
+
borderWidth: 1,
|
|
577
|
+
borderRadius: 10,
|
|
578
|
+
paddingVertical: 10,
|
|
579
|
+
marginTop: 18
|
|
580
|
+
},
|
|
581
|
+
wipeAllText: {
|
|
582
|
+
color: buoyColors.error,
|
|
583
|
+
fontSize: 12.5,
|
|
584
|
+
fontWeight: "600"
|
|
585
|
+
},
|
|
586
|
+
wipeAllCaption: {
|
|
373
587
|
color: buoyColors.textMuted,
|
|
374
|
-
fontSize:
|
|
588
|
+
fontSize: 10,
|
|
589
|
+
textAlign: "center",
|
|
590
|
+
marginTop: 6
|
|
375
591
|
},
|
|
376
592
|
outcomePanel: {
|
|
377
593
|
backgroundColor: buoyColors.card,
|