diff --git a/packages/react/src/Timeline/Timeline.dependabot.features.stories.tsx b/packages/react/src/Timeline/Timeline.dependabot.features.stories.tsx index 7768c168dff..b756a162b32 100644 --- a/packages/react/src/Timeline/Timeline.dependabot.features.stories.tsx +++ b/packages/react/src/Timeline/Timeline.dependabot.features.stories.tsx @@ -29,6 +29,7 @@ import { UserActor, VariantSection, } from './internal/timelineStoryHelpers' +import {actorTypeForLogin, DEPENDABOT_TAXONOMY, toEventDataAttributes, type DependabotEventType} from './taxonomy' /** * Dependabot alert Timeline event examples (Phase 2 of github/primer#6663). @@ -56,10 +57,26 @@ import { * base `Timeline` component's own stories, and any docs-site representation is a * Phase 3 consideration via base-component story changes, out of scope here. * - * FUTURE FILTERING (taxonomy still open — github/primer#6663): category - * `data-*` attributes (e.g. `data-event-category="opened"`) will attach to each - * `Timeline.Item` below so stories can be filtered/grouped by event family. We - * intentionally do NOT add them yet to avoid baking in a taxonomy. + * TAXONOMY `data-*` CONTRACT: every cataloged `Timeline.Item` below carries the + * event `data-*` attributes projected from the merged taxonomy module + * (`./taxonomy`, primer/react#8180) — the single source of truth for Timeline + * event categorization (github/primer#6664, docs github/primer#6888). Each row + * spreads the output of `toEventDataAttributes` via the local `dependabotAttrs` + * helper, which derives `category` / `visibility` FROM the catalog entry + * (`DEPENDABOT_TAXONOMY`) so the stories stay in sync with the catalog, and + * resolves `data-actor-type` at runtime from each row's rendered actor login + * (`actorTypeForLogin`): Dependabot-authored rows resolve to `bot`, user-driven + * rows to `user`. The contract per rendered `
  • `: `data-event-scope`, + * `data-event-type` (the UNSCOPED leaf), `data-event-category`, + * `data-event-visibility` (defaults `primary`), and `data-actor-type`. This + * applies the same contract proven by the License Compliance pilot + * (primer/react#8216). + * + * SHARED / PARKED EVENTS (left untagged): the Assignment and Copilot-work groups + * are cross-surface SHARED events, deliberately kept OUT of the per-surface + * Dependabot catalog (github/primer#6888), so they intentionally carry NO + * `data-*` attributes. See the code comments above `EventAssignment` and + * `EventCopilotWork`. * * SLOT USAGE (Phase 1 slots — same convention as the Issues group): * - `Timeline.Avatar` (gutter slot, #6677): the 40px LEFT-GUTTER avatar. @@ -120,6 +137,25 @@ const PushPill = ({sha}: {sha: string}) => ( ) +/** + * Local projection of the taxonomy `data-*` contract for this surface. Given a + * Dependabot leaf `type` (and, when the row renders an actor, that actor's + * `login`), it returns the `data-*` attribute set to spread on the + * `Timeline.Item`. `category` and `visibility` come FROM the catalog entry so + * the stories track `DEPENDABOT_TAXONOMY`; `data-actor-type` is resolved at + * runtime from the login (Dependabot-authored rows pass a `…[bot]` login so they + * resolve to `bot`; user-driven rows pass the rendered user login). See + * github/primer#6664 and the taxonomy docs (github/primer#6888). + */ +const dependabotAttrs = (type: DependabotEventType, login?: string) => + toEventDataAttributes({ + scope: 'dependabot', + type, + category: DEPENDABOT_TAXONOMY[type].category, + visibility: DEPENDABOT_TAXONOMY[type].visibility, + actorType: login ? actorTypeForLogin(login) : undefined, + }) + export default { title: 'Components/Timeline/Events/Dependabot', component: Timeline, @@ -160,7 +196,7 @@ export const EventOpened = () => ( {/* Opened — no source */} - + @@ -176,7 +212,7 @@ export const EventOpened = () => ( {/* OpenedFromPR — bold `#123` pull-request link (scheme: primary, bold) */} - + @@ -192,7 +228,7 @@ export const EventOpened = () => ( {/* OpenedFromPush — blue push-pill with the 7-char `after` SHA */} - + @@ -225,7 +261,7 @@ export const EventFixed = () => ( {/* Fixed — no source */} - + @@ -241,7 +277,7 @@ export const EventFixed = () => ( {/* FixedViaPR — bold `#123` pull-request link */} - + @@ -257,7 +293,7 @@ export const EventFixed = () => ( {/* FixedViaPush — blue push-pill */} - + @@ -290,7 +326,7 @@ export const EventDismissed = () => ( {/* Manual — risk is tolerable (with an optional dismissal note) */} - + @@ -309,7 +345,7 @@ export const EventDismissed = () => ( {/* Manual — fix started */} - + @@ -325,7 +361,7 @@ export const EventDismissed = () => ( {/* Manual — no bandwidth to fix this */} - + @@ -341,7 +377,7 @@ export const EventDismissed = () => ( {/* Manual — vulnerable code is not actually used */} - + @@ -357,7 +393,7 @@ export const EventDismissed = () => ( {/* Manual — inaccurate */} - + @@ -373,7 +409,7 @@ export const EventDismissed = () => ( {/* Auto — rule-based, no source (with optional rule comment) */} - + @@ -396,7 +432,7 @@ export const EventDismissed = () => ( {/* Auto — from a pull request */} - + @@ -412,7 +448,7 @@ export const EventDismissed = () => ( {/* Auto — from a push */} - + @@ -441,7 +477,7 @@ export const EventReopened = () => ( {/* Manual reopen — user actor */} - + @@ -457,7 +493,7 @@ export const EventReopened = () => ( {/* Reintroduced — no source */} - + @@ -473,7 +509,7 @@ export const EventReopened = () => ( {/* Reintroduced — from a pull request */} - + @@ -489,7 +525,7 @@ export const EventReopened = () => ( {/* Reintroduced — from a push */} - + @@ -505,7 +541,7 @@ export const EventReopened = () => ( {/* Auto-reopened — rule change (with optional rule comment) */} - + @@ -560,7 +596,7 @@ export const EventDismissalRequest = () => ( place that right-aligned control in the `Timeline.Actions` slot. */} - + @@ -584,7 +620,7 @@ export const EventDismissalRequest = () => ( {/* Dismissal approved — circle user actor, success/check badge */} - + @@ -601,7 +637,7 @@ export const EventDismissalRequest = () => ( {/* Dismissal denied — circle user actor, danger/x badge */} - + @@ -619,7 +655,7 @@ export const EventDismissalRequest = () => ( "x")` (no bg) → a bare default badge, not a danger/emphasis one. */} - + @@ -651,6 +687,12 @@ export const EventDismissalRequest = () => ( * The five variants mirror the Secret scanning assignment story: self-assign, * assign another, self-unassign, unassign another, and a combined assign + * unassign example. + * + * SHARED / PARKED — NO `data-*` TAXONOMY: assignment is a cross-surface SHARED + * event, deliberately kept OUT of the per-surface Dependabot catalog + * (`DEPENDABOT_TAXONOMY` has no assignment leaf), per the taxonomy docs + * (github/primer#6888). It has no per-surface taxonomy leaf yet, so these rows + * intentionally carry NO `data-*` attributes. */ export const EventAssignment = () => ( @@ -758,6 +800,12 @@ export const EventAssignment = () => ( * button above. * - Work finished (`with_badge(icon: "repo-push")`): default (gray) badge, no * right control. + * + * SHARED / PARKED — NO `data-*` TAXONOMY: Copilot-agent work is a cross-surface + * SHARED event, deliberately kept OUT of the per-surface Dependabot catalog + * (`DEPENDABOT_TAXONOMY` has no copilot leaf), per the taxonomy docs + * (github/primer#6888). It has no per-surface taxonomy leaf yet, so these rows + * intentionally carry NO `data-*` attributes. */ export const EventCopilotWork = () => (