Skip to content

Commit bdfc0c0

Browse files
improve debug log -> rule association, persist search input
1 parent 60e796f commit bdfc0c0

File tree

12 files changed

+52
-56
lines changed

12 files changed

+52
-56
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,10 @@ Some notes
6464

6565
## Changelog
6666

67+
*1.1.2* (2025-03-25)
68+
- Persist feature and experiment search filter
69+
- Bug fix: Improve association of debug logs to feature rules
70+
6771
*1.1.1* (2025-03-17)
6872
- Choose between live, draft, and inactive revisions of features using the GrowthBook API
6973
- Quickly apply feature overrides from feature rules

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gb-devtools",
3-
"version": "1.1.1",
3+
"version": "1.1.2",
44
"private": true,
55
"scripts": {
66
"dev": "webpack --config webpack/webpack.dev.js --watch",

public/manifest.chrome.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
"name": "GrowthBook DevTools",
55
"description": "GrowthBook DevTools helps you debug feature flags and experiments and design A/B tests visually — all from your browser.",
6-
"version": "1.1.1",
6+
"version": "1.1.2",
77

88
"content_scripts": [
99
{

public/manifest.firefox.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
"name": "GrowthBook DevTools",
55
"description": "GrowthBook DevTools helps you debug feature flags and experiments and design A/B tests visually — all from your browser.",
6-
"version": "1.1.1",
6+
"version": "1.1.2",
77

88
"browser_specific_settings": {
99
"gecko": {

src/app/components/DebugLogger.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ export default function DebugLogger({
1010
logs,
1111
startCollapsed = true,
1212
showContext = true,
13+
showCount = false,
1314
}: {
1415
logs?: DebugLog[];
1516
startCollapsed?: boolean;
1617
showContext?: boolean;
18+
showCount?: boolean;
1719
}) {
1820
const [collapsed, setCollapsed] = useState(startCollapsed);
1921

@@ -34,6 +36,9 @@ export default function DebugLogger({
3436
size={12}
3537
/>
3638
Debug log
39+
{showCount ? (<>
40+
{" "}({logs?.length || 0})
41+
</>) : null}
3742
</Link>
3843
</div>
3944
{!collapsed && (

src/app/components/ExperimentsTab.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,13 +107,19 @@ export default function ExperimentsTab() {
107107
const [hideInactiveExperiments, setHideInactiveExperiments] =
108108
useTabState<boolean>("hideInactiveExperiments", false);
109109

110+
const [searchValue, setSearchValue] = useTabState<string>(
111+
"experimentsSearchValue",
112+
""
113+
);
114+
110115
const {
111116
items: filteredExperiments,
112117
searchInputProps,
113118
clear: clearSearch,
114119
} = useSearch({
115120
items: allExperiments,
116121
defaultSortField: "key",
122+
searchValueTuple: [searchValue, setSearchValue],
117123
});
118124

119125
const sortedFilteredExperiments = useMemo(

src/app/components/FeatureDetail.tsx

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -588,7 +588,6 @@ export default function FeatureDetail({
588588
<Rule
589589
key={i}
590590
rule={rule}
591-
rules={selectedFeature.feature.rules || []}
592591
i={i}
593592
fid={selectedFid}
594593
valueType={selectedFeature.valueType}

src/app/components/FeaturesTab.tsx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,13 +102,19 @@ export default function FeaturesTab() {
102102
false,
103103
);
104104

105+
const [searchValue, setSearchValue] = useTabState<string>(
106+
"featuresSearchValue",
107+
""
108+
);
109+
105110
const {
106111
items: filteredFeatures,
107112
searchInputProps,
108113
clear: clearSearch,
109114
} = useSearch({
110115
items: allFeatures,
111116
defaultSortField: "id",
117+
searchValueTuple: [searchValue, setSearchValue],
112118
});
113119

114120
const sortedFilteredFeatures = useMemo(

src/app/components/Rule.tsx

Lines changed: 5 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,6 @@ export const GLOBAL_OVERRIDE = "Global override"; // FF override
3939

4040
export default function Rule({
4141
rule,
42-
rules,
4342
i,
4443
fid,
4544
valueType = "string",
@@ -48,7 +47,6 @@ export default function Rule({
4847
onApply,
4948
}: {
5049
rule: FeatureRule;
51-
rules: FeatureRule[];
5250
i: number;
5351
fid: string;
5452
valueType?: ValueType;
@@ -67,37 +65,10 @@ export default function Rule({
6765
const [jsonMode, setJsonMode] = useState(false);
6866

6967
const debug = evaluatedFeature?.debug || [];
70-
const debugForRule = useMemo(() => {
71-
const d: DebugLog[] = [];
72-
let r = 0; // current parent rule number
73-
debug.forEach((item, itemNo) => {
74-
const nextItem = debug?.[itemNo + 1];
75-
// Skip tracking callbacks
76-
// if (item?.[0].startsWith("Tracking callback")) return;
77-
// If the log id matches our feature's id, assume we can rely on the log's
78-
// rule number (i).
79-
if (item?.[1]?.id === fid && item?.[1]?.rule?.i !== undefined) {
80-
r = item[1].rule.i as number;
81-
}
82-
// Probably an experiment rule (no rule, has id, id doesn't match),
83-
// assume this log belongs to current feature's next rule.
84-
if (
85-
!item?.[1]?.rule &&
86-
item?.[1]?.id &&
87-
item[1].id !== fid &&
88-
itemNo > 0 &&
89-
// these get lumped in the wrong rule otherwise
90-
!nextItem?.[0]?.startsWith("Skip rule because prerequisite") &&
91-
!nextItem?.[0]?.startsWith("Feature blocked")
92-
) {
93-
r++;
94-
}
95-
if (r === i) {
96-
d.push(item);
97-
}
98-
});
99-
return d;
100-
}, [fid, i, debug]);
68+
const debugForRule = useMemo(
69+
() => debug.filter((d) => d?.[1]?.i === i),
70+
[fid, i, debug]
71+
);
10172

10273
let status: "skipped" | "unreachable" | "matches" | "gates" | "overridden" =
10374
"skipped";
@@ -275,7 +246,7 @@ export default function Rule({
275246
/>
276247
)}
277248
<div className="pt-1 border-t border-t-gray-a6">
278-
<DebugLogger startCollapsed={true} logs={debugForRule} />
249+
<DebugLogger startCollapsed={true} logs={debugForRule} showCount={true} />
279250
</div>
280251
</div>
281252
);

src/app/components/SdkTab/index.tsx

Lines changed: 1 addition & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ export default function SdkTab() {
122122
title="Status"
123123
status={canConnectStatus}
124124
color={canConnectStatusColor}
125-
showCaret={isResponsive}
126125
/>
127126
</div>
128127

@@ -144,7 +143,6 @@ export default function SdkTab() {
144143
: "")
145144
}
146145
color={versionStatusColor}
147-
showCaret={isResponsive}
148146
/>
149147
</div>
150148

@@ -159,7 +157,6 @@ export default function SdkTab() {
159157
title="Tracking Callback"
160158
status={trackingCallbackStatus}
161159
color={trackingCallbackStatusColor}
162-
showCaret={isResponsive}
163160
/>
164161
</div>
165162

@@ -174,7 +171,6 @@ export default function SdkTab() {
174171
title="Payload Security"
175172
status={securityStatus}
176173
color="gray"
177-
showCaret={isResponsive}
178174
/>
179175
</div>
180176

@@ -189,7 +185,6 @@ export default function SdkTab() {
189185
title="Sticky Bucketing"
190186
status={usingStickyBucketing}
191187
color="gray"
192-
showCaret={isResponsive}
193188
/>
194189
</div>
195190

@@ -204,7 +199,6 @@ export default function SdkTab() {
204199
title="Streaming"
205200
status={streaming}
206201
color="gray"
207-
showCaret={isResponsive}
208202
/>
209203
</div>
210204

@@ -219,7 +213,6 @@ export default function SdkTab() {
219213
title="SDK Payload"
220214
status={hasPayload}
221215
color="gray"
222-
showCaret={isResponsive}
223216
/>
224217
</div>
225218

@@ -234,7 +227,6 @@ export default function SdkTab() {
234227
title="Log Event Callback"
235228
status={usingLogEvent}
236229
color="gray"
237-
showCaret={isResponsive}
238230
/>
239231
</div>
240232

@@ -249,7 +241,6 @@ export default function SdkTab() {
249241
title="On Feature Usage Callback"
250242
status={usingOnFeatureUsage}
251243
color="gray"
252-
showCaret={isResponsive}
253244
/>
254245
</div>
255246
</>
@@ -273,12 +264,10 @@ function ItemStatus({
273264
title,
274265
status,
275266
color,
276-
showCaret,
277267
}: {
278268
title: string;
279269
status?: string | boolean;
280270
color: "green" | "red" | "gray" | "orange";
281-
showCaret: boolean;
282271
}) {
283272
if (typeof status === "boolean") {
284273
status = status ? "Yes" : "No";
@@ -288,11 +277,7 @@ function ItemStatus({
288277
<div className="title pl-4 pr-6">{title}</div>
289278
<div className="flex pr-4 items-center flex-shrink-0 text-sm">
290279
<Text color={color}>{status}</Text>
291-
{showCaret && (
292-
<div className="ml-5 font-bold">
293-
<PiCaretRight />
294-
</div>
295-
)}
280+
<PiCaretRight className="ml-5 text-gray-10" />
296281
</div>
297282
</>
298283
);

0 commit comments

Comments
 (0)