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