@buoy-gg/network 7.0.12 → 7.0.14
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/index.js +52 -0
- package/lib/commonjs/network/components/NetworkDetailStepper.js +26 -14
- package/lib/commonjs/network/components/NetworkEventDetailView.js +86 -14
- package/lib/commonjs/network/components/NetworkEventItemCompact.js +4 -0
- package/lib/commonjs/network/components/NetworkHeaderLive.js +32 -7
- package/lib/commonjs/network/components/NetworkHeaderMenu.js +183 -0
- package/lib/commonjs/network/components/NetworkListScreen.js +134 -8
- package/lib/commonjs/network/components/NetworkModal.js +198 -51
- package/lib/commonjs/network/components/NetworkNumberPrompt.js +178 -0
- package/lib/commonjs/network/components/NetworkOverrideEditor.js +797 -0
- package/lib/commonjs/network/components/NetworkOverrideHeaderButton.js +102 -0
- package/lib/commonjs/network/components/NetworkOverridesButton.js +88 -0
- package/lib/commonjs/network/components/NetworkOverridesScreen.js +489 -0
- package/lib/commonjs/network/components/response-editor/Explorer.js +973 -0
- package/lib/commonjs/network/components/response-editor/deleteNestedDataByPath.js +56 -0
- package/lib/commonjs/network/components/response-editor/editorContext.js +33 -0
- package/lib/commonjs/network/components/response-editor/updateNestedDataByPath.js +61 -0
- package/lib/commonjs/network/hooks/useNetworkSelection.js +53 -0
- package/lib/commonjs/network/hooks/useOverrideRules.js +36 -0
- package/lib/commonjs/network/overrides/applyToFetch.js +80 -0
- package/lib/commonjs/network/overrides/applyToXhr.js +190 -0
- package/lib/commonjs/network/overrides/engine.js +70 -0
- package/lib/commonjs/network/overrides/matchRule.js +81 -0
- package/lib/commonjs/network/overrides/overrideRulesStore.js +550 -0
- package/lib/commonjs/network/overrides/presets.js +70 -0
- package/lib/commonjs/network/overrides/resolveOverride.js +158 -0
- package/lib/commonjs/network/overrides/types.js +85 -0
- package/lib/commonjs/network/sync/networkSyncAdapter.js +230 -1
- package/lib/commonjs/network/types/index.js +5 -1
- package/lib/commonjs/network/utils/networkEventStore.js +52 -6
- package/lib/commonjs/network/utils/networkListener.js +90 -10
- package/lib/commonjs/network/utils/networkSelectionStore.js +193 -0
- package/lib/commonjs/preset.js +11 -0
- package/lib/module/index.js +19 -0
- package/lib/module/network/components/NetworkDetailStepper.js +27 -15
- package/lib/module/network/components/NetworkEventDetailView.js +87 -15
- package/lib/module/network/components/NetworkEventItemCompact.js +5 -1
- package/lib/module/network/components/NetworkHeaderLive.js +32 -7
- package/lib/module/network/components/NetworkHeaderMenu.js +177 -0
- package/lib/module/network/components/NetworkListScreen.js +135 -9
- package/lib/module/network/components/NetworkModal.js +200 -53
- package/lib/module/network/components/NetworkNumberPrompt.js +174 -0
- package/lib/module/network/components/NetworkOverrideEditor.js +794 -0
- package/lib/module/network/components/NetworkOverrideHeaderButton.js +99 -0
- package/lib/module/network/components/NetworkOverridesButton.js +85 -0
- package/lib/module/network/components/NetworkOverridesScreen.js +485 -0
- package/lib/module/network/components/response-editor/Explorer.js +972 -0
- package/lib/module/network/components/response-editor/deleteNestedDataByPath.js +51 -0
- package/lib/module/network/components/response-editor/editorContext.js +29 -0
- package/lib/module/network/components/response-editor/updateNestedDataByPath.js +56 -0
- package/lib/module/network/hooks/useNetworkSelection.js +46 -0
- package/lib/module/network/hooks/useOverrideRules.js +32 -0
- package/lib/module/network/overrides/applyToFetch.js +72 -0
- package/lib/module/network/overrides/applyToXhr.js +185 -0
- package/lib/module/network/overrides/engine.js +64 -0
- package/lib/module/network/overrides/matchRule.js +75 -0
- package/lib/module/network/overrides/overrideRulesStore.js +547 -0
- package/lib/module/network/overrides/presets.js +65 -0
- package/lib/module/network/overrides/resolveOverride.js +152 -0
- package/lib/module/network/overrides/types.js +80 -0
- package/lib/module/network/sync/networkSyncAdapter.js +230 -1
- package/lib/module/network/types/index.js +3 -1
- package/lib/module/network/utils/networkEventStore.js +52 -6
- package/lib/module/network/utils/networkListener.js +91 -10
- package/lib/module/network/utils/networkSelectionStore.js +188 -0
- package/lib/module/preset.js +13 -1
- package/lib/typescript/index.d.ts +9 -0
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkDetailStepper.d.ts +8 -5
- package/lib/typescript/network/components/NetworkDetailStepper.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts +36 -1
- package/lib/typescript/network/components/NetworkEventDetailView.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts +6 -0
- package/lib/typescript/network/components/NetworkEventItemCompact.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts +13 -3
- package/lib/typescript/network/components/NetworkHeaderLive.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts +46 -0
- package/lib/typescript/network/components/NetworkHeaderMenu.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkListScreen.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkModal.d.ts.map +1 -1
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts +33 -0
- package/lib/typescript/network/components/NetworkNumberPrompt.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts +17 -0
- package/lib/typescript/network/components/NetworkOverrideEditor.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts +27 -0
- package/lib/typescript/network/components/NetworkOverrideHeaderButton.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts +17 -0
- package/lib/typescript/network/components/NetworkOverridesButton.d.ts.map +1 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts +29 -0
- package/lib/typescript/network/components/NetworkOverridesScreen.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/Explorer.d.ts +17 -0
- package/lib/typescript/network/components/response-editor/Explorer.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts +9 -0
- package/lib/typescript/network/components/response-editor/deleteNestedDataByPath.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/editorContext.d.ts +29 -0
- package/lib/typescript/network/components/response-editor/editorContext.d.ts.map +1 -0
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts +10 -0
- package/lib/typescript/network/components/response-editor/updateNestedDataByPath.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useNetworkSelection.d.ts +26 -0
- package/lib/typescript/network/hooks/useNetworkSelection.d.ts.map +1 -0
- package/lib/typescript/network/hooks/useOverrideRules.d.ts +29 -0
- package/lib/typescript/network/hooks/useOverrideRules.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts +16 -0
- package/lib/typescript/network/overrides/__tests__/applyToFetch.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts +19 -0
- package/lib/typescript/network/overrides/__tests__/applyToXhr.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts +22 -0
- package/lib/typescript/network/overrides/__tests__/resolveOverride.test.d.ts.map +1 -0
- package/lib/typescript/network/overrides/applyToFetch.d.ts +50 -0
- package/lib/typescript/network/overrides/applyToFetch.d.ts.map +1 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts +43 -0
- package/lib/typescript/network/overrides/applyToXhr.d.ts.map +1 -0
- package/lib/typescript/network/overrides/engine.d.ts +47 -0
- package/lib/typescript/network/overrides/engine.d.ts.map +1 -0
- package/lib/typescript/network/overrides/matchRule.d.ts +22 -0
- package/lib/typescript/network/overrides/matchRule.d.ts.map +1 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts +205 -0
- package/lib/typescript/network/overrides/overrideRulesStore.d.ts.map +1 -0
- package/lib/typescript/network/overrides/presets.d.ts +38 -0
- package/lib/typescript/network/overrides/presets.d.ts.map +1 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts +46 -0
- package/lib/typescript/network/overrides/resolveOverride.d.ts.map +1 -0
- package/lib/typescript/network/overrides/types.d.ts +169 -0
- package/lib/typescript/network/overrides/types.d.ts.map +1 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts +73 -0
- package/lib/typescript/network/sync/networkSyncAdapter.d.ts.map +1 -1
- package/lib/typescript/network/types/index.d.ts +10 -0
- package/lib/typescript/network/types/index.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkEventStore.d.ts +14 -0
- package/lib/typescript/network/utils/networkEventStore.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkListener.d.ts +3 -0
- package/lib/typescript/network/utils/networkListener.d.ts.map +1 -1
- package/lib/typescript/network/utils/networkSelectionStore.d.ts +117 -0
- package/lib/typescript/network/utils/networkSelectionStore.d.ts.map +1 -0
- package/lib/typescript/preset.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.NetworkOverrideEditor = NetworkOverrideEditor;
|
|
7
|
+
var _react = require("react");
|
|
8
|
+
var _reactNative = require("react-native");
|
|
9
|
+
var _sharedUi = require("@buoy-gg/shared-ui");
|
|
10
|
+
var _Explorer = _interopRequireDefault(require("./response-editor/Explorer"));
|
|
11
|
+
var _editorContext = require("./response-editor/editorContext");
|
|
12
|
+
var _NetworkNumberPrompt = require("./NetworkNumberPrompt");
|
|
13
|
+
var _types = require("../overrides/types");
|
|
14
|
+
var _jsxRuntime = require("react/jsx-runtime");
|
|
15
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
|
+
/**
|
|
17
|
+
* The rule form — one decision, everything else out of the way.
|
|
18
|
+
*
|
|
19
|
+
* It used to ask for six things at equal weight (URL, method, kind, status,
|
|
20
|
+
* body, lifetime) with three paragraphs of hint text explaining them. That's a
|
|
21
|
+
* form, not a tool, and the hints were the tell: a control that needs a
|
|
22
|
+
* paragraph is the wrong control.
|
|
23
|
+
*
|
|
24
|
+
* Two things fixed it.
|
|
25
|
+
*
|
|
26
|
+
* FIRST, `kind` is gone from the UI. `respond | fail | delay` is our data
|
|
27
|
+
* model, not the developer's — nobody thinks "kind=respond, status=500", they
|
|
28
|
+
* think "make it a 500" or "make it go offline". Folding kind + status +
|
|
29
|
+
* failKind into a single OUTCOME list removes a section, a paragraph, and an
|
|
30
|
+
* entire concept, and every option now says what it does without being
|
|
31
|
+
* explained.
|
|
32
|
+
*
|
|
33
|
+
* SECOND, everything that arrives already correct is collapsed. A rule made
|
|
34
|
+
* from a real request knows its URL and method, so those become one summary
|
|
35
|
+
* line you can open if you need it. The body is prefilled and usually edited in
|
|
36
|
+
* the response tree instead, so it collapses too. What's left on arrival is the
|
|
37
|
+
* question actually being asked.
|
|
38
|
+
*/const METHODS = ["GET", "POST", "PUT", "PATCH", "DELETE"];
|
|
39
|
+
const DELAY_PRESETS = [0, 500, 1000, 3000, 10000];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* The single decision, ordered by how often a developer reaches for it.
|
|
43
|
+
*
|
|
44
|
+
* Each carries a plain-language name AND its status code: scanning for "the
|
|
45
|
+
* auth one" shouldn't require knowing that 401 is unauthorized, and someone who
|
|
46
|
+
* does know should be able to find 401 without reading labels.
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
const OUTCOMES = [{
|
|
50
|
+
id: "500",
|
|
51
|
+
label: "Server error",
|
|
52
|
+
code: "500",
|
|
53
|
+
danger: true,
|
|
54
|
+
patch: {
|
|
55
|
+
kind: "respond",
|
|
56
|
+
status: 500,
|
|
57
|
+
statusText: "Internal Server Error"
|
|
58
|
+
}
|
|
59
|
+
}, {
|
|
60
|
+
id: "401",
|
|
61
|
+
label: "Unauthorized",
|
|
62
|
+
code: "401",
|
|
63
|
+
danger: true,
|
|
64
|
+
patch: {
|
|
65
|
+
kind: "respond",
|
|
66
|
+
status: 401,
|
|
67
|
+
statusText: "Unauthorized"
|
|
68
|
+
}
|
|
69
|
+
}, {
|
|
70
|
+
id: "404",
|
|
71
|
+
label: "Not found",
|
|
72
|
+
code: "404",
|
|
73
|
+
danger: true,
|
|
74
|
+
patch: {
|
|
75
|
+
kind: "respond",
|
|
76
|
+
status: 404,
|
|
77
|
+
statusText: "Not Found"
|
|
78
|
+
}
|
|
79
|
+
}, {
|
|
80
|
+
id: "403",
|
|
81
|
+
label: "Forbidden",
|
|
82
|
+
code: "403",
|
|
83
|
+
danger: true,
|
|
84
|
+
patch: {
|
|
85
|
+
kind: "respond",
|
|
86
|
+
status: 403,
|
|
87
|
+
statusText: "Forbidden"
|
|
88
|
+
}
|
|
89
|
+
}, {
|
|
90
|
+
id: "429",
|
|
91
|
+
label: "Rate limited",
|
|
92
|
+
code: "429",
|
|
93
|
+
danger: true,
|
|
94
|
+
patch: {
|
|
95
|
+
kind: "respond",
|
|
96
|
+
status: 429,
|
|
97
|
+
statusText: "Too Many Requests"
|
|
98
|
+
}
|
|
99
|
+
}, {
|
|
100
|
+
id: "503",
|
|
101
|
+
label: "Unavailable",
|
|
102
|
+
code: "503",
|
|
103
|
+
danger: true,
|
|
104
|
+
patch: {
|
|
105
|
+
kind: "respond",
|
|
106
|
+
status: 503,
|
|
107
|
+
statusText: "Service Unavailable"
|
|
108
|
+
}
|
|
109
|
+
}, {
|
|
110
|
+
id: "400",
|
|
111
|
+
label: "Bad request",
|
|
112
|
+
code: "400",
|
|
113
|
+
danger: true,
|
|
114
|
+
patch: {
|
|
115
|
+
kind: "respond",
|
|
116
|
+
status: 400,
|
|
117
|
+
statusText: "Bad Request"
|
|
118
|
+
}
|
|
119
|
+
}, {
|
|
120
|
+
id: "200",
|
|
121
|
+
label: "Success",
|
|
122
|
+
code: "200",
|
|
123
|
+
patch: {
|
|
124
|
+
kind: "respond",
|
|
125
|
+
status: 200,
|
|
126
|
+
statusText: "OK"
|
|
127
|
+
}
|
|
128
|
+
}, {
|
|
129
|
+
id: "offline",
|
|
130
|
+
label: "Offline",
|
|
131
|
+
danger: true,
|
|
132
|
+
patch: {
|
|
133
|
+
kind: "fail",
|
|
134
|
+
failKind: "network"
|
|
135
|
+
}
|
|
136
|
+
}, {
|
|
137
|
+
id: "timeout",
|
|
138
|
+
label: "Timeout",
|
|
139
|
+
danger: true,
|
|
140
|
+
patch: {
|
|
141
|
+
kind: "fail",
|
|
142
|
+
failKind: "timeout"
|
|
143
|
+
}
|
|
144
|
+
}, {
|
|
145
|
+
id: "passthrough",
|
|
146
|
+
label: "Real response",
|
|
147
|
+
patch: {
|
|
148
|
+
kind: "delay"
|
|
149
|
+
}
|
|
150
|
+
}];
|
|
151
|
+
function outcomeIdFor(draft) {
|
|
152
|
+
if (draft.kind === "delay") return "passthrough";
|
|
153
|
+
if (draft.kind === "fail") {
|
|
154
|
+
return draft.failKind === "timeout" ? "timeout" : "offline";
|
|
155
|
+
}
|
|
156
|
+
return String(draft.status ?? 200);
|
|
157
|
+
}
|
|
158
|
+
function OutcomeChip({
|
|
159
|
+
outcome,
|
|
160
|
+
active,
|
|
161
|
+
onPress
|
|
162
|
+
}) {
|
|
163
|
+
const accent = outcome.danger ? _sharedUi.macOSColors.semantic.error : _sharedUi.macOSColors.semantic.info;
|
|
164
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
165
|
+
onPress: onPress,
|
|
166
|
+
"sentry-label": "ignore override outcome",
|
|
167
|
+
accessibilityLabel: `${outcome.label}${outcome.code ? ` ${outcome.code}` : ""}`,
|
|
168
|
+
style: [styles.outcome, active && {
|
|
169
|
+
borderColor: accent,
|
|
170
|
+
backgroundColor: `${accent}1F`
|
|
171
|
+
}],
|
|
172
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
173
|
+
style: [styles.outcomeLabel, active && {
|
|
174
|
+
color: accent
|
|
175
|
+
}],
|
|
176
|
+
children: outcome.label
|
|
177
|
+
}), outcome.code ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
178
|
+
style: [styles.outcomeCode, active && {
|
|
179
|
+
color: accent
|
|
180
|
+
}],
|
|
181
|
+
children: outcome.code
|
|
182
|
+
}) : null]
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/** A collapsed row that opens to reveal its controls. */
|
|
187
|
+
function Disclosure({
|
|
188
|
+
title,
|
|
189
|
+
summary,
|
|
190
|
+
open,
|
|
191
|
+
onToggle,
|
|
192
|
+
children
|
|
193
|
+
}) {
|
|
194
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
195
|
+
style: styles.disclosure,
|
|
196
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.TouchableOpacity, {
|
|
197
|
+
onPress: onToggle,
|
|
198
|
+
"sentry-label": "ignore override disclosure",
|
|
199
|
+
style: styles.disclosureHeader,
|
|
200
|
+
children: [open ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronDown, {
|
|
201
|
+
size: 12,
|
|
202
|
+
color: _sharedUi.macOSColors.text.muted
|
|
203
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_sharedUi.ChevronRight, {
|
|
204
|
+
size: 12,
|
|
205
|
+
color: _sharedUi.macOSColors.text.muted
|
|
206
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
207
|
+
style: styles.disclosureTitle,
|
|
208
|
+
children: title
|
|
209
|
+
}), summary && !open ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
210
|
+
style: styles.disclosureSummary,
|
|
211
|
+
numberOfLines: 1,
|
|
212
|
+
children: summary
|
|
213
|
+
}) : null]
|
|
214
|
+
}), open ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.View, {
|
|
215
|
+
style: styles.disclosureBody,
|
|
216
|
+
children: children
|
|
217
|
+
}) : null]
|
|
218
|
+
});
|
|
219
|
+
}
|
|
220
|
+
function Chip({
|
|
221
|
+
label,
|
|
222
|
+
active,
|
|
223
|
+
onPress
|
|
224
|
+
}) {
|
|
225
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
226
|
+
onPress: onPress,
|
|
227
|
+
"sentry-label": "ignore override chip",
|
|
228
|
+
style: [styles.chip, active && styles.chipActive],
|
|
229
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
230
|
+
style: [styles.chipText, active && styles.chipTextActive],
|
|
231
|
+
children: label
|
|
232
|
+
})
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
function NetworkOverrideEditor({
|
|
236
|
+
draft,
|
|
237
|
+
onChange,
|
|
238
|
+
onSave,
|
|
239
|
+
onCancel,
|
|
240
|
+
saveLabel = "Save",
|
|
241
|
+
applySafeAreaInset = false
|
|
242
|
+
}) {
|
|
243
|
+
// `minBottom` is a floor, not a preference: the dimension map can't know
|
|
244
|
+
// about a device that ships next year, and an unmapped one falls through to
|
|
245
|
+
// `bottom: 0`. This guarantees the buttons clear the indicator either way.
|
|
246
|
+
const insets = (0, _sharedUi.useSafeAreaInsets)({
|
|
247
|
+
minBottom: 16
|
|
248
|
+
});
|
|
249
|
+
const bottomInset = applySafeAreaInset ? insets.bottom : 0;
|
|
250
|
+
const patch = next => onChange({
|
|
251
|
+
...draft,
|
|
252
|
+
...next
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// A rule made from a request arrives with its scope already right, so it
|
|
256
|
+
// starts closed. A blank one has nothing to match on yet, so it starts open.
|
|
257
|
+
const [scopeOpen, setScopeOpen] = (0, _react.useState)(!draft.urlPattern.trim());
|
|
258
|
+
const [bodyOpen, setBodyOpen] = (0, _react.useState)(false);
|
|
259
|
+
/**
|
|
260
|
+
* The "Edit all" buffer — deliberately NOT seeded with the current body.
|
|
261
|
+
*
|
|
262
|
+
* Prefilling it would be the obvious thing and it's wrong twice over: a real
|
|
263
|
+
* response is routinely hundreds of KB, which a multiline TextInput handles
|
|
264
|
+
* badly, and you only reach for this when you intend to REPLACE the whole
|
|
265
|
+
* thing anyway. Starting empty means paste-and-go instead of select-all-
|
|
266
|
+
* delete-paste on a field that's fighting you.
|
|
267
|
+
*/
|
|
268
|
+
const [pasteText, setPasteText] = (0, _react.useState)(null);
|
|
269
|
+
/** Which custom number the top-of-screen prompt is asking for, if any. */
|
|
270
|
+
const [prompt, setPrompt] = (0, _react.useState)(null);
|
|
271
|
+
const activeOutcome = outcomeIdFor(draft);
|
|
272
|
+
/** True when the status is a real one that no listed outcome covers. */
|
|
273
|
+
const customStatusActive = draft.kind === "respond" && typeof draft.status === "number" && !OUTCOMES.some(outcome => outcome.code === String(draft.status));
|
|
274
|
+
const showsBody = draft.kind === "respond";
|
|
275
|
+
const method = draft.methods?.[0];
|
|
276
|
+
const scopeSummary = `${method ?? "Any"} ${draft.urlPattern || "No URL yet"}`;
|
|
277
|
+
const bodySummary = (0, _react.useMemo)(() => {
|
|
278
|
+
const body = (draft.body ?? "").trim();
|
|
279
|
+
if (!body) return "Empty";
|
|
280
|
+
const lines = body.split("\n").length;
|
|
281
|
+
return `${lines} line${lines === 1 ? "" : "s"}`;
|
|
282
|
+
}, [draft.body]);
|
|
283
|
+
|
|
284
|
+
/**
|
|
285
|
+
* The body as a tree, or null when it can't be one (empty, or not JSON).
|
|
286
|
+
*
|
|
287
|
+
* Memoized on the raw string because an override body can be large and this
|
|
288
|
+
* would otherwise re-parse on every keystroke elsewhere in the form.
|
|
289
|
+
*/
|
|
290
|
+
const parsedBody = (0, _react.useMemo)(() => {
|
|
291
|
+
const body = (draft.body ?? "").trim();
|
|
292
|
+
if (!body) return null;
|
|
293
|
+
try {
|
|
294
|
+
return JSON.parse(body);
|
|
295
|
+
} catch {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
}, [draft.body]);
|
|
299
|
+
const bodyIsNonJsonText = (draft.body ?? "").trim().length > 0 && !parsedBody;
|
|
300
|
+
const delayMs = draft.delayMs ?? 0;
|
|
301
|
+
/** Custom fields own the value only when no preset chip already claims it. */
|
|
302
|
+
const customDelayActive = delayMs > 0 && !DELAY_PRESETS.includes(delayMs);
|
|
303
|
+
const customTimesActive = !draft.alternate && typeof draft.times === "number" && draft.times !== 1;
|
|
304
|
+
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
305
|
+
style: styles.root,
|
|
306
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.ScrollView, {
|
|
307
|
+
style: styles.scroll,
|
|
308
|
+
contentContainerStyle: styles.scrollContent,
|
|
309
|
+
keyboardShouldPersistTaps: "handled",
|
|
310
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(Disclosure, {
|
|
311
|
+
title: "Applies to",
|
|
312
|
+
summary: scopeSummary,
|
|
313
|
+
open: scopeOpen,
|
|
314
|
+
onToggle: () => setScopeOpen(v => !v),
|
|
315
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
|
|
316
|
+
style: styles.input,
|
|
317
|
+
value: draft.urlPattern,
|
|
318
|
+
onChangeText: urlPattern => patch({
|
|
319
|
+
urlPattern
|
|
320
|
+
}),
|
|
321
|
+
placeholder: "https://api.example.com/v1/users*",
|
|
322
|
+
placeholderTextColor: _sharedUi.macOSColors.text.muted,
|
|
323
|
+
autoCapitalize: "none",
|
|
324
|
+
autoCorrect: false,
|
|
325
|
+
multiline: true,
|
|
326
|
+
"sentry-label": "ignore override url pattern"
|
|
327
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
328
|
+
style: styles.chipRow,
|
|
329
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, {
|
|
330
|
+
label: "Any",
|
|
331
|
+
active: !method,
|
|
332
|
+
onPress: () => patch({
|
|
333
|
+
methods: undefined
|
|
334
|
+
})
|
|
335
|
+
}), METHODS.map(m => /*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, {
|
|
336
|
+
label: m,
|
|
337
|
+
active: method === m,
|
|
338
|
+
onPress: () => patch({
|
|
339
|
+
methods: [m]
|
|
340
|
+
})
|
|
341
|
+
}, m))]
|
|
342
|
+
})]
|
|
343
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
344
|
+
style: styles.outcomeGrid,
|
|
345
|
+
children: [OUTCOMES.map(outcome => /*#__PURE__*/(0, _jsxRuntime.jsx)(OutcomeChip, {
|
|
346
|
+
outcome: outcome,
|
|
347
|
+
active: activeOutcome === outcome.id,
|
|
348
|
+
onPress: () => patch(outcome.patch)
|
|
349
|
+
}, outcome.id)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
350
|
+
onPress: () => setPrompt("status"),
|
|
351
|
+
"sentry-label": "ignore custom status",
|
|
352
|
+
accessibilityLabel: "Custom status code",
|
|
353
|
+
style: [styles.customField, customStatusActive && styles.customFieldActive],
|
|
354
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
355
|
+
style: [styles.customValue, customStatusActive && styles.customInputActive],
|
|
356
|
+
children: customStatusActive ? String(draft.status) : "Custom"
|
|
357
|
+
})
|
|
358
|
+
})]
|
|
359
|
+
}), showsBody ? /*#__PURE__*/(0, _jsxRuntime.jsx)(Disclosure, {
|
|
360
|
+
title: "Response body",
|
|
361
|
+
summary: bodySummary,
|
|
362
|
+
open: bodyOpen,
|
|
363
|
+
onToggle: () => setBodyOpen(v => !v),
|
|
364
|
+
children: pasteText !== null ?
|
|
365
|
+
/*#__PURE__*/
|
|
366
|
+
/* Replace-the-whole-thing mode. Starts empty — see `pasteText`. */
|
|
367
|
+
(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
368
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TextInput, {
|
|
369
|
+
style: [styles.input, styles.bodyInput],
|
|
370
|
+
value: pasteText,
|
|
371
|
+
onChangeText: setPasteText,
|
|
372
|
+
placeholder: "Paste a new body\u2026",
|
|
373
|
+
placeholderTextColor: _sharedUi.macOSColors.text.muted,
|
|
374
|
+
autoCapitalize: "none",
|
|
375
|
+
autoCorrect: false,
|
|
376
|
+
autoFocus: true,
|
|
377
|
+
multiline: true,
|
|
378
|
+
"sentry-label": "ignore override body paste"
|
|
379
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
380
|
+
style: styles.inlineActions,
|
|
381
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
382
|
+
onPress: () => setPasteText(null),
|
|
383
|
+
"sentry-label": "ignore cancel body paste",
|
|
384
|
+
style: styles.textButton,
|
|
385
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
386
|
+
style: styles.textButtonMuted,
|
|
387
|
+
children: "Cancel"
|
|
388
|
+
})
|
|
389
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
390
|
+
onPress: () => {
|
|
391
|
+
const next = pasteText.trim();
|
|
392
|
+
// Pretty-print JSON on the way in so the tree it becomes
|
|
393
|
+
// is readable; anything else is kept exactly as pasted.
|
|
394
|
+
try {
|
|
395
|
+
patch({
|
|
396
|
+
body: JSON.stringify(JSON.parse(next), null, 2)
|
|
397
|
+
});
|
|
398
|
+
} catch {
|
|
399
|
+
patch({
|
|
400
|
+
body: next
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
setPasteText(null);
|
|
404
|
+
},
|
|
405
|
+
disabled: !pasteText.trim(),
|
|
406
|
+
"sentry-label": "ignore apply body paste",
|
|
407
|
+
style: styles.textButton,
|
|
408
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
409
|
+
style: [styles.textButtonLabel, !pasteText.trim() && styles.textButtonDisabled],
|
|
410
|
+
children: "Replace"
|
|
411
|
+
})
|
|
412
|
+
})]
|
|
413
|
+
})]
|
|
414
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
415
|
+
children: [parsedBody !== null ?
|
|
416
|
+
/*#__PURE__*/
|
|
417
|
+
/* The SAME tree as the request detail — tap a value to edit
|
|
418
|
+
it. Editing writes the whole document back as the rule's
|
|
419
|
+
body, so the two surfaces behave identically. */
|
|
420
|
+
(0, _jsxRuntime.jsx)(_editorContext.ResponseEditorContext.Provider, {
|
|
421
|
+
value: {
|
|
422
|
+
root: parsedBody,
|
|
423
|
+
onChange: next => patch({
|
|
424
|
+
body: JSON.stringify(next, null, 2)
|
|
425
|
+
})
|
|
426
|
+
},
|
|
427
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Explorer.default, {
|
|
428
|
+
editable: true,
|
|
429
|
+
label: "",
|
|
430
|
+
value: parsedBody,
|
|
431
|
+
defaultExpanded: [""]
|
|
432
|
+
})
|
|
433
|
+
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
434
|
+
style: styles.emptyBody,
|
|
435
|
+
children: bodyIsNonJsonText ? "This body isn't JSON, so there's no tree to show." : "No body yet."
|
|
436
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
437
|
+
onPress: () => setPasteText(""),
|
|
438
|
+
"sentry-label": "ignore edit all body",
|
|
439
|
+
style: styles.textButton,
|
|
440
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
441
|
+
style: styles.textButtonLabel,
|
|
442
|
+
children: "Edit all"
|
|
443
|
+
})
|
|
444
|
+
})]
|
|
445
|
+
})
|
|
446
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
447
|
+
style: styles.field,
|
|
448
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
449
|
+
style: styles.subLabel,
|
|
450
|
+
children: "Delay"
|
|
451
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
452
|
+
style: styles.chipRow,
|
|
453
|
+
children: [DELAY_PRESETS.map(ms => /*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, {
|
|
454
|
+
label: ms === 0 ? "None" : `${ms / 1000}s`,
|
|
455
|
+
active: delayMs === ms,
|
|
456
|
+
onPress: () => patch({
|
|
457
|
+
delayMs: ms
|
|
458
|
+
})
|
|
459
|
+
}, ms)), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
460
|
+
onPress: () => setPrompt("delay"),
|
|
461
|
+
"sentry-label": "ignore custom delay",
|
|
462
|
+
accessibilityLabel: "Custom delay in seconds",
|
|
463
|
+
style: [styles.customField, customDelayActive && styles.customFieldActive],
|
|
464
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
465
|
+
style: [styles.customValue, customDelayActive && styles.customInputActive],
|
|
466
|
+
children: customDelayActive ? `${delayMs / 1000}s` : "Custom"
|
|
467
|
+
})
|
|
468
|
+
})]
|
|
469
|
+
})]
|
|
470
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
471
|
+
style: styles.field,
|
|
472
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
473
|
+
style: styles.subLabel,
|
|
474
|
+
children: "Fires"
|
|
475
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
476
|
+
style: styles.subHint,
|
|
477
|
+
children: "A limited rule switches itself off once it's used up. Every other alternates forever \u2014 the first request through, the next overridden."
|
|
478
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
479
|
+
style: styles.chipRow,
|
|
480
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, {
|
|
481
|
+
label: "Always",
|
|
482
|
+
active: !draft.alternate && draft.times == null,
|
|
483
|
+
onPress: () => patch({
|
|
484
|
+
alternate: false,
|
|
485
|
+
times: null
|
|
486
|
+
})
|
|
487
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, {
|
|
488
|
+
label: "Once",
|
|
489
|
+
active: !draft.alternate && draft.times === 1,
|
|
490
|
+
onPress: () => patch({
|
|
491
|
+
alternate: false,
|
|
492
|
+
times: 1
|
|
493
|
+
})
|
|
494
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(Chip, {
|
|
495
|
+
label: "Every other",
|
|
496
|
+
active: draft.alternate === true,
|
|
497
|
+
onPress: () => patch({
|
|
498
|
+
alternate: true,
|
|
499
|
+
times: null
|
|
500
|
+
})
|
|
501
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
502
|
+
onPress: () => {
|
|
503
|
+
patch({
|
|
504
|
+
alternate: false
|
|
505
|
+
});
|
|
506
|
+
setPrompt("times");
|
|
507
|
+
},
|
|
508
|
+
"sentry-label": "ignore custom times",
|
|
509
|
+
accessibilityLabel: "Custom number of times",
|
|
510
|
+
style: [styles.customField, customTimesActive && styles.customFieldActive],
|
|
511
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
512
|
+
style: [styles.customValue, customTimesActive && styles.customInputActive],
|
|
513
|
+
children: customTimesActive ? `${draft.times}×` : "Custom"
|
|
514
|
+
})
|
|
515
|
+
})]
|
|
516
|
+
})]
|
|
517
|
+
})]
|
|
518
|
+
}), prompt === "status" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkNumberPrompt.NetworkNumberPrompt, {
|
|
519
|
+
title: "Custom status code",
|
|
520
|
+
hint: `${_types.STATUS_MIN}–${_types.STATUS_MAX}`,
|
|
521
|
+
value: customStatusActive ? draft.status : undefined,
|
|
522
|
+
min: _types.STATUS_MIN,
|
|
523
|
+
max: _types.STATUS_MAX,
|
|
524
|
+
onSubmit: next => {
|
|
525
|
+
patch({
|
|
526
|
+
kind: "respond",
|
|
527
|
+
status: next ?? undefined,
|
|
528
|
+
statusText: undefined
|
|
529
|
+
});
|
|
530
|
+
setPrompt(null);
|
|
531
|
+
},
|
|
532
|
+
onCancel: () => setPrompt(null)
|
|
533
|
+
}) : null, prompt === "delay" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkNumberPrompt.NetworkNumberPrompt, {
|
|
534
|
+
title: "Custom delay",
|
|
535
|
+
hint: "Seconds",
|
|
536
|
+
value: customDelayActive ? delayMs / 1000 : undefined,
|
|
537
|
+
min: 0,
|
|
538
|
+
onSubmit: next => {
|
|
539
|
+
patch({
|
|
540
|
+
delayMs: next != null ? Math.round(next * 1000) : 0
|
|
541
|
+
});
|
|
542
|
+
setPrompt(null);
|
|
543
|
+
},
|
|
544
|
+
onCancel: () => setPrompt(null)
|
|
545
|
+
}) : null, prompt === "times" ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_NetworkNumberPrompt.NetworkNumberPrompt, {
|
|
546
|
+
title: "Fires how many times",
|
|
547
|
+
hint: "Leave empty for always",
|
|
548
|
+
value: customTimesActive ? draft.times : undefined,
|
|
549
|
+
min: 1,
|
|
550
|
+
onSubmit: next => {
|
|
551
|
+
// Empty or zero means "no limit" rather than a rule that is spent
|
|
552
|
+
// before it ever fires.
|
|
553
|
+
patch({
|
|
554
|
+
alternate: false,
|
|
555
|
+
times: next && next > 0 ? next : null
|
|
556
|
+
});
|
|
557
|
+
setPrompt(null);
|
|
558
|
+
},
|
|
559
|
+
onCancel: () => setPrompt(null)
|
|
560
|
+
}) : null, /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactNative.View, {
|
|
561
|
+
style: [styles.footer, {
|
|
562
|
+
paddingBottom: 12 + bottomInset
|
|
563
|
+
}],
|
|
564
|
+
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
565
|
+
onPress: onCancel,
|
|
566
|
+
"sentry-label": "ignore cancel override",
|
|
567
|
+
style: [styles.footerButton, styles.cancelButton],
|
|
568
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
569
|
+
style: styles.cancelText,
|
|
570
|
+
children: "Cancel"
|
|
571
|
+
})
|
|
572
|
+
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.TouchableOpacity, {
|
|
573
|
+
onPress: onSave,
|
|
574
|
+
disabled: !draft.urlPattern.trim(),
|
|
575
|
+
"sentry-label": "ignore save override",
|
|
576
|
+
style: [styles.footerButton, styles.saveButton, !draft.urlPattern.trim() && styles.saveButtonDisabled],
|
|
577
|
+
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactNative.Text, {
|
|
578
|
+
style: styles.saveText,
|
|
579
|
+
children: saveLabel
|
|
580
|
+
})
|
|
581
|
+
})]
|
|
582
|
+
})]
|
|
583
|
+
});
|
|
584
|
+
}
|
|
585
|
+
const styles = _reactNative.StyleSheet.create({
|
|
586
|
+
root: {
|
|
587
|
+
flex: 1
|
|
588
|
+
},
|
|
589
|
+
scroll: {
|
|
590
|
+
flex: 1
|
|
591
|
+
},
|
|
592
|
+
scrollContent: {
|
|
593
|
+
padding: 12,
|
|
594
|
+
paddingBottom: 24,
|
|
595
|
+
gap: 4
|
|
596
|
+
},
|
|
597
|
+
field: {
|
|
598
|
+
gap: 8,
|
|
599
|
+
paddingVertical: 6
|
|
600
|
+
},
|
|
601
|
+
outcomeGrid: {
|
|
602
|
+
flexDirection: "row",
|
|
603
|
+
flexWrap: "wrap",
|
|
604
|
+
gap: 6,
|
|
605
|
+
paddingVertical: 10
|
|
606
|
+
},
|
|
607
|
+
outcome: {
|
|
608
|
+
flexDirection: "row",
|
|
609
|
+
alignItems: "center",
|
|
610
|
+
gap: 6,
|
|
611
|
+
paddingHorizontal: 10,
|
|
612
|
+
paddingVertical: 9,
|
|
613
|
+
borderRadius: 6,
|
|
614
|
+
borderWidth: 1,
|
|
615
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
616
|
+
backgroundColor: _sharedUi.macOSColors.background.card
|
|
617
|
+
},
|
|
618
|
+
outcomeLabel: {
|
|
619
|
+
fontSize: 12,
|
|
620
|
+
fontWeight: "600",
|
|
621
|
+
color: _sharedUi.macOSColors.text.primary
|
|
622
|
+
},
|
|
623
|
+
outcomeCode: {
|
|
624
|
+
fontSize: 10,
|
|
625
|
+
fontWeight: "700",
|
|
626
|
+
color: _sharedUi.macOSColors.text.muted
|
|
627
|
+
},
|
|
628
|
+
disclosure: {
|
|
629
|
+
borderRadius: 6,
|
|
630
|
+
borderWidth: 1,
|
|
631
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
632
|
+
backgroundColor: _sharedUi.macOSColors.background.card,
|
|
633
|
+
overflow: "hidden"
|
|
634
|
+
},
|
|
635
|
+
disclosureHeader: {
|
|
636
|
+
flexDirection: "row",
|
|
637
|
+
alignItems: "center",
|
|
638
|
+
gap: 6,
|
|
639
|
+
paddingHorizontal: 10,
|
|
640
|
+
paddingVertical: 10
|
|
641
|
+
},
|
|
642
|
+
disclosureTitle: {
|
|
643
|
+
fontSize: 12,
|
|
644
|
+
fontWeight: "600",
|
|
645
|
+
color: _sharedUi.macOSColors.text.primary
|
|
646
|
+
},
|
|
647
|
+
disclosureSummary: {
|
|
648
|
+
flex: 1,
|
|
649
|
+
textAlign: "right",
|
|
650
|
+
fontSize: 11,
|
|
651
|
+
color: _sharedUi.macOSColors.text.muted
|
|
652
|
+
},
|
|
653
|
+
disclosureBody: {
|
|
654
|
+
paddingHorizontal: 10,
|
|
655
|
+
paddingBottom: 10,
|
|
656
|
+
gap: 8
|
|
657
|
+
},
|
|
658
|
+
input: {
|
|
659
|
+
backgroundColor: _sharedUi.macOSColors.background.input,
|
|
660
|
+
borderWidth: 1,
|
|
661
|
+
borderColor: _sharedUi.macOSColors.border.input,
|
|
662
|
+
borderRadius: 6,
|
|
663
|
+
paddingHorizontal: 10,
|
|
664
|
+
paddingVertical: 8,
|
|
665
|
+
color: _sharedUi.macOSColors.text.primary,
|
|
666
|
+
fontSize: 12,
|
|
667
|
+
fontFamily: "monospace",
|
|
668
|
+
minHeight: 40
|
|
669
|
+
},
|
|
670
|
+
bodyInput: {
|
|
671
|
+
minHeight: 140,
|
|
672
|
+
textAlignVertical: "top"
|
|
673
|
+
},
|
|
674
|
+
chipRow: {
|
|
675
|
+
flexDirection: "row",
|
|
676
|
+
flexWrap: "wrap",
|
|
677
|
+
gap: 6
|
|
678
|
+
},
|
|
679
|
+
chip: {
|
|
680
|
+
paddingHorizontal: 10,
|
|
681
|
+
paddingVertical: 6,
|
|
682
|
+
borderRadius: 5,
|
|
683
|
+
borderWidth: 1,
|
|
684
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
685
|
+
backgroundColor: _sharedUi.macOSColors.background.base
|
|
686
|
+
},
|
|
687
|
+
chipActive: {
|
|
688
|
+
borderColor: _sharedUi.macOSColors.semantic.info,
|
|
689
|
+
backgroundColor: `${_sharedUi.macOSColors.semantic.info}1F`
|
|
690
|
+
},
|
|
691
|
+
chipText: {
|
|
692
|
+
fontSize: 11,
|
|
693
|
+
fontWeight: "600",
|
|
694
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
695
|
+
},
|
|
696
|
+
chipTextActive: {
|
|
697
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
698
|
+
},
|
|
699
|
+
customField: {
|
|
700
|
+
flexDirection: "row",
|
|
701
|
+
alignItems: "center",
|
|
702
|
+
paddingHorizontal: 8,
|
|
703
|
+
borderRadius: 5,
|
|
704
|
+
borderWidth: 1,
|
|
705
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
706
|
+
backgroundColor: _sharedUi.macOSColors.background.base
|
|
707
|
+
},
|
|
708
|
+
customFieldActive: {
|
|
709
|
+
borderColor: _sharedUi.macOSColors.semantic.info,
|
|
710
|
+
backgroundColor: `${_sharedUi.macOSColors.semantic.info}1F`
|
|
711
|
+
},
|
|
712
|
+
customValue: {
|
|
713
|
+
paddingVertical: 6,
|
|
714
|
+
fontSize: 11,
|
|
715
|
+
fontWeight: "600",
|
|
716
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
717
|
+
},
|
|
718
|
+
customInputActive: {
|
|
719
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
720
|
+
},
|
|
721
|
+
subHint: {
|
|
722
|
+
fontSize: 10,
|
|
723
|
+
lineHeight: 14,
|
|
724
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
725
|
+
marginTop: -2
|
|
726
|
+
},
|
|
727
|
+
subLabel: {
|
|
728
|
+
fontSize: 10,
|
|
729
|
+
fontWeight: "700",
|
|
730
|
+
letterSpacing: 0.6,
|
|
731
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
732
|
+
textTransform: "uppercase"
|
|
733
|
+
},
|
|
734
|
+
textButton: {
|
|
735
|
+
alignSelf: "flex-start",
|
|
736
|
+
paddingVertical: 4
|
|
737
|
+
},
|
|
738
|
+
textButtonLabel: {
|
|
739
|
+
fontSize: 11,
|
|
740
|
+
fontWeight: "600",
|
|
741
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
742
|
+
},
|
|
743
|
+
textButtonMuted: {
|
|
744
|
+
fontSize: 11,
|
|
745
|
+
fontWeight: "600",
|
|
746
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
747
|
+
},
|
|
748
|
+
textButtonDisabled: {
|
|
749
|
+
opacity: 0.4
|
|
750
|
+
},
|
|
751
|
+
inlineActions: {
|
|
752
|
+
flexDirection: "row",
|
|
753
|
+
alignItems: "center",
|
|
754
|
+
justifyContent: "space-between"
|
|
755
|
+
},
|
|
756
|
+
emptyBody: {
|
|
757
|
+
fontSize: 11,
|
|
758
|
+
color: _sharedUi.macOSColors.text.muted,
|
|
759
|
+
paddingVertical: 6
|
|
760
|
+
},
|
|
761
|
+
footer: {
|
|
762
|
+
flexDirection: "row",
|
|
763
|
+
gap: 8,
|
|
764
|
+
padding: 12,
|
|
765
|
+
borderTopWidth: 1,
|
|
766
|
+
borderTopColor: _sharedUi.macOSColors.border.default,
|
|
767
|
+
backgroundColor: _sharedUi.macOSColors.background.base
|
|
768
|
+
},
|
|
769
|
+
footerButton: {
|
|
770
|
+
flex: 1,
|
|
771
|
+
paddingVertical: 11,
|
|
772
|
+
borderRadius: 6,
|
|
773
|
+
alignItems: "center",
|
|
774
|
+
borderWidth: 1
|
|
775
|
+
},
|
|
776
|
+
cancelButton: {
|
|
777
|
+
borderColor: _sharedUi.macOSColors.border.default,
|
|
778
|
+
backgroundColor: _sharedUi.macOSColors.background.card
|
|
779
|
+
},
|
|
780
|
+
cancelText: {
|
|
781
|
+
fontSize: 12,
|
|
782
|
+
fontWeight: "600",
|
|
783
|
+
color: _sharedUi.macOSColors.text.secondary
|
|
784
|
+
},
|
|
785
|
+
saveButton: {
|
|
786
|
+
borderColor: _sharedUi.macOSColors.semantic.info,
|
|
787
|
+
backgroundColor: `${_sharedUi.macOSColors.semantic.info}22`
|
|
788
|
+
},
|
|
789
|
+
saveButtonDisabled: {
|
|
790
|
+
opacity: 0.4
|
|
791
|
+
},
|
|
792
|
+
saveText: {
|
|
793
|
+
fontSize: 12,
|
|
794
|
+
fontWeight: "700",
|
|
795
|
+
color: _sharedUi.macOSColors.semantic.info
|
|
796
|
+
}
|
|
797
|
+
});
|