@ainyc/canonry 4.180.7 → 4.182.3

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 (41) hide show
  1. package/README.md +80 -45
  2. package/assets/agent-workspace/skills/canonry/SKILL.md +13 -10
  3. package/assets/agent-workspace/skills/canonry/references/canonry-cli.md +7 -6
  4. package/assets/assets/{AuditHistoryPanel-B1lmI7wm.js → AuditHistoryPanel-1_FHpzj-.js} +1 -1
  5. package/assets/assets/{BacklinksPage-Bw61uQu8.js → BacklinksPage-045za10_.js} +1 -1
  6. package/assets/assets/{ChartPrimitives-DG35TyhH.js → ChartPrimitives-DLEICrrL.js} +1 -1
  7. package/assets/assets/{HistoryPage-D8z9-NkT.js → HistoryPage-36K_6asu.js} +1 -1
  8. package/assets/assets/{MeasurementPropertyPage-CXX9GFj8.js → MeasurementPropertyPage-B4DJGoY6.js} +1 -1
  9. package/assets/assets/ProjectPage-CshC68Ne.js +9 -0
  10. package/assets/assets/{RunRow-DXHy16T3.js → RunRow-U2CN755e.js} +1 -1
  11. package/assets/assets/{RunsPage-D2aE620i.js → RunsPage-D0CtU4d-.js} +1 -1
  12. package/assets/assets/SettingsPage-zMWieTPK.js +1 -0
  13. package/assets/assets/SiteHealthSection-TpQPu_Uj.js +4 -0
  14. package/assets/assets/{TrafficPage-DFHWgvkU.js → TrafficPage-DfLUt-64.js} +1 -1
  15. package/assets/assets/{TrafficSourceDetailPage-DxjyRL8Y.js → TrafficSourceDetailPage-DbjNNWSt.js} +1 -1
  16. package/assets/assets/extract-error-message-CWqz1QPC.js +1 -0
  17. package/assets/assets/index-Brb7M_6G.js +86 -0
  18. package/assets/assets/index-DwdK2e4e.css +1 -0
  19. package/assets/assets/{react-sigma_core.esm.min-DAcOZae7.js → react-sigma_core.esm.min-Drqprr9L.js} +1 -1
  20. package/assets/assets/{vendor-lucide-nYKv-BB7.js → vendor-lucide-XjCNFK0x.js} +1 -1
  21. package/assets/assets/{vendor-markdown-Bn7fRwrx.js → vendor-markdown-9tTeP8v7.js} +1 -1
  22. package/assets/assets/{vendor-radix-4UOaVWza.js → vendor-radix-BpmvLvpp.js} +1 -1
  23. package/assets/assets/{vendor-recharts-D8rt5lKn.js → vendor-recharts-FA0uySU7.js} +1 -1
  24. package/assets/assets/{vendor-tanstack-Dock0eH1.js → vendor-tanstack-CYBjbqVr.js} +1 -1
  25. package/assets/index.html +7 -7
  26. package/dist/{chunk-VZO6CLHY.js → chunk-BDJT7XZL.js} +169 -64
  27. package/dist/{chunk-RXXZ5BU5.js → chunk-DY5ZDKQW.js} +183 -1
  28. package/dist/{chunk-CWXPBQR5.js → chunk-FVC7PGYQ.js} +47 -5
  29. package/dist/{chunk-XYTSKRO3.js → chunk-I3KSOMJA.js} +2 -2
  30. package/dist/{chunk-WJFBNCVD.js → chunk-K45YKXE4.js} +4310 -3323
  31. package/dist/cli.js +323 -99
  32. package/dist/index.js +4 -4
  33. package/dist/{intelligence-service-MEPYXRBS.js → intelligence-service-HGA553GT.js} +2 -2
  34. package/dist/mcp.js +3 -3
  35. package/package.json +7 -7
  36. package/assets/assets/ProjectPage-BaN_rvoV.js +0 -9
  37. package/assets/assets/SettingsPage-BiiFqarS.js +0 -1
  38. package/assets/assets/SiteHealthSection-DCH2Ejtc.js +0 -4
  39. package/assets/assets/extract-error-message-BdXUZQW9.js +0 -1
  40. package/assets/assets/index-BuEq5Rhg.css +0 -1
  41. package/assets/assets/index-CSictO9U.js +0 -83
