Skip to content

Commit 341ffa3

Browse files
committed
2.4.0 feat: watch/pin data path
test: add partial prefix util fix testid issues add tests docs
1 parent fab1a3a commit 341ffa3

File tree

13 files changed

+286
-24
lines changed

13 files changed

+286
-24
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"early-access": "rm -rf dist && npm --prefix packages/shell-chrome-v3 run build && npm run postpackage",
1515
"ea": "npm run early-access",
1616
"watch": "npm start",
17-
"test": "node --test tests/*",
17+
"test": "node --test tests/* && node --experimental-strip-types --test **/*.test.ts",
1818
"cy:run": "cypress run",
1919
"cy:open": "cypress open",
2020
"format": "prettier './{packages/**/,cypress/**/*,lib/}*.{js,ts,tsx,html,css}' --write",
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
it('should display (pin) and filter/toggle to (unpin) when clicked', () => {
2+
cy.visit('/simulator?target=v3.html').get('[data-testid=component-name]').should('be.visible');
3+
4+
// Setup
5+
cy.get('[data-testid=component-name]').first().click();
6+
7+
cy.get('[data-testid="data-property-name-el"]').click();
8+
cy.get('[data-testid="data-property-name-children"]').should('be.visible');
9+
cy.get('[data-testid="data-property-name-children"]').click();
10+
// End setup
11+
12+
cy.get('[data-testid="pin-el.children"]').should('be.visible');
13+
cy.get('[data-testid="pin-el.children"]').should('have.text', '(pin)');
14+
15+
// Pre-condition, this will get filtered out
16+
cy.get('[data-testid="data-property-name-myFunction"]').should('exist');
17+
18+
cy.get('[data-testid="pin-el.children"]').click();
19+
20+
// Assertions
21+
cy.get('[data-testid="pin-el.children"]').should('not.exist');
22+
cy.get('[data-testid="unpin-el.children"]').should('be.visible');
23+
cy.get('[data-testid="unpin-el.children"]').should('have.text', '(unpin)');
24+
25+
cy.get('[data-testid="data-property-name-myFunction"]').should('not.exist');
26+
27+
cy.get('[data-testid="data-property-name-0"]').should('be.visible');
28+
cy.get('[data-testid="data-property-name-1"]').should('be.visible');
29+
cy.get('[data-testid="pin-el.children.2"]').click();
30+
cy.get('[data-testid="data-property-name-0"]').should('not.exist');
31+
cy.get('[data-testid="data-property-name-1"]').should('not.exist');
32+
33+
// Unpin
34+
cy.get('[data-testid="unpin-el.children.2"]').should('have.text', '(unpin)');
35+
cy.get('[data-testid="unpin-el.children.2"]').click();
36+
37+
// Assert that we reset correctly
38+
cy.get('[data-testid="pin-el.children"]').should('be.visible');
39+
cy.get('[data-testid="pin-el.children"]').should('have.text', '(pin)');
40+
cy.get('[data-testid="unpin-el.children"]').should('not.exist');
41+
cy.get('[data-testid="data-property-name-myFunction"]').should('exist');
42+
});
43+
44+
it('displays pinned path, clicking on path loosens the filtering', () => {
45+
cy.visit('/simulator?target=v3.html').get('[data-testid=component-name]').should('be.visible');
46+
47+
// Setup
48+
cy.get('[data-testid=component-name]').first().click();
49+
50+
cy.get('[data-testid="data-property-name-el"]').click();
51+
cy.get('[data-testid="data-property-name-children"]').should('be.visible');
52+
cy.get('[data-testid="data-property-name-children"]').click();
53+
// End setup
54+
55+
cy.get('[data-testid="pinned-path"').should('not.exist');
56+
57+
cy.get('[data-testid="pin-el.children"]').click();
58+
59+
// Assertions
60+
cy.get('[data-testid="data-property-name-myFunction"]').should('not.exist');
61+
cy.get('[data-testid="pinned-path"').should('be.visible');
62+
cy.get('[data-testid="pinned-path"').should('have.text', 'el>children');
63+
64+
cy.get('[data-testid="pinned-path-children"')
65+
.should('be.visible')
66+
.should('have.text', 'children');
67+
cy.get('[data-testid="pinned-path-el"').click();
68+
cy.get('[data-testid="pinned-path-children"').should('not.exist');
69+
70+
cy.get('[data-testid="pinned-path-el"').click();
71+
72+
cy.get('[data-testid="pinned-path"').should('not.exist');
73+
cy.get('[data-testid="data-property-name-myFunction"]').should('exist');
74+
});

