diff --git a/packages/react/src/Timeline/Timeline.secret-scanning.features.stories.tsx b/packages/react/src/Timeline/Timeline.secret-scanning.features.stories.tsx index d9aa3afd1c8..c7e48924ab0 100644 --- a/packages/react/src/Timeline/Timeline.secret-scanning.features.stories.tsx +++ b/packages/react/src/Timeline/Timeline.secret-scanning.features.stories.tsx @@ -20,6 +20,12 @@ import { import {Button} from '../Button' import Octicon from '../Octicon' import {EventSubRow, MutedTime, RealisticTimeline, UserActor, VariantSection} from './internal/timelineStoryHelpers' +import { + actorTypeForLogin, + SECRET_SCANNING_TAXONOMY, + toEventDataAttributes, + type SecretScanningEventType, +} from './taxonomy' /** * Secret Scanning alert Timeline event examples (Phase 2 of github/primer#6663). @@ -53,10 +59,18 @@ import {EventSubRow, MutedTime, RealisticTimeline, UserActor, VariantSection} fr * 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="created"`) 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. + * EVENT TAXONOMY TAGGING (github/primer#6664, Phase 3): each cataloged + * `Timeline.Item` below carries the `data-*` event contract + * (`data-event-scope` / `data-event-type` / `data-event-category` / + * `data-event-visibility` / `data-actor-type`), projected from the shared + * `SECRET_SCANNING_TAXONOMY` catalog via `toEventDataAttributes`. This mirrors + * the License Compliance pilot (primer/react#8216) and consumes the merged + * taxonomy module (#8180) documented in github/primer#6888. + * + * The catalog was scoped to the five live `switch (event.type)` cases and is + * NARROWER than this story set, so MANY variants have no catalog leaf and are + * left UNTAGGED on purpose (each such item carries a comment explaining why). + * We tag ONLY the seven cataloged leaves and never invent a value. * * SLOT USAGE (Phase 1 slots — same convention as the Issues / Dependabot groups): * - `Timeline.Avatar` (gutter slot, #6677): the 40px LEFT-GUTTER avatar. @@ -97,6 +111,21 @@ import {EventSubRow, MutedTime, RealisticTimeline, UserActor, VariantSection} fr const SIX7_AVATAR = 'https://avatars.githubusercontent.com/u/4548309?v=4' const HUBOT_AVATAR = 'https://avatars.githubusercontent.com/u/480938?v=4' +// Projects a cataloged Secret Scanning leaf into the event `data-*` contract +// (github/primer#6664), same shape as the License Compliance pilot +// (primer/react#8216). `category` and `visibility` are read FROM the catalog so +// the story never re-declares the taxonomy; `login` is the actor rendered in the +// row, resolved to `data-actor-type` via `actorTypeForLogin`. Omit `login` for +// actor-less rows so no `data-actor-type` is emitted. +const secretScanningAttrs = (type: SecretScanningEventType, login?: string) => + toEventDataAttributes({ + scope: 'secret-scanning', + type, + category: SECRET_SCANNING_TAXONOMY[type].category, + visibility: SECRET_SCANNING_TAXONOMY[type].visibility, + actorType: login ? actorTypeForLogin(login) : undefined, + }) + export default { title: 'Components/Timeline/Events/Secret Scanning', component: Timeline, @@ -137,7 +166,12 @@ export const EventCreated = () => ( {/* Created — GitHub system actor, ShieldIcon on success (green) */} - + {/* `detected` leaf. Renders the GitHub SYSTEM-IDENTITY actor + (``); GitHub is not in the bot set, so + actorTypeForLogin('GitHub') classifies it as 'user' -> data-actor-type='user'. + FLAGGED: whether a system identity should classify as user vs bot is + worth confirming (see report). */} + @@ -177,7 +211,8 @@ export const EventResolution = () => ( badge. Shown WITH an optional resolution-comment sub-row. */} - + {/* `closed` leaf (Resolution, any non-reopened resolution.type); user actor. */} + @@ -196,7 +231,8 @@ export const EventResolution = () => ( {/* Closed as false positive — gray (default) ShieldSlash badge. */} - + {/* `closed` leaf; user actor. */} + @@ -212,7 +248,8 @@ export const EventResolution = () => ( {/* Closed as won't fix */} - + {/* `closed` leaf; user actor. */} + @@ -228,7 +265,8 @@ export const EventResolution = () => ( {/* Closed as used in tests */} - + {/* `closed` leaf; user actor. */} + @@ -244,7 +282,8 @@ export const EventResolution = () => ( {/* Closed as pattern deleted */} - + {/* `closed` leaf; user actor. */} + @@ -260,7 +299,8 @@ export const EventResolution = () => ( {/* Closed as pattern edited */} - + {/* `closed` leaf; user actor. */} + @@ -276,7 +316,8 @@ export const EventResolution = () => ( {/* Closed as ignored by configuration (resolution type `hidden_by_config`) */} - + {/* `closed` leaf; user actor. */} + @@ -297,7 +338,9 @@ export const EventResolution = () => ( placement rather than leaving the Break as a stray first child. */} - + {/* Context row: a `closed` leaf preceding the reopen, tagged in place + like the seven dedicated "Closed as …" variants; user actor. */} + @@ -308,7 +351,8 @@ export const EventResolution = () => ( - + {/* `reopened` leaf (Resolution, resolution.type === 'reopened'); user actor. */} + @@ -338,7 +382,8 @@ export const EventBypass = () => ( {/* Bypassed — AlertIcon, default (gray) badge */} - + {/* `bypassed` leaf; user actor. */} + @@ -355,6 +400,9 @@ export const EventBypass = () => ( repo has delegated bypass enabled. */} + {/* UNTAGGED: the delegated-BYPASS request/approve flow has no catalog + leaf. The catalog's dismissal_requested / dismissal_reviewed cover the + delegated-CLOSURE flow, a different thing. No leaf -> no data-* tag. */} @@ -371,6 +419,8 @@ export const EventBypass = () => ( {/* Bypass approved — CheckCircleIcon. Delegated bypass: gated as above. */} + {/* UNTAGGED: delegated-BYPASS flow, no catalog leaf (see the request + variant above). No leaf -> no data-* tag. */} @@ -403,7 +453,8 @@ export const EventValidityChange = () => ( {/* Active — automated (GitHub), AlertIcon on danger (red) */} - + {/* `validity_changed` leaf; automated -> GitHub system actor -> 'user'. */} + @@ -419,7 +470,8 @@ export const EventValidityChange = () => ( {/* Active — manual (user), same danger badge */} - + {/* `validity_changed` leaf; manual -> user actor. */} + @@ -435,7 +487,8 @@ export const EventValidityChange = () => ( {/* Inactive — automated (GitHub), SkipIcon on default (gray) */} - + {/* `validity_changed` leaf; automated -> GitHub system actor -> 'user'. */} + @@ -451,7 +504,8 @@ export const EventValidityChange = () => ( {/* Inactive — manual (user) */} - + {/* `validity_changed` leaf; manual -> user actor. */} + @@ -467,7 +521,8 @@ export const EventValidityChange = () => ( {/* Unknown — automated (GitHub), AlertIcon on attention (amber) */} - + {/* `validity_changed` leaf; automated -> GitHub system actor -> 'user'. */} + @@ -483,7 +538,8 @@ export const EventValidityChange = () => ( {/* Unknown — manual (user) */} - + {/* `validity_changed` leaf; manual -> user actor. */} + @@ -511,6 +567,10 @@ export const EventReport = () => ( {/* Reported — ShieldCheckIcon, default (gray) badge, user actor */} + {/* UNTAGGED: the catalog maps Report -> validity_changed, but + github/primer#6888 lists that mapping as UNCONFIRMED (open item #2). + Emitting an unconfirmed value would bake in a guess, so leave untagged + until the docs confirm the leaf. */} @@ -545,6 +605,8 @@ export const EventMetadata = () => ( {/* Metadata created — GitHub system actor, FileAddedIcon, default (gray) badge */} + {/* UNTAGGED: MetadataCreated is PARKED per github/primer#6888 ('Parked' + section), no catalog leaf. No leaf -> no data-* tag. */} @@ -561,6 +623,8 @@ export const EventMetadata = () => ( {/* Metadata removed — GitHub system actor, FileRemovedIcon, default (gray) badge */} + {/* UNTAGGED: MetadataRemoved is PARKED per github/primer#6888 ('Parked' + section), no catalog leaf. No leaf -> no data-* tag. */} @@ -606,7 +670,8 @@ export const EventClosureRequest = () => ( un-bolded `resolutionText(exemption_request.reason)`. */} - + {/* `dismissal_requested` leaf (DelegatedClosureRequestOpened); user actor. */} + @@ -630,7 +695,8 @@ export const EventClosureRequest = () => ( {/* Requested — requester view: the invisible "Cancel request" button. */} - + {/* `dismissal_requested` leaf; user actor. */} + @@ -651,7 +717,8 @@ export const EventClosureRequest = () => ( {/* Approved — CheckCircleIcon, with a reviewer comment sub-row. */} - + {/* `dismissal_reviewed` leaf; reviewer user actor (six7). */} + @@ -670,7 +737,8 @@ export const EventClosureRequest = () => ( {/* Denied — XIcon */} - + {/* `dismissal_reviewed` leaf; reviewer user actor (six7). */} + @@ -689,6 +757,8 @@ export const EventClosureRequest = () => ( {/* Cancelled — SkipIcon */} + {/* UNTAGGED: Secret Scanning has NO dismissal_cancelled leaf (unlike + Dependabot). No leaf -> no data-* tag. */} @@ -717,6 +787,9 @@ export const EventClosureRequest = () => ( */ export const EventAssignment = () => ( + {/* UNTAGGED (whole group): Assignment is a cross-surface SHARED event, + deliberately kept OUT of the per-surface Secret Scanning catalog. All five + variants below carry no data-* event tag. */} {/* Self-assigned — actor === assignee */}