@canonry/canonry 7.10.0 → 7.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/assets/agent-workspace/skills/aero/references/reporting.md +2 -0
  2. package/assets/agent-workspace/skills/canonry/references/aeo-analysis.md +1 -1
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +30 -4
  4. package/assets/assets/{AuditHistoryPanel-BgcvPo6g.js → AuditHistoryPanel-Bpkuj-iF.js} +1 -1
  5. package/assets/assets/{BacklinksPage-DZ4tauAs.js → BacklinksPage-CbRIZhu5.js} +1 -1
  6. package/assets/assets/{HistoryPage-DWG52dz1.js → HistoryPage-Dfq1vK9k.js} +1 -1
  7. package/assets/assets/{MeasurementPropertyPage-DTx2iQLV.js → MeasurementPropertyPage-DcH0zYNN.js} +1 -1
  8. package/assets/assets/ProjectPage-enF4twWt.js +8 -0
  9. package/assets/assets/{RunsPage-B6MhRqxN.js → RunsPage-aOeJ60pX.js} +1 -1
  10. package/assets/assets/{SettingsPage-Bxv7OSHT.js → SettingsPage-nA0_ImoQ.js} +1 -1
  11. package/assets/assets/{SiteHealthSection-C5x7oiFL.js → SiteHealthSection-CUOt7jeo.js} +3 -3
  12. package/assets/assets/{TrafficPage-C5gyQopi.js → TrafficPage-C0fVYizx.js} +1 -1
  13. package/assets/assets/{TrafficSourceDetailPage-Dv2ZRNvN.js → TrafficSourceDetailPage-LMhXbFlA.js} +1 -1
  14. package/assets/assets/{extract-error-message-C5pr51ph.js → extract-error-message-5aHy0fsK.js} +1 -1
  15. package/assets/assets/index-BJh8cX5E.js +86 -0
  16. package/assets/assets/index-BNeiohKS.css +1 -0
  17. package/assets/assets/{react-sigma_core.esm.min-P5bVaYly.js → react-sigma_core.esm.min-ldX35rMq.js} +1 -1
  18. package/assets/assets/{v2-overview-adapter-QtI4xO_4.js → v2-overview-adapter-CaO9vY-l.js} +1 -1
  19. package/assets/index.html +2 -2
  20. package/dist/{chunk-5ZBN3EEK.js → chunk-7I64KEGM.js} +2 -2
  21. package/dist/{chunk-66DVP4DN.js → chunk-AU7OUDWR.js} +5786 -4450
  22. package/dist/{chunk-VSZJVBVR.js → chunk-BTHEFJCI.js} +60 -8
  23. package/dist/{chunk-FVMWUT2R.js → chunk-DXI2FTSW.js} +706 -257
  24. package/dist/{chunk-HL3C6Z7T.js → chunk-EPSHIH63.js} +3 -3
  25. package/dist/{chunk-52PHEGHT.js → chunk-GQMSJEMZ.js} +3515 -2266
  26. package/dist/{chunk-IKXVLT4M.js → chunk-SM6ZZAPK.js} +93 -5
  27. package/dist/cli.js +177 -40
  28. package/dist/{demo-server-WZIB4JKJ.js → demo-server-WJUA4EIG.js} +4 -4
  29. package/dist/index.js +6 -6
  30. package/dist/{intelligence-service-KC62A4X5.js → intelligence-service-DJRH4Z3D.js} +2 -2
  31. package/dist/mcp.js +4 -4
  32. package/package.json +12 -12
  33. package/assets/assets/ProjectPage-CCf70zbI.js +0 -8
  34. package/assets/assets/index-BhXHm5nG.js +0 -86
  35. package/assets/assets/index-Rcbm8bK1.css +0 -1
@@ -25,6 +25,8 @@ statistically honest comparison. **Share of voice is less exposed to an engine's
25
25
  - **`moved`** — disjoint intervals; a real directional move (the point sign is the direction).
26
26
  - **`model-discontinuous` / `model-unknown`** — the engine's configured model changed, was mixed within a month, or is unrecorded (legacy rows). **No directional call is made for that comparison; never attribute the swing to the site.** Read `continuity` (its `status` plus the per-provider evidence) for what was excluded and why — `continuity` is the enforcement decision, `modelChanges` is advisory context only.
27
27
 
28
+ **Check `competitorIdentityChangedAt` before quoting a period someone has already seen.** Share of voice reads both months with the tracked competitors' names as the project has them now (curated, auto-detected, minus blocked; market pin names and names learned for market-only competitors are not read), so a change to those names restates every month. The field also moves for a market pin rename or a change to a market-only competitor's learned names, which leaves share of voice unchanged but restates the competitor landscape. When it is later than an earlier report, that report's figures for the same months may differ from today's; say the period was restated (and why) instead of presenting the difference as a change. A scoped comparison (a group, market or property scope, or a `marketKey`) reads frozen plan history and carries no such field. The competitor landscape and analytics metrics carry the same field.
29
+
28
30
  A silent upstream version bump under an unchanged configured id is undetectable; the tool does not pretend otherwise. Honor `lowRunCount` (a month under 5 sweeps → intervals too wide to resolve a move; recommend raising the sweep schedule). Report the point with its interval, not a bare number.
29
31
 
30
32
  The class rates (`mention-rate-branded`, `mention-rate-non-brand`, and their `cited-rate-*` pairs) are separate instruments with their own denominators; `classification-unavailable` means no split was possible, never a zero. On an Advanced project without a scope, those class rates come from the frozen frame in `classComparison`: judge them by `classComparison.continuity`, basket and run counts, not by the top-level `continuity`, which gates the four original metrics only. A Property, group or market scope answers entirely from the frozen frame.
@@ -11,7 +11,7 @@ A "mentioned" query means the client's brand was NAMED in the AI provider's answ
11
11
 
12
12
  A "not-mentioned" query means the answer text never named the client. `answerMentioned = null` is distinct: the mention was not checked for that snapshot — treat it as missing, not negative.
13
13
 
14
- **Mention share** is the competitive read: of all brand names appearing across the answer set (the project plus tracked competitors), the fraction that were the project = AI share-of-voice. A competitor taking mention share on a query you used to own is the highest-signal regression. A competitor is named by its domain label (4+ letters or digits) plus its curated aliases; when answers call a competitor something its domain does not say ("TuneSpoke" for `spoketuneworks.example`, a 3-letter brand), set `cnry competitor aliases <project> <domain> --set <name>` first, or the share overstates the project.
14
+ **Mention share** is the competitive read: of all brand names appearing across the answer set (the project plus tracked competitors), the fraction that were the project = AI share-of-voice. A competitor taking mention share on a query you used to own is the highest-signal regression. A competitor is named by its domain label (4+ letters or digits) plus its curated aliases and the names Canonry detected from the stored answers themselves (`autoAliases`); when answers call a competitor something its domain does not say ("TuneSpoke" for `spoketuneworks.example`, a 3-letter brand), check `cnry competitor aliases detect <project>`, or the share overstates the project. Names it lists only for review mix the competitor's real names with partners, rivals, places and services: confirm in the answers that a name refers to that competitor, then add it with `cnry competitor aliases <project> <domain> --add <name>`. Never `--set` from the review list: it replaces the curated list.
15
15
 
16
16
  ### First diagnostic read (mention-first)
17
17
 
@@ -54,6 +54,7 @@ cnry project update <name> --dispatch-mode claude=batch # scheduled sweeps bat
54
54
  cnry project update <name> --clear-dispatch-mode claude # back to sync
55
55
  cnry project update <name> --negative-review-max-stars 2 # review.negative for 1-2 star Google reviews only (1-4, or "default" for 3)
56
56
  cnry project update <name> --site-audit-max-pages 2500 # Site Health page budget for scans that set none (1-50000, or "full" for the full site); create takes it too, spec.siteAuditMaxPages in apply
57
+ cnry project update <name> --competitor-auto-aliases apply # store answer-derived competitor names after each sweep (off | preview | apply; default preview logs only); spec.competitorAutoAliases in apply
57
58
  cnry project update <name> --add-qualified-alias "Acme NYC" # sentiment treats this existing alias as the brand's own name (see Brand aliases)
58
59
  cnry project update <name> --remove-qualified-alias "Acme NYC" # repeatable; create takes --qualified-alias
59
60
  cnry project delete <name> # delete a project
@@ -408,11 +409,15 @@ cnry query generate <project> --provider gemini --count 10 --save
408
409
 
409
410
  cnry competitor add <project> competitor1.com competitor2.com
410
411
  cnry competitor add <project> spoketuneworks.example --alias TuneSpoke # one domain; repeat --alias for more names
411
- cnry competitor list <project> # text shows each competitor's aliases; JSON rows carry `aliases`
412
- cnry competitor aliases <project> qvx.example # read one competitor's aliases
412
+ cnry competitor list <project> # text shows each competitor's aliases and auto names; JSON rows carry `aliases`, `autoAliases`, `blockedAliases`
413
+ cnry competitor aliases <project> qvx.example # read one competitor's curated, auto-detected (with evidence) and blocked names
413
414
  cnry competitor aliases <project> qvx.example --set QVX # exact list (repeat --set); --clear empties it
414
415
  cnry competitor aliases <project> qvx.example --add "QVX Stores" # appends server-side in one call
415
416
  cnry competitor aliases <project> qvx.example --remove qvx # read, edit, write back (a concurrent edit can be overwritten)
417
+ cnry competitor aliases <project> spoketuneworks.example --block "Spoke Crew" # never auto-apply this name (removes it if auto)
418
+ cnry competitor aliases <project> spoketuneworks.example --unblock "Spoke Crew" # release it to detection again
419
+ cnry competitor aliases detect <project> --format json # dry run: names the stored answers tie to each site, with evidence
420
+ cnry competitor aliases detect <project> --apply # run detection now and store it, in any mode (after each sweep the project's mode decides)
416
421
  cnry competitor landscape <project> --query-class non-brand --window 30d --format json
