Add tracker pattern detail page with properties and detected trackers sections

Signed-off-by: Émile Ré <emile@probo.com>
This commit is contained in:
Émile Ré
2026-05-22 11:54:44 +02:00
parent f8debf5406
commit b46f2656f5
20 changed files with 1077 additions and 3 deletions

View File

@@ -0,0 +1,72 @@
---
description: Extract connection list items (table rows, list entries) into their own fragment component
globs: "**/*.tsx"
alwaysApply: false
---
# Extract connection items into fragment components
When rendering items from a Relay connection (e.g. `edges.map(…)`), each item
MUST be rendered by a dedicated component that owns its own fragment — never
inline the rendering of node fields directly in the parent's `.map()` body.
This ensures:
- Data requirements are colocated with the rendering component
- Adding/removing fields in a row doesn't bloat the parent's fragment
- The row component is independently testable and reusable
## Pattern
```tsx
// _components/ThingRow.tsx — owns its fragment
const thingRowFragment = graphql`
fragment ThingRow_thing on Thing {
id
name
status
}
`;
interface ThingRowProps {
thingKey: ThingRow_thing$key;
}
export function ThingRow({ thingKey }: ThingRowProps) {
const thing = useFragment(thingRowFragment, thingKey);
return (
<Tr>
<Td>{thing.name}</Td>
<Td>{thing.status}</Td>
</Tr>
);
}
```
```tsx
// Parent — spreads the row fragment in its connection and renders the component
const parentFragment = graphql`
fragment ParentPage_things on Query
@refetchable(queryName: "ParentPageRefetchQuery") {
things(first: $first, after: $after) @connection(key: "ParentPage_things") {
edges {
node {
id
...ThingRow_thing
}
}
}
}
`;
// In JSX:
{things.map(thing => (
<ThingRow key={thing.id} thingKey={thing} />
))}
```
## Naming
- File: `_components/<NodeType>Row.tsx` (for table rows) or
`_components/<NodeType>Card.tsx` (for card lists)
- Fragment: `<ComponentName>_<typeName>` (e.g. `ThingRow_thing`)
- Prop: `<typeName>Key` (e.g. `thingKey`)

View File

@@ -39,3 +39,6 @@ interface EditCookieRowProps {
Callback props (`onSave`, `onCancel`) and configuration props (`isUpdating`,
`variant`) are fine — only **domain data** must come from fragments.
For connection items (table rows, list entries rendered in `.map()`), see the
companion rule `relay-connection-item-components.mdc`.