@rozenite/storage-plugin 2.1.0 → 2.3.0
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/CHANGELOG.md +34 -0
- package/dist/devtools/assets/panel-CcThj-0Z.js +32 -0
- package/dist/devtools/assets/panel-DTYbHqnH.css +1 -0
- package/dist/devtools/panel.html +2 -2
- package/dist/react-native/cjs/package.json +3 -0
- package/dist/react-native/cjs/react-native.js +38 -0
- package/dist/react-native/cjs/src/react-native/adapters/async-storage.js +60 -0
- package/dist/react-native/cjs/src/react-native/adapters/index.js +10 -0
- package/dist/react-native/cjs/src/react-native/adapters/mmkv.js +143 -0
- package/dist/react-native/cjs/src/react-native/adapters/secure-storage.js +51 -0
- package/dist/react-native/cjs/src/react-native/entry-preview-pagination.js +198 -0
- package/dist/react-native/cjs/src/react-native/export-snapshot.js +70 -0
- package/dist/react-native/cjs/src/react-native/full-entry-request.js +72 -0
- package/dist/react-native/cjs/src/react-native/import.js +185 -0
- package/dist/react-native/cjs/src/react-native/storage-discovery.js +69 -0
- package/dist/react-native/cjs/src/react-native/storage-view.js +128 -0
- package/dist/react-native/cjs/src/react-native/useRozeniteStoragePlugin.js +145 -0
- package/dist/react-native/cjs/src/react-native/useStorageAgentTools.js +228 -0
- package/dist/react-native/cjs/src/shared/agent-tools.js +119 -0
- package/dist/react-native/cjs/src/shared/entry-preview.js +48 -0
- package/dist/react-native/cjs/src/shared/messaging.js +2 -0
- package/dist/react-native/cjs/src/shared/snapshot.js +185 -0
- package/dist/react-native/cjs/src/shared/types.js +13 -0
- package/dist/react-native/package.json +3 -0
- package/dist/react-native/react-native.d.ts +7 -0
- package/dist/react-native/react-native.js +40 -0
- package/dist/react-native/src/react-native/adapters/async-storage.d.ts +34 -0
- package/dist/react-native/src/react-native/adapters/async-storage.js +56 -0
- package/dist/react-native/src/react-native/adapters/index.d.ts +6 -0
- package/dist/react-native/src/react-native/adapters/index.js +3 -0
- package/dist/react-native/src/react-native/adapters/mmkv.d.ts +13 -0
- package/dist/react-native/src/react-native/adapters/mmkv.js +139 -0
- package/dist/react-native/src/react-native/adapters/secure-storage.d.ts +18 -0
- package/dist/react-native/src/react-native/adapters/secure-storage.js +47 -0
- package/dist/react-native/src/react-native/entry-preview-pagination.d.ts +7 -0
- package/dist/react-native/src/react-native/entry-preview-pagination.js +194 -0
- package/dist/react-native/src/react-native/export-snapshot.d.ts +5 -0
- package/dist/react-native/src/react-native/export-snapshot.js +66 -0
- package/dist/react-native/src/react-native/full-entry-request.d.ts +5 -0
- package/dist/react-native/src/react-native/full-entry-request.js +68 -0
- package/dist/react-native/src/react-native/import.d.ts +7 -0
- package/dist/react-native/src/react-native/import.js +180 -0
- package/dist/react-native/src/react-native/storage-discovery.d.ts +5 -0
- package/dist/react-native/src/react-native/storage-discovery.js +65 -0
- package/dist/react-native/src/react-native/storage-view.d.ts +19 -0
- package/dist/react-native/src/react-native/storage-view.js +123 -0
- package/dist/react-native/src/react-native/useRozeniteStoragePlugin.d.ts +6 -0
- package/dist/react-native/src/react-native/useRozeniteStoragePlugin.js +141 -0
- package/dist/react-native/src/react-native/useStorageAgentTools.d.ts +37 -0
- package/dist/react-native/src/react-native/useStorageAgentTools.js +223 -0
- package/dist/react-native/src/shared/agent-tools.d.ts +76 -0
- package/dist/react-native/src/shared/agent-tools.js +116 -0
- package/dist/react-native/src/shared/entry-preview.d.ts +4 -0
- package/dist/react-native/src/shared/entry-preview.js +44 -0
- package/dist/react-native/src/shared/messaging.d.ts +134 -0
- package/dist/react-native/src/shared/messaging.js +1 -0
- package/dist/react-native/src/shared/snapshot.d.ts +53 -0
- package/dist/react-native/src/shared/snapshot.js +179 -0
- package/dist/react-native/src/shared/types.d.ts +78 -0
- package/dist/react-native/src/shared/types.js +8 -0
- package/dist/rozenite.json +1 -1
- package/dist/sdk/package.json +3 -0
- package/dist/sdk/sdk.d.ts +44 -0
- package/dist/sdk/sdk.js +9 -0
- package/dist/sdk/src/shared/agent-tools.d.ts +76 -0
- package/dist/sdk/src/shared/agent-tools.js +119 -0
- package/dist/sdk/src/shared/types.d.ts +78 -0
- package/dist/sdk/src/shared/types.js +13 -0
- package/package.json +16 -16
- package/react-native.ts +8 -1
- package/rozenite.config.ts +1 -0
- package/src/__tests__/release-bundle.test.ts +32 -0
- package/src/ui/__tests__/panel.test.tsx +14 -0
- package/src/ui/add-entry-dialog.tsx +63 -73
- package/src/ui/binary-value-editor.tsx +1 -1
- package/src/ui/edit-entry-dialog.tsx +59 -70
- package/src/ui/entry-detail-dialog.tsx +4 -2
- package/src/ui/format-value.tsx +1 -1
- package/src/ui/import-dialog.tsx +5 -5
- package/src/ui/panel.tsx +70 -88
- package/tsconfig.json +4 -7
- package/dist/devtools/assets/panel-BlDRXgVW.js +0 -32
- package/dist/devtools/assets/panel-DBweZnW5.css +0 -1
- package/dist/react-native/chunks/async-storage.require.cjs +0 -1
- package/dist/react-native/chunks/async-storage.require.js +0 -53
- package/dist/react-native/chunks/index.require.cjs +0 -1
- package/dist/react-native/chunks/index.require.js +0 -103
- package/dist/react-native/chunks/secure-storage.require.cjs +0 -1
- package/dist/react-native/chunks/secure-storage.require.js +0 -46
- package/dist/react-native/chunks/types.cjs +0 -1
- package/dist/react-native/chunks/types.js +0 -11
- package/dist/react-native/chunks/useRozeniteStoragePlugin.require.cjs +0 -1
- package/dist/react-native/chunks/useRozeniteStoragePlugin.require.js +0 -1037
- package/dist/react-native/index.cjs +0 -1
- package/dist/react-native/index.d.ts +0 -365
- package/dist/react-native/index.js +0 -28
- package/dist/sdk/index.cjs +0 -1
- package/dist/sdk/index.d.ts +0 -206
- package/dist/sdk/index.js +0 -122
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rozenite/storage-plugin",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Generic Storage Inspector for Rozenite.",
|
|
5
5
|
"homepage": "https://github.com/callstackincubator/rozenite#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -12,20 +12,19 @@
|
|
|
12
12
|
"url": "https://github.com/callstackincubator/rozenite.git"
|
|
13
13
|
},
|
|
14
14
|
"type": "module",
|
|
15
|
-
"main": "./dist/react-native/
|
|
16
|
-
"module": "./dist/react-native/
|
|
17
|
-
"types": "./dist/react-native/
|
|
15
|
+
"main": "./dist/react-native/cjs/react-native.js",
|
|
16
|
+
"module": "./dist/react-native/react-native.js",
|
|
17
|
+
"types": "./dist/react-native/react-native.d.ts",
|
|
18
18
|
"exports": {
|
|
19
19
|
".": {
|
|
20
|
-
"types": "./dist/react-native/
|
|
21
|
-
"import": "./dist/react-native/
|
|
22
|
-
"require": "./dist/react-native/
|
|
20
|
+
"types": "./dist/react-native/react-native.d.ts",
|
|
21
|
+
"import": "./dist/react-native/react-native.js",
|
|
22
|
+
"require": "./dist/react-native/cjs/react-native.js"
|
|
23
23
|
},
|
|
24
24
|
"./sdk": {
|
|
25
25
|
"development": "./sdk.ts",
|
|
26
|
-
"types": "./dist/sdk/
|
|
27
|
-
"
|
|
28
|
-
"require": "./dist/sdk/index.cjs"
|
|
26
|
+
"types": "./dist/sdk/sdk.d.ts",
|
|
27
|
+
"default": "./dist/sdk/sdk.js"
|
|
29
28
|
},
|
|
30
29
|
"./package.json": "./package.json"
|
|
31
30
|
},
|
|
@@ -33,10 +32,10 @@
|
|
|
33
32
|
"access": "public"
|
|
34
33
|
},
|
|
35
34
|
"dependencies": {
|
|
36
|
-
"@rozenite/agent-
|
|
37
|
-
"@rozenite/
|
|
38
|
-
"@rozenite/
|
|
39
|
-
"@rozenite/
|
|
35
|
+
"@rozenite/agent-shared": "2.3.0",
|
|
36
|
+
"@rozenite/plugin-bridge": "2.3.0",
|
|
37
|
+
"@rozenite/ui": "2.3.0",
|
|
38
|
+
"@rozenite/agent-bridge": "2.3.0"
|
|
40
39
|
},
|
|
41
40
|
"devDependencies": {
|
|
42
41
|
"@codemirror/commands": "^6.10.3",
|
|
@@ -57,8 +56,9 @@
|
|
|
57
56
|
"react-virtuoso": "^4.14.1",
|
|
58
57
|
"typescript": "~5.9.3",
|
|
59
58
|
"vite": "^7.3.1",
|
|
60
|
-
"@rozenite/
|
|
61
|
-
"rozenite": "2.
|
|
59
|
+
"@rozenite/test-utils": "2.3.0",
|
|
60
|
+
"@rozenite/vite-plugin": "2.3.0",
|
|
61
|
+
"rozenite": "2.3.0"
|
|
62
62
|
},
|
|
63
63
|
"peerDependencies": {
|
|
64
64
|
"@react-native-async-storage/async-storage": "*",
|
package/react-native.ts
CHANGED
|
@@ -26,8 +26,15 @@ export let createMMKVStorageAdapter: typeof import('./src/react-native/adapters'
|
|
|
26
26
|
export let useRozeniteStoragePlugin: typeof import('./src/react-native/useRozeniteStoragePlugin').useRozeniteStoragePlugin;
|
|
27
27
|
|
|
28
28
|
const isWeb = typeof window !== 'undefined' && window.navigator.product !== 'ReactNative';
|
|
29
|
+
// Neither Lynx runtime has a `window`, so `typeof window` alone reported
|
|
30
|
+
// every Lynx app as a server and installed the no-op stub below. `lynx` is
|
|
31
|
+
// a free binding in module scope, not a property of `globalThis`. Kept
|
|
32
|
+
// inline rather than imported so this stays a foldable expression and the
|
|
33
|
+
// `require`s below can still be dropped from production bundles.
|
|
34
|
+
declare const lynx: unknown;
|
|
35
|
+
|
|
29
36
|
const isDev = process.env.NODE_ENV !== 'production';
|
|
30
|
-
const isServer = typeof window === 'undefined';
|
|
37
|
+
const isServer = typeof window === 'undefined' && typeof lynx === 'undefined';
|
|
31
38
|
|
|
32
39
|
const createNoopStorageAdapter = (
|
|
33
40
|
options: { adapterId?: string; adapterName?: string } | undefined,
|
package/rozenite.config.ts
CHANGED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { bundleForRelease, RELEASE_BUNDLE_TIMEOUT } from '@rozenite/test-utils';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
|
|
6
|
+
// An app importing this plugin ships its React Native code -- that much is
|
|
7
|
+
// the app's own choice. What must never follow it into the bundle is the
|
|
8
|
+
// panel: the DevTools UI, its React DOM tree and `@rozenite/ui`.
|
|
9
|
+
// See docs/agents/release-bundle-testing.md.
|
|
10
|
+
const packageRoot = path.resolve(fileURLToPath(import.meta.url), '../../..');
|
|
11
|
+
const reactNativeEntry = path.join(packageRoot, 'dist/react-native/cjs/react-native.js');
|
|
12
|
+
|
|
13
|
+
describe('@rozenite/storage-plugin in a release bundle', () => {
|
|
14
|
+
it(
|
|
15
|
+
'ships no panel code when an app imports it',
|
|
16
|
+
async () => {
|
|
17
|
+
const result = await bundleForRelease({
|
|
18
|
+
resolveFrom: packageRoot,
|
|
19
|
+
files: {
|
|
20
|
+
'index.js': `require(${JSON.stringify(reactNativeEntry)});\n`,
|
|
21
|
+
},
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
// Keeps the check below honest: the entry really did get bundled.
|
|
25
|
+
expect(result.rozeniteModules).toContain(
|
|
26
|
+
'packages/storage-plugin/dist/react-native/cjs/react-native.js',
|
|
27
|
+
);
|
|
28
|
+
expect(result.panelModules).toEqual([]);
|
|
29
|
+
},
|
|
30
|
+
RELEASE_BUNDLE_TIMEOUT,
|
|
31
|
+
);
|
|
32
|
+
});
|
|
@@ -93,9 +93,23 @@ vi.mock('@rozenite/ui', async () => {
|
|
|
93
93
|
Button: ({ children, onClick }: { children?: ReactNode; onClick?: () => void }) => (
|
|
94
94
|
<button onClick={onClick}>{children}</button>
|
|
95
95
|
),
|
|
96
|
+
IconButton: ({
|
|
97
|
+
children,
|
|
98
|
+
onClick,
|
|
99
|
+
label,
|
|
100
|
+
}: {
|
|
101
|
+
children?: ReactNode;
|
|
102
|
+
onClick?: () => void;
|
|
103
|
+
label: string;
|
|
104
|
+
}) => (
|
|
105
|
+
<button onClick={onClick} aria-label={label}>
|
|
106
|
+
{children}
|
|
107
|
+
</button>
|
|
108
|
+
),
|
|
96
109
|
ConfirmDialog: () => null,
|
|
97
110
|
EmptyState: () => <div />,
|
|
98
111
|
PluginShell,
|
|
112
|
+
useConfirmDialog: () => async () => true,
|
|
99
113
|
SearchField: ({
|
|
100
114
|
value,
|
|
101
115
|
onChange,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button,
|
|
1
|
+
import { Button, Dialog, Field, Input, useConfirmDialog } from '@rozenite/ui';
|
|
2
2
|
import { useEffect, useState } from 'react';
|
|
3
3
|
import type { StorageEntry, StorageEntryType, StorageEntryValue } from '../shared/types';
|
|
4
4
|
import { TypedValueEditor } from './typed-value-editor';
|
|
@@ -45,7 +45,7 @@ export const AddEntryDialog = ({
|
|
|
45
45
|
const [currentValue, setCurrentValue] = useState<StorageEntryValue | null>(
|
|
46
46
|
defaultValueForType(initialType),
|
|
47
47
|
);
|
|
48
|
-
const
|
|
48
|
+
const confirm = useConfirmDialog();
|
|
49
49
|
|
|
50
50
|
// Reset state every time the dialog opens, so a previous session's
|
|
51
51
|
// type / value doesn't bleed in.
|
|
@@ -66,21 +66,23 @@ export const AddEntryDialog = ({
|
|
|
66
66
|
onClose();
|
|
67
67
|
};
|
|
68
68
|
|
|
69
|
-
const handleAdd = () => {
|
|
69
|
+
const handleAdd = async () => {
|
|
70
70
|
if (!newEntryKey.trim() || currentValue === null) return;
|
|
71
71
|
|
|
72
72
|
if (!isCurrentTypeSupported) {
|
|
73
|
-
|
|
73
|
+
await confirm({
|
|
74
|
+
variant: 'alert',
|
|
74
75
|
title: 'Unsupported Type',
|
|
75
|
-
|
|
76
|
+
description: 'Selected type is not supported by this storage.',
|
|
76
77
|
});
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
if (existingKeys.includes(newEntryKey)) {
|
|
81
|
-
|
|
82
|
+
await confirm({
|
|
83
|
+
variant: 'alert',
|
|
82
84
|
title: 'Key Already Exists',
|
|
83
|
-
|
|
85
|
+
description: 'An entry with this key already exists.',
|
|
84
86
|
});
|
|
85
87
|
return;
|
|
86
88
|
}
|
|
@@ -91,7 +93,7 @@ export const AddEntryDialog = ({
|
|
|
91
93
|
|
|
92
94
|
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
93
95
|
if (event.key === 'Enter' && newEntryKey.trim() && currentType !== 'buffer') {
|
|
94
|
-
handleAdd();
|
|
96
|
+
void handleAdd();
|
|
95
97
|
}
|
|
96
98
|
};
|
|
97
99
|
|
|
@@ -100,70 +102,58 @@ export const AddEntryDialog = ({
|
|
|
100
102
|
const isAddDisabled = !newEntryKey.trim() || !isCurrentTypeSupported || currentValue === null;
|
|
101
103
|
|
|
102
104
|
return (
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
>
|
|
110
|
-
<Dialog.
|
|
111
|
-
<Dialog.
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
<
|
|
116
|
-
<Field>
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
<Field>
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
<
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
</Dialog>
|
|
157
|
-
|
|
158
|
-
<ConfirmDialog
|
|
159
|
-
open={alert !== null}
|
|
160
|
-
onOpenChange={(open) => {
|
|
161
|
-
if (!open) setAlert(null);
|
|
162
|
-
}}
|
|
163
|
-
variant="alert"
|
|
164
|
-
title={alert?.title ?? ''}
|
|
165
|
-
description={alert?.message}
|
|
166
|
-
/>
|
|
167
|
-
</>
|
|
105
|
+
<Dialog
|
|
106
|
+
open={isOpen}
|
|
107
|
+
onOpenChange={(open) => {
|
|
108
|
+
if (!open) resetAndClose();
|
|
109
|
+
}}
|
|
110
|
+
>
|
|
111
|
+
<Dialog.Content onKeyDown={handleKeyDown}>
|
|
112
|
+
<Dialog.Header>
|
|
113
|
+
<Dialog.Title>Add New Entry</Dialog.Title>
|
|
114
|
+
</Dialog.Header>
|
|
115
|
+
|
|
116
|
+
<div className="flex flex-col gap-4">
|
|
117
|
+
<Field>
|
|
118
|
+
<Field.Label htmlFor="new-entry-key">Key</Field.Label>
|
|
119
|
+
<Input
|
|
120
|
+
id="new-entry-key"
|
|
121
|
+
value={newEntryKey}
|
|
122
|
+
onChange={(event) => setNewEntryKey(event.target.value)}
|
|
123
|
+
placeholder="Enter key name"
|
|
124
|
+
autoFocus
|
|
125
|
+
/>
|
|
126
|
+
</Field>
|
|
127
|
+
|
|
128
|
+
<Field>
|
|
129
|
+
<Field.Label htmlFor="new-entry-value">Value</Field.Label>
|
|
130
|
+
<TypedValueEditor
|
|
131
|
+
supportedTypes={supportedTypes}
|
|
132
|
+
type={currentType}
|
|
133
|
+
value={currentValue}
|
|
134
|
+
onChange={(nextType, nextValue) => {
|
|
135
|
+
setCurrentType(nextType);
|
|
136
|
+
setCurrentValue(nextValue);
|
|
137
|
+
}}
|
|
138
|
+
inputId="new-entry-value"
|
|
139
|
+
/>
|
|
140
|
+
{!isCurrentTypeSupported && (
|
|
141
|
+
<Field.Description className="text-danger">
|
|
142
|
+
Selected type is not supported by this storage.
|
|
143
|
+
</Field.Description>
|
|
144
|
+
)}
|
|
145
|
+
</Field>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<Dialog.Footer>
|
|
149
|
+
<Button tone="neutral" variant="outline" onClick={resetAndClose}>
|
|
150
|
+
Cancel
|
|
151
|
+
</Button>
|
|
152
|
+
<Button onClick={() => void handleAdd()} disabled={isAddDisabled}>
|
|
153
|
+
Add Entry
|
|
154
|
+
</Button>
|
|
155
|
+
</Dialog.Footer>
|
|
156
|
+
</Dialog.Content>
|
|
157
|
+
</Dialog>
|
|
168
158
|
);
|
|
169
159
|
};
|
|
@@ -173,7 +173,7 @@ export const BinaryValueEditor = ({ initialBytes, onChange }: BinaryValueEditorP
|
|
|
173
173
|
ASCII: <span className="font-mono text-foreground">{asciiPreview}</span>
|
|
174
174
|
</div>
|
|
175
175
|
)}
|
|
176
|
-
{state.error && <div className="text-
|
|
176
|
+
{state.error && <div className="text-danger">{state.error}</div>}
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|
|
179
179
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Button,
|
|
1
|
+
import { Button, Dialog, Field, useConfirmDialog } from '@rozenite/ui';
|
|
2
2
|
import { useEffect, useRef, useState } from 'react';
|
|
3
3
|
import type { StorageEntry, StorageEntryType, StorageEntryValue } from '../shared/types';
|
|
4
4
|
import { TypedValueEditor } from './typed-value-editor';
|
|
@@ -28,7 +28,7 @@ export const EditEntryDialog = ({
|
|
|
28
28
|
const [currentValue, setCurrentValue] = useState<StorageEntryValue | null>(
|
|
29
29
|
defaultValueForType('string'),
|
|
30
30
|
);
|
|
31
|
-
const
|
|
31
|
+
const confirm = useConfirmDialog();
|
|
32
32
|
|
|
33
33
|
useEffect(() => {
|
|
34
34
|
if (entry && isOpen) {
|
|
@@ -48,13 +48,14 @@ export const EditEntryDialog = ({
|
|
|
48
48
|
onClose();
|
|
49
49
|
};
|
|
50
50
|
|
|
51
|
-
const handleSave = () => {
|
|
51
|
+
const handleSave = async () => {
|
|
52
52
|
if (!entry || currentValue === null) return;
|
|
53
53
|
|
|
54
54
|
if (!isCurrentTypeSupported) {
|
|
55
|
-
|
|
55
|
+
await confirm({
|
|
56
|
+
variant: 'alert',
|
|
56
57
|
title: 'Unsupported Type',
|
|
57
|
-
|
|
58
|
+
description: 'This storage does not support the selected type.',
|
|
58
59
|
});
|
|
59
60
|
return;
|
|
60
61
|
}
|
|
@@ -65,7 +66,7 @@ export const EditEntryDialog = ({
|
|
|
65
66
|
|
|
66
67
|
const handleKeyDown = (event: React.KeyboardEvent) => {
|
|
67
68
|
if (event.key === 'Enter' && currentType !== 'buffer') {
|
|
68
|
-
handleSave();
|
|
69
|
+
void handleSave();
|
|
69
70
|
}
|
|
70
71
|
};
|
|
71
72
|
|
|
@@ -79,69 +80,57 @@ export const EditEntryDialog = ({
|
|
|
79
80
|
const isSaveDisabled = !isCurrentTypeSupported || currentValue === null;
|
|
80
81
|
|
|
81
82
|
return (
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
>
|
|
89
|
-
<Dialog.
|
|
90
|
-
<Dialog.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
<
|
|
95
|
-
<Field>
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
<Field>
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
</Dialog>
|
|
135
|
-
|
|
136
|
-
<ConfirmDialog
|
|
137
|
-
open={alert !== null}
|
|
138
|
-
onOpenChange={(open) => {
|
|
139
|
-
if (!open) setAlert(null);
|
|
140
|
-
}}
|
|
141
|
-
variant="alert"
|
|
142
|
-
title={alert?.title ?? ''}
|
|
143
|
-
description={alert?.message}
|
|
144
|
-
/>
|
|
145
|
-
</>
|
|
83
|
+
<Dialog
|
|
84
|
+
open={isOpen}
|
|
85
|
+
onOpenChange={(open) => {
|
|
86
|
+
if (!open) resetAndClose();
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<Dialog.Content onKeyDown={handleKeyDown}>
|
|
90
|
+
<Dialog.Header>
|
|
91
|
+
<Dialog.Title>Edit Entry</Dialog.Title>
|
|
92
|
+
</Dialog.Header>
|
|
93
|
+
|
|
94
|
+
<div className="flex flex-col gap-4">
|
|
95
|
+
<Field>
|
|
96
|
+
<Field.Label>Key</Field.Label>
|
|
97
|
+
<div className="h-8 w-full truncate rounded-md border border-input bg-muted px-3 py-1.5 font-mono text-sm text-foreground">
|
|
98
|
+
{entryForDisplay.key}
|
|
99
|
+
</div>
|
|
100
|
+
<Field.Description>Key cannot be changed during editing</Field.Description>
|
|
101
|
+
</Field>
|
|
102
|
+
|
|
103
|
+
<Field>
|
|
104
|
+
<Field.Label htmlFor="edit-entry-value">Value</Field.Label>
|
|
105
|
+
<TypedValueEditor
|
|
106
|
+
key={entryForDisplay.key}
|
|
107
|
+
supportedTypes={supportedTypes}
|
|
108
|
+
type={currentType}
|
|
109
|
+
value={currentValue}
|
|
110
|
+
onChange={(nextType, nextValue) => {
|
|
111
|
+
setCurrentType(nextType);
|
|
112
|
+
setCurrentValue(nextValue);
|
|
113
|
+
}}
|
|
114
|
+
inputId="edit-entry-value"
|
|
115
|
+
autoFocus
|
|
116
|
+
/>
|
|
117
|
+
{!isCurrentTypeSupported && (
|
|
118
|
+
<Field.Description className="text-danger">
|
|
119
|
+
This storage does not support {currentType} values.
|
|
120
|
+
</Field.Description>
|
|
121
|
+
)}
|
|
122
|
+
</Field>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<Dialog.Footer>
|
|
126
|
+
<Button tone="neutral" variant="outline" onClick={resetAndClose}>
|
|
127
|
+
Cancel
|
|
128
|
+
</Button>
|
|
129
|
+
<Button onClick={() => void handleSave()} disabled={isSaveDisabled}>
|
|
130
|
+
Save Changes
|
|
131
|
+
</Button>
|
|
132
|
+
</Dialog.Footer>
|
|
133
|
+
</Dialog.Content>
|
|
134
|
+
</Dialog>
|
|
146
135
|
);
|
|
147
136
|
};
|
|
@@ -69,7 +69,9 @@ export const EntryDetailDialog = ({
|
|
|
69
69
|
|
|
70
70
|
<div>
|
|
71
71
|
<div className="mb-1 text-sm font-medium text-foreground">Type</div>
|
|
72
|
-
<Badge variant="outline">
|
|
72
|
+
<Badge tone="neutral" variant="outline">
|
|
73
|
+
{entry.type}
|
|
74
|
+
</Badge>
|
|
73
75
|
</div>
|
|
74
76
|
|
|
75
77
|
<div className="flex min-h-0 flex-1 flex-col">
|
|
@@ -96,7 +98,7 @@ export const EntryDetailDialog = ({
|
|
|
96
98
|
|
|
97
99
|
<Dialog.Footer>
|
|
98
100
|
{entry && onEdit && (
|
|
99
|
-
<Button variant="outline" onClick={() => onEdit(entry)}>
|
|
101
|
+
<Button tone="neutral" variant="outline" onClick={() => onEdit(entry)}>
|
|
100
102
|
<Edit3 className="h-3.5 w-3.5" />
|
|
101
103
|
Edit
|
|
102
104
|
</Button>
|
package/src/ui/format-value.tsx
CHANGED
|
@@ -13,7 +13,7 @@ export const formatValue = (entry: StorageEntry) => {
|
|
|
13
13
|
|
|
14
14
|
if (entry.type === 'boolean') {
|
|
15
15
|
return (
|
|
16
|
-
<span className={cn('font-mono', entry.value ? 'text-primary' : 'text-
|
|
16
|
+
<span className={cn('font-mono', entry.value ? 'text-primary' : 'text-danger')}>
|
|
17
17
|
{entry.value ? 'true' : 'false'}
|
|
18
18
|
</span>
|
|
19
19
|
);
|
package/src/ui/import-dialog.tsx
CHANGED
|
@@ -89,7 +89,7 @@ const PreviewBody = ({
|
|
|
89
89
|
)}
|
|
90
90
|
|
|
91
91
|
{hasUnsupported && (
|
|
92
|
-
<div className="flex items-start gap-2 rounded-md border border-
|
|
92
|
+
<div className="flex items-start gap-2 rounded-md border border-danger/40 bg-danger/10 p-2 text-xs text-danger">
|
|
93
93
|
<XCircle className="mt-0.5 h-4 w-4 shrink-0" />
|
|
94
94
|
<div>
|
|
95
95
|
{preview.unsupportedTypes.length}{' '}
|
|
@@ -117,7 +117,7 @@ const PreviewBody = ({
|
|
|
117
117
|
</div>
|
|
118
118
|
|
|
119
119
|
<Dialog.Footer>
|
|
120
|
-
<Button variant="outline" onClick={onCancel}>
|
|
120
|
+
<Button tone="neutral" variant="outline" onClick={onCancel}>
|
|
121
121
|
Cancel
|
|
122
122
|
</Button>
|
|
123
123
|
<Button onClick={onApply} disabled={hasUnsupported}>
|
|
@@ -158,7 +158,7 @@ const ResultBody = ({
|
|
|
158
158
|
</div>
|
|
159
159
|
) : (
|
|
160
160
|
<div className="flex flex-col gap-2 py-2">
|
|
161
|
-
<div className="flex items-center gap-2 text-
|
|
161
|
+
<div className="flex items-center gap-2 text-danger">
|
|
162
162
|
<XCircle className="h-5 w-5" />
|
|
163
163
|
<div className="text-sm font-medium">
|
|
164
164
|
Import failed after {state.written} of {state.total}.
|
|
@@ -167,12 +167,12 @@ const ResultBody = ({
|
|
|
167
167
|
{state.failedKey && (
|
|
168
168
|
<div className="text-xs text-muted-foreground">
|
|
169
169
|
Failed at key:{' '}
|
|
170
|
-
<Badge variant="outline" className="font-mono">
|
|
170
|
+
<Badge tone="neutral" variant="outline" className="font-mono">
|
|
171
171
|
{state.failedKey}
|
|
172
172
|
</Badge>
|
|
173
173
|
</div>
|
|
174
174
|
)}
|
|
175
|
-
<div className="rounded-md bg-muted px-2 py-1 font-mono text-xs text-
|
|
175
|
+
<div className="rounded-md bg-muted px-2 py-1 font-mono text-xs text-danger">
|
|
176
176
|
{state.error}
|
|
177
177
|
</div>
|
|
178
178
|
</div>
|