417
422
  ```
418
423
 
@@ -427,9 +432,30 @@ A competitor is stored as its registrable domain, and every competitor mention m
427
432
  - Any spelling of a tracked domain (`www.`, a subdomain, or a row an older build's discovery promote stored as a subdomain) finds its stored row; discovery promote now stores the registrable domain. A competitor stored as two rows refuses alias edits; the error names both rows and the aliases to restate: `competitor remove` (which removes every row of it), then `competitor add <project> <domain> --alias ...`.
428
433
  - Matching is exact brand identity over answer prose (complete words, case and punctuation variants), never fuzzy. Aliases add to mention matching only; citations stay domain-based.
429
434
  - Read time: mention share (overview card, trend buckets, `visibility-stats --share-of-voice`, `visibility-compare`), the competitor landscape, mention gaps, and run/history competitor signals reinterpret stored answers as soon as aliases change. The stored `competitorOverlap` / `recommendedCompetitors` columns are recomputed in the background; the project's own `answerMentioned` is never touched by an alias edit.
430
- - Frozen: a Simple run freezes the competitor identity it dispatched with (domain label plus aliases), so the AI Visibility report keeps each run's own identity; only runs dispatched after the edit use new aliases, and the next run reads as a changed definition. Advanced plan revisions keep their own frozen competitor names (`measurement-plan advanced ... draft-action` with `upsert-competitor`); pinning a tracked competitor into a market by domain alone copies its curated aliases into the draft.
435
+ - Frozen: a Simple run freezes the competitor identity it dispatched with (domain label plus aliases), so the AI Visibility report keeps each run's own identity; only runs dispatched after the edit use new aliases. A names change does not break the comparison with the previous sweep: the definition identity behind it covers the project's own coverage and leaves competitor names out. Advanced plan revisions keep their own frozen competitor names (`measurement-plan advanced ... draft-action` with `upsert-competitor`); pinning a tracked competitor into a market by domain alone copies its curated aliases into the draft.
431
436
  - REST: `PUT /api/v1/projects/{name}/competitors/{domain}/aliases` with `{ "aliases": [...] }` (exact set, idempotent, audited as `competitors.aliases-updated`); `POST /competitors` accepts `{ domain, aliases }` entries (aliases are added). `PUT /competitors` (domain replace) keeps the aliases of domains that stay. Deletes record the discarded aliases on the audit row. MCP: `canonry_competitors_aliases_set` and `canonry_competitors_add` with `{ domain, aliases }` entries (setup toolkit).
432
- - Config-as-code: a `spec.competitors` entry is a domain string or `{ domain, aliases }`. A string keeps that competitor's stored aliases (no opinion); an object sets them exactly, and `aliases: []` clears them. `cnry export` writes aliased competitors as objects, so export then apply round-trips.
437
+ - Config-as-code: a `spec.competitors` entry is a domain string or `{ domain, aliases }`. A string keeps that competitor's stored aliases (no opinion); an object sets them exactly, and `aliases: []` clears them. `cnry export` writes aliased competitors as objects, so export then apply round-trips. Auto-detected and blocked names are not part of a config spec: apply keeps them for competitors that stay.
438
+
439
+ ### Answer-derived auto aliases
440
+
441
+ Canonry also learns competitor names from the project's own stored answers, never from a competitor's website and never with a live call. The local server queues a pass after every completed or partial sweep (probes excluded), when a competitor is added (REST, apply or discovery promote), when a name is unblocked, and when a market pin write changes the pins; a curated alias edit, a competitor removal, a block and a project edit queue none. What the pass does follows the project's `competitorAutoAliases` mode (`cnry project update <project> --competitor-auto-aliases <mode>`, `spec.competitorAutoAliases` in apply, shown by `project show`):
442
+
443
+ - `preview` (every project's default, existing ones included): the pass scores the answers and logs what it would add or remove, and stores nothing. `detect` (dry run) shows the same evidence.
444
+ - `apply`: the pass stores the names that qualify.
445
+ - `off`: no pass runs.
446
+ - `cnry competitor aliases detect <project> --apply` stores one pass's result in every mode (a one-off apply). Switching to `apply` takes effect at the next queued pass (the next sweep, competitor add, unblock or pin change); `detect --apply` stores now. Switching to `preview` or `off` never deletes names already stored; block them to remove them.
447
+ - Restatement: the read-time competitor matchers use the names the project has now, so a names change restates every period they read, months already reported included. Frozen names are not restated: a Simple definition keeps the names it froze at dispatch, and Advanced measurement reports read each revision's own names. The competitor landscape, project-frame `visibility-compare` and analytics metrics responses carry `competitorIdentityChangedAt` (null if never): the newest change to a tracked competitor's curated or stored auto names (a block counts only when it removes a stored name), a detection pass that stores or removes a market-only competitor's learned names, a write that claims, releases or drops a market-only competitor's learned names (project edit, apply, competitor add, alias edit, block, unblock or removal, discovery promote, market pin write), or a published revision that renames a market pin. The landscape reads all of these names; `visibility-compare` share of voice and analytics mention share read only tracked competitors' names, so a pin or learned-name change moves the time without changing them. A scoped `visibility-compare` (a group, market or property scope, or a `marketKey`) reads frozen plan history and has no such field. A figure quoted before that time may differ from the same period read now.
448
+
449
+ - Evidence: a direct pair is an answer tying a name to the competitor's site: a provider citation anchoring the text that names it to a page on the domain (OpenAI annotations, Claude citations, Gemini grounding supports, Perplexity `[N]` markers), a named link `[TuneSpoke](https://spoketuneworks.example/...)`, or `TuneSpoke (spoketuneworks.example)` / `TuneSpoke - spoketuneworks.example`. A co-occurrence (the answer cites the site and lists the name elsewhere) is reported but never enough on its own. An answer names a candidate only where it writes it outside the competitor's longer names (its domain label, a curated alias, a longer stored name, and for a market-only competitor its plan label and aliases): an answer that writes only "Lark Bay Suites" does not name "Lark Bay". Of the scanned answers that name it: precision is the share citing the competitor's site; lift is how many times more often they cite it than the answers that do not name it (smoothed); name casing is how many write it capitalized as a name. Lift and casing are what reject generic phrases: a much-cited competitor gives any phrase near it a high precision, but naming a phrase barely moves its citation rate, and answers write a phrase in lowercase.
450
+ - Applied when: direct pairs in at least 2 answers from at least 2 sweeps (runs started together, one multi-location sweep, count once); at least 3 answers name it; precision at least 10%; lift at least 3; written as a name in at least 75% of them; it reads as a business name (at most 6 capitalized words, no `% + ? : / |`, no host, not a heading such as "Why ..." or "Top ...", a leading number only before a capitalized singular word such as "1 Spoke Lane", and not written as a place: "Larkfield, CO", "Larkfield, Colorado", "Oakvale County", "Metro Larkfield", "Downtown Larkfield", "West LA"); a brand key of at least 4 letters or digits; this competitor has at least twice the pairs of any other tracked competitor; and it visibly belongs to the domain. That tie holds when consecutive whole words of the name spell the domain label ("Spoke Garage Bikes" for `spokegarage.example`); when a name of two or more words opens the label whole, at its start or right after a lead word (my, the, get, try, go, use, hey, join, shop, visit), and covers at least half of it ("SpokeIQ" for `myspokeiq.example`); when two or more of its words sit back to back in the label from that opening and cover at least half of it, one of them 4 or more letters long and inside fewer than two tracked identity labels (the project's and every competitor's), so a shared industry word such as "roofing" proves nothing ("TuneSpoke" for `spoketuneworks.example`); or when a name of two or more words is an in-order abbreviation of the label that opens like it, with the same first 4 letters or a first word of 3 or more letters the label starts with ("FoamSeal" for `foamandsealworks.example`). One shared word never ties a name to the domain unless it is the whole label: a city the label opens or ends with ("Larkfield" for `larkfieldroofing.example`), a neighbour sharing the label's first word ("Rim Doctor" for `doctorspokes.example`) and a one-word brand shorter than its label ("Acme" for `acmecycles.example`) all go to review.
451
+ - Review: a candidate that passes everything except that tie (`no-label-affinity`) or the 4-character floor (`needs-approval`) is listed as `review` only, after checks at the 3-character floor against the project's names and hosts, other competitors' domain labels, hosts and curated aliases, market pins of another domain, blocks, and the competitor's own names and planned auto names. Unlike applied names, review names are not checked against other competitors' auto-detected names, so a name another competitor stores can still be listed. Such lists still mix the competitor's real names with its partners, rivals and services, and a one-word city or a longer region name has no place shape and can appear, so check that the name refers to that competitor in the answers, then add it with `--add` (never `--set`, which replaces the curated list).
452
+ - Never applied: a blocked name; a name the competitor's own identity already matches as complete words (`already-matched`: its domain label, a curated alias, a kept auto name, or a name of its own active or draft Advanced pin, so "Velo Hub Springfield" is not learned under the pin "Velo Hub"; a superseded revision's pin does not count); a name overlapping the project, another competitor's curated identity, or the names of an Advanced market pin of another domain (active, draft, or a superseded revision the project's runs were measured under) (curated always wins); a longer variant of an applied name (`subsumed`: blocking the short name frees the longer ones). At most 10 auto names per competitor: stored names first, then new names strongest evidence first (`over-limit` for the rest).
453
+ - Stored names are sticky: one is removed only when blocked; claimed by identity (the competitor's own curated aliases or domain label already cover it, `already-matched`; it overlaps the project's names or hosts, `project-brand`; or it overlaps another competitor's domain label, host or curated alias, a market pin of another domain, or, after an identity change, another competitor's stored auto name that resolves first (tracked competitors before market-only ones, each in domain order), `other-competitor`); replaced by an accepted shorter name it is built on (`subsumed`); or contradicted by the scanned answers: named in 3+ with precision under 5%, lift under 1.5, or written as a name in under half; another tracked competitor now pairing it in at least 2 answers and at least twice as often as this one (`other-competitor-dominates`); or no tie to the domain label left, judged on the stored spelling (`no-label-affinity`). A tracked competitor's own pin never removes a stored name; a market-only competitor's active pin names are its curated names and do (`already-matched`).
454
+ - Blocking: `--block` removes a stored auto name and keeps it out of detection. The block outlives the row: `competitor remove` keeps it, and the next `competitor add` of that domain (or an apply that re-adds it, or a market-only pin promoted to a competitor) starts with it. A curated alias cannot be blocked (remove it with `--remove`), and neither can a name the measurement plan's own pin of that competitor carries (active revision or pending draft): the pin keeps counting it, so change the pin's names in a measurement draft.
455
+ - Scan: the newest 60 completed or partial answer-visibility runs (probes excluded) and at most 6000 snapshots, stopping inside a run when the cap falls there. One pass per project at a time: an apply-now waits for a running storing pass and runs after it. A names change is audited (`competitors.auto-aliases-updated`, actor `system`; an apply-now that changed names also writes `competitors.auto-aliases-apply-requested` with who asked) and recomputes the stored competitor columns in the background. Matchers and frozen Simple definitions (for runs dispatched afterward) use curated + auto minus blocked. An Advanced pin by domain alone copies only the curated aliases; auto and learned names are layered onto it when answers are read, never frozen into a revision, so a later block can still take them back.
456
+ - Advanced: a competitor the active plan pins in a market without tracking it project-wide is detected from that market's answers only, its plan label and aliases count as its curated names, and its learned names apply only where a run's plan revision pins it (never as a project competitor). `detect` lists it with `(Advanced markets: ...)` and `marketKeys` in JSON; `--block` / `--unblock` work on it by domain, and on a domain a later revision stopped pinning while its learned or blocked names are still stored. `competitor aliases <project> <domain>` without a flag reads project competitors only; for a market-only competitor use `detect`.
457
+ - Aero can run the dry run (`canonry_competitors_auto_aliases_detect`) but never applies: `canonry_competitors_auto_aliases_apply` is not in its catalog, and it cannot change a project's `competitorAutoAliases` mode. Applying and switching a project to `apply` stay operator actions.
458
+ - REST: `GET` / `POST /api/v1/projects/{name}/competitor-auto-aliases` (dry run / apply), `POST /api/v1/projects/{name}/competitors/{domain}/aliases/block` and `/unblock` with `{ "aliases": [...] }`. MCP: `canonry_competitors_auto_aliases_detect` (read), `canonry_competitors_auto_aliases_apply`, `canonry_competitors_aliases_block`, `canonry_competitors_aliases_unblock` (setup toolkit). `detect` is a reserved word after `competitor aliases`.
433
459
 