package/README.md CHANGED
@@ -2,40 +2,91 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/@canonry/canonry)](https://www.npmjs.com/package/@canonry/canonry) [![Node.js >= 22.14](https://img.shields.io/badge/node-%3E%3D22.14-brightgreen)](https://nodejs.org)
4
4
 
5
- Your entire AEO/GEO/AI Visibility, technical SEO + web analytics stack. **Agent-first. Self-hosted. Local.**
5
+ **Give your agent the evidence, tools, and skills to run AEO.**
6
6
 
7
- Think PostHog, for AI search visibility. Canonry tracks what ChatGPT, Claude, Gemini, and Perplexity say about you, joins it with your search, server side traffic data and paid media, and gives your agent the tools + skills to fix what it finds.
7
+ Canonry is an **agent-first, open-source AEO operating platform.**
8
+
9
+ <p align="center">
10
+ <a href="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/measure-act.svg">
11
+ <img src="https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/measure-act.svg" alt="Supported external sources feed Canonry. Canonry stores project evidence in SQLite for your agent, dashboard, and client reports. Your agent combines its own execution tools with Canonry's WordPress and indexing workflows. Webhooks connect Discord and other systems." width="94%" />
12
+ </a>
13
+ </p>
14
+
15
+ Connect the sources you use. Schedule syncs and checks, or run them on demand.
16
+
17
+ **Connect your agent:** [Agent Plugin](docs/plugins.md) · [MCP](docs/mcp.md) · CLI · REST API
18
+
19
+ - **Track AI visibility:** Brand mentions and citations across answer engines.
20
+ - **Compare competitors:** Citation gaps and the domains and pages getting cited.
21
+ - **Measure complex portfolios:** Properties and market groups, with questions, engines, models, and locations tailored per property.
22
+ - **Investigate what changed:** Combine search and local performance, server-side crawler visits, AI page fetches, referrals, conversion evidence, and technical audits.
23
+ - **Improve your site:** Your agent uses its own coding tools alongside Canonry's content, WordPress publishing, schema, and indexing workflows.
24
+ - **Report and follow up:** Generate client reports, schedule data syncs and checks, and send alerts to Discord or your own systems.
25
+
26
+ **Self-hosted, with your own provider keys.** Use the dashboard to review the same evidence and recommendations as your agent.
8
27
 
9
28
  `npm install -g @canonry/canonry`
10
29
 
11
- ![Canonry AI Visibility mention share trend across answer engines](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/ai-visibility-trend.png)
30
+ **Give your agent a job:**
12
31
 
13
- *Track your share of answer-engine brand mentions over time.*
32
+ > Review what changed across search, local visibility, AI citations, and server-side traffic. Find where competitors get cited and we don't. Use that evidence and the site audit to propose the next changes. Prepare a pull request or WordPress draft for review, then report the results and next steps to the client.
14
33
 
15
- **Measure → diagnose → approve action → measure change**
34
+ Your agent coordinates the work through Canonry and its own tools. After changes ship, rerun the relevant checks to measure progress.
16
35
 
17
- | Phase | What Canonry does |
18
- |---|---|
19
- | **Measure** | Track mentions and citations across Gemini, ChatGPT, Claude, Perplexity, and local models. Join them with GSC, GA4, Bing, server side traffic, Business Profile, and backlink data. |
20
- | **Diagnose** | Crawl the site, score Page Health, inspect evidence, compare competitors, and explain regressions. |
21
- | **Act** | Give your agent the context + skills to make surgical on-site technical SEO changes and coordinate content, indexing, analytics, and paid media. |
22
- | **Operate** | Create automation workflows, schedule checks, sync data, send webhooks, and generate client-ready reports. |
36
+ ### Compare competitors and measure complex portfolios
37
+
38
+ - **Competitor comparisons:** Compare brand mentions and citations across tracked questions and answer engines. Find questions where competitors are cited and your site is absent.
39
+ - **Who gets cited:** [Rank cited domains](skills/canonry/references/canonry-cli.md#cited-source-rankings-cnry-sources) and inspect exact URLs, including your pages, competitors, aggregators, and publishers.
40
+ - **Advanced Measurement:** Build [versioned measurement plans](docs/mcp.md#tool-surface) for portfolios of locations, products, or site sections. Assign questions, engines, models, and locations per property, separate branded and non-brand coverage, and organize overlapping market groups with their own competitors. Compare results across properties, groups, answer engines, and locations, then drill down to exact answers and cited sources.
23
41
 
24
42
  ### Built-in integrations and workflows
25
43
 
26
44
  - **Answer engines:** Canonry measures Gemini, ChatGPT, Claude, Perplexity, and OpenAI-compatible local models.
27
45
  - **Agent workflows:** Use the [MCP adapter](docs/mcp.md), [Agent Plugin](docs/plugins.md), [external webhooks](skills/canonry/references/canonry-cli.md#agent), or built-in [Aero](skills/aero/SKILL.md).
28
46
  - **Search and analytics:** Connect [Google Search Console](docs/google-search-console-setup.md), [Google Analytics 4](docs/google-analytics-setup.md), and [Bing Webmaster Tools](docs/bing-webmaster-setup.md).
29
- - **Server traffic:** Capture events from [Cloudflare, Cloud Run, Vercel, and WordPress](skills/canonry/references/server-side-traffic.md).
47
+ - **Server traffic:** Inspect recorded crawler visits, AI page fetches, and referral arrivals from [Cloudflare, Cloud Run, Vercel, and WordPress](skills/canonry/references/server-side-traffic.md).
30
48
  - **Backlinks:** Query [Common Crawl hyperlink releases](skills/canonry/references/canonry-cli.md#backlinks-common-crawl) locally with DuckDB, and sync new releases on a schedule.
31
- - **Paid media:** Connect [OpenAI Ads Manager](docs/mcp.md#tool-surface) for account, conversion, campaign, and performance workflows.
32
49
  - **Conversion measurement:** Audit [Google Ads and Google Tag Manager](docs/google-marketing.md) with read-only snapshots and declared conversion contracts.
33
50
  - **Local presence:** Connect [Google Business Profile](skills/canonry/references/google-business-profile.md) for search terms, performance, lodging data, and booking actions.
34
51
  - **Publishing and indexing:** Publish through [WordPress](docs/wordpress-setup.md), generate JSON-LD, and [submit sitemaps or URLs for indexing](skills/canonry/references/indexing.md).
35
- - **Client reporting:** Automate [scheduled checks and data syncs](skills/canonry/references/canonry-cli.md#scheduling--notifications), send webhook alerts, and generate [client-ready HTML reports](skills/canonry/references/canonry-cli.md#reports).
52
+ - **Client reporting:** Generate [client-ready HTML reports or JSON evidence](skills/canonry/references/canonry-cli.md#reports), use the report API/MCP tools, or build your own reporting pipeline.
53
+ - **Schedules and alerts:** Configure [data syncs and checks](skills/canonry/references/canonry-cli.md#scheduling--notifications) independently; send webhook alerts to Discord, Slack, or your own systems.
54
+ - **ChatGPT Ads:** Use the [ads tools](docs/mcp.md#tool-surface) to measure campaigns, create and update paused campaign trees, activate approved trees, and reconcile operation receipts.
36
55
 
37
56
  The dashboard, CLI, and agent tools share the same project API.
38
57
 
58
+ <a id="or-use-any-shell-capable-coding-agent"></a>
59
+
60
+ ## Start with your agent
61
+
62
+ Connect the [Agent Plugin](docs/plugins.md) or [MCP adapter](docs/mcp.md) to your agent, or use built-in [Aero](skills/aero/SKILL.md). For any shell-capable agent, copy the setup request below.
63
+
64
+ <details>
65
+ <summary>Copy the Site Health-first setup request</summary>
66
+
67
+ <br />
68
+
69
+ ```text
70
+ Help me set up Canonry for my public site.
71
+
72
+ Use the official Canonry docs:
73
+ - Agent quickstart: https://github.com/Canonry/canonry#or-use-any-shell-capable-coding-agent
74
+ - CLI reference: https://github.com/Canonry/canonry/blob/main/skills/canonry/references/canonry-cli.md
75
+ - Plugin setup: https://github.com/Canonry/canonry/blob/main/docs/plugins.md
76
+ - MCP setup: https://github.com/Canonry/canonry/blob/main/docs/mcp.md
77
+
78
+ If a Canonry installation or connected plugin/MCP is available, use it. Do not create a duplicate. Choose the connected tools or the shell path, not both. The `cnry` and `canonry` commands are interchangeable.
79
+
80
+ 1. Ask for my public domain, country, and language. Do not create or scan anything yet.
81
+ 2. If connected tools are available, use them for the remaining steps. For the shell path, make sure that `cnry` is on PATH. Then run `cnry --version`. If Canonry is missing, propose `npm install -g @canonry/canonry` and wait for approval. If configuration is missing, tell me to run `cnry bootstrap` in my private terminal and wait. Never ask me to paste passwords, API keys, OAuth credentials, or command output.
82
+ 3. Make sure that the API or connected tool is reachable. If the shell API is unavailable, propose `cnry start`. Wait for approval. List the projects with the connected project tool or `cnry project list --format json`. Reuse a project with the same domain. Make sure that the proposed name is not assigned to a different domain. If no match exists, show the exact create operation and wait for approval.
83
+ 4. Propose a bounded Site Health scan. Include `--max-pages` and the state of dead-link checking. Show the connected operation or exact `cnry technical-aeo run ... --wait --format json` command. Wait for separate approval before scanning.
84
+ 5. If the run status is `completed` or `partial`, read its score and worst pages with run-pinned connected tools. For the shell path, use `cnry technical-aeo score <project> --run-id <run-id> --format json` and `cnry technical-aeo pages <project> --run-id <run-id> --sort score-asc --limit 10 --format jsonl`. If the run failed or was cancelled, inspect the run error and stop. Summarize completed evidence and propose AI Visibility setup.
85
+ 6. Ask before you add queries, connect providers, start a provider-backed or quota-consuming run, edit files, or publish.
86
+ ```
87
+
88
+ </details>
89
+
39
90
  ## Get a Page Health baseline
40
91
 
41
92
  ![Canonry Site Map graph](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/dashboard.png)
@@ -54,7 +105,9 @@ The dashboard, CLI, and agent tools share the same project API.
54
105
  cnry bootstrap
55
106
  ```
56
107
 
57
- Keep the output private. Provider credentials are optional. Bootstrap imports supported variables that are already in your environment.
108
+ Canonry stores `config.yaml` and `data.db` in `~/.canonry` by default. Set
109
+ `CANONRY_CONFIG_DIR` before `bootstrap`, `serve`, and later CLI commands to
110
+ keep an install in another private directory; use the same value every time.
58
111
 
59
112
  3. Start Canonry.
60
113
 
@@ -82,37 +135,11 @@ The dashboard, CLI, and agent tools share the same project API.
82
135
 
83
136
  `--wait` polls for up to 15 minutes. If the scan remains active, use the progress command below. If it fails or is cancelled, inspect it with `cnry run show <run-id> --format json`.
84
137
 
85
- ## Or use any shell-capable coding agent
86
-
87
- If your client supports the [Agent Plugin](docs/plugins.md) or [MCP adapter](docs/mcp.md), use that integration. Otherwise, paste this request into any shell-capable agent.
88
-
89
- <details>
90
- <summary>Copy the Site Health-first setup request</summary>
91
-
92
- <br />
93
-
94
- ```text
95
- Help me set up Canonry for my public site.
96
-
97
- Use the official Canonry docs:
98
- - Agent quickstart: https://github.com/Canonry/canonry#or-use-any-shell-capable-coding-agent
99
- - CLI reference: https://github.com/Canonry/canonry/blob/main/skills/canonry/references/canonry-cli.md
100
- - Plugin setup: https://github.com/Canonry/canonry/blob/main/docs/plugins.md
101
- - MCP setup: https://github.com/Canonry/canonry/blob/main/docs/mcp.md
102
-
103
- If a Canonry installation or connected plugin/MCP is available, use it. Do not create a duplicate. Choose the connected tools or the shell path, not both. The `cnry` and `canonry` commands are interchangeable.
104
-
105
- 1. Ask for my public domain, country, and language. Do not create or scan anything yet.
106
- 2. If connected tools are available, use them for the remaining steps. For the shell path, make sure that `cnry` is on PATH. Then run `cnry --version`. If Canonry is missing, propose `npm install -g @canonry/canonry` and wait for approval. If configuration is missing, tell me to run `cnry bootstrap` in my private terminal and wait. Never ask me to paste passwords, API keys, OAuth credentials, or command output.
107
- 3. Make sure that the API or connected tool is reachable. If the shell API is unavailable, propose `cnry start`. Wait for approval. List the projects with the connected project tool or `cnry project list --format json`. Reuse a project with the same domain. Make sure that the proposed name is not assigned to a different domain. If no match exists, show the exact create operation and wait for approval.
108
- 4. Propose a bounded Site Health scan. Include `--max-pages` and the state of dead-link checking. Show the connected operation or exact `cnry technical-aeo run ... --wait --format json` command. Wait for separate approval before scanning.
109
- 5. If the run status is `completed` or `partial`, read its score and worst pages with run-pinned connected tools. For the shell path, use `cnry technical-aeo score <project> --run-id <run-id> --format json` and `cnry technical-aeo pages <project> --run-id <run-id> --sort score-asc --limit 10 --format jsonl`. If the run failed or was cancelled, inspect the run error and stop. Summarize completed evidence and propose AI Visibility setup.
110
- 6. Ask before you add queries, connect providers, start a provider-backed or quota-consuming run, edit files, or publish.
111
- ```
138
+ ## Add AI Visibility when you need it
112
139
 
113
- </details>
140
+ ![Canonry AI Visibility mention share trend across answer engines](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/ai-visibility-trend.png)
114
141
 
115
- ## Add AI Visibility when you need it
142
+ *Track your share of answer-engine brand mentions over time.*
116
143
 
117
144
  ![Canonry AI Visibility citation map across queries and answer engines](https://raw.githubusercontent.com/Canonry/canonry/main/docs/images/ai-visibility-diagnostics.png)
118
145
 
@@ -134,6 +161,14 @@ cnry run my-site --wait
134
161
  cnry visibility-stats my-site --by-provider
135
162
  ```
136
163
 
164
+ ### Why we use model providers' APIs directly (not a router)
165
+
166
+ Canonry uses direct provider APIs to capture answers, citations, and available
167
+ search details that model routers can omit. This richer data helps us measure
168
+ brand mentions and website citations accurately and explain changes in your
169
+ visibility.
170
+ [Read more about accuracy and why we chose models and direct provider API adapters individually](docs/providers/model-selection.md).
171
+
137
172
  ## Technical surface
138
173
 
139
174
  | Surface | Use it for |
@@ -141,7 +176,7 @@ cnry visibility-stats my-site --by-provider
141
176
  | **CLI and REST API** | Script project measurements, diagnoses, actions, reports, and schedules. OpenAPI is available at `GET /api/v1/openapi.json`. |
142
177
  | **MCP and Agent Plugin** | Give Codex, Claude, Cursor, or a custom agent a typed, task-shaped tool surface. |
143
178
  | **Aero** | When enabled and configured, use the built-in analyst that reviews evidence and wakes after completed runs. |
144
- | **Dashboard** | Approve work, inspect evidence, and observe the same project record used by agents. |
179
+ | **Dashboard** | Review recommendations, inspect evidence, and observe the same project record used by agents. |
145
180
 
146
181
  ## Deployment and trust boundary
147
182
 
@@ -33,27 +33,30 @@ Then prepare the runtime in this order:
33
33
  1. With approval, install the global runtime if `command -v cnry` failed.
34
34
  2. Check only whether `$CANONRY_CONFIG_DIR/config.yaml` (when that variable is
35
35
  set) or `~/.canonry/config.yaml` exists; do not print the file. If it does
36
- not exist, pause and ask the operator to run `cnry init --skip-skills --skip-mcp`
37
- in their own private terminal, then confirm completion without
38
- pasting the output. Never execute `init` inside the agent session: it prompts
39
- for provider credentials and prints the new full-access API key once. The
40
- plugin already supplies the skills and MCP registration.
41
- 3. After a fresh initialization, get approval and run `cnry start --format
36
+ not exist, pause and ask the operator to run `cnry bootstrap` in their own
37
+ private terminal, then confirm completion without pasting the output.
38
+ Bootstrap needs no provider credential, but it prints the new full-access
39
+ API key once. Use `cnry init` only as an optional interactive first-time
40
+ path when the operator also wants provider/OAuth provisioning. The plugin
41
+ already supplies the skills and MCP registration.
42
+ 3. After a fresh bootstrap, get approval and run `cnry start --format
42
43
  json`; `start` waits for the health endpoint before returning. On an
43
44
  existing installation, try the doctor command first and start only when the
44
45
  transport is unavailable. Never stop or restart a healthy daemon just to
45
46
  install the plugin.
46
47
  4. Run `cnry doctor --format json` after the daemon is ready. A successful JSON
47
48
  response proves the health-check path works; individual checks may still
48
- report actionable `warn` or `fail` statuses. Plugin installation state is
49
+ report actionable `warn` or `fail` statuses. No provider is a warning, not a
50
+ failure: Page Health works without one and AI Visibility stays disabled.
51
+ Plugin installation state is
49
52
  read live, so installing the plugin alone does not require a daemon restart.
50
53
 
51
54
  Never ask the operator to paste credentials into the chat, print the raw API
52
55
  key, or inspect `~/.canonry/config.yaml` for secrets. The plugin does not expand
53
56
  the configured key's server-enforced scope, but it gives the client tools that
54
- can exercise that scope. Fresh `cnry init` creates a full-instance `*` key, so
55
- the default plugin has teammate-level access to every project and shared
56
- instance settings. A write-capable key exposes write tools by default; a
57
+ can exercise that scope. Fresh `cnry bootstrap` creates a full-instance `*` key.
58
+ The default plugin has teammate-level access to every project and shared
59
+ instance setting. A write-capable key exposes write tools by default; a
57
60
  read-only key restricts the catalog to reads, while a project-scoped key keeps
58
61
  its project route boundary but is not tenant isolation: a write-capable scoped
59
62
  key can still mutate shared instance settings. Do not work around a missing
@@ -5,8 +5,8 @@ The CLI is invoked as `cnry` (short form) or `canonry` — both ship with the `@
5
5
  ## Server Management
6
6
 
7
7
  ```bash
8
- cnry init # interactive setup
9
- cnry bootstrap # non-interactive setup from env vars
8
+ cnry bootstrap # local config/database; providers optional
9
+ cnry init # optional interactive provider/OAuth setup
10
10
  cnry start # start daemon
11
11
  cnry stop # stop daemon
12
12
  cnry serve # foreground mode
@@ -15,10 +15,11 @@ cnry serve --embed --embed-allow-origin https://app.example.com # read-only em
15
15
  cnry --version
16
16
  ```
17
17
 
18
- `cnry init` prompts for credentials and prints the new API key once. An agent
19
- must pause and ask the operator to run it in a private terminal, without
20
- pasting the output back. Do not run `init` or secret-bearing `bootstrap` inside
21
- an agent transcript.
18
+ `cnry bootstrap` is the provider-free Page Health path. It stores state under
19
+ `$CANONRY_CONFIG_DIR` when set, otherwise `~/.canonry`, and prints a new API key
20
+ once. `cnry init` is the optional interactive path when provider/OAuth setup is
21
+ wanted at the same time. An agent must ask the operator to run either
22
+ secret-bearing command in a private terminal without pasting the output back.
22
23
 
23
24
  ### Read-only embed mode (#716)
24
25
 
@@ -1 +1 @@
1
- import{r as a,u as h,j as e}from"./vendor-tanstack-Dock0eH1.js";import{cz as L,cA as P,bW as E,i as u,B as x,f as v,T as M}from"./index-CSictO9U.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 O(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 z(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(""),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=>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:z(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:O(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-CYBjbqVr.js";import{cG as L,cH as P,bW as E,f as u,B as x,e as v,T as M}from"./index-Brb7M_6G.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 O(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 B(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 F({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:B(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:O(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{F as A};
@@ -1 +1 @@
1
- import{r as n,j as e}from"./vendor-tanstack-Dock0eH1.js";import{cO as _,ah as H,cP as U,cQ as K,cR as V,f as x,T as j,j as u,B as w,l as F,cS as Y,cT as J,ak as X,cU as Z}from"./index-CSictO9U.js";import{D as ee,T as se,E as te,P as ae,v as ne,t as re}from"./vendor-lucide-nYKv-BB7.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-recharts-D8rt5lKn.js";import"./vendor-markdown-Bn7fRwrx.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,E]=n.useState(!1),[p,I]=n.useState(!1),[N,v]=n.useState(""),[T,k]=n.useState(!1),[P,l]=n.useState(null),[A,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(()=>[]),K().catch(()=>[]),V().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(){E(!0),l(null),o(null);try{const s=await Y();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{E(!1)}}async function q(){const s=N.trim()||void 0;I(!0),l(null),o(null);try{const r=await J(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{I(!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."})]})}),P&&e.jsx(x,{className:"surface-card p-4 mb-4 border-negative-800/60",children:e.jsx("p",{className:"text-sm text-negative",children:P})}),A&&e.jsx(x,{className:"surface-card p-4 mb-4 border-positive-800/60",children:e.jsx("p",{className:"text-sm text-positive",children:A})}),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
+ import{r as n,j as e}from"./vendor-tanstack-CYBjbqVr.js";import{cV as O,ag as H,cW as U,cX as V,cY as Y,e as x,T as j,i as u,B as w,k as $,cZ as K,c_ as X,aj as Z,c$ as J}from"./index-Brb7M_6G.js";import{D as ee,T as se,E as te,P as ae,v as ne,t as re}from"./vendor-lucide-XjCNFK0x.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-markdown-9tTeP8v7.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,F]=n.useState([]),[m,L]=n.useState(null),[B,D]=n.useState(!0),[R,E]=n.useState(!1),[p,I]=n.useState(!1),[N,v]=n.useState(""),[M,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,W,_,z]=await Promise.all([O(),H().catch(()=>null),U().catch(()=>[]),V().catch(()=>[]),Y().catch(()=>null)]);h(s),i(r),y(W),F(_),L(z)}catch(s){l(s instanceof Error?s.message:"Failed to load backlinks status")}finally{D(!1)}},[]);n.useEffect(()=>{f()},[f]);async function T(){E(!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{E(!1)}}async function q(){const s=N.trim()||void 0;I(!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 Z&&r.code==="MISSING_DEPENDENCY"?l("DuckDB is not installed. Install it first."):l(r instanceof Error?r.message:"Failed to trigger sync")}finally{I(!1)}}async function G(s){l(null),o(null);try{await J(s),o(`Pruned cached release ${s}.`),await f()}catch(r){l(r instanceof Error?r.message:"Failed to prune release")}}const Q=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:$(T),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."}),Q&&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:$(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:M?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 +1 @@
1
- import{j as i}from"./vendor-tanstack-Dock0eH1.js";import{R as k,C,a as R,e as A,X as I,Y as _,T as D,d as m}from"./vendor-recharts-D8rt5lKn.js";const L={contentStyle:{backgroundColor:"var(--chart-tooltip-bg, #18181b)",border:"1px solid var(--chart-tooltip-border, #3f3f46)",borderRadius:8,fontSize:12},labelStyle:{color:"var(--chart-tooltip-label, #e4e4e7)"},itemStyle:{color:"var(--chart-tooltip-item, #a1a1aa)"}},v={fill:"var(--chart-neutral-text-dim, #8b8b93)",fontSize:11},O="var(--chart-grid, #27272a)",b="var(--chart-axis, #27272a)",p=["var(--chart-series-1, #34d399)","var(--chart-series-2, #60a5fa)","var(--chart-series-3, #f472b6)","var(--chart-series-4, #facc15)","var(--chart-series-5, #a78bfa)","var(--chart-series-6, #fb923c)","var(--chart-series-7, #22d3ee)","var(--chart-series-8, #f87171)"],j={gemini:"#60a5fa",openai:"#34d399",claude:"#fb923c",perplexity:"#22d3ee",local:"#a78bfa"};function $(r,a=0){return j[r]??p[a%p.length]}const K={text:"var(--chart-neutral-text, #a1a1aa)",textDim:"var(--chart-neutral-text-dim, #8b8b93)",textFaint:"var(--chart-neutral-text-faint, #52525b)",surface:"var(--chart-neutral-surface, #27272a)",trackSubtle:"var(--chart-neutral-track-subtle, rgb(255 255 255 / 0.04))"},H={positive:"var(--chart-tone-positive, #34d399)",positiveDeep:"var(--chart-tone-positive-deep, #10b981)",caution:"var(--chart-tone-caution, #fbbf24)",negative:"var(--chart-tone-negative, #fb7185)"};function N(r){return r}function y(r){const a=/^(\d{4})-(\d{2})-(\d{2})/.exec(r);return a?{year:Number(a[1]),month:Number(a[2]),day:Number(a[3])}:null}function M(r){const a=String(r),e=y(a);return e?new Date(Date.UTC(e.year,e.month-1,e.day)).toLocaleDateString(void 0,{timeZone:"UTC",month:"short",day:"numeric",year:"numeric"}):a}function F(r){const a=y(String(r));return a?`${a.month}/${a.day}`:String(r)}function G(r){return new Date(r).toLocaleDateString(void 0,{month:"short",day:"numeric",year:"numeric"})}function P(r){const a=new Date(r);return`${a.getMonth()+1}/${a.getDate()}`}function U({data:r,xKey:a,series:e,height:x=260,xTickFormatter:g,labelFormatter:f,onSelectX:d,selectedX:u}){const h=[...new Set(e.map(t=>t.axisId))],S=new Map(e.map(t=>[t.label,t.formatValue])),T=r.map((t,s)=>{const n={...t};for(const o of e){if(!o.trend)continue;const c=o.trend.startIndex??0,l=o.trend.endIndex??r.length-1;if(s<c||s>l){n[`${o.dataKey}__trend`]=null;continue}n[`${o.dataKey}__trend`]=l<=c?o.trend.start:o.trend.start+(o.trend.end-o.trend.start)*(s-c)/(l-c)}return n});return i.jsx(k,{width:"100%",height:x,children:i.jsxs(C,{data:T,margin:{top:8,right:8,bottom:4,left:0},onClick:d?t=>{t?.activeLabel!==void 0&&d(String(t.activeLabel))}:void 0,style:d?{cursor:"pointer"}:void 0,children:[i.jsx(R,{stroke:O,strokeDasharray:"3 3",vertical:!1}),u!=null&&i.jsx(A,{x:u,yAxisId:h[0],stroke:K.text,strokeDasharray:"2 3",strokeWidth:1}),i.jsx(I,{dataKey:a,tick:v,stroke:b,tickFormatter:g,minTickGap:24}),h.map((t,s)=>{const n=e.find(o=>o.axisId===t);return i.jsx(_,{yAxisId:t,orientation:s===1?"right":"left",hide:s>1,reversed:n.inverted??!1,domain:n.inverted?[1,"auto"]:[0,"auto"],tick:v,stroke:b,width:48,tickFormatter:n.formatValue},t)}),i.jsx(D,{...L,labelFormatter:t=>f?f(String(t)):String(t),formatter:(t,s)=>{const n=String(s??"");return typeof t!="number"?[String(t??""),n]:[S.get(n)?.(t)??t.toLocaleString(),n]}}),e.filter(t=>t.trend).map(t=>i.jsx(m,{yAxisId:t.axisId,dataKey:`${t.dataKey}__trend`,name:`${t.label} trend`,stroke:t.color,strokeWidth:1.5,strokeDasharray:"5 4",strokeOpacity:.55,dot:!1,activeDot:!1,isAnimationActive:!1,legendType:"none",tooltipType:"none"},`${t.dataKey}-trend`)),e.map(t=>i.jsx(m,{yAxisId:t.axisId,dataKey:t.dataKey,name:t.label,stroke:t.color,strokeWidth:2,dot:!1,activeDot:{r:3},connectNulls:!1,isAnimationActive:!1},t.dataKey))]})})}export{O as C,U as M,b as a,v as b,M as c,L as d,p as e,F as f,K as g,H as h,P as i,G as j,N as o,$ as p};
1
+ import{j as i}from"./vendor-tanstack-CYBjbqVr.js";import{R as k,C,a as R,e as A,X as I,Y as _,T as D,d as m}from"./vendor-recharts-FA0uySU7.js";const L={contentStyle:{backgroundColor:"var(--chart-tooltip-bg, #18181b)",border:"1px solid var(--chart-tooltip-border, #3f3f46)",borderRadius:8,fontSize:12},labelStyle:{color:"var(--chart-tooltip-label, #e4e4e7)"},itemStyle:{color:"var(--chart-tooltip-item, #a1a1aa)"}},v={fill:"var(--chart-neutral-text-dim, #8b8b93)",fontSize:11},O="var(--chart-grid, #27272a)",b="var(--chart-axis, #27272a)",p=["var(--chart-series-1, #34d399)","var(--chart-series-2, #60a5fa)","var(--chart-series-3, #f472b6)","var(--chart-series-4, #facc15)","var(--chart-series-5, #a78bfa)","var(--chart-series-6, #fb923c)","var(--chart-series-7, #22d3ee)","var(--chart-series-8, #f87171)"],j={gemini:"#60a5fa",openai:"#34d399",claude:"#fb923c",perplexity:"#22d3ee",local:"#a78bfa"};function $(r,a=0){return j[r]??p[a%p.length]}const K={text:"var(--chart-neutral-text, #a1a1aa)",textDim:"var(--chart-neutral-text-dim, #8b8b93)",textFaint:"var(--chart-neutral-text-faint, #52525b)",surface:"var(--chart-neutral-surface, #27272a)",trackSubtle:"var(--chart-neutral-track-subtle, rgb(255 255 255 / 0.04))"},H={positive:"var(--chart-tone-positive, #34d399)",positiveDeep:"var(--chart-tone-positive-deep, #10b981)",caution:"var(--chart-tone-caution, #fbbf24)",negative:"var(--chart-tone-negative, #fb7185)"};function N(r){return r}function y(r){const a=/^(\d{4})-(\d{2})-(\d{2})/.exec(r);return a?{year:Number(a[1]),month:Number(a[2]),day:Number(a[3])}:null}function M(r){const a=String(r),e=y(a);return e?new Date(Date.UTC(e.year,e.month-1,e.day)).toLocaleDateString(void 0,{timeZone:"UTC",month:"short",day:"numeric",year:"numeric"}):a}function F(r){const a=y(String(r));return a?`${a.month}/${a.day}`:String(r)}function G(r){return new Date(r).toLocaleDateString(void 0,{month:"short",day:"numeric",year:"numeric"})}function P(r){const a=new Date(r);return`${a.getMonth()+1}/${a.getDate()}`}function U({data:r,xKey:a,series:e,height:x=260,xTickFormatter:g,labelFormatter:f,onSelectX:d,selectedX:u}){const h=[...new Set(e.map(t=>t.axisId))],S=new Map(e.map(t=>[t.label,t.formatValue])),T=r.map((t,s)=>{const n={...t};for(const o of e){if(!o.trend)continue;const c=o.trend.startIndex??0,l=o.trend.endIndex??r.length-1;if(s<c||s>l){n[`${o.dataKey}__trend`]=null;continue}n[`${o.dataKey}__trend`]=l<=c?o.trend.start:o.trend.start+(o.trend.end-o.trend.start)*(s-c)/(l-c)}return n});return i.jsx(k,{width:"100%",height:x,children:i.jsxs(C,{data:T,margin:{top:8,right:8,bottom:4,left:0},onClick:d?t=>{t?.activeLabel!==void 0&&d(String(t.activeLabel))}:void 0,style:d?{cursor:"pointer"}:void 0,children:[i.jsx(R,{stroke:O,strokeDasharray:"3 3",vertical:!1}),u!=null&&i.jsx(A,{x:u,yAxisId:h[0],stroke:K.text,strokeDasharray:"2 3",strokeWidth:1}),i.jsx(I,{dataKey:a,tick:v,stroke:b,tickFormatter:g,minTickGap:24}),h.map((t,s)=>{const n=e.find(o=>o.axisId===t);return i.jsx(_,{yAxisId:t,orientation:s===1?"right":"left",hide:s>1,reversed:n.inverted??!1,domain:n.inverted?[1,"auto"]:[0,"auto"],tick:v,stroke:b,width:48,tickFormatter:n.formatValue},t)}),i.jsx(D,{...L,labelFormatter:t=>f?f(String(t)):String(t),formatter:(t,s)=>{const n=String(s??"");return typeof t!="number"?[String(t??""),n]:[S.get(n)?.(t)??t.toLocaleString(),n]}}),e.filter(t=>t.trend).map(t=>i.jsx(m,{yAxisId:t.axisId,dataKey:`${t.dataKey}__trend`,name:`${t.label} trend`,stroke:t.color,strokeWidth:1.5,strokeDasharray:"5 4",strokeOpacity:.55,dot:!1,activeDot:!1,isAnimationActive:!1,legendType:"none",tooltipType:"none"},`${t.dataKey}-trend`)),e.map(t=>i.jsx(m,{yAxisId:t.axisId,dataKey:t.dataKey,name:t.label,stroke:t.color,strokeWidth:2,dot:!1,activeDot:{r:3},connectNulls:!1,isAnimationActive:!1},t.dataKey))]})})}export{O as C,U as M,b as a,v as b,M as c,L as d,p as e,F as f,K as g,H as h,P as i,G as j,N as o,$ as p};
@@ -1 +1 @@
1
- import{j as e}from"./vendor-tanstack-Dock0eH1.js";import{A as s}from"./AuditHistoryPanel-B1lmI7wm.js";import"./index-CSictO9U.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-recharts-D8rt5lKn.js";import"./vendor-lucide-nYKv-BB7.js";import"./vendor-markdown-Bn7fRwrx.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-CYBjbqVr.js";import{A as s}from"./AuditHistoryPanel-1_FHpzj-.js";import"./index-Brb7M_6G.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-lucide-XjCNFK0x.js";import"./vendor-markdown-9tTeP8v7.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{C as ie,r as w,u as L,D as oe,j as e,L as T}from"./vendor-tanstack-Dock0eH1.js";import{aN as le,c3 as de,dc as ce,i as E,dd as he,c9 as me,bY as xe,B as j,T as N,I as P,de as pe,df as ue,dg as je}from"./index-CSictO9U.js";import{j as ye,o as be}from"./ChartPrimitives-DG35TyhH.js";import{m as ve}from"./v2-overview-adapter-COMP5UGt.js";import{y as ge}from"./vendor-lucide-nYKv-BB7.js";import"./vendor-radix-4UOaVWza.js";import"./vendor-recharts-D8rt5lKn.js";import"./vendor-markdown-Bn7fRwrx.js";import"./vendor-yaml-GWJz5H2G.js";const K=50,h={branded:{headline:"When they know your name",technical:"Branded queries"},"non-brand":{headline:"When they don't",technical:"Non-brand queries"}},Ne={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",not_applicable:"Not applicable for this Property"},W={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"}},D={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 fe(s){return[...s].sort((t,a)=>+(a.classification==="assigned")-+(t.classification==="assigned"))}function we(s){return`${s.expectedSlotId}:${s.usageEdgeId}`}function Pe({row:s}){return s.mentioned===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(N,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"No mention signal for this Property"})]}):e.jsx(N,{tone:s.mentioned?"positive":"neutral",children:s.mentioned?"Mentioned":"Not mentioned"})}const Ce="—";function Le({row:s}){return s.cited===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(N,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"Sources were not fully captured"})]}):e.jsx(N,{tone:s.cited?"positive":"neutral",children:s.cited?"Cited":"Not cited"})}function Ee({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.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:fe(s.sources).map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx(N,{tone:D[t.classification].tone,children:D[t.classification].label})}),e.jsx("td",{className:"break-all text-secondary",children:t.sourceUrl})]},t.sourceUrl))})]})})}function Me({project:s,targetKey:t,row:a}){const n=L({...je({client:E,path:{name:s},query:{targetKey:t,resultId:a.observationId}})});if(n.isPending)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"status","aria-live":"polite",children:"Loading the answer…"});if(n.isError)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"alert",children:"Could not load this answer."});const o=n.data?.answer;return o==null||o.trim()===""?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer was measured, but its text was not stored."}):e.jsxs("div",{className:"py-2",children:[e.jsxs("h4",{className:"mb-1 text-xs font-medium tracking-wide text-muted uppercase",children:["What ",a.provider," answered"]}),e.jsx("p",{className:"max-h-64 overflow-y-auto whitespace-pre-wrap text-sm leading-relaxed text-secondary",children:o})]})}function q(s){return Ne[s.reason]??"Not measured"}function k({metric:s,emphasis:t=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:t?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:q(s)})]});const a=`${Math.round(s.value*100)}%`,n=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`;return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:t?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:a}),n?e.jsx("span",{className:"text-xs text-muted",children:n}):null]})}function H(s,t,a){return pe({client:E,path:{name:s},query:{scope:"property",targetKey:t,queryClass:a}})}function G(s){return s?.properties.items.at(0)}function Re({measuredAt:s,unmeasuredReason:t,queryClass:a}){const n=s===void 0?null:s===null?"No completed sweep yet":`Measured ${ye(be(s))}`;return n===null&&t===void 0?null:e.jsxs("p",{className:"supporting-copy",children:[[n,t].filter(Boolean).join(" · "),n!==null&&t===void 0?` · ${h[a].technical.toLocaleLowerCase()} only`:""]})}function Se({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(j,{asChild:!0,type:"button",size:"sm",variant:"outline",children:e.jsx(T,{to:"/projects/$projectName",params:{projectName:s},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 S({label:s,metric:t,failed:a=!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:a?"Unavailable":"…"}),a?e.jsx("div",{}):e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true"}),e.jsx("p",{className:"aeo-hero-row-detail",children:a?"Could not be loaded":"Loading"})]});if(t.state==="unavailable"){const m=q(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:m==="Not measured"?"":m})]})}const n=Math.round(t.value*100),o=t.numerator===void 0||t.denominator===void 0?null:`${t.numerator} of ${t.denominator}`;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:[n,e.jsx("span",{className:"text-faint",children:"%"})]}),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:`${n}%`}})}),e.jsx("p",{className:"aeo-hero-row-detail tabular-nums",children:o??""})]})}function Te({branded:s,nonBrand:t,brandedFailed:a=!1,nonBrandFailed:n=!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(S,{label:"Mentioned",metric:t?.mentionCoverage,failed:n}),e.jsx(S,{label:"Cited",metric:t?.citationCoverage,failed:n})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Branded · already named"}),e.jsx(S,{label:"Mentioned",metric:s?.mentionCoverage,failed:a}),e.jsx(S,{label:"Cited",metric:s?.citationCoverage,failed:a})]})]})]})}function ke({branded:s,nonBrand:t,brandedError:a,nonBrandError:n,onRetry:o}){const m=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:t,isError:n}];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:m.map(({queryClass:r,row:l,isError:y})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:h[r].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:h[r].technical}),l&&y?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(j,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>o(r),children:["Retry ",h[r].technical.toLocaleLowerCase()]})]}):null]}),l?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(k,{metric:l.mentionCoverage,emphasis:!0})}),e.jsx("td",{children:e.jsx(k,{metric:l.citationCoverage,emphasis:!0})})]}):y?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 ",h[r].technical.toLocaleLowerCase(),"."]}),e.jsxs(j,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>o(r),children:["Retry ",h[r].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…"})})]})]},r))})]})})]})}function qe({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 ",h[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 ",h[t].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${q(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(n=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:n.provider}),e.jsx("td",{children:e.jsx(k,{metric:n.mentionCoverage})}),e.jsx("td",{children:e.jsx(k,{metric:n.citationCoverage})})]},n.provider))})]})})]})}function Ae(s){const t=s.questions.join(" · ");return s.questionsTruncated?`${t} +${s.questionTotal-s.questions.length} more`:t}function Be({project:s,targetKey:t,queryClass:a}){const n=L({...ue({client:E,path:{name:s},query:{targetKey:t,queryClass:a}})});if(n.isPending||n.isError)return null;const o=n.data?.competitors??[],m=n.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."})]})}),o.length>0?e.jsxs("p",{className:"supporting-copy",children:[n.data?.total??o.length," named"]}):null]}),o.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:o.map(r=>e.jsxs("tr",{children:[e.jsx("td",{className:"text-strong",children:r.name}),e.jsx("td",{className:"tabular-nums text-secondary",children:r.occurrences}),e.jsxs("td",{className:"text-secondary",children:[r.providers.join(", "),r.providersTruncated?` +${r.providerTotal-r.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:r.questionTotal}),e.jsx(P,{text:Ae(r)})]})})]},r.name))})]})}),m?.state==="available"?e.jsxs("p",{className:"supporting-copy mt-2",children:[m.targetMissResults," of ",m.answeredResults," answers to ",h[a].technical.toLocaleLowerCase()," did not name this Property."]}):null]})]})}function Ue({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:[h[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 ",h[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 Ie({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 He(){const{projectName:s,targetKey:t}=ie({strict:!1}),[a,n]=w.useState("non-brand"),[o,m]=w.useState(new Set),r=s??"",l=t??"",y=!!r&&!!l,{canWrite:A}=le(),C=L({...de({client:E,path:{name:r}}),enabled:y}),b=L({...H(r,l,"branded"),enabled:y}),v=L({...H(r,l,"non-brand"),enabled:y}),B=G(b.data),U=G(v.data),x=a==="branded"?b.data:v.data,f=a==="branded"?B:U,O=(a==="branded"?b.isError:v.isError)&&f===void 0,Q=x?.measurement.displayedRunId,Y=f?.mentionCoverage.state==="unavailable"?q(f.mentionCoverage):void 0,Z=x===void 0?void 0:x.measurement.completedAt??null,M={client:E,path:{name:r},query:{targetKey:l,queryClass:a,shape:ce.answers,limit:K,...Q?{runId:Q}:{}}},d=oe({...he(M),enabled:y&&x!==void 0,initialPageParam:M,getNextPageParam:i=>i.answers?.nextCursor?{path:M.path,query:{...M.query,cursor:i.answers.nextCursor}}:void 0}),I=C.data?.active??null,p=I?.plan.schemaVersion===2?I.plan:null,J=I!==null&&p===null,R=p?.targets.find(i=>i.stableKey===l)??null,X=w.useMemo(()=>{if(!p)return[];const i=new Map(p.querySnapshots.map(c=>[c.queryId,c.queryText]));return[...new Set(p.assignments.filter(c=>c.targetKey===l&&c.queryClass===a).flatMap(c=>{const u=i.get(c.queryId);return u===void 0?[]:[u]}))].sort((c,u)=>c.localeCompare(u))},[p,l,a]),ee=w.useMemo(()=>R?.urlMatchers.map(ve)??[],[R]),se=w.useMemo(()=>p?.groups.filter(i=>i.targetKeys.includes(l))??[],[p,l]),g=w.useMemo(()=>(d.data?.pages??[]).flatMap(u=>u.answers?.items??[]),[d.data]),V=d.data?.pages[0]?.answers?.totalEstimate??g.length,te=(d.data?.pages??[]).length>0&&(d.data?.pages??[]).every(i=>i.answers===void 0),ae=d.data?.pages[0]?.measurement.state,$=e.jsxs(T,{to:"/projects/$projectName",params:{projectName:r},className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(ge,{className:"size-3.5","aria-hidden":"true"}),"Back to measurement overview"]});if(!y)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(!me("portfolio",xe()?.projectTabs))return e.jsx("div",{className:"page-container",children: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 ne=C.isError&&C.data===void 0,F=b.isError&&b.data===void 0,z=v.isError&&v.data===void 0;return ne||F&&z?e.jsxs("div",{className:"page-container space-y-3",children:[$,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(j,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{C.refetch(),b.refetch(),v.refetch()},children:"Try again"})]}):!p||!R?e.jsxs("div",{className:"page-container space-y-3",children:[$,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:p?"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(j,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(T,{to:"/projects/$projectName/portfolio",params:{projectName:r},children:A?J?"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:[$,e.jsx("h1",{className:"page-title mt-2",children:R.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",r]})]}),e.jsxs("div",{className:"page-header-right",children:[x?e.jsx(N,{tone:W[x.measurement.state].tone,children:W[x.measurement.state].label}):null,f&&f.flags>0?e.jsxs(N,{tone:"caution",children:[f.flags," flagged"]}):null]})]}),e.jsx(Te,{branded:B,nonBrand:U,brandedFailed:F,nonBrandFailed:z}),e.jsx(ke,{branded:B,nonBrand:U,brandedError:b.isError,nonBrandError:v.isError,onRetry:i=>{i==="branded"?b.refetch():v.refetch()}}),x&&(x.measurement.state==="not_measured"||x.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:A?"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(j,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(T,{to:"/projects/$projectName",params:{projectName:r},children:A?"Go to measurement overview":"View measurement overview"})})]}):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:a,onChange:i=>n(i.target.value==="branded"?"branded":"non-brand"),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:h["non-brand"].technical}),e.jsx("option",{value:"branded",children:h.branded.technical})]})]}),e.jsx(Re,{measuredAt:Z,unmeasuredReason:Y,queryClass:a})]}),e.jsx(qe,{row:f,queryClass:a,isError:O}),e.jsx(Be,{project:r,targetKey:l,queryClass:a}),e.jsx(Ue,{questions:X,queryClass:a}),e.jsx(Ie,{urls:ee}),e.jsx(Se,{project:r,groups:se}),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."})]})}),g.length>0?e.jsxs("p",{className:"supporting-copy",children:[g.length," of ",V]}):null]}),O?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",h[a].technical.toLocaleLowerCase()," is unavailable. Retry that query type above."]}):d.isPending&&g.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):d.isError&&g.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(j,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{d.refetch()},children:"Retry evidence"})]}):ae==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:"Not measured yet. Run a measurement to collect the answers for this Property."}):te?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."}):g.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:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[720px]",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:g.map(i=>{const c=we(i),u=o.has(c);return e.jsxs(w.Fragment,{children:[e.jsxs("tr",{children:[e.jsxs("td",{className:"text-secondary",children:[e.jsx("span",{className:"block",children:i.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[i.provider,i.location].filter(Boolean).join(" · ")}),i.historical||i.bridged?e.jsx("span",{className:"mt-1 flex",children:e.jsx(N,{tone:"caution",children:"Historical"})}):null]}),e.jsx("td",{children:e.jsx(Pe,{row:i})}),e.jsx("td",{children:e.jsx(Le,{row:i})}),e.jsx("td",{className:"tabular-nums text-secondary",children:i.cited===null?Ce:i.sources.length}),e.jsx("td",{className:"text-right",children:e.jsx(j,{type:"button",size:"sm",variant:"ghost","aria-expanded":u,onClick:()=>m(re=>{const _=new Set(re);return _.delete(c)||_.add(c),_}),children:u?`Hide the answer for ${i.queryText}`:`Read the answer for ${i.queryText}`})})]}),u?e.jsx("tr",{children:e.jsxs("td",{colSpan:5,className:"bg-surface-subtle px-4",children:[e.jsx(Me,{project:r,targetKey:l,row:i}),e.jsx(Ee,{row:i})]})}):null]},c)})})]})}),d.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",g.length," of ",V]}),d.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(j,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:d.isFetchingNextPage,onClick:()=>{d.fetchNextPage()},children:d.isFetchingNextPage?"Loading…":d.isFetchNextPageError?"Retry more evidence":`Show ${K} more`})]}):null]})]})]})}export{He as MeasurementPropertyPage};
1
+ import{C as ie,r as w,u as L,D as oe,j as e,L as T}from"./vendor-tanstack-CYBjbqVr.js";import{aM as le,c7 as de,dj as ce,f as E,dk as he,cf as me,c1 as xe,B as j,T as N,I as P,dl as pe,dm as ue,dn as je}from"./index-Brb7M_6G.js";import{j as ye,o as be}from"./ChartPrimitives-DLEICrrL.js";import{m as ve}from"./v2-overview-adapter-COMP5UGt.js";import{y as ge}from"./vendor-lucide-XjCNFK0x.js";import"./vendor-radix-BpmvLvpp.js";import"./vendor-recharts-FA0uySU7.js";import"./vendor-markdown-9tTeP8v7.js";import"./vendor-yaml-GWJz5H2G.js";const K=50,h={branded:{headline:"When they know your name",technical:"Branded queries"},"non-brand":{headline:"When they don't",technical:"Non-brand queries"}},Ne={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",not_applicable:"Not applicable for this Property"},W={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"}},D={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 fe(s){return[...s].sort((t,a)=>+(a.classification==="assigned")-+(t.classification==="assigned"))}function we(s){return`${s.expectedSlotId}:${s.usageEdgeId}`}function Pe({row:s}){return s.mentioned===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(N,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"No mention signal for this Property"})]}):e.jsx(N,{tone:s.mentioned?"positive":"neutral",children:s.mentioned?"Mentioned":"Not mentioned"})}const Ce="—";function Le({row:s}){return s.cited===null?e.jsxs("span",{className:"inline-flex flex-col items-start gap-0.5",children:[e.jsx(N,{tone:"neutral",children:"Not measured"}),e.jsx("span",{className:"text-xs text-muted",children:"Sources were not fully captured"})]}):e.jsx(N,{tone:s.cited?"positive":"neutral",children:s.cited?"Cited":"Not cited"})}function Ee({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.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:fe(s.sources).map(t=>e.jsxs("tr",{children:[e.jsx("td",{children:e.jsx(N,{tone:D[t.classification].tone,children:D[t.classification].label})}),e.jsx("td",{className:"break-all text-secondary",children:t.sourceUrl})]},t.sourceUrl))})]})})}function Me({project:s,targetKey:t,row:a}){const n=L({...je({client:E,path:{name:s},query:{targetKey:t,resultId:a.observationId}})});if(n.isPending)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"status","aria-live":"polite",children:"Loading the answer…"});if(n.isError)return e.jsx("p",{className:"py-2 text-sm text-secondary",role:"alert",children:"Could not load this answer."});const o=n.data?.answer;return o==null||o.trim()===""?e.jsx("p",{className:"py-2 text-sm text-secondary",children:"This answer was measured, but its text was not stored."}):e.jsxs("div",{className:"py-2",children:[e.jsxs("h4",{className:"mb-1 text-xs font-medium tracking-wide text-muted uppercase",children:["What ",a.provider," answered"]}),e.jsx("p",{className:"max-h-64 overflow-y-auto whitespace-pre-wrap text-sm leading-relaxed text-secondary",children:o})]})}function q(s){return Ne[s.reason]??"Not measured"}function k({metric:s,emphasis:t=!1}){if(s.state==="unavailable")return e.jsxs("span",{className:"inline-flex flex-col gap-0.5",children:[e.jsx("span",{className:t?"text-lg font-semibold text-secondary":"text-sm font-medium text-secondary",children:"Not measured"}),e.jsx("span",{className:"text-sm text-secondary",children:q(s)})]});const a=`${Math.round(s.value*100)}%`,n=s.numerator===void 0||s.denominator===void 0?null:`${s.numerator} of ${s.denominator}`;return e.jsxs("span",{className:"inline-flex flex-col gap-0.5 tabular-nums",children:[e.jsx("span",{className:t?"text-lg font-semibold text-heading":"text-sm font-medium text-primary",children:a}),n?e.jsx("span",{className:"text-xs text-muted",children:n}):null]})}function H(s,t,a){return pe({client:E,path:{name:s},query:{scope:"property",targetKey:t,queryClass:a}})}function G(s){return s?.properties.items.at(0)}function Re({measuredAt:s,unmeasuredReason:t,queryClass:a}){const n=s===void 0?null:s===null?"No completed sweep yet":`Measured ${ye(be(s))}`;return n===null&&t===void 0?null:e.jsxs("p",{className:"supporting-copy",children:[[n,t].filter(Boolean).join(" · "),n!==null&&t===void 0?` · ${h[a].technical.toLocaleLowerCase()} only`:""]})}function Se({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(j,{asChild:!0,type:"button",size:"sm",variant:"outline",children:e.jsx(T,{to:"/projects/$projectName",params:{projectName:s},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 S({label:s,metric:t,failed:a=!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:a?"Unavailable":"…"}),a?e.jsx("div",{}):e.jsx("div",{className:"aeo-hero-row-bar","aria-hidden":"true"}),e.jsx("p",{className:"aeo-hero-row-detail",children:a?"Could not be loaded":"Loading"})]});if(t.state==="unavailable"){const m=q(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:m==="Not measured"?"":m})]})}const n=Math.round(t.value*100),o=t.numerator===void 0||t.denominator===void 0?null:`${t.numerator} of ${t.denominator}`;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:[n,e.jsx("span",{className:"text-faint",children:"%"})]}),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:`${n}%`}})}),e.jsx("p",{className:"aeo-hero-row-detail tabular-nums",children:o??""})]})}function Te({branded:s,nonBrand:t,brandedFailed:a=!1,nonBrandFailed:n=!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(S,{label:"Mentioned",metric:t?.mentionCoverage,failed:n}),e.jsx(S,{label:"Cited",metric:t?.citationCoverage,failed:n})]}),e.jsxs("div",{className:"space-y-2",children:[e.jsx("p",{className:"eyebrow eyebrow-soft",children:"Branded · already named"}),e.jsx(S,{label:"Mentioned",metric:s?.mentionCoverage,failed:a}),e.jsx(S,{label:"Cited",metric:s?.citationCoverage,failed:a})]})]})]})}function ke({branded:s,nonBrand:t,brandedError:a,nonBrandError:n,onRetry:o}){const m=[{queryClass:"branded",row:s,isError:a},{queryClass:"non-brand",row:t,isError:n}];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:m.map(({queryClass:r,row:l,isError:y})=>e.jsxs("tr",{children:[e.jsxs("td",{children:[e.jsx("span",{className:"block font-medium text-heading",children:h[r].headline}),e.jsx("span",{className:"mt-0.5 block text-xs text-muted",children:h[r].technical}),l&&y?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(j,{type:"button",size:"sm",variant:"ghost",className:"h-11 px-3 text-sm md:h-11",onClick:()=>o(r),children:["Retry ",h[r].technical.toLocaleLowerCase()]})]}):null]}),l?e.jsxs(e.Fragment,{children:[e.jsx("td",{children:e.jsx(k,{metric:l.mentionCoverage,emphasis:!0})}),e.jsx("td",{children:e.jsx(k,{metric:l.citationCoverage,emphasis:!0})})]}):y?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 ",h[r].technical.toLocaleLowerCase(),"."]}),e.jsxs(j,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>o(r),children:["Retry ",h[r].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…"})})]})]},r))})]})})]})}function qe({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 ",h[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 ",h[t].technical.toLocaleLowerCase()," for this Property.",s.mentionCoverage.state==="unavailable"?` ${q(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(n=>e.jsxs("tr",{children:[e.jsx("td",{className:"font-medium text-heading",children:n.provider}),e.jsx("td",{children:e.jsx(k,{metric:n.mentionCoverage})}),e.jsx("td",{children:e.jsx(k,{metric:n.citationCoverage})})]},n.provider))})]})})]})}function Ae(s){const t=s.questions.join(" · ");return s.questionsTruncated?`${t} +${s.questionTotal-s.questions.length} more`:t}function Be({project:s,targetKey:t,queryClass:a}){const n=L({...ue({client:E,path:{name:s},query:{targetKey:t,queryClass:a}})});if(n.isPending||n.isError)return null;const o=n.data?.competitors??[],m=n.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."})]})}),o.length>0?e.jsxs("p",{className:"supporting-copy",children:[n.data?.total??o.length," named"]}):null]}),o.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:o.map(r=>e.jsxs("tr",{children:[e.jsx("td",{className:"text-strong",children:r.name}),e.jsx("td",{className:"tabular-nums text-secondary",children:r.occurrences}),e.jsxs("td",{className:"text-secondary",children:[r.providers.join(", "),r.providersTruncated?` +${r.providerTotal-r.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:r.questionTotal}),e.jsx(P,{text:Ae(r)})]})})]},r.name))})]})}),m?.state==="available"?e.jsxs("p",{className:"supporting-copy mt-2",children:[m.targetMissResults," of ",m.answeredResults," answers to ",h[a].technical.toLocaleLowerCase()," did not name this Property."]}):null]})]})}function Ue({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:[h[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 ",h[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 Ie({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 He(){const{projectName:s,targetKey:t}=ie({strict:!1}),[a,n]=w.useState("non-brand"),[o,m]=w.useState(new Set),r=s??"",l=t??"",y=!!r&&!!l,{canWrite:A}=le(),C=L({...de({client:E,path:{name:r}}),enabled:y}),b=L({...H(r,l,"branded"),enabled:y}),v=L({...H(r,l,"non-brand"),enabled:y}),B=G(b.data),U=G(v.data),x=a==="branded"?b.data:v.data,f=a==="branded"?B:U,O=(a==="branded"?b.isError:v.isError)&&f===void 0,Q=x?.measurement.displayedRunId,Z=f?.mentionCoverage.state==="unavailable"?q(f.mentionCoverage):void 0,J=x===void 0?void 0:x.measurement.completedAt??null,M={client:E,path:{name:r},query:{targetKey:l,queryClass:a,shape:ce.answers,limit:K,...Q?{runId:Q}:{}}},d=oe({...he(M),enabled:y&&x!==void 0,initialPageParam:M,getNextPageParam:i=>i.answers?.nextCursor?{path:M.path,query:{...M.query,cursor:i.answers.nextCursor}}:void 0}),I=C.data?.active??null,p=I?.plan.schemaVersion===2?I.plan:null,X=I!==null&&p===null,R=p?.targets.find(i=>i.stableKey===l)??null,Y=w.useMemo(()=>{if(!p)return[];const i=new Map(p.querySnapshots.map(c=>[c.queryId,c.queryText]));return[...new Set(p.assignments.filter(c=>c.targetKey===l&&c.queryClass===a).flatMap(c=>{const u=i.get(c.queryId);return u===void 0?[]:[u]}))].sort((c,u)=>c.localeCompare(u))},[p,l,a]),ee=w.useMemo(()=>R?.urlMatchers.map(ve)??[],[R]),se=w.useMemo(()=>p?.groups.filter(i=>i.targetKeys.includes(l))??[],[p,l]),g=w.useMemo(()=>(d.data?.pages??[]).flatMap(u=>u.answers?.items??[]),[d.data]),V=d.data?.pages[0]?.answers?.totalEstimate??g.length,te=(d.data?.pages??[]).length>0&&(d.data?.pages??[]).every(i=>i.answers===void 0),ae=d.data?.pages[0]?.measurement.state,$=e.jsxs(T,{to:"/projects/$projectName",params:{projectName:r},className:"inline-flex items-center gap-1 text-xs text-muted hover:text-strong",children:[e.jsx(ge,{className:"size-3.5","aria-hidden":"true"}),"Back to measurement overview"]});if(!y)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(!me("portfolio",xe()?.projectTabs))return e.jsx("div",{className:"page-container",children: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 ne=C.isError&&C.data===void 0,F=b.isError&&b.data===void 0,z=v.isError&&v.data===void 0;return ne||F&&z?e.jsxs("div",{className:"page-container space-y-3",children:[$,e.jsx("p",{role:"alert",className:"text-sm text-negative",children:"Could not load this Property."}),e.jsx(j,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{C.refetch(),b.refetch(),v.refetch()},children:"Try again"})]}):!p||!R?e.jsxs("div",{className:"page-container space-y-3",children:[$,e.jsx("p",{role:"status",className:"text-sm text-secondary",children:p?"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(j,{asChild:!0,type:"button",variant:"outline",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(T,{to:"/projects/$projectName/portfolio",params:{projectName:r},children:A?X?"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:[$,e.jsx("h1",{className:"page-title mt-2",children:R.label}),e.jsxs("p",{className:"page-subtitle",children:["Property in ",r]})]}),e.jsxs("div",{className:"page-header-right",children:[x?e.jsx(N,{tone:W[x.measurement.state].tone,children:W[x.measurement.state].label}):null,f&&f.flags>0?e.jsxs(N,{tone:"caution",children:[f.flags," flagged"]}):null]})]}),e.jsx(Te,{branded:B,nonBrand:U,brandedFailed:F,nonBrandFailed:z}),e.jsx(ke,{branded:B,nonBrand:U,brandedError:b.isError,nonBrandError:v.isError,onRetry:i=>{i==="branded"?b.refetch():v.refetch()}}),x&&(x.measurement.state==="not_measured"||x.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:A?"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(j,{asChild:!0,type:"button",className:"h-11 px-4 text-sm md:h-11",children:e.jsx(T,{to:"/projects/$projectName",params:{projectName:r},children:A?"Go to measurement overview":"View measurement overview"})})]}):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:a,onChange:i=>n(i.target.value==="branded"?"branded":"non-brand"),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:h["non-brand"].technical}),e.jsx("option",{value:"branded",children:h.branded.technical})]})]}),e.jsx(Re,{measuredAt:J,unmeasuredReason:Z,queryClass:a})]}),e.jsx(qe,{row:f,queryClass:a,isError:O}),e.jsx(Be,{project:r,targetKey:l,queryClass:a}),e.jsx(Ue,{questions:Y,queryClass:a}),e.jsx(Ie,{urls:ee}),e.jsx(Se,{project:r,groups:se}),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."})]})}),g.length>0?e.jsxs("p",{className:"supporting-copy",children:[g.length," of ",V]}):null]}),O?e.jsxs("p",{className:"text-sm text-secondary",children:["Evidence for ",h[a].technical.toLocaleLowerCase()," is unavailable. Retry that query type above."]}):d.isPending&&g.length===0?e.jsx("p",{className:"text-sm text-secondary",children:"Loading evidence…"}):d.isError&&g.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(j,{type:"button",size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",onClick:()=>{d.refetch()},children:"Retry evidence"})]}):ae==="not_measured"?e.jsx("p",{className:"text-sm text-secondary",children:"Not measured yet. Run a measurement to collect the answers for this Property."}):te?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."}):g.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:"overflow-x-auto rounded-md border border-default",children:e.jsxs("table",{className:"evidence-table min-w-[720px]",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:g.map(i=>{const c=we(i),u=o.has(c);return e.jsxs(w.Fragment,{children:[e.jsxs("tr",{children:[e.jsxs("td",{className:"text-secondary",children:[e.jsx("span",{className:"block",children:i.queryText}),e.jsx("span",{className:"mt-1 block text-xs text-muted",children:[i.provider,i.location].filter(Boolean).join(" · ")}),i.historical||i.bridged?e.jsx("span",{className:"mt-1 flex",children:e.jsx(N,{tone:"caution",children:"Historical"})}):null]}),e.jsx("td",{children:e.jsx(Pe,{row:i})}),e.jsx("td",{children:e.jsx(Le,{row:i})}),e.jsx("td",{className:"tabular-nums text-secondary",children:i.cited===null?Ce:i.sources.length}),e.jsx("td",{className:"text-right",children:e.jsx(j,{type:"button",size:"sm",variant:"ghost","aria-expanded":u,onClick:()=>m(re=>{const _=new Set(re);return _.delete(c)||_.add(c),_}),children:u?`Hide the answer for ${i.queryText}`:`Read the answer for ${i.queryText}`})})]}),u?e.jsx("tr",{children:e.jsxs("td",{colSpan:5,className:"bg-surface-subtle px-4",children:[e.jsx(Me,{project:r,targetKey:l,row:i}),e.jsx(Ee,{row:i})]})}):null]},c)})})]})}),d.hasNextPage?e.jsxs("div",{className:"mt-2 flex flex-wrap items-center gap-3 text-sm text-secondary",children:[e.jsxs("span",{children:["Showing ",g.length," of ",V]}),d.isFetchNextPageError?e.jsx("span",{role:"alert",children:"Could not load more evidence."}):null,e.jsx(j,{size:"sm",variant:"outline",className:"h-11 px-4 text-sm md:h-11",disabled:d.isFetchingNextPage,onClick:()=>{d.fetchNextPage()},children:d.isFetchingNextPage?"Loading…":d.isFetchNextPageError?"Retry more evidence":`Show ${K} more`})]}):null]})]})]})}export{He as MeasurementPropertyPage};