packages/shell-chrome-v3/manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Alpine.js devtools - Early Access",
33
"description": "DevTools extension for debugging Alpine.js applications.",
4-
"version": "2.3.0",
4+
"version": "2.4.0",
55
"manifest_version": 3,
66
"icons": {
77
"16": "icons/16.png",

packages/shell-chrome-v3/package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/shell-chrome-v3/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "shell-chrome-v3",
33
"private": true,
4-
"version": "2.3.0",
4+
"version": "2.4.0",
55
"description": "Alpine.js devtools with Chrome manifest v3 compatibility",
66
"type": "module",
77
"scripts": {
@@ -10,6 +10,7 @@
1010
"dev": "npm run esbuild && NODE_ENV=dev vite build",
1111
"dev:main": "VITE_MAINLINE_PUBLISH=true npm run dev",
1212
"build": "NODE_ENV=production npm run esbuild && vite build",
13+
"test": "node --experimental-strip-types --test **/*.test.ts",
1314
"typecheck": "tsc",
1415
"format": "prettier -w .",
1516
"esbuild": "node build.js && prettier -w manifest.json",

packages/shell-chrome-v3/src/devtools/components/component-grid.tsx

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
import { For, Show } from 'solid-js';
2-
import { componentsValue, openComponentValue, selectedComponentFlattenedData } from '../state';
2+
import {
3+
componentsValue,
4+
filteredSelectedCompData,
5+
openComponentValue,
6+
pinnedPrefix,
7+
} from '../state';
38
import { ComponentListItem } from './component-list-item';
49
import { DataAttributeDisplay } from './data-attribute-display';
510
import { SplitPane } from './split-pane';
11+
import { PinnedPrefixPath } from './pinned-prefix-path';
612

713
export function ComponentGrid() {
814
return (
@@ -29,9 +35,15 @@ export function ComponentGrid() {
2935
<>
3036
{openComponentValue() ? (
3137
<div class="sticky top-0 left-0 z-20 w-full flex items-center px-3 py-2 text-base font-mono text-gray-600 bg-gray-100 dark:text-gray-100 dark:bg-alpine-400">
32-
<span class="opacity-25">&lt;</span>
33-
<span>{openComponentValue()?.name}</span>
34-
<span class="opacity-25">&gt;</span>
38+
{pinnedPrefix() ? (
39+
<PinnedPrefixPath pinnedPrefix={pinnedPrefix} />
40+
) : (
41+
<>
42+
<span class="opacity-25">&lt;</span>
43+
<span>{openComponentValue()?.name}</span>
44+
<span class="opacity-25">&gt;</span>
45+
</>
46+
)}
3547
</div>
3648
) : (
3749
<div
@@ -49,9 +61,9 @@ export function ComponentGrid() {
4961
class="flex-1 px-3 py-2 dark:bg-alpine-400 dark:text-gray-50"
5062
>
5163
<div class="font-mono">
52-
<div class="leading-6 text-gray-300">x-data: {'{'}</div>
53-
<Show when={selectedComponentFlattenedData().length > 0}>
54-
<For each={selectedComponentFlattenedData()}>
64+
<div class="leading-6 text-gray-300">$data: {'{'}</div>
65+
<Show when={filteredSelectedCompData().length > 0}>
66+
<For each={filteredSelectedCompData()}>
5567
{(data) => <DataAttributeDisplay attributeData={data} />}
5668
</For>
5769
</Show>

packages/shell-chrome-v3/src/devtools/components/data-attribute-display.tsx

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,15 @@ import {
33
FlattenedComponentData,
44
FlattenedStoreData,
55
isReadOnly,
6+
pinnedPrefix,
67
saveComponentAttributeEdit,
78
saveStoreAttributeEdit,
9+
setPinnedPrefix,
810
toggleDataAttributeOpen,
911
} from '../state';
1012
import { effect } from 'solid-js/web';
1113
import { metric } from '../metrics';
14+
import { isEarlyAccess } from '../../lib/isEarlyAccess';
1215

1316
interface DataDisplayProps {
1417
attributeData: FlattenedComponentData | FlattenedStoreData;
@@ -92,13 +95,42 @@ export function DataAttributeDisplay(props: DataDisplayProps) {
9295
</Show>
9396
</div>
9497

95-
<span
96-
class="text-purple dark:brightness-150"
97-
data-testid={`data-property-name-${props.attributeData.attributeName}`}
98-
>
98+
<span class="text-purple dark:brightness-150">
9999
{/* TODO: do something about __root_value */}
100100
{/* {props.attributeData.attributeName === '__root_value' ? '' : props.attributeData.attributeName} */}
101-
{props.attributeData.attributeName}
101+
<span data-testid={`data-property-name-${props.attributeData.attributeName}`}>
102+
{props.attributeData.attributeName}
103+
</span>
104+
105+
<Show when={isEarlyAccess()}>
106+
<button
107+
data-testid={
108+
pinnedPrefix() !== props.attributeData.id
109+
? `pin-${props.attributeData.id}`
110+
: `unpin-${props.attributeData.id}`
111+
}
112+
onClick={(e) => {
113+
e.stopPropagation();
114+
e.preventDefault();
115+
if (pinnedPrefix() !== props.attributeData.id) {
116+
metric('set_prefix_on_pin', {
117+
datasource:
118+
'parentStoreName' in props.attributeData ? 'stores' : 'components',
119+
});
120+
setPinnedPrefix(props.attributeData.id);
121+
} else {
122+
metric('set_prefix_on_unpin', {
123+
datasource:
124+
'parentStoreName' in props.attributeData ? 'stores' : 'components',
125+
});
126+
setPinnedPrefix('');
127+
}
128+
}}
129+
class="text-gray-500 cursor-pointer ml-1 text-xs"
130+
>
131+
{pinnedPrefix() !== props.attributeData.id ? '(pin)' : '(unpin)'}
132+
</button>
133+
</Show>
102134
</span>
103135

104136
<span class="text-black dark:text-gray-100">:</span>
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import { Accessor, createMemo, For } from 'solid-js';
2+
import { setPinnedPrefix } from '../state';
3+
import { metric } from '../metrics';
4+
5+
function getPathSegments(pinnedPrefix: string) {
6+
console.log('pathSegs', pinnedPrefix);
7+
const subPaths: { idx: number; subPath: string; display: string }[] = [];
8+
let prevPart = '';
9+
pinnedPrefix.split('.').forEach((part, i) => {
10+
if (prevPart.length > 0) {
11+
prevPart += '.';
12+
}
13+
prevPart += part;
14+
subPaths.push({ idx: i, subPath: prevPart, display: part });
15+
});
16+
console.log(subPaths);
17+
return subPaths;
18+
}
19+
export function PinnedPrefixPath({ pinnedPrefix }: { pinnedPrefix: Accessor<string> }) {
20+
const pathSegs = createMemo(() => getPathSegments(pinnedPrefix()));
21+
return (
22+
<span data-testid="pinned-path">
23+
<For each={pathSegs()}>
24+
{(seg) => {
25+
return (
26+
<>
27+
<button
28+
data-testid={`pinned-path-${seg.display}`}
29+
class="text-purple dark:brightness-150 hover:underline cursor-pointer"
30+
onClick={() => {
31+
metric('set_prefix_from_path', {
32+
pathDepth: seg.subPath.split('.').length,
33+
});
34+
if (seg.subPath === pinnedPrefix()) {
35+
setPinnedPrefix('');
36+
} else {
37+
setPinnedPrefix(seg.subPath);
38+
}
39+
}}
40+
>
41+
{seg.display}
42+
</button>
43+
{seg.idx !== pathSegs().length - 1 ? <span class="mx-2 opacity-50">&gt;</span> : ''}
44+
</>
45+
);
46+
}}
47+
</For>
48+
</span>
49+
);
50+
}

packages/shell-chrome-v3/src/devtools/components/store-grid.tsx

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,19 @@
11
import { isRequiredVersion } from '../../lib/utils';
2-
import { openStoreValue, selectedStoreFlattenedData, state, storesValue } from '../state';
2+
import {
3+
filteredStoreFlattenedData,
4+
openStoreValue,
5+
pinnedPrefix,
6+
state,
7+
storesValue,
8+
} from '../state';
39
import { StoreListItem } from './store-list-item';
410
import { DataAttributeDisplay } from './data-attribute-display';
511
import { SplitPane } from './split-pane';
612
import { EarlyAccessNotice } from './early-access';
713
import { isEarlyAccess } from '../../lib/isEarlyAccess';
814
import { For, Show } from 'solid-js';
915
import { metric } from '../metrics';
16+
import { PinnedPrefixPath } from './pinned-prefix-path';
1017

1118
export function StoreGrid() {
1219
if (!isEarlyAccess()) {
@@ -50,9 +57,15 @@ export function StoreGrid() {
5057
<>
5158
{openStoreValue() ? (
5259
<div class="sticky top-0 left-0 z-20 w-full flex items-center px-3 py-2 text-base font-mono text-gray-600 bg-gray-100 dark:text-gray-100 dark:bg-alpine-400">
53-
<span class="opacity-25">$store{'['}'</span>
54-
<span>{openStoreValue()?.name}</span>
55-
<span class="opacity-25">'{']'}</span>
60+
{pinnedPrefix() ? (
61+
<PinnedPrefixPath pinnedPrefix={pinnedPrefix} />
62+
) : (
63+
<>
64+
<span class="opacity-25">$store{'['}'</span>
65+
<span>{openStoreValue()?.name}</span>
66+
<span class="opacity-25">'{']'}</span>
67+
</>
68+
)}
5669
</div>
5770
) : (
5871
<div
@@ -71,8 +84,8 @@ export function StoreGrid() {
7184
>
7285
<div class="font-mono">
7386
<div class="leading-6 text-gray-300">{'{'}</div>
74-
<Show when={selectedStoreFlattenedData().length > 0}>
75-
<For each={selectedStoreFlattenedData()}>
87+
<Show when={filteredStoreFlattenedData().length > 0}>
88+
<For each={filteredStoreFlattenedData()}>
7689
{(data) => <DataAttributeDisplay attributeData={data} />}
7790
</For>
7891
</Show>

0 commit comments

Comments
 (0)