434
460
  ```yaml
435
461
  spec:
@@ -1 +1 @@
1
- import{r as a,u as h,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{dC as L,dD as P,cx as E,x as u,B as x,v,T as M}from"./index-BhXHm5nG.js";const o=100;function k(s){if(s==="all")return;const n=Number.parseInt(s,10);return new Date(Date.now()-n*24*60*60*1e3).toISOString()}function D(s){const n=s.userAgent?.toLowerCase()??"";return n.includes("canonry-mcp")?"MCP":n.includes("canonry-cli")?"CLI":n.includes("mozilla/")?"Dashboard":s.actor==="scheduler"?"Scheduler":s.actor==="agent"?"Agent":s.actor==="mcp"?"MCP":s.actor==="cli"?"CLI":s.actor}function O(s){return/delete|remove|revoke|disconnect|failed/.test(s)?"negative":/create|add|connect|completed/.test(s)?"positive":/update|replace|sync|apply/.test(s)?"caution":"neutral"}function B(s){return[s.action,s.actor,s.entityType,s.entityId,s.actorSession,s.userAgent,s.diff==null?"":JSON.stringify(s.diff)].filter(Boolean).join(" ").toLowerCase()}function H({projectName:s}){const[n,l]=a.useState(0),[c,y]=a.useState("90d"),[m,N]=a.useState(""),[p,w]=a.useState(""),C=a.useMemo(()=>k(c),[c]),g={limit:o,offset:n*o,since:C,actor:m||void 0},S=h({...L({client:u,path:{name:s??""},query:g}),enabled:!!s}),A=h({...P({client:u,query:g}),enabled:!s}),f=h({...E({client:u}),enabled:!s}),i=s?S:A,r=i.data??[],I=a.useMemo(()=>new Map((f.data??[]).map(t=>[t.id,t.displayName||t.name])),[f.data]),d=p.trim().toLowerCase(),j=a.useMemo(()=>d?r.filter(t=>B(t).includes(d)):r,[r,d]),b=t=>{l(0),t()};return i.isLoading?e.jsx("p",{className:"supporting-copy mt-6",role:"status",children:"Loading change history…"}):e.jsxs("section",{className:"mt-6","aria-labelledby":"change-history-heading",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Audit trail"}),e.jsx("h2",{id:"change-history-heading",children:"Change history"}),e.jsx("p",{className:"supporting-copy mt-1 max-w-2xl",children:"Configuration and operator actions. Execution outcomes remain in Runs."})]}),e.jsx(x,{type:"button",variant:"outline",size:"sm",onClick:()=>{i.refetch()},disabled:i.isFetching,children:i.isFetching?"Refreshing…":"Refresh"})]}),e.jsxs("div",{className:"mt-4 grid gap-2 sm:grid-cols-3",children:[e.jsx("input",{type:"search","aria-label":"Search change history",value:p,onChange:t=>w(t.target.value),placeholder:"Search actions, entities, or details",className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong placeholder-mono-600 focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600"}),e.jsxs("select",{"aria-label":"Filter change history by actor",value:m,onChange:t=>b(()=>N(t.target.value)),className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"",children:"All actors"}),e.jsx("option",{value:"api",children:"API and dashboard"}),e.jsx("option",{value:"cli",children:"CLI"}),e.jsx("option",{value:"scheduler",children:"Scheduler"}),e.jsx("option",{value:"agent",children:"Agent"}),e.jsx("option",{value:"mcp",children:"MCP"})]}),e.jsxs("select",{"aria-label":"Filter change history by date range",value:c,onChange:t=>b(()=>y(t.target.value)),className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"30d",children:"Last 30 days"}),e.jsx("option",{value:"90d",children:"Last 90 days"}),e.jsx("option",{value:"365d",children:"Last year"}),e.jsx("option",{value:"all",children:"All retained history"})]})]}),i.isError?e.jsxs(v,{className:"surface-card empty-card mt-4",children:[e.jsx("h3",{children:"Change history unavailable"}),e.jsx("p",{children:i.error instanceof Error?i.error.message:"Could not load the audit trail."})]}):j.length===0?e.jsxs(v,{className:"surface-card empty-card mt-4",children:[e.jsx("h3",{children:"No changes match these filters"}),e.jsx("p",{children:"Widen the date range or clear the actor and search filters."})]}):e.jsx("div",{className:"evidence-table-wrap mt-4",children:e.jsxs("table",{className:"evidence-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"When"}),s?null:e.jsx("th",{children:"Scope"}),e.jsx("th",{children:"Action"}),e.jsx("th",{children:"Entity"}),e.jsx("th",{children:"Origin"}),e.jsx("th",{children:"Details"})]})}),e.jsx("tbody",{children:j.map(t=>e.jsxs("tr",{children:[e.jsx("td",{className:"whitespace-nowrap tabular-nums text-muted",children:new Date(t.createdAt).toLocaleString()}),s?null:e.jsx("td",{className:"text-secondary",children:t.projectId?I.get(t.projectId)??`Deleted project · ${t.projectId}`:"Instance settings"}),e.jsx("td",{children:e.jsx(M,{tone:O(t.action),children:t.action})}),e.jsxs("td",{children:[e.jsx("span",{className:"text-strong",children:t.entityType}),t.entityId?e.jsx("span",{className:"mt-0.5 block max-w-48 truncate font-mono text-[11px] text-faint",title:t.entityId,children:t.entityId}):null]}),e.jsxs("td",{children:[e.jsx("span",{className:"text-secondary",children:D(t)}),t.actorSession?e.jsxs("span",{className:"mt-0.5 block max-w-40 truncate font-mono text-[11px] text-faint",title:t.actorSession,children:["Session ",t.actorSession]}):null]}),e.jsx("td",{children:t.diff==null?e.jsx("span",{className:"text-faint",children:"No field diff"}):e.jsxs("details",{children:[e.jsx("summary",{className:"min-h-11 cursor-pointer py-3 text-sm text-secondary hover:text-strong",children:"View diff"}),e.jsx("pre",{className:"max-h-72 max-w-xl overflow-auto whitespace-pre-wrap break-words rounded-md bg-bg-elevated p-3 text-xs text-secondary",children:JSON.stringify(t.diff,null,2)})]})})]},t.id))})]})}),!i.isError&&(n>0||r.length===o)?e.jsxs("div",{className:"mt-4 flex items-center justify-between gap-3",children:[e.jsx(x,{type:"button",variant:"outline",size:"sm",disabled:n===0,onClick:()=>l(t=>Math.max(0,t-1)),children:"Previous"}),e.jsxs("span",{className:"text-xs tabular-nums text-muted",children:["Page ",n+1]}),e.jsx(x,{type:"button",variant:"outline",size:"sm",disabled:r.length<o,onClick:()=>l(t=>t+1),children:"Next"})]}):null]})}export{H as A};
1
+ import{r as a,u as h,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{dA as L,dB as P,cx as E,x as u,B as x,v,T as M}from"./index-BJh8cX5E.js";const o=100;function k(s){if(s==="all")return;const n=Number.parseInt(s,10);return new Date(Date.now()-n*24*60*60*1e3).toISOString()}function B(s){const n=s.userAgent?.toLowerCase()??"";return n.includes("canonry-mcp")?"MCP":n.includes("canonry-cli")?"CLI":n.includes("mozilla/")?"Dashboard":s.actor==="scheduler"?"Scheduler":s.actor==="agent"?"Agent":s.actor==="mcp"?"MCP":s.actor==="cli"?"CLI":s.actor}function O(s){return/delete|remove|revoke|disconnect|failed/.test(s)?"negative":/create|add|connect|completed/.test(s)?"positive":/update|replace|sync|apply/.test(s)?"caution":"neutral"}function D(s){return[s.action,s.actor,s.entityType,s.entityId,s.actorSession,s.userAgent,s.diff==null?"":JSON.stringify(s.diff)].filter(Boolean).join(" ").toLowerCase()}function H({projectName:s}){const[n,l]=a.useState(0),[c,y]=a.useState("90d"),[m,N]=a.useState(""),[p,w]=a.useState(""),S=a.useMemo(()=>k(c),[c]),g={limit:o,offset:n*o,since:S,actor:m||void 0},C=h({...L({client:u,path:{name:s??""},query:g}),enabled:!!s}),A=h({...P({client:u,query:g}),enabled:!s}),f=h({...E({client:u}),enabled:!s}),i=s?C:A,r=i.data??[],I=a.useMemo(()=>new Map((f.data??[]).map(t=>[t.id,t.displayName||t.name])),[f.data]),d=p.trim().toLowerCase(),j=a.useMemo(()=>d?r.filter(t=>D(t).includes(d)):r,[r,d]),b=t=>{l(0),t()};return i.isLoading?e.jsx("p",{className:"supporting-copy mt-6",role:"status",children:"Loading change history…"}):e.jsxs("section",{className:"mt-6","aria-labelledby":"change-history-heading",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Audit trail"}),e.jsx("h2",{id:"change-history-heading",children:"Change history"}),e.jsx("p",{className:"supporting-copy mt-1 max-w-2xl",children:"Configuration and operator actions. Execution outcomes remain in Runs."})]}),e.jsx(x,{type:"button",variant:"outline",size:"sm",onClick:()=>{i.refetch()},disabled:i.isFetching,children:i.isFetching?"Refreshing…":"Refresh"})]}),e.jsxs("div",{className:"mt-4 grid gap-2 sm:grid-cols-3",children:[e.jsx("input",{type:"search","aria-label":"Search change history",value:p,onChange:t=>w(t.target.value),placeholder:"Search actions, entities, or details",className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong placeholder-mono-600 focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600"}),e.jsxs("select",{"aria-label":"Filter change history by actor",value:m,onChange:t=>b(()=>N(t.target.value)),className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"",children:"All actors"}),e.jsx("option",{value:"api",children:"API and dashboard"}),e.jsx("option",{value:"cli",children:"CLI"}),e.jsx("option",{value:"scheduler",children:"Scheduler"}),e.jsx("option",{value:"agent",children:"Agent"}),e.jsx("option",{value:"mcp",children:"MCP"})]}),e.jsxs("select",{"aria-label":"Filter change history by date range",value:c,onChange:t=>b(()=>y(t.target.value)),className:"min-h-11 rounded-md border border-base bg-bg px-3 text-sm text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-600",children:[e.jsx("option",{value:"30d",children:"Last 30 days"}),e.jsx("option",{value:"90d",children:"Last 90 days"}),e.jsx("option",{value:"365d",children:"Last year"}),e.jsx("option",{value:"all",children:"All retained history"})]})]}),i.isError?e.jsxs(v,{className:"surface-card empty-card mt-4",children:[e.jsx("h3",{children:"Change history unavailable"}),e.jsx("p",{children:i.error instanceof Error?i.error.message:"Could not load the audit trail."})]}):j.length===0?e.jsxs(v,{className:"surface-card empty-card mt-4",children:[e.jsx("h3",{children:"No changes match these filters"}),e.jsx("p",{children:"Widen the date range or clear the actor and search filters."})]}):e.jsx("div",{className:"evidence-table-wrap mt-4",children:e.jsxs("table",{className:"evidence-table",children:[e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"When"}),s?null:e.jsx("th",{children:"Scope"}),e.jsx("th",{children:"Action"}),e.jsx("th",{children:"Entity"}),e.jsx("th",{children:"Origin"}),e.jsx("th",{children:"Details"})]})}),e.jsx("tbody",{children:j.map(t=>e.jsxs("tr",{children:[e.jsx("td",{className:"whitespace-nowrap tabular-nums text-muted",children:new Date(t.createdAt).toLocaleString()}),s?null:e.jsx("td",{className:"text-secondary",children:t.projectId?I.get(t.projectId)??`Deleted project · ${t.projectId}`:"Instance settings"}),e.jsx("td",{children:e.jsx(M,{tone:O(t.action),children:t.action})}),e.jsxs("td",{children:[e.jsx("span",{className:"text-strong",children:t.entityType}),t.entityId?e.jsx("span",{className:"mt-0.5 block max-w-48 truncate font-mono text-[11px] text-faint",title:t.entityId,children:t.entityId}):null]}),e.jsxs("td",{children:[e.jsx("span",{className:"text-secondary",children:B(t)}),t.actorSession?e.jsxs("span",{className:"mt-0.5 block max-w-40 truncate font-mono text-[11px] text-faint",title:t.actorSession,children:["Session ",t.actorSession]}):null]}),e.jsx("td",{children:t.diff==null?e.jsx("span",{className:"text-faint",children:"No field diff"}):e.jsxs("details",{children:[e.jsx("summary",{className:"min-h-11 cursor-pointer py-3 text-sm text-secondary hover:text-strong",children:"View diff"}),e.jsx("pre",{className:"max-h-72 max-w-xl overflow-auto whitespace-pre-wrap break-words rounded-md bg-bg-elevated p-3 text-xs text-secondary",children:JSON.stringify(t.diff,null,2)})]})})]},t.id))})]})}),!i.isError&&(n>0||r.length===o)?e.jsxs("div",{className:"mt-4 flex items-center justify-between gap-3",children:[e.jsx(x,{type:"button",variant:"outline",size:"sm",disabled:n===0,onClick:()=>l(t=>Math.max(0,t-1)),children:"Previous"}),e.jsxs("span",{className:"text-xs tabular-nums text-muted",children:["Page ",n+1]}),e.jsx(x,{type:"button",variant:"outline",size:"sm",disabled:r.length<o,onClick:()=>l(t=>t+1),children:"Next"})]}):null]})}export{H as A};
@@ -1 +1 @@
1
- import{r as n,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{dR as _,ay as H,dS as U,dT as V,dU as J,v as x,T as j,y as u,B as w,D as P,dV as K,dW as X,aB as Y,dX as Z}from"./index-BhXHm5nG.js";import{I as ee,T as se,E as te,j as ae,O as ne,J as re}from"./vendor-lucide-N6vOpZmh.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";function g({children:t,label:h="More info",placement:a="top",className:i}){const d=n.useId(),[y,c]=n.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${i??""}`,children:[e.jsx("button",{type:"button","aria-label":h,"aria-describedby":y?d:void 0,className:"inline-flex h-4 w-4 items-center justify-center rounded-full text-muted hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:e.jsx(re,{className:"h-3.5 w-3.5","aria-hidden":!0})}),y&&e.jsx("span",{id:d,role:"tooltip",className:`absolute z-50 w-64 rounded border border-strong bg-bg-elevated px-3 py-2 text-xs font-normal leading-relaxed text-strong shadow-lg ${a==="top"?"bottom-full mb-2":"top-full mt-2"} left-1/2 -translate-x-1/2 whitespace-normal`,children:t})]})}const le="https://commoncrawl.org/web-graphs";function S(t){return t==null?"—":t>=1e12?`${(t/1e12).toFixed(1)} TB`:t>=1e9?`${(t/1e9).toFixed(1)} GB`:t>=1e6?`${(t/1e6).toFixed(1)} MB`:t>=1e3?`${(t/1e3).toFixed(1)} KB`:`${t} B`}function b(t){if(!t)return"—";const h=Date.now()-new Date(t).getTime(),a=Math.floor(h/6e4);if(a<1)return"just now";if(a<60)return`${a}m ago`;const i=Math.floor(a/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function C(t){switch(t){case"ready":return"positive";case"failed":return"negative";case"downloading":case"querying":case"queued":return"caution"}}function me(){const[t,h]=n.useState(null),[a,i]=n.useState(null),[d,y]=n.useState([]),[c,$]=n.useState([]),[m,L]=n.useState(null),[B,D]=n.useState(!0),[R,I]=n.useState(!1),[p,E]=n.useState(!1),[N,v]=n.useState(""),[T,k]=n.useState(!1),[A,l]=n.useState(null),[F,o]=n.useState(null),f=n.useCallback(async()=>{D(!0),l(null);try{const[s,r,Q,W,z]=await Promise.all([_(),H().catch(()=>null),U().catch(()=>[]),V().catch(()=>[]),J().catch(()=>null)]);h(s),i(r),y(Q),$(W),L(z)}catch(s){l(s instanceof Error?s.message:"Failed to load backlinks status")}finally{D(!1)}},[]);n.useEffect(()=>{f()},[f]);async function M(){I(!0),l(null),o(null);try{const s=await K();o(s.alreadyPresent?`DuckDB already installed (${s.version}).`:`Installed DuckDB ${s.version}.`),await f()}catch(s){l(s instanceof Error?s.message:"Failed to install DuckDB")}finally{I(!1)}}async function q(){const s=N.trim()||void 0;E(!0),l(null),o(null);try{const r=await X(s);o(s?`Queued sync for ${r.release}. Download + query runs in the background.`:`Queued sync for auto-discovered release ${r.release}. Download + query runs in the background.`),v(""),k(!1),await f()}catch(r){r instanceof Y&&r.code==="MISSING_DEPENDENCY"?l("DuckDB is not installed. Install it first."):l(r instanceof Error?r.message:"Failed to trigger sync")}finally{E(!1)}}async function G(s){l(null),o(null);try{await Z(s),o(`Pruned cached release ${s}.`),await f()}catch(r){l(r instanceof Error?r.message:"Failed to prune release")}}const O=a?.status==="ready"&&c.every(s=>s.release!==a.release);return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"Backlink data"}),e.jsx("p",{className:"page-subtitle",children:"Manage the shared backlink source and review its latest data."})]})}),A&&e.jsx(x,{className:"surface-card p-4 mb-4 border-negative-800/60",children:e.jsx("p",{className:"text-sm text-negative",children:A})}),F&&e.jsx(x,{className:"surface-card p-4 mb-4 border-positive-800/60",children:e.jsx("p",{className:"text-sm text-positive",children:F})}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Readiness"}),e.jsx("h2",{children:"Backlink source"})]}),t?.duckdbInstalled?e.jsx(j,{tone:"positive",children:"Installed"}):e.jsx(j,{tone:"caution",children:"Not installed"})]}),e.jsx(x,{className:"surface-card p-4",children:B?e.jsx("p",{className:"text-sm text-muted",children:"Checking…"}):t?.duckdbInstalled?e.jsx("p",{className:"text-sm text-secondary",children:"Ready to sync a Common Crawl release."}):e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("p",{className:"text-sm text-secondary",children:"Install the local query engine to enable release syncs."}),!u()&&e.jsxs(w,{type:"button",size:"sm",disabled:R,onClick:P(M),children:[e.jsx(ee,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),R?"Installing…":"Install DuckDB"]})]})})]}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Latest sync"}),e.jsxs("h2",{className:"flex items-center gap-2",children:["Release sync",e.jsx(g,{label:"What is a release sync?",children:"A release sync downloads one Common Crawl dump (~16 GB) and extracts backlinks for every project in this workspace in one pass. This is the heavy job — subsequent per-project re-runs skip the download and just re-query the cached files."})]})]}),a&&e.jsx(j,{tone:C(a.status),children:a.status})]}),e.jsxs(x,{className:"surface-card p-5",children:[a?e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("p",{className:"text-strong",children:["Release ",e.jsx("code",{className:"text-neutral",children:a.release})]}),a.phaseDetail&&e.jsx("p",{className:"text-secondary",children:a.phaseDetail}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-xs text-muted pt-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Projects"}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.projectsProcessed??"—"})]}),e.jsxs("div",{children:[e.jsxs("p",{className:"text-faint uppercase tracking-wide flex items-center gap-1",children:["Rows",e.jsx(g,{label:"What are rows?",children:"Total number of (project, referring domain) pairs persisted in SQLite from this sync, across every project in the workspace."})]}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.domainsDiscovered??"—"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Started"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.downloadStartedAt??a.createdAt)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Finished"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.queryFinishedAt)})]})]}),a.error&&e.jsx("p",{className:"text-sm text-negative-400 pt-2",children:a.error})]}):e.jsx("p",{className:"text-sm text-muted",children:"No release sync has run in this workspace yet."}),O&&e.jsx("div",{className:"mt-4 rounded border border-caution-800/60 bg-caution-950/20 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(se,{className:"h-4 w-4 text-caution-400 shrink-0 mt-0.5","aria-hidden":!0}),e.jsxs("div",{className:"text-sm text-neutral leading-relaxed",children:[e.jsx("p",{className:"font-medium text-caution-200",children:"Cached files for this release are missing."}),e.jsx("p",{className:"mt-1 text-secondary",children:"Sync this release again, or sync the newest release, before refreshing individual projects."})]})]})}),e.jsxs("div",{className:"mt-4 rounded border border-base bg-bg-elevated/40 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted",children:"Auto-detected release"}),m?e.jsxs("p",{className:"text-sm text-strong mt-0.5",children:[e.jsx("code",{className:"text-heading",children:m.release}),e.jsxs("span",{className:"ml-2 text-xs text-muted",children:["Vertex ",S(m.vertexBytes),", edges ",S(m.edgesBytes)]})]}):e.jsx("p",{className:"text-sm text-muted mt-0.5",children:B?"Checking Common Crawl…":"Could not find a release. Choose one below."}),e.jsxs("a",{href:le,target:"_blank",rel:"noopener noreferrer",className:"mt-1 inline-flex items-center gap-1 text-xs text-secondary hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:["Browse all Common Crawl web-graph releases",e.jsx(te,{className:"h-3 w-3","aria-hidden":!0})]})]}),!u()&&e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsxs(w,{type:"button",size:"sm",disabled:p||!t?.duckdbInstalled||!m&&!N.trim(),onClick:P(q),children:[e.jsx(ae,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),p?"Queuing…":"Run sync"]}),e.jsxs(g,{label:"What does Run sync do?",children:[e.jsxs("span",{className:"block",children:["Downloads the auto-detected (or chosen) Common Crawl release (~16 GB) to"," ",e.jsx("code",{className:"text-neutral",children:"~/.canonry/cache/commoncrawl/"}),", then runs a single DuckDB query that extracts referring domains for every project in this workspace."]}),e.jsxs("span",{className:"mt-2 block text-secondary",children:["First time for a release: ",e.jsx("span",{className:"text-strong",children:"~10–20 min download + ~5 min query"}),". Re-running the same release later: ",e.jsx("span",{className:"text-strong",children:"skips download, just re-queries"})," (~5 min)."]})]})]})]}),u()?null:T?e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",className:"flex-1 min-w-[240px] rounded border border-strong bg-transparent px-2.5 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none",placeholder:"cc-main-2026-jan-feb-mar",value:N,onChange:s=>v(s.target.value),disabled:p,autoFocus:!0}),e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>{v(""),k(!1)},disabled:p,children:"Cancel"})]}):e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>k(!0),disabled:p,children:"Use a different release →"})]}),!t?.duckdbInstalled&&e.jsx("p",{className:"text-sm text-secondary mt-2",children:"Install DuckDB first to enable sync."})]})]}),e.jsxs("details",{className:"page-section-divider group",children:[e.jsx("summary",{className:"cursor-pointer text-sm font-medium text-secondary hover:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:"Technical details and cache"}),e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-secondary mb-3",children:"Cached releases support project re-extracts. Pruning a release does not remove saved backlink results."}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Sync status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Size"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Last used"}),!u()&&e.jsx("th",{className:"px-4 py-2 font-medium sr-only",children:"Actions"})]})}),e.jsxs("tbody",{children:[c.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:s.syncStatus?e.jsx(j,{tone:C(s.syncStatus),children:s.syncStatus}):e.jsx("span",{className:"text-faint",children:"—"})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:S(s.bytes)}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.lastUsedAt)}),!u()&&e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsxs("div",{className:"inline-flex items-center gap-1",children:[e.jsxs(w,{type:"button",variant:"outline",size:"sm",onClick:()=>{G(s.release)},children:[e.jsx(ne,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),"Prune"]}),e.jsx(g,{label:"What does Prune do?",placement:"top",children:"Deletes the ~16 GB cache for this release from disk. Backlink results already in SQLite remain untouched. To re-run extracts against this release, you’d have to sync it again (another ~16 GB download)."})]})})]},s.release)),c.length===0&&e.jsx("tr",{children:e.jsx("td",{className:"px-4 py-4 text-sm text-muted",colSpan:u()?4:5,children:"No cached releases on this machine. If you ran a sync from a different machine (or deleted the cache), the backlink data is still in the database — but you’ll need to re-sync a release to run new extracts."})})]})]})}),e.jsx("p",{className:"mt-3 text-xs text-muted",children:"Common Crawl files are stored locally. DuckDB reads them; Canonry stores results in its normal database."})]})]}),d.length>1&&e.jsxs("section",{className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"History"}),e.jsx("h2",{children:"Past release syncs"})]})}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Projects"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Rows"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Finished"})]})}),e.jsx("tbody",{children:d.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:e.jsx(j,{tone:C(s.status),children:s.status})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.projectsProcessed??"—"}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.domainsDiscovered??"—"}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.queryFinishedAt??s.updatedAt)})]},s.id))})]})})]})]})}export{me as BacklinksPage};
1
+ import{r as n,j as e}from"./vendor-tanstack-ZXXkndVj.js";import{dP as _,ay as H,dQ as U,dR as V,dS as J,v as x,T as j,y as u,B as w,D as F,dT as K,dU as Y,aB as X,dV as Z}from"./index-BJh8cX5E.js";import{I as ee,T as se,E as te,j as ae,O as ne,J as re}from"./vendor-lucide-N6vOpZmh.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";function g({children:t,label:h="More info",placement:a="top",className:i}){const d=n.useId(),[y,c]=n.useState(!1);return e.jsxs("span",{className:`relative inline-flex ${i??""}`,children:[e.jsx("button",{type:"button","aria-label":h,"aria-describedby":y?d:void 0,className:"inline-flex h-4 w-4 items-center justify-center rounded-full text-muted hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500",onMouseEnter:()=>c(!0),onMouseLeave:()=>c(!1),onFocus:()=>c(!0),onBlur:()=>c(!1),children:e.jsx(re,{className:"h-3.5 w-3.5","aria-hidden":!0})}),y&&e.jsx("span",{id:d,role:"tooltip",className:`absolute z-50 w-64 rounded border border-strong bg-bg-elevated px-3 py-2 text-xs font-normal leading-relaxed text-strong shadow-lg ${a==="top"?"bottom-full mb-2":"top-full mt-2"} left-1/2 -translate-x-1/2 whitespace-normal`,children:t})]})}const le="https://commoncrawl.org/web-graphs";function S(t){return t==null?"—":t>=1e12?`${(t/1e12).toFixed(1)} TB`:t>=1e9?`${(t/1e9).toFixed(1)} GB`:t>=1e6?`${(t/1e6).toFixed(1)} MB`:t>=1e3?`${(t/1e3).toFixed(1)} KB`:`${t} B`}function b(t){if(!t)return"—";const h=Date.now()-new Date(t).getTime(),a=Math.floor(h/6e4);if(a<1)return"just now";if(a<60)return`${a}m ago`;const i=Math.floor(a/60);return i<24?`${i}h ago`:`${Math.floor(i/24)}d ago`}function C(t){switch(t){case"ready":return"positive";case"failed":return"negative";case"downloading":case"querying":case"queued":return"caution"}}function me(){const[t,h]=n.useState(null),[a,i]=n.useState(null),[d,y]=n.useState([]),[c,$]=n.useState([]),[m,L]=n.useState(null),[B,D]=n.useState(!0),[R,I]=n.useState(!1),[p,E]=n.useState(!1),[N,v]=n.useState(""),[T,k]=n.useState(!1),[A,l]=n.useState(null),[P,o]=n.useState(null),f=n.useCallback(async()=>{D(!0),l(null);try{const[s,r,O,z,W]=await Promise.all([_(),H().catch(()=>null),U().catch(()=>[]),V().catch(()=>[]),J().catch(()=>null)]);h(s),i(r),y(O),$(z),L(W)}catch(s){l(s instanceof Error?s.message:"Failed to load backlinks status")}finally{D(!1)}},[]);n.useEffect(()=>{f()},[f]);async function M(){I(!0),l(null),o(null);try{const s=await K();o(s.alreadyPresent?`DuckDB already installed (${s.version}).`:`Installed DuckDB ${s.version}.`),await f()}catch(s){l(s instanceof Error?s.message:"Failed to install DuckDB")}finally{I(!1)}}async function q(){const s=N.trim()||void 0;E(!0),l(null),o(null);try{const r=await Y(s);o(s?`Queued sync for ${r.release}. Download + query runs in the background.`:`Queued sync for auto-discovered release ${r.release}. Download + query runs in the background.`),v(""),k(!1),await f()}catch(r){r instanceof X&&r.code==="MISSING_DEPENDENCY"?l("DuckDB is not installed. Install it first."):l(r instanceof Error?r.message:"Failed to trigger sync")}finally{E(!1)}}async function Q(s){l(null),o(null);try{await Z(s),o(`Pruned cached release ${s}.`),await f()}catch(r){l(r instanceof Error?r.message:"Failed to prune release")}}const G=a?.status==="ready"&&c.every(s=>s.release!==a.release);return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"Backlink data"}),e.jsx("p",{className:"page-subtitle",children:"Manage the shared backlink source and review its latest data."})]})}),A&&e.jsx(x,{className:"surface-card p-4 mb-4 border-negative-800/60",children:e.jsx("p",{className:"text-sm text-negative",children:A})}),P&&e.jsx(x,{className:"surface-card p-4 mb-4 border-positive-800/60",children:e.jsx("p",{className:"text-sm text-positive",children:P})}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Readiness"}),e.jsx("h2",{children:"Backlink source"})]}),t?.duckdbInstalled?e.jsx(j,{tone:"positive",children:"Installed"}):e.jsx(j,{tone:"caution",children:"Not installed"})]}),e.jsx(x,{className:"surface-card p-4",children:B?e.jsx("p",{className:"text-sm text-muted",children:"Checking…"}):t?.duckdbInstalled?e.jsx("p",{className:"text-sm text-secondary",children:"Ready to sync a Common Crawl release."}):e.jsxs("div",{className:"flex items-center justify-between gap-4",children:[e.jsx("p",{className:"text-sm text-secondary",children:"Install the local query engine to enable release syncs."}),!u()&&e.jsxs(w,{type:"button",size:"sm",disabled:R,onClick:F(M),children:[e.jsx(ee,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),R?"Installing…":"Install DuckDB"]})]})})]}),e.jsxs("section",{className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Latest sync"}),e.jsxs("h2",{className:"flex items-center gap-2",children:["Release sync",e.jsx(g,{label:"What is a release sync?",children:"A release sync downloads one Common Crawl dump (~16 GB) and extracts backlinks for every project in this workspace in one pass. This is the heavy job — subsequent per-project re-runs skip the download and just re-query the cached files."})]})]}),a&&e.jsx(j,{tone:C(a.status),children:a.status})]}),e.jsxs(x,{className:"surface-card p-5",children:[a?e.jsxs("div",{className:"space-y-2 text-sm",children:[e.jsxs("p",{className:"text-strong",children:["Release ",e.jsx("code",{className:"text-neutral",children:a.release})]}),a.phaseDetail&&e.jsx("p",{className:"text-secondary",children:a.phaseDetail}),e.jsxs("div",{className:"grid grid-cols-2 md:grid-cols-4 gap-4 text-xs text-muted pt-2",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Projects"}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.projectsProcessed??"—"})]}),e.jsxs("div",{children:[e.jsxs("p",{className:"text-faint uppercase tracking-wide flex items-center gap-1",children:["Rows",e.jsx(g,{label:"What are rows?",children:"Total number of (project, referring domain) pairs persisted in SQLite from this sync, across every project in the workspace."})]}),e.jsx("p",{className:"text-neutral mt-0.5",children:a.domainsDiscovered??"—"})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Started"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.downloadStartedAt??a.createdAt)})]}),e.jsxs("div",{children:[e.jsx("p",{className:"text-faint uppercase tracking-wide",children:"Finished"}),e.jsx("p",{className:"text-neutral mt-0.5",children:b(a.queryFinishedAt)})]})]}),a.error&&e.jsx("p",{className:"text-sm text-negative-400 pt-2",children:a.error})]}):e.jsx("p",{className:"text-sm text-muted",children:"No release sync has run in this workspace yet."}),G&&e.jsx("div",{className:"mt-4 rounded border border-caution-800/60 bg-caution-950/20 p-3",children:e.jsxs("div",{className:"flex items-start gap-2",children:[e.jsx(se,{className:"h-4 w-4 text-caution-400 shrink-0 mt-0.5","aria-hidden":!0}),e.jsxs("div",{className:"text-sm text-neutral leading-relaxed",children:[e.jsx("p",{className:"font-medium text-caution-200",children:"Cached files for this release are missing."}),e.jsx("p",{className:"mt-1 text-secondary",children:"Sync this release again, or sync the newest release, before refreshing individual projects."})]})]})}),e.jsxs("div",{className:"mt-4 rounded border border-base bg-bg-elevated/40 p-3",children:[e.jsxs("div",{className:"flex items-start justify-between gap-3 mb-3",children:[e.jsxs("div",{children:[e.jsx("p",{className:"text-[10px] uppercase tracking-wide text-muted",children:"Auto-detected release"}),m?e.jsxs("p",{className:"text-sm text-strong mt-0.5",children:[e.jsx("code",{className:"text-heading",children:m.release}),e.jsxs("span",{className:"ml-2 text-xs text-muted",children:["Vertex ",S(m.vertexBytes),", edges ",S(m.edgesBytes)]})]}):e.jsx("p",{className:"text-sm text-muted mt-0.5",children:B?"Checking Common Crawl…":"Could not find a release. Choose one below."}),e.jsxs("a",{href:le,target:"_blank",rel:"noopener noreferrer",className:"mt-1 inline-flex items-center gap-1 text-xs text-secondary hover:text-strong focus:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:["Browse all Common Crawl web-graph releases",e.jsx(te,{className:"h-3 w-3","aria-hidden":!0})]})]}),!u()&&e.jsxs("div",{className:"flex items-center gap-2 shrink-0",children:[e.jsxs(w,{type:"button",size:"sm",disabled:p||!t?.duckdbInstalled||!m&&!N.trim(),onClick:F(q),children:[e.jsx(ae,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),p?"Queuing…":"Run sync"]}),e.jsxs(g,{label:"What does Run sync do?",children:[e.jsxs("span",{className:"block",children:["Downloads the auto-detected (or chosen) Common Crawl release (~16 GB) to"," ",e.jsx("code",{className:"text-neutral",children:"~/.canonry/cache/commoncrawl/"}),", then runs a single DuckDB query that extracts referring domains for every project in this workspace."]}),e.jsxs("span",{className:"mt-2 block text-secondary",children:["First time for a release: ",e.jsx("span",{className:"text-strong",children:"~10–20 min download + ~5 min query"}),". Re-running the same release later: ",e.jsx("span",{className:"text-strong",children:"skips download, just re-queries"})," (~5 min)."]})]})]})]}),u()?null:T?e.jsxs("div",{className:"flex flex-wrap items-center gap-2",children:[e.jsx("input",{type:"text",className:"flex-1 min-w-[240px] rounded border border-strong bg-transparent px-2.5 py-1.5 text-sm text-strong placeholder-mono-600 focus:border-mono-500 focus:outline-none",placeholder:"cc-main-2026-jan-feb-mar",value:N,onChange:s=>v(s.target.value),disabled:p,autoFocus:!0}),e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>{v(""),k(!1)},disabled:p,children:"Cancel"})]}):e.jsx("button",{type:"button",className:"text-sm text-secondary hover:text-neutral focus:text-neutral focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",onClick:()=>k(!0),disabled:p,children:"Use a different release →"})]}),!t?.duckdbInstalled&&e.jsx("p",{className:"text-sm text-secondary mt-2",children:"Install DuckDB first to enable sync."})]})]}),e.jsxs("details",{className:"page-section-divider group",children:[e.jsx("summary",{className:"cursor-pointer text-sm font-medium text-secondary hover:text-strong focus:outline-none focus-visible:ring-1 focus-visible:ring-mono-500 rounded",children:"Technical details and cache"}),e.jsxs("div",{className:"mt-4",children:[e.jsx("p",{className:"text-sm text-secondary mb-3",children:"Cached releases support project re-extracts. Pruning a release does not remove saved backlink results."}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Sync status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Size"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Last used"}),!u()&&e.jsx("th",{className:"px-4 py-2 font-medium sr-only",children:"Actions"})]})}),e.jsxs("tbody",{children:[c.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:s.syncStatus?e.jsx(j,{tone:C(s.syncStatus),children:s.syncStatus}):e.jsx("span",{className:"text-faint",children:"—"})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:S(s.bytes)}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.lastUsedAt)}),!u()&&e.jsx("td",{className:"px-4 py-2 text-right",children:e.jsxs("div",{className:"inline-flex items-center gap-1",children:[e.jsxs(w,{type:"button",variant:"outline",size:"sm",onClick:()=>{Q(s.release)},children:[e.jsx(ne,{className:"h-4 w-4 mr-1.5","aria-hidden":!0}),"Prune"]}),e.jsx(g,{label:"What does Prune do?",placement:"top",children:"Deletes the ~16 GB cache for this release from disk. Backlink results already in SQLite remain untouched. To re-run extracts against this release, you’d have to sync it again (another ~16 GB download)."})]})})]},s.release)),c.length===0&&e.jsx("tr",{children:e.jsx("td",{className:"px-4 py-4 text-sm text-muted",colSpan:u()?4:5,children:"No cached releases on this machine. If you ran a sync from a different machine (or deleted the cache), the backlink data is still in the database — but you’ll need to re-sync a release to run new extracts."})})]})]})}),e.jsx("p",{className:"mt-3 text-xs text-muted",children:"Common Crawl files are stored locally. DuckDB reads them; Canonry stores results in its normal database."})]})]}),d.length>1&&e.jsxs("section",{className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"History"}),e.jsx("h2",{children:"Past release syncs"})]})}),e.jsx(x,{className:"surface-card overflow-hidden",children:e.jsxs("table",{className:"w-full text-sm",children:[e.jsx("thead",{children:e.jsxs("tr",{className:"border-b border-base text-left text-xs uppercase tracking-wide text-faint",children:[e.jsx("th",{className:"px-4 py-2 font-medium",children:"Release"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Status"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Projects"}),e.jsx("th",{className:"px-4 py-2 text-right font-medium",children:"Rows"}),e.jsx("th",{className:"px-4 py-2 font-medium",children:"Finished"})]})}),e.jsx("tbody",{children:d.map(s=>e.jsxs("tr",{className:"border-b border-mono-900 last:border-0",children:[e.jsx("td",{className:"px-4 py-2 text-strong",children:e.jsx("code",{children:s.release})}),e.jsx("td",{className:"px-4 py-2",children:e.jsx(j,{tone:C(s.status),children:s.status})}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.projectsProcessed??"—"}),e.jsx("td",{className:"px-4 py-2 text-right text-secondary tabular-nums",children:s.domainsDiscovered??"—"}),e.jsx("td",{className:"px-4 py-2 text-secondary",children:b(s.queryFinishedAt??s.updatedAt)})]},s.id))})]})})]})]})}export{me as BacklinksPage};
@@ -1 +1 @@
1
- import{j as e}from"./vendor-tanstack-ZXXkndVj.js";import{A as s}from"./AuditHistoryPanel-BgcvPo6g.js";import"./index-BhXHm5nG.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-lucide-N6vOpZmh.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";function l(){return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"History"}),e.jsx("p",{className:"page-subtitle",children:"Changes to projects and settings."})]})}),e.jsx(s,{})]})}export{l as HistoryPage};
1
+ import{j as e}from"./vendor-tanstack-ZXXkndVj.js";import{A as s}from"./AuditHistoryPanel-Bpkuj-iF.js";import"./index-BJh8cX5E.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-lucide-N6vOpZmh.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";function l(){return e.jsxs("div",{className:"page-container",children:[e.jsx("div",{className:"page-header",children:e.jsxs("div",{className:"page-header-left",children:[e.jsx("h1",{className:"page-title",children:"History"}),e.jsx("p",{className:"page-subtitle",children:"Changes to projects and settings."})]})}),e.jsx(s,{})]})}export{l as HistoryPage};
@@ -1 +1 @@
1
- import{D as we,k as Pe,l as Ce,r as b,u as L,C as Ee,j as e,L as I}from"./vendor-tanstack-ZXXkndVj.js";import{cH as Le,d3 as Me,cA as Se,cy as Ae,L as Re,cT as Te,cO as z,eb as ke,ec as qe,x as M,ed as Ie,B as g,I as P,T as w,aK as ae,aL as ne,d9 as H,ee as Ue,ca as Be,ef as $e,eg as _e,j as Oe,s as Ve,f as ce,a$ as he}from"./index-BhXHm5nG.js";import{j as Ke,o as Qe}from"./ChartPrimitives-CYlrwLJs.js";import{m as Fe,a as me,M as ze,A as He}from"./v2-overview-adapter-QtI4xO_4.js";import{Z as De}from"./vendor-lucide-N6vOpZmh.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";const re=50,u={branded:{headline:"When they know your name",technical:"Branded queries"},"non-brand":{headline:"When they don't",technical:"Non-brand queries"}},We={plan_v1:"Setup update required",no_completed_run:"No completed measurement yet",no_population:"No queries of this type are assigned",evidence_incomplete:"Source evidence is incomplete",identity_ambiguous:Be,not_applicable:"Not applicable for this Property"},ie={complete:{label:"Measured",tone:"positive"},partial:{label:"Partly measured",tone:"caution"},running:{label:"Measuring now",tone:"neutral"},queued:{label:"Measurement queued",tone:"neutral"},failed:{label:"Measurement failed",tone:"negative"},not_measured:{label:"Not measured",tone:"neutral"}},oe={assigned:{label:"Matches this Property",tone:"positive"},sibling:{label:"Matches another Property",tone:"caution"},ownedUnmapped:{label:"Site URL not in a Property",tone:"caution"},external:{label:"External URL",tone:"neutral"},ambiguous:{label:"Matches multiple Properties",tone:"caution"},invalid:{label:"Invalid URL",tone:"negative"}};function Ge(s){return[...s].sort((t,a)=>+(a.classification==="assigned")-+(t.classification==="assigned"))}function Ye(s){return`${s.expectedSlotId}:${s.usageEdgeId}`}function Ze({row:s}){return s.mentioned===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(w,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"No mention signal for this Property"})]}):e.jsx(w,{tone:s.mentioned?"positive":"neutral",children:s.mentioned?"Mentioned":"Not mentioned"})}const Je="—";function Xe({row:s}){return s.cited===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(w,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"Sources were not fully captured"})]}):e.jsx(w,{tone:s.cited?"positive":"neutral",children:s.cited?"Cited":"Not cited"})}function es({row:s}){return s.cited===null&&s.sources.length===0?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"The sources for this answer were not fully captured, so none can be shown."}):s.sources.length===0?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer returned no source URLs at all."}):e.jsxs("details",{className:"mt-2","data-answer-sources":!0,children:[e.jsxs("summary",{className:"min-h-11 cursor-pointer py-3 text-sm text-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mono-400",children:[me," (",s.sources.length,")"]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsxs("caption",{className:"sr-only",children:["Source URLs for ",s.queryText]}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Match"}),e.jsx("th",{children:"URL"})]})}),e.jsx("tbody",{children:Ge(s.sources).map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx(w,{tone:oe[t.classification].tone,children:oe[t.classification].label})}),e.jsx("td",{children:e.jsx(Oe,{url:t.sourceUrl})})]},t.sourceUrl))})]})})]})}function ss({project:s,targetKey:t,row:a}){const r=L({..._e({client:M,path:{name:s},query:{targetKey:t,resultId:a.observationId}})});if(r.isPending)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"status","aria-live":"polite",children:"Loading the answer…"});if(r.isError)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"alert",children:"Could not load this answer."});const i=r.data?.answer;return i==null||i.trim()===""?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer was measured, but its text was not stored."}):e.jsx("div",{className:"py-2",children:e.jsx(He,{headingLevel:4,copyable:!0,children:i})})}function B(s){return We[s.reason]??"Not measured"}function U({metric:s,signal:t,emphasis:a=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:a?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:B(s)})]});const r=ce(s.value),i=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`,p=he(s,t);return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:a?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:r}),i?e.jsx("span",{className:"text-xs text-muted",children:i}):null,p?e.jsx("span",{className:"text-xs text-muted",children:p}):null]})}function le(s,t,a){return Ue({client:M,path:{name:s},query:{scope:"property",targetKey:t,queryClass:a}})}function de(s){return s?.properties.items.at(0)}function ts({measuredAt:s,unmeasuredReason:t,queryClass:a}){const r=s===void 0?null:s===null?"No completed sweep yet":`Measured ${Ke(Qe(s))}`;return r===null&&t===void 0?null:e.jsxs("p",{className:"supporting-copy",children:[[r,t].filter(Boolean).join(" · "),r!==null&&t===void 0?` · ${u[a].technical.toLocaleLowerCase()} only`:""]})}function as({project:s,groups:t}){return t.length===0?null:e.jsxs("section",{"aria-labelledby":"property-market",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Competitive comparison"}),e.jsxs("h2",{id:"property-market",className:"text-base font-semibold text-heading",children:["Measured at the market level",e.jsx(P,{text:"Competitors are attached to a market rather than to a single Property, because one building has nobody to be compared against. Share of voice and competitor pressure are reported for the market this Property sits in."})]})]}),e.jsx(g,{asChild:!0,type:"button",size:"sm",variant:"outline",children:e.jsx(I,{to:"/projects/$projectName",params:{projectName:s},search:a=>z(H(a),{measurementScope:"project"}),children:"Open measurement overview"})})]}),e.jsx("ul",{className:"flex flex-wrap gap-2",children:t.map(a=>e.jsxs("li",{className:"rounded-md border border-default px-3 py-1.5 text-sm text-strong",children:[a.label,e.jsxs("span",{className:"ml-2 text-xs text-muted",children:[a.competitors.length," ",a.competitors.length===1?"competitor":"competitors"]})]},a.stableKey))})]})}function q({label:s,metric:t,signal:a,failed:r=!1}){if(t===void 0)return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsx("p",{className:"aeo-hero-row-value text-base font-semibold text-secondary",children:r?"Unavailable":"…"}),r?e.jsx("div",{}):e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true"}),e.jsx("p",{className:"aeo-hero-row-detail",children:r?"Could not be loaded":"Loading"})]});if(t.state==="unavailable"){const c=B(t);return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsx("p",{className:"aeo-hero-row-value text-base font-semibold text-secondary",children:"Not measured"}),e.jsx("div",{}),e.jsx("p",{className:"aeo-hero-row-detail",children:c==="Not measured"?"":c})]})}const{figure:i,sign:p}=Ve(ce(t.value)),o=t.numerator===void 0||t.denominator===void 0?null:`${t.numerator} of ${t.denominator}`,l=he(t,a);return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsxs("p",{className:"aeo-hero-row-value text-heading",children:[i,p?e.jsx("span",{className:"text-faint",children:p}):null]}),e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true",children:e.jsx("div",{className:"metric-card-bar-fill progress-fill-neutral",style:{width:`${t.value*100}%`}})}),e.jsxs("p",{className:"aeo-hero-row-detail tabular-nums",children:[o??"",l?e.jsx("span",{className:"block",children:l}):null]})]})}function ns({branded:s,nonBrand:t,brandedFailed:a=!1,nonBrandFailed:r=!1}){return e.jsxs("section",{"aria-labelledby":"property-coverage-hero",children:[e.jsx("h2",{id:"property-coverage-hero",className:"sr-only",children:"Coverage for this Property"}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Non-brand · the demand to earn"}),e.jsx(q,{label:"Mentioned",metric:t?.mentionCoverage,signal:"mentioned",failed:r}),e.jsx(q,{label:"Cited",metric:t?.citationCoverage,signal:"cited",failed:r})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Branded · already named"}),e.jsx(q,{label:"Mentioned",metric:s?.mentionCoverage,signal:"mentioned",failed:a}),e.jsx(q,{label:"Cited",metric:s?.citationCoverage,signal:"cited",failed:a})]})]})]})}function rs({branded:s,nonBrand:t,brandedError:a,nonBrandError:r,onRetry:i}){const p=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:t,isError:r}];return e.jsxs("section",{"aria-labelledby":"property-brand-contrast",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"The gap"}),e.jsxs("h2",{id:"property-brand-contrast",className:"text-base font-semibold text-heading",children:["Named versus not named",e.jsx(P,{text:"Branded queries already contain your name, so an answer engine has an easy path back to you. Non-brand queries describe the need instead, and that is the demand you have to earn. Each row is measured only over the queries assigned to this Property in that class; a class with no assigned query reads Not measured rather than 0%."})]})]})}),e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[560px]",children:[e.jsx("caption",{className:"sr-only",children:"Mention and citation coverage for this Property, split by query class"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Query type"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"})]})}),e.jsx("tbody",{children:p.map(({queryClass:o,row:l,isError:c})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:u[o].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:u[o].technical}),l&&c?e.jsxs("span",{className:"mt-2 flex flex-wrap items-center gap-2 text-sm text-caution",children:[e.jsx("span",{role:"status",children:"Refresh failed."}),e.jsxs(g,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>i(o),children:["Retry ",u[o].technical.toLocaleLowerCase()]})]}):null]}),l?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(U,{metric:l.mentionCoverage,signal:"mentioned",emphasis:!0})}),e.jsx("td",{children:e.jsx(U,{metric:l.citationCoverage,signal:"cited",emphasis:!0})})]}):c?e.jsx("td",{colSpan:2,children:e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{role:"alert",children:["Could not load ",u[o].technical.toLocaleLowerCase(),"."]}),e.jsxs(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>i(o),children:["Retry ",u[o].technical.toLocaleLowerCase()]})]})}):e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})}),e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})})]})]},o))})]})})]})}function is({row:s,queryClass:t,isError:a}){return e.jsxs("section",{"aria-labelledby":"property-providers",className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsx("div",{children:e.jsxs("h2",{id:"property-providers",className:"text-base font-semibold text-heading",children:["Which engines answer for this Property",e.jsx(P,{text:"Each row is measured over the queries that engine actually answered for this Property, so the rows are a split of the same population rather than parts that add up to the Property total. An engine that answered nothing for this Property is absent instead of shown at 0%."})]})})}),s===void 0&&a?e.jsxs("p",{className:"text-sm text-secondary",children:["Details for ",u[t].technical.toLocaleLowerCase()," are unavailable. Retry that query type above."]}):s===void 0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading…"}):s.providers.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No answer engine has measured ",u[t].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${B(s.mentionCoverage)}.`:""]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[520px]",children:[e.jsx("caption",{className:"sr-only",children:"Per-engine mention and citation coverage"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Engine"}),e.jsx("th",{children:"Mentioned"}),e.jsx("th",{children:"Cited"})]})}),e.jsx("tbody",{children:s.providers.map(r=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:r.provider}),e.jsx("td",{children:e.jsx(U,{metric:r.mentionCoverage,signal:"mentioned"})}),e.jsx("td",{children:e.jsx(U,{metric:r.citationCoverage,signal:"cited"})})]},r.provider))})]})})]})}function os(s){const t=s.questions.join(" · ");return s.questionsTruncated?`${t} +${s.questionTotal-s.questions.length} more`:t}function ls({project:s,targetKey:t,queryClass:a}){const r=L({...$e({client:M,path:{name:s},query:{targetKey:t,queryClass:a}})});if(r.isPending||r.isError)return null;const i=r.data?.competitors??[],p=r.data?.basis;return e.jsxs("section",{"aria-labelledby":"property-named-instead",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-named-instead",className:"text-base font-semibold text-heading",children:["Named instead of this Property",e.jsx(P,{text:"Counted from the answers that did not name this Property, so a name here is one an engine recommended in its place. Occurrences count answers, not positions: an engine naming the same rival in two answers counts twice, and one naming it twice in a single answer counts once."})]})}),i.length>0?e.jsxs("p",{className:"supporting-copy",children:[r.data?.total??i.length," named"]}):null]}),i.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No rival was named in the answers this Property missed. Nothing to compete with here yet."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Names the engines gave instead of this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Named"}),e.jsx("th",{children:"Answers"}),e.jsx("th",{children:"Engines"}),e.jsx("th",{children:"Queries"})]})}),e.jsx("tbody",{children:i.map(o=>e.jsxs("tr",{children:[e.jsx("td",{className:"text-strong",children:o.name}),e.jsx("td",{className:"tabular-nums text-secondary",children:o.occurrences}),e.jsxs("td",{className:"text-secondary",children:[o.providers.join(", "),o.providersTruncated?` +${o.providerTotal-o.providers.length}`:""]}),e.jsx("td",{className:"text-right",children:e.jsxs("span",{className:"inline-flex items-center justify-end gap-1",children:[e.jsx("span",{className:"tabular-nums text-secondary",children:o.questionTotal}),e.jsx(P,{text:os(o)})]})})]},o.name))})]})}),p?.state==="available"?e.jsxs("p",{className:"supporting-copy mt-2",children:[p.targetMissResults," of ",p.answeredResults," answers to ",u[a].technical.toLocaleLowerCase()," did not name this Property."]}):null]})]})}function ds({questions:s,queryClass:t}){return e.jsxs("section",{"aria-labelledby":"property-questions",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-questions",className:"text-base font-semibold text-heading",children:[u[t].technical," assigned to this Property"]})}),e.jsxs("p",{className:"supporting-copy",children:[s.length," assigned"]})]}),s.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No ",u[t].technical.toLocaleLowerCase()," are assigned. Add one in advanced measurement setup to measure this class."]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Queries assigned to this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"Query"})})}),e.jsx("tbody",{children:s.map(a=>e.jsx("tr",{children:e.jsx("td",{className:"text-secondary",children:a})},a))})]})})]})}function cs({urls:s}){return e.jsxs("section",{"aria-labelledby":"property-urls",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-urls",className:"text-base font-semibold text-heading",children:["URLs that count as this Property",e.jsx(P,{text:"A cited source URL is credited to this Property when it matches one of these. The most specific matcher wins, so a URL covered by two Properties at the same specificity is flagged for review instead of being credited to either."})]})}),e.jsxs("p",{className:"supporting-copy",children:[s.length," configured"]})]}),s.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No URLs are configured for this Property."}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"URL matchers configured for this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"URL"})})}),e.jsx("tbody",{children:s.map(t=>e.jsx("tr",{children:e.jsx("td",{className:"break-all text-secondary",children:t})},t))})]})})]})}function hs(s,t){const a=[s.marketKey?t??"the selected market":null,s.provider?`the ${s.provider} answer engine`:null,s.model?`the ${s.model} model`:null,s.location?`location ${s.location}`:null,s.from||s.to?"a date range":null,s.measurementRunId?"a saved sweep":null].filter(r=>r!==null);return a.length===0?null:`AI Visibility is filtered to ${a.join(", ")}. This page shows the latest measurement for ${ze.allMarkets.toLocaleLowerCase()} and answer engines.`}function Ns(){const{projectName:s,targetKey:t}=we({strict:!1}),a=Pe(),r=Ce({strict:!1}),i=b.useMemo(()=>Le(r),[r]),[p,o]=b.useState(new Set),l=s??"",c=t??"",D=!!l&&!!c,W=b.useMemo(()=>Me("portfolio",Se(Ae())),[]),S=D&&W,{canWrite:$}=Re(),C=L({...Te({client:M,path:{name:l}}),enabled:S}),G=C.data?.active?.plan,_=G?.schemaVersion===2?G:null,O=i.queryClass==="branded"||i.queryClass==="non-brand"?i.queryClass:null,Y=n=>_?.assignments.some(d=>d.targetKey===c&&d.queryClass===n)??!1,h=O??(!Y("non-brand")&&Y("branded")?"branded":"non-brand");b.useEffect(()=>{!_||O||a({to:".",replace:!0,search:n=>z(n,{queryClass:h})})},[_,O,h,a]);const v=L({...le(l,c,"branded"),enabled:S}),f=L({...le(l,c,"non-brand"),enabled:S}),V=de(v.data),K=de(f.data),y=h==="branded"?v.data:f.data,E=h==="branded"?V:K,Z=(h==="branded"?v.isError:f.isError)&&E===void 0,A=y?.measurement.displayedRunId;ke(l,{view:"property",selection:{mode:"advanced",scope:"property",scopeKey:c,queryClass:h,limit:10,...A?{runId:A}:{}}});const xe=E?.mentionCoverage.state==="unavailable"?B(E.mentionCoverage):void 0,ue=y===void 0?void 0:y.measurement.completedAt??null,R={client:M,path:{name:l},query:{targetKey:c,queryClass:h,shape:qe.answers,limit:re,...A?{runId:A}:{}}},m=Ee({...Ie(R),enabled:S&&y!==void 0,initialPageParam:R,getNextPageParam:n=>n.answers?.nextCursor?{path:R.path,query:{...R.query,cursor:n.answers.nextCursor}}:void 0}),Q=C.data?.active??null,j=Q?.plan.schemaVersion===2?Q.plan:null,pe=Q!==null&&j===null,T=j?.targets.find(n=>n.stableKey===c)??null,J=hs(i,j?.reportingScopes?.find(n=>n.stableKey===i.marketKey)?.label),je=b.useMemo(()=>{if(!j)return[];const n=new Map(j.querySnapshots.map(d=>[d.queryId,d.queryText]));return[...new Set(j.assignments.filter(d=>d.targetKey===c&&d.queryClass===h).flatMap(d=>{const x=n.get(d.queryId);return x===void 0?[]:[x]}))].sort((d,x)=>d.localeCompare(x))},[j,c,h]),ye=b.useMemo(()=>T?.urlMatchers.map(Fe)??[],[T]),be=b.useMemo(()=>j?.groups.filter(n=>n.targetKeys.includes(c))??[],[j,c]),N=b.useMemo(()=>(m.data?.pages??[]).flatMap(x=>x.answers?.items??[]),[m.data]),X=m.data?.pages[0]?.answers?.totalEstimate??N.length,ge=(m.data?.pages??[]).length>0&&(m.data?.pages??[]).every(n=>n.answers===void 0),ve=m.data?.pages[0]?.measurement.state,k=e.jsxs(I,{to:"/projects/$projectName",params:{projectName:l},search:H,className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(De,{className:"size-3.5","aria-hidden":"true"}),"Back to AI Visibility"]});if(!D)return e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"Missing project name or Property key in URL."})});if(!W)return e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{className:"text-sm text-muted",children:"This view is not available here."})]});if(C.isPending&&!C.isError)return e.jsx("div",{className:"page-container",children:e.jsxs("div",{role:"status","aria-live":"polite",children:[e.jsx("span",{className:"sr-only",children:"Loading Property"}),e.jsx("div",{className:"h-32 animate-pulse rounded-md bg-surface-subtle","aria-hidden":"true"})]})});const fe=C.isError&&C.data===void 0,ee=v.isError&&v.data===void 0,se=f.isError&&f.data===void 0;return fe||ee&&se?e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{C.refetch(),v.refetch(),f.refetch()},children:"Try again"})]}):!j||!T?e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:j?"This Property is not in the published setup. It may have been renamed or removed.":"A Property page needs a published advanced measurement setup. Republish setup from the project Portfolio tab."}),e.jsx(g,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(I,{to:"/projects/$projectName/portfolio",params:{projectName:l},children:$?pe?"Republish setup":"Open measurement setup":"View measurement setup"})})]}):e.jsxs("div",{className:"page-container space-y-8",children:[e.jsxs("div",{className:"page-header",children:[e.jsxs("div",{className:"page-header-left",children:[k,e.jsx("h1",{className:"page-title mt-2",children:T.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",l,J?e.jsxs(e.Fragment,{children:[" · Filters not applied ",e.jsx(P,{text:J})]}):null]})]}),e.jsxs("div",{className:"page-header-right",children:[y?e.jsx(w,{tone:ie[y.measurement.state].tone,children:ie[y.measurement.state].label}):null,E&&E.flags>0?e.jsxs(w,{tone:"caution",children:[E.flags," flagged"]}):null]})]}),e.jsx(ns,{branded:V,nonBrand:K,brandedFailed:ee,nonBrandFailed:se}),e.jsx(rs,{branded:V,nonBrand:K,brandedError:v.isError,nonBrandError:f.isError,onRetry:n=>{n==="branded"?v.refetch():f.refetch()}}),y&&(y.measurement.state==="not_measured"||y.nextAction.kind==="run_measurement")?e.jsxs("section",{className:"flex flex-wrap items-center justify-between gap-3 border-y border-default py-4","aria-label":"Measurement next step",children:[e.jsx("p",{className:"text-sm text-secondary",children:ne()?ae:$?"Run a measurement from the project overview to collect this Property’s coverage and source evidence.":"This Property needs a new measurement before coverage and source evidence are available."}),e.jsx(g,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(I,{to:"/projects/$projectName",params:{projectName:l},search:H,children:$?"Go to AI Visibility":"View AI Visibility"})})]}):null,e.jsxs("div",{className:"flex flex-wrap items-end gap-4 border-y border-default py-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{htmlFor:"property-query-class",className:"block text-sm font-medium text-heading",children:"Query type"}),e.jsxs("select",{id:"property-query-class",value:h,onChange:n=>{const d=n.target.value==="branded"?"branded":"non-brand";a({to:".",search:x=>z(x,{queryClass:d})})},className:"h-11 rounded-md border border-default bg-surface px-3 text-sm text-primary focus:outline-none focus:ring-2 focus:ring-mono-400",children:[e.jsx("option",{value:"non-brand",children:u["non-brand"].technical}),e.jsx("option",{value:"branded",children:u.branded.technical})]})]}),e.jsx(ts,{measuredAt:ue,unmeasuredReason:xe,queryClass:h})]}),e.jsx(is,{row:E,queryClass:h,isError:Z}),e.jsx(ls,{project:l,targetKey:c,queryClass:h}),e.jsx(ds,{questions:je,queryClass:h}),e.jsx(cs,{urls:ye}),e.jsx(as,{project:l,groups:be}),e.jsxs("section",{"aria-labelledby":"property-evidence",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-evidence",className:"text-base font-semibold text-heading",children:["Answers the engines gave",e.jsx(P,{text:"One row per answer an engine gave for the queries assigned to this Property in the displayed measurement. Mentioned and cited are independent: an answer can name this Property without linking it, or link it without naming it. Answers that did neither are listed first, because those are what a gap is made of. Where the answer text was not stored the mention reads Not measured, never a zero. Open a row to read what the engine actually said, followed by the source URLs it returned, this Property's own first. The answer is where a miss becomes actionable: a query this Property was not named in may still have named a sibling building."})]})}),N.length>0?e.jsxs("p",{className:"supporting-copy",children:[N.length," of ",X]}):null]}),Z?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",u[h].technical.toLocaleLowerCase()," is unavailable. Retry that query type above."]}):m.isPending&&N.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):m.isError&&N.length===0?e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsx("span",{role:"alert",children:"Evidence could not be loaded."}),e.jsx(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{m.refetch()},children:"Retry evidence"})]}):ve==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:ne()?ae:"Not measured yet. Run a measurement to collect the answers for this Property."}):ge?e.jsx("p",{role:"alert",className:"text-sm text-caution",children:"This measurement was returned in an older format, so the answers cannot be shown here. The numbers above are unaffected."}):N.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No answers matched this Property in the displayed measurement."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"property-answer-table-container overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table property-evidence-table",children:[e.jsx("caption",{className:"sr-only",children:"Answers measured for this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Query"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"}),e.jsx("th",{children:"Sources"}),e.jsx("th",{children:e.jsx("span",{className:"sr-only",children:"Sources detail"})})]})}),e.jsx("tbody",{children:N.map(n=>{const d=Ye(n),x=p.has(d),te=`property-answer-${encodeURIComponent(d)}`;return e.jsxs(b.Fragment,{children:[e.jsxs("tr",{className:"property-answer-summary",children:[e.jsxs("td",{className:"text-secondary",children:[e.jsx("h3",{className:"text-sm font-medium text-heading",children:n.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[n.provider,n.location].filter(Boolean).join(" · ")}),n.historical||n.bridged?e.jsx("span",{className:"mt-1 flex",children:e.jsx(w,{tone:"caution",children:"Historical"})}):null]}),e.jsxs("td",{children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:"Mentioned"}),e.jsx(Ze,{row:n})]}),e.jsxs("td",{children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:"Cited"}),e.jsx(Xe,{row:n})]}),e.jsxs("td",{className:"tabular-nums text-secondary",children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:me}),n.cited===null?Je:n.sources.length]}),e.jsx("td",{className:"text-right",children:e.jsx(g,{type:"button",size:"sm",variant:"ghost",className:"h-auto min-h-11 max-w-full whitespace-normal py-2 text-left md:h-auto","aria-expanded":x,"aria-label":x?`Hide the answer for ${n.queryText}`:`Read the answer for ${n.queryText}`,"aria-controls":x?te:void 0,onClick:()=>o(Ne=>{const F=new Set(Ne);return F.delete(d)||F.add(d),F}),children:x?"Hide answer":"Read answer"})})]}),x?e.jsx("tr",{className:"property-answer-detail",children:e.jsxs("td",{id:te,colSpan:5,className:"bg-surface-subtle px-4",children:[e.jsx(ss,{project:l,targetKey:c,row:n}),e.jsx(es,{row:n})]})}):null]},d)})})]})}),m.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",N.length," of ",X]}),m.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(g,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:m.isFetchingNextPage,onClick:()=>{m.fetchNextPage()},children:m.isFetchingNextPage?"Loading…":m.isFetchNextPageError?"Retry more evidence":`Show ${re} more`})]}):null]})]})]})}export{oe as EVIDENCE_LABELS,Ns as MeasurementPropertyPage};
1
+ import{D as we,k as Pe,l as Ce,r as b,u as L,C as Ee,j as e,L as I}from"./vendor-tanstack-ZXXkndVj.js";import{cH as Le,d3 as Me,cA as Se,cy as Ae,L as Re,cT as Te,cO as z,e9 as ke,ea as qe,x as M,eb as Ie,B as g,I as P,T as w,aK as ae,aL as ne,d9 as H,ec as Ue,ca as Be,ed as $e,ee as _e,j as Oe,s as Ve,f as ce,a$ as he}from"./index-BJh8cX5E.js";import{j as Ke,o as Qe}from"./ChartPrimitives-CYlrwLJs.js";import{m as Fe,a as me,M as ze,A as He}from"./v2-overview-adapter-CaO9vY-l.js";import{Z as De}from"./vendor-lucide-N6vOpZmh.js";import"./vendor-radix-twS1M3FF.js";import"./vendor-recharts-D-cUuLZo.js";import"./vendor-markdown-B4giJcws.js";import"./vendor-yaml-GWJz5H2G.js";const re=50,u={branded:{headline:"When they know your name",technical:"Branded queries"},"non-brand":{headline:"When they don't",technical:"Non-brand queries"}},We={plan_v1:"Setup update required",no_completed_run:"No completed measurement yet",no_population:"No queries of this type are assigned",evidence_incomplete:"Source evidence is incomplete",identity_ambiguous:Be,not_applicable:"Not applicable for this Property"},ie={complete:{label:"Measured",tone:"positive"},partial:{label:"Partly measured",tone:"caution"},running:{label:"Measuring now",tone:"neutral"},queued:{label:"Measurement queued",tone:"neutral"},failed:{label:"Measurement failed",tone:"negative"},not_measured:{label:"Not measured",tone:"neutral"}},oe={assigned:{label:"Matches this Property",tone:"positive"},sibling:{label:"Matches another Property",tone:"caution"},ownedUnmapped:{label:"Site URL not in a Property",tone:"caution"},external:{label:"External URL",tone:"neutral"},ambiguous:{label:"Matches multiple Properties",tone:"caution"},invalid:{label:"Invalid URL",tone:"negative"}};function Ge(s){return[...s].sort((t,a)=>+(a.classification==="assigned")-+(t.classification==="assigned"))}function Ye(s){return`${s.expectedSlotId}:${s.usageEdgeId}`}function Ze({row:s}){return s.mentioned===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(w,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"No mention signal for this Property"})]}):e.jsx(w,{tone:s.mentioned?"positive":"neutral",children:s.mentioned?"Mentioned":"Not mentioned"})}const Je="—";function Xe({row:s}){return s.cited===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(w,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"Sources were not fully captured"})]}):e.jsx(w,{tone:s.cited?"positive":"neutral",children:s.cited?"Cited":"Not cited"})}function es({row:s}){return s.cited===null&&s.sources.length===0?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"The sources for this answer were not fully captured, so none can be shown."}):s.sources.length===0?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer returned no source URLs at all."}):e.jsxs("details",{className:"mt-2","data-answer-sources":!0,children:[e.jsxs("summary",{className:"min-h-11 cursor-pointer py-3 text-sm text-secondary focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-mono-400",children:[me," (",s.sources.length,")"]}),e.jsx("div",{className:"overflow-x-auto",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsxs("caption",{className:"sr-only",children:["Source URLs for ",s.queryText]}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Match"}),e.jsx("th",{children:"URL"})]})}),e.jsx("tbody",{children:Ge(s.sources).map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx(w,{tone:oe[t.classification].tone,children:oe[t.classification].label})}),e.jsx("td",{children:e.jsx(Oe,{url:t.sourceUrl})})]},t.sourceUrl))})]})})]})}function ss({project:s,targetKey:t,row:a}){const r=L({..._e({client:M,path:{name:s},query:{targetKey:t,resultId:a.observationId}})});if(r.isPending)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"status","aria-live":"polite",children:"Loading the answer…"});if(r.isError)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"alert",children:"Could not load this answer."});const i=r.data?.answer;return i==null||i.trim()===""?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer was measured, but its text was not stored."}):e.jsx("div",{className:"py-2",children:e.jsx(He,{headingLevel:4,copyable:!0,children:i})})}function B(s){return We[s.reason]??"Not measured"}function U({metric:s,signal:t,emphasis:a=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:a?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:B(s)})]});const r=ce(s.value),i=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`,p=he(s,t);return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:a?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:r}),i?e.jsx("span",{className:"text-xs text-muted",children:i}):null,p?e.jsx("span",{className:"text-xs text-muted",children:p}):null]})}function le(s,t,a){return Ue({client:M,path:{name:s},query:{scope:"property",targetKey:t,queryClass:a}})}function de(s){return s?.properties.items.at(0)}function ts({measuredAt:s,unmeasuredReason:t,queryClass:a}){const r=s===void 0?null:s===null?"No completed sweep yet":`Measured ${Ke(Qe(s))}`;return r===null&&t===void 0?null:e.jsxs("p",{className:"supporting-copy",children:[[r,t].filter(Boolean).join(" · "),r!==null&&t===void 0?` · ${u[a].technical.toLocaleLowerCase()} only`:""]})}function as({project:s,groups:t}){return t.length===0?null:e.jsxs("section",{"aria-labelledby":"property-market",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Competitive comparison"}),e.jsxs("h2",{id:"property-market",className:"text-base font-semibold text-heading",children:["Measured at the market level",e.jsx(P,{text:"Competitors are attached to a market rather than to a single Property, because one building has nobody to be compared against. Share of voice and competitor pressure are reported for the market this Property sits in."})]})]}),e.jsx(g,{asChild:!0,type:"button",size:"sm",variant:"outline",children:e.jsx(I,{to:"/projects/$projectName",params:{projectName:s},search:a=>z(H(a),{measurementScope:"project"}),children:"Open measurement overview"})})]}),e.jsx("ul",{className:"flex flex-wrap gap-2",children:t.map(a=>e.jsxs("li",{className:"rounded-md border border-default px-3 py-1.5 text-sm text-strong",children:[a.label,e.jsxs("span",{className:"ml-2 text-xs text-muted",children:[a.competitors.length," ",a.competitors.length===1?"competitor":"competitors"]})]},a.stableKey))})]})}function q({label:s,metric:t,signal:a,failed:r=!1}){if(t===void 0)return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsx("p",{className:"aeo-hero-row-value text-base font-semibold text-secondary",children:r?"Unavailable":"…"}),r?e.jsx("div",{}):e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true"}),e.jsx("p",{className:"aeo-hero-row-detail",children:r?"Could not be loaded":"Loading"})]});if(t.state==="unavailable"){const c=B(t);return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsx("p",{className:"aeo-hero-row-value text-base font-semibold text-secondary",children:"Not measured"}),e.jsx("div",{}),e.jsx("p",{className:"aeo-hero-row-detail",children:c==="Not measured"?"":c})]})}const{figure:i,sign:p}=Ve(ce(t.value)),o=t.numerator===void 0||t.denominator===void 0?null:`${t.numerator} of ${t.denominator}`,l=he(t,a);return e.jsxs("div",{className:"aeo-hero-row",children:[e.jsx("p",{className:"aeo-hero-row-label",children:s}),e.jsxs("p",{className:"aeo-hero-row-value text-heading",children:[i,p?e.jsx("span",{className:"text-faint",children:p}):null]}),e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true",children:e.jsx("div",{className:"metric-card-bar-fill progress-fill-neutral",style:{width:`${t.value*100}%`}})}),e.jsxs("p",{className:"aeo-hero-row-detail tabular-nums",children:[o??"",l?e.jsx("span",{className:"block",children:l}):null]})]})}function ns({branded:s,nonBrand:t,brandedFailed:a=!1,nonBrandFailed:r=!1}){return e.jsxs("section",{"aria-labelledby":"property-coverage-hero",children:[e.jsx("h2",{id:"property-coverage-hero",className:"sr-only",children:"Coverage for this Property"}),e.jsxs("div",{className:"space-y-5",children:[e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Non-brand · the demand to earn"}),e.jsx(q,{label:"Mentioned",metric:t?.mentionCoverage,signal:"mentioned",failed:r}),e.jsx(q,{label:"Cited",metric:t?.citationCoverage,signal:"cited",failed:r})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Branded · already named"}),e.jsx(q,{label:"Mentioned",metric:s?.mentionCoverage,signal:"mentioned",failed:a}),e.jsx(q,{label:"Cited",metric:s?.citationCoverage,signal:"cited",failed:a})]})]})]})}function rs({branded:s,nonBrand:t,brandedError:a,nonBrandError:r,onRetry:i}){const p=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:t,isError:r}];return e.jsxs("section",{"aria-labelledby":"property-brand-contrast",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsxs("div",{children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"The gap"}),e.jsxs("h2",{id:"property-brand-contrast",className:"text-base font-semibold text-heading",children:["Named versus not named",e.jsx(P,{text:"Branded queries already contain your name, so an answer engine has an easy path back to you. Non-brand queries describe the need instead, and that is the demand you have to earn. Each row is measured only over the queries assigned to this Property in that class; a class with no assigned query reads Not measured rather than 0%."})]})]})}),e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[560px]",children:[e.jsx("caption",{className:"sr-only",children:"Mention and citation coverage for this Property, split by query class"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Query type"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"})]})}),e.jsx("tbody",{children:p.map(({queryClass:o,row:l,isError:c})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:u[o].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:u[o].technical}),l&&c?e.jsxs("span",{className:"mt-2 flex flex-wrap items-center gap-2 text-sm text-caution",children:[e.jsx("span",{role:"status",children:"Refresh failed."}),e.jsxs(g,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>i(o),children:["Retry ",u[o].technical.toLocaleLowerCase()]})]}):null]}),l?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(U,{metric:l.mentionCoverage,signal:"mentioned",emphasis:!0})}),e.jsx("td",{children:e.jsx(U,{metric:l.citationCoverage,signal:"cited",emphasis:!0})})]}):c?e.jsx("td",{colSpan:2,children:e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{role:"alert",children:["Could not load ",u[o].technical.toLocaleLowerCase(),"."]}),e.jsxs(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>i(o),children:["Retry ",u[o].technical.toLocaleLowerCase()]})]})}):e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})}),e.jsx("td",{children:e.jsx("span",{className:"text-sm text-secondary",children:"Loading…"})})]})]},o))})]})})]})}function is({row:s,queryClass:t,isError:a}){return e.jsxs("section",{"aria-labelledby":"property-providers",className:"page-section-divider",children:[e.jsx("div",{className:"section-head section-head-inline",children:e.jsx("div",{children:e.jsxs("h2",{id:"property-providers",className:"text-base font-semibold text-heading",children:["Which engines answer for this Property",e.jsx(P,{text:"Each row is measured over the queries that engine actually answered for this Property, so the rows are a split of the same population rather than parts that add up to the Property total. An engine that answered nothing for this Property is absent instead of shown at 0%."})]})})}),s===void 0&&a?e.jsxs("p",{className:"text-sm text-secondary",children:["Details for ",u[t].technical.toLocaleLowerCase()," are unavailable. Retry that query type above."]}):s===void 0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading…"}):s.providers.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No answer engine has measured ",u[t].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${B(s.mentionCoverage)}.`:""]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[520px]",children:[e.jsx("caption",{className:"sr-only",children:"Per-engine mention and citation coverage"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Engine"}),e.jsx("th",{children:"Mentioned"}),e.jsx("th",{children:"Cited"})]})}),e.jsx("tbody",{children:s.providers.map(r=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:r.provider}),e.jsx("td",{children:e.jsx(U,{metric:r.mentionCoverage,signal:"mentioned"})}),e.jsx("td",{children:e.jsx(U,{metric:r.citationCoverage,signal:"cited"})})]},r.provider))})]})})]})}function os(s){const t=s.questions.join(" · ");return s.questionsTruncated?`${t} +${s.questionTotal-s.questions.length} more`:t}function ls({project:s,targetKey:t,queryClass:a}){const r=L({...$e({client:M,path:{name:s},query:{targetKey:t,queryClass:a}})});if(r.isPending||r.isError)return null;const i=r.data?.competitors??[],p=r.data?.basis;return e.jsxs("section",{"aria-labelledby":"property-named-instead",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-named-instead",className:"text-base font-semibold text-heading",children:["Named instead of this Property",e.jsx(P,{text:"Counted from the answers that did not name this Property, so a name here is one an engine recommended in its place. Occurrences count answers, not positions: an engine naming the same rival in two answers counts twice, and one naming it twice in a single answer counts once."})]})}),i.length>0?e.jsxs("p",{className:"supporting-copy",children:[r.data?.total??i.length," named"]}):null]}),i.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No rival was named in the answers this Property missed. Nothing to compete with here yet."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Names the engines gave instead of this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Named"}),e.jsx("th",{children:"Answers"}),e.jsx("th",{children:"Engines"}),e.jsx("th",{children:"Queries"})]})}),e.jsx("tbody",{children:i.map(o=>e.jsxs("tr",{children:[e.jsx("td",{className:"text-strong",children:o.name}),e.jsx("td",{className:"tabular-nums text-secondary",children:o.occurrences}),e.jsxs("td",{className:"text-secondary",children:[o.providers.join(", "),o.providersTruncated?` +${o.providerTotal-o.providers.length}`:""]}),e.jsx("td",{className:"text-right",children:e.jsxs("span",{className:"inline-flex items-center justify-end gap-1",children:[e.jsx("span",{className:"tabular-nums text-secondary",children:o.questionTotal}),e.jsx(P,{text:os(o)})]})})]},o.name))})]})}),p?.state==="available"?e.jsxs("p",{className:"supporting-copy mt-2",children:[p.targetMissResults," of ",p.answeredResults," answers to ",u[a].technical.toLocaleLowerCase()," did not name this Property."]}):null]})]})}function ds({questions:s,queryClass:t}){return e.jsxs("section",{"aria-labelledby":"property-questions",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-questions",className:"text-base font-semibold text-heading",children:[u[t].technical," assigned to this Property"]})}),e.jsxs("p",{className:"supporting-copy",children:[s.length," assigned"]})]}),s.length===0?e.jsxs("p",{className:"text-sm text-secondary",children:["No ",u[t].technical.toLocaleLowerCase()," are assigned. Add one in advanced measurement setup to measure this class."]}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"Queries assigned to this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"Query"})})}),e.jsx("tbody",{children:s.map(a=>e.jsx("tr",{children:e.jsx("td",{className:"text-secondary",children:a})},a))})]})})]})}function cs({urls:s}){return e.jsxs("section",{"aria-labelledby":"property-urls",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-urls",className:"text-base font-semibold text-heading",children:["URLs that count as this Property",e.jsx(P,{text:"A cited source URL is credited to this Property when it matches one of these. The most specific matcher wins, so a URL covered by two Properties at the same specificity is flagged for review instead of being credited to either."})]})}),e.jsxs("p",{className:"supporting-copy",children:[s.length," configured"]})]}),s.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No URLs are configured for this Property."}):e.jsx("div",{className:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[420px]",children:[e.jsx("caption",{className:"sr-only",children:"URL matchers configured for this Property"}),e.jsx("thead",{children:e.jsx("tr",{children:e.jsx("th",{children:"URL"})})}),e.jsx("tbody",{children:s.map(t=>e.jsx("tr",{children:e.jsx("td",{className:"break-all text-secondary",children:t})},t))})]})})]})}function hs(s,t){const a=[s.marketKey?t??"the selected market":null,s.provider?`the ${s.provider} answer engine`:null,s.model?`the ${s.model} model`:null,s.location?`location ${s.location}`:null,s.from||s.to?"a date range":null,s.measurementRunId?"a saved sweep":null].filter(r=>r!==null);return a.length===0?null:`AI Visibility is filtered to ${a.join(", ")}. This page shows the latest measurement for ${ze.allMarkets.toLocaleLowerCase()} and answer engines.`}function Ns(){const{projectName:s,targetKey:t}=we({strict:!1}),a=Pe(),r=Ce({strict:!1}),i=b.useMemo(()=>Le(r),[r]),[p,o]=b.useState(new Set),l=s??"",c=t??"",D=!!l&&!!c,W=b.useMemo(()=>Me("portfolio",Se(Ae())),[]),S=D&&W,{canWrite:$}=Re(),C=L({...Te({client:M,path:{name:l}}),enabled:S}),G=C.data?.active?.plan,_=G?.schemaVersion===2?G:null,O=i.queryClass==="branded"||i.queryClass==="non-brand"?i.queryClass:null,Y=n=>_?.assignments.some(d=>d.targetKey===c&&d.queryClass===n)??!1,h=O??(!Y("non-brand")&&Y("branded")?"branded":"non-brand");b.useEffect(()=>{!_||O||a({to:".",replace:!0,search:n=>z(n,{queryClass:h})})},[_,O,h,a]);const v=L({...le(l,c,"branded"),enabled:S}),f=L({...le(l,c,"non-brand"),enabled:S}),V=de(v.data),K=de(f.data),y=h==="branded"?v.data:f.data,E=h==="branded"?V:K,Z=(h==="branded"?v.isError:f.isError)&&E===void 0,A=y?.measurement.displayedRunId;ke(l,{view:"property",selection:{mode:"advanced",scope:"property",scopeKey:c,queryClass:h,limit:10,...A?{runId:A}:{}}});const xe=E?.mentionCoverage.state==="unavailable"?B(E.mentionCoverage):void 0,ue=y===void 0?void 0:y.measurement.completedAt??null,R={client:M,path:{name:l},query:{targetKey:c,queryClass:h,shape:qe.answers,limit:re,...A?{runId:A}:{}}},m=Ee({...Ie(R),enabled:S&&y!==void 0,initialPageParam:R,getNextPageParam:n=>n.answers?.nextCursor?{path:R.path,query:{...R.query,cursor:n.answers.nextCursor}}:void 0}),Q=C.data?.active??null,j=Q?.plan.schemaVersion===2?Q.plan:null,pe=Q!==null&&j===null,T=j?.targets.find(n=>n.stableKey===c)??null,J=hs(i,j?.reportingScopes?.find(n=>n.stableKey===i.marketKey)?.label),je=b.useMemo(()=>{if(!j)return[];const n=new Map(j.querySnapshots.map(d=>[d.queryId,d.queryText]));return[...new Set(j.assignments.filter(d=>d.targetKey===c&&d.queryClass===h).flatMap(d=>{const x=n.get(d.queryId);return x===void 0?[]:[x]}))].sort((d,x)=>d.localeCompare(x))},[j,c,h]),ye=b.useMemo(()=>T?.urlMatchers.map(Fe)??[],[T]),be=b.useMemo(()=>j?.groups.filter(n=>n.targetKeys.includes(c))??[],[j,c]),N=b.useMemo(()=>(m.data?.pages??[]).flatMap(x=>x.answers?.items??[]),[m.data]),X=m.data?.pages[0]?.answers?.totalEstimate??N.length,ge=(m.data?.pages??[]).length>0&&(m.data?.pages??[]).every(n=>n.answers===void 0),ve=m.data?.pages[0]?.measurement.state,k=e.jsxs(I,{to:"/projects/$projectName",params:{projectName:l},search:H,className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(De,{className:"size-3.5","aria-hidden":"true"}),"Back to AI Visibility"]});if(!D)return e.jsx("div",{className:"page-container",children:e.jsx("p",{className:"text-sm text-muted",children:"Missing project name or Property key in URL."})});if(!W)return e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{className:"text-sm text-muted",children:"This view is not available here."})]});if(C.isPending&&!C.isError)return e.jsx("div",{className:"page-container",children:e.jsxs("div",{role:"status","aria-live":"polite",children:[e.jsx("span",{className:"sr-only",children:"Loading Property"}),e.jsx("div",{className:"h-32 animate-pulse rounded-md bg-surface-subtle","aria-hidden":"true"})]})});const fe=C.isError&&C.data===void 0,ee=v.isError&&v.data===void 0,se=f.isError&&f.data===void 0;return fe||ee&&se?e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{C.refetch(),v.refetch(),f.refetch()},children:"Try again"})]}):!j||!T?e.jsxs("div",{className:"page-container space-y-3",children:[k,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:j?"This Property is not in the published setup. It may have been renamed or removed.":"A Property page needs a published advanced measurement setup. Republish setup from the project Portfolio tab."}),e.jsx(g,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(I,{to:"/projects/$projectName/portfolio",params:{projectName:l},children:$?pe?"Republish setup":"Open measurement setup":"View measurement setup"})})]}):e.jsxs("div",{className:"page-container space-y-8",children:[e.jsxs("div",{className:"page-header",children:[e.jsxs("div",{className:"page-header-left",children:[k,e.jsx("h1",{className:"page-title mt-2",children:T.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",l,J?e.jsxs(e.Fragment,{children:[" · Filters not applied ",e.jsx(P,{text:J})]}):null]})]}),e.jsxs("div",{className:"page-header-right",children:[y?e.jsx(w,{tone:ie[y.measurement.state].tone,children:ie[y.measurement.state].label}):null,E&&E.flags>0?e.jsxs(w,{tone:"caution",children:[E.flags," flagged"]}):null]})]}),e.jsx(ns,{branded:V,nonBrand:K,brandedFailed:ee,nonBrandFailed:se}),e.jsx(rs,{branded:V,nonBrand:K,brandedError:v.isError,nonBrandError:f.isError,onRetry:n=>{n==="branded"?v.refetch():f.refetch()}}),y&&(y.measurement.state==="not_measured"||y.nextAction.kind==="run_measurement")?e.jsxs("section",{className:"flex flex-wrap items-center justify-between gap-3 border-y border-default py-4","aria-label":"Measurement next step",children:[e.jsx("p",{className:"text-sm text-secondary",children:ne()?ae:$?"Run a measurement from the project overview to collect this Property’s coverage and source evidence.":"This Property needs a new measurement before coverage and source evidence are available."}),e.jsx(g,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(I,{to:"/projects/$projectName",params:{projectName:l},search:H,children:$?"Go to AI Visibility":"View AI Visibility"})})]}):null,e.jsxs("div",{className:"flex flex-wrap items-end gap-4 border-y border-default py-4",children:[e.jsxs("div",{className:"space-y-1",children:[e.jsx("label",{htmlFor:"property-query-class",className:"block text-sm font-medium text-heading",children:"Query type"}),e.jsxs("select",{id:"property-query-class",value:h,onChange:n=>{const d=n.target.value==="branded"?"branded":"non-brand";a({to:".",search:x=>z(x,{queryClass:d})})},className:"h-11 rounded-md border border-default bg-surface px-3 text-sm text-primary focus:outline-none focus:ring-2 focus:ring-mono-400",children:[e.jsx("option",{value:"non-brand",children:u["non-brand"].technical}),e.jsx("option",{value:"branded",children:u.branded.technical})]})]}),e.jsx(ts,{measuredAt:ue,unmeasuredReason:xe,queryClass:h})]}),e.jsx(is,{row:E,queryClass:h,isError:Z}),e.jsx(ls,{project:l,targetKey:c,queryClass:h}),e.jsx(ds,{questions:je,queryClass:h}),e.jsx(cs,{urls:ye}),e.jsx(as,{project:l,groups:be}),e.jsxs("section",{"aria-labelledby":"property-evidence",className:"page-section-divider",children:[e.jsxs("div",{className:"section-head section-head-inline",children:[e.jsx("div",{children:e.jsxs("h2",{id:"property-evidence",className:"text-base font-semibold text-heading",children:["Answers the engines gave",e.jsx(P,{text:"One row per answer an engine gave for the queries assigned to this Property in the displayed measurement. Mentioned and cited are independent: an answer can name this Property without linking it, or link it without naming it. Answers that did neither are listed first, because those are what a gap is made of. Where the answer text was not stored the mention reads Not measured, never a zero. Open a row to read what the engine actually said, followed by the source URLs it returned, this Property's own first. The answer is where a miss becomes actionable: a query this Property was not named in may still have named a sibling building."})]})}),N.length>0?e.jsxs("p",{className:"supporting-copy",children:[N.length," of ",X]}):null]}),Z?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",u[h].technical.toLocaleLowerCase()," is unavailable. Retry that query type above."]}):m.isPending&&N.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):m.isError&&N.length===0?e.jsxs("div",{className:"flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsx("span",{role:"alert",children:"Evidence could not be loaded."}),e.jsx(g,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{m.refetch()},children:"Retry evidence"})]}):ve==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:ne()?ae:"Not measured yet. Run a measurement to collect the answers for this Property."}):ge?e.jsx("p",{role:"alert",className:"text-sm text-caution",children:"This measurement was returned in an older format, so the answers cannot be shown here. The numbers above are unaffected."}):N.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"No answers matched this Property in the displayed measurement."}):e.jsxs(e.Fragment,{children:[e.jsx("div",{className:"property-answer-table-container overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table property-evidence-table",children:[e.jsx("caption",{className:"sr-only",children:"Answers measured for this Property"}),e.jsx("thead",{children:e.jsxs("tr",{children:[e.jsx("th",{children:"Query"}),e.jsx("th",{children:"Mentioned in the answer"}),e.jsx("th",{children:"Cited as a source"}),e.jsx("th",{children:"Sources"}),e.jsx("th",{children:e.jsx("span",{className:"sr-only",children:"Sources detail"})})]})}),e.jsx("tbody",{children:N.map(n=>{const d=Ye(n),x=p.has(d),te=`property-answer-${encodeURIComponent(d)}`;return e.jsxs(b.Fragment,{children:[e.jsxs("tr",{className:"property-answer-summary",children:[e.jsxs("td",{className:"text-secondary",children:[e.jsx("h3",{className:"text-sm font-medium text-heading",children:n.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[n.provider,n.location].filter(Boolean).join(" · ")}),n.historical||n.bridged?e.jsx("span",{className:"mt-1 flex",children:e.jsx(w,{tone:"caution",children:"Historical"})}):null]}),e.jsxs("td",{children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:"Mentioned"}),e.jsx(Ze,{row:n})]}),e.jsxs("td",{children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:"Cited"}),e.jsx(Xe,{row:n})]}),e.jsxs("td",{className:"tabular-nums text-secondary",children:[e.jsx("span",{className:"property-evidence-mobile-label","aria-hidden":"true",children:me}),n.cited===null?Je:n.sources.length]}),e.jsx("td",{className:"text-right",children:e.jsx(g,{type:"button",size:"sm",variant:"ghost",className:"h-auto min-h-11 max-w-full whitespace-normal py-2 text-left md:h-auto","aria-expanded":x,"aria-label":x?`Hide the answer for ${n.queryText}`:`Read the answer for ${n.queryText}`,"aria-controls":x?te:void 0,onClick:()=>o(Ne=>{const F=new Set(Ne);return F.delete(d)||F.add(d),F}),children:x?"Hide answer":"Read answer"})})]}),x?e.jsx("tr",{className:"property-answer-detail",children:e.jsxs("td",{id:te,colSpan:5,className:"bg-surface-subtle px-4",children:[e.jsx(ss,{project:l,targetKey:c,row:n}),e.jsx(es,{row:n})]})}):null]},d)})})]})}),m.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",N.length," of ",X]}),m.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(g,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:m.isFetchingNextPage,onClick:()=>{m.fetchNextPage()},children:m.isFetchingNextPage?"Loading…":m.isFetchNextPageError?"Retry more evidence":`Show ${re} more`})]}):null]})]})]})}export{oe as EVIDENCE_LABELS,Ns as MeasurementPropertyPage};