@prenta/admin 1.6.2 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/__tests__/components/seo-editor-pane.render.test.js +2 -1
  3. package/dist/__tests__/components/seo-editor-pane.render.test.js.map +1 -1
  4. package/dist/__tests__/components/seo-issue-fix-panel.render.test.d.ts +2 -0
  5. package/dist/__tests__/components/seo-issue-fix-panel.render.test.d.ts.map +1 -0
  6. package/dist/__tests__/components/seo-issue-fix-panel.render.test.js +60 -0
  7. package/dist/__tests__/components/seo-issue-fix-panel.render.test.js.map +1 -0
  8. package/dist/__tests__/components/seo-linking-section.render.test.d.ts +2 -0
  9. package/dist/__tests__/components/seo-linking-section.render.test.d.ts.map +1 -0
  10. package/dist/__tests__/components/seo-linking-section.render.test.js +94 -0
  11. package/dist/__tests__/components/seo-linking-section.render.test.js.map +1 -0
  12. package/dist/__tests__/lib/collection-routes.test.js +8 -1
  13. package/dist/__tests__/lib/collection-routes.test.js.map +1 -1
  14. package/dist/__tests__/lib/seo-service-errors.test.js +24 -1
  15. package/dist/__tests__/lib/seo-service-errors.test.js.map +1 -1
  16. package/dist/__tests__/views/seo-content-pane.render.test.js +1 -0
  17. package/dist/__tests__/views/seo-content-pane.render.test.js.map +1 -1
  18. package/dist/components/seo/SeoEditorPane.d.ts +2 -1
  19. package/dist/components/seo/SeoEditorPane.d.ts.map +1 -1
  20. package/dist/components/seo/SeoEditorPane.js +2 -2
  21. package/dist/components/seo/SeoEditorPane.js.map +1 -1
  22. package/dist/components/seo/SeoIssueFixPanel.d.ts.map +1 -1
  23. package/dist/components/seo/SeoIssueFixPanel.js +32 -8
  24. package/dist/components/seo/SeoIssueFixPanel.js.map +1 -1
  25. package/dist/components/seo/SeoLinkingSection.d.ts +5 -1
  26. package/dist/components/seo/SeoLinkingSection.d.ts.map +1 -1
  27. package/dist/components/seo/SeoLinkingSection.js +50 -3
  28. package/dist/components/seo/SeoLinkingSection.js.map +1 -1
  29. package/dist/lib/collection-routes.d.ts +2 -0
  30. package/dist/lib/collection-routes.d.ts.map +1 -1
  31. package/dist/lib/collection-routes.js +5 -0
  32. package/dist/lib/collection-routes.js.map +1 -1
  33. package/dist/lib/seo-service.d.ts +12 -1
  34. package/dist/lib/seo-service.d.ts.map +1 -1
  35. package/dist/lib/seo-service.js +10 -0
  36. package/dist/lib/seo-service.js.map +1 -1
  37. package/dist/views/SEO.d.ts.map +1 -1
  38. package/dist/views/SEO.js +1 -1
  39. package/dist/views/SEO.js.map +1 -1
  40. package/dist/views/page-editor/PageSectionEditor.d.ts.map +1 -1
  41. package/dist/views/page-editor/PageSectionEditor.js +1 -1
  42. package/dist/views/page-editor/PageSectionEditor.js.map +1 -1
  43. package/dist/views/post-editor/PostSectionEditor.d.ts.map +1 -1
  44. package/dist/views/post-editor/PostSectionEditor.js +1 -1
  45. package/dist/views/post-editor/PostSectionEditor.js.map +1 -1
  46. package/dist/views/seo/ContentTab.d.ts +2 -1
  47. package/dist/views/seo/ContentTab.d.ts.map +1 -1
  48. package/dist/views/seo/ContentTab.js +2 -2
  49. package/dist/views/seo/ContentTab.js.map +1 -1
  50. package/dist/views/seo/LinksTab.d.ts +3 -1
  51. package/dist/views/seo/LinksTab.d.ts.map +1 -1
  52. package/dist/views/seo/LinksTab.js +36 -6
  53. package/dist/views/seo/LinksTab.js.map +1 -1
  54. package/package.json +3 -3
  55. package/src/__tests__/components/seo-editor-pane.render.test.tsx +4 -1
  56. package/src/__tests__/components/seo-issue-fix-panel.render.test.tsx +65 -0
  57. package/src/__tests__/components/seo-linking-section.render.test.tsx +146 -0
  58. package/src/__tests__/lib/collection-routes.test.ts +13 -1
  59. package/src/__tests__/lib/seo-service-errors.test.ts +29 -0
  60. package/src/__tests__/views/seo-content-pane.render.test.tsx +1 -0
  61. package/src/components/seo/SeoEditorPane.tsx +3 -0
  62. package/src/components/seo/SeoIssueFixPanel.tsx +34 -10
  63. package/src/components/seo/SeoLinkingSection.tsx +116 -18
  64. package/src/lib/collection-routes.ts +13 -0
  65. package/src/lib/seo-service.ts +19 -1
  66. package/src/views/SEO.tsx +2 -1
  67. package/src/views/page-editor/PageSectionEditor.tsx +1 -0
  68. package/src/views/post-editor/PostSectionEditor.tsx +1 -0
  69. package/src/views/seo/ContentTab.tsx +3 -0
  70. package/src/views/seo/LinksTab.tsx +108 -19
@@ -1 +1 @@
1
- {"version":3,"file":"LinksTab.js","sourceRoot":"","sources":["../../../src/views/seo/LinksTab.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"LinksTab.js","sourceRoot":"","sources":["../../../src/views/seo/LinksTab.tsx"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@prenta/admin",
3
- "version": "1.6.2",
3
+ "version": "1.7.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -99,7 +99,7 @@
99
99
  "typescript": "^5.7.0",
100
100
  "vitest": "^4.1.0",
101
101
  "@prenta/component-blocks": "0.3.0",
102
- "@prenta/core": "4.1.1",
102
+ "@prenta/core": "4.2.0",
103
103
  "@prenta/plugin-ai": "1.0.0",
104
104
  "@prenta/plugin-blocks": "0.2.0",
105
105
  "@prenta/plugin-commerce": "0.2.1",
@@ -107,7 +107,7 @@
107
107
  "@prenta/plugin-media": "0.2.0",
108
108
  "@prenta/plugin-navigation": "0.3.0",
109
109
  "@prenta/plugin-seo": "0.1.1",
110
- "@prenta/sections-react": "0.17.19"
110
+ "@prenta/sections-react": "0.17.20"
111
111
  },
112
112
  "scripts": {
113
113
  "build": "tsc --project tsconfig.json && npx @tailwindcss/cli -i src/styles/build-input.css -o dist/prenta-admin.css --minify",
@@ -61,6 +61,7 @@ vi.mock('../../lib/seo-service.js', () => ({
61
61
  updateSeoFields: vi.fn(async () => ({})),
62
62
  generateSeoField: (field: string, ctx: unknown) => generateSeoField(field, ctx),
63
63
  fetchLinkSuggestions: vi.fn(async () => ({ data: { suggestions: [] } })),
64
+ applySeoInternalLink: vi.fn(async () => ({})),
64
65
  SEO_SCHEMA_TYPES: ['Article', 'WebPage'],
65
66
  }))
66
67
 
@@ -81,7 +82,9 @@ beforeEach(() => {
81
82
 
82
83
  describe('SeoEditorPane header', () => {
83
84
  it('labels the analysis number as "Content analysis N/100", not "Live analysis"', async () => {
84
- render(<SeoEditorPane entityType="page" entityId="p1" onClose={() => {}} />)
85
+ render(
86
+ <SeoEditorPane entityType="page" entityId="p1" onClose={() => {}} onNavigate={() => {}} />,
87
+ )
85
88
  // Score header renders once the record loads.
86
89
  expect(await screen.findByText(/SEO score:/)).toBeTruthy()
87
90
  await waitFor(() => expect(screen.getByText(/Content analysis 72\/100/)).toBeTruthy())
@@ -0,0 +1,65 @@
1
+ // @vitest-environment happy-dom
2
+ import { describe, expect, it, vi } from 'vitest'
3
+ import { render, screen } from '@testing-library/react'
4
+ import type { SeoIssue } from '../../lib/seo-service.js'
5
+
6
+ const orphanIssue: SeoIssue = {
7
+ id: 'iss-orphan',
8
+ auditRunId: 'run-1',
9
+ entityType: 'page',
10
+ entityId: 'p1',
11
+ entityTitle: 'Orphan',
12
+ url: '/orphan',
13
+ severity: 'warning',
14
+ category: 'content',
15
+ type: 'orphan-page',
16
+ title: 'Orphan page',
17
+ description: null,
18
+ impact: null,
19
+ recommendation: null,
20
+ status: 'open',
21
+ fixable: true,
22
+ fixActionType: 'insert-link',
23
+ relatedEntityIds: [],
24
+ source: 'audit',
25
+ firstDetectedAt: null,
26
+ lastDetectedAt: null,
27
+ resolvedAt: null,
28
+ }
29
+
30
+ vi.mock('../../lib/seo-service.js', async (importOriginal) => {
31
+ const actual = await importOriginal<typeof import('../../lib/seo-service.js')>()
32
+ return {
33
+ ...actual,
34
+ fetchSeoIssueFixSuggestion: vi.fn(async () => ({
35
+ suggestion: {
36
+ autoFixable: true,
37
+ source: 'deterministic',
38
+ fixStrategy: 'insert-link',
39
+ fingerprint: 'fp-insert',
40
+ patch: {},
41
+ changes: [],
42
+ justification: 'Add an inbound link from a related page.',
43
+ },
44
+ })),
45
+ applySeoIssueFix: vi.fn(async () => ({})),
46
+ fetchSeoContentBrief: vi.fn(async () => ({})),
47
+ fetchSeoContentResearch: vi.fn(async () => ({})),
48
+ generateSeoContentBrief: vi.fn(async () => ({})),
49
+ ignoreSeoIssue: vi.fn(async () => ({})),
50
+ researchAndBriefSeoIssue: vi.fn(async () => ({})),
51
+ }
52
+ })
53
+
54
+ vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() } }))
55
+
56
+ const { SeoIssueFixPanel } = await import('../../components/seo/SeoIssueFixPanel.js')
57
+
58
+ describe('SeoIssueFixPanel insert-link copy', () => {
59
+ it('labels orphan-page insert-link Approve as Approve link, not Approve redirect', async () => {
60
+ render(<SeoIssueFixPanel issue={orphanIssue} expanded />)
61
+
62
+ expect(await screen.findByRole('button', { name: 'Approve link' })).toBeTruthy()
63
+ expect(screen.queryByRole('button', { name: 'Approve redirect' })).toBeNull()
64
+ })
65
+ })
@@ -0,0 +1,146 @@
1
+ // @vitest-environment happy-dom
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest'
3
+ import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'
4
+ import type { LinkSuggestion } from '../../lib/seo-service.js'
5
+
6
+ const wrappable: LinkSuggestion = {
7
+ sourceEntityId: 'src-1',
8
+ sourceTitle: 'Related guide',
9
+ sourceUrl: '/guides/related',
10
+ anchorText: 'RankMath',
11
+ confidence: 0.9,
12
+ excerpt: 'We recommend RankMath for on-page SEO.',
13
+ fingerprint: 'fp-1',
14
+ wrappable: true,
15
+ }
16
+
17
+ const notWrappable: LinkSuggestion = {
18
+ sourceEntityId: 'src-2',
19
+ sourceTitle: 'Other post',
20
+ sourceUrl: '/blog/other',
21
+ anchorText: 'missing phrase',
22
+ confidence: 0.35,
23
+ excerpt: 'This page never mentions the target title.',
24
+ fingerprint: 'fp-2',
25
+ wrappable: false,
26
+ sourceCollection: 'blog',
27
+ }
28
+
29
+ const fetchLinkSuggestions = vi.fn(async () => ({
30
+ data: {
31
+ target: { id: 'tgt-1', title: 'Orphan', url: '/orphan' },
32
+ suggestions: [wrappable, notWrappable],
33
+ },
34
+ }))
35
+
36
+ const applySeoInternalLink = vi.fn(async () => ({}))
37
+ const fetchPlanInfo = vi.fn(async () => null)
38
+
39
+ vi.mock('../../lib/seo-service.js', () => ({
40
+ fetchLinkSuggestions: () => fetchLinkSuggestions(),
41
+ applySeoInternalLink: () => applySeoInternalLink(),
42
+ }))
43
+
44
+ vi.mock('../../lib/plan.js', async (importOriginal) => {
45
+ const actual = await importOriginal<typeof import('../../lib/plan.js')>()
46
+ return {
47
+ ...actual,
48
+ fetchPlanInfo: () => fetchPlanInfo(),
49
+ }
50
+ })
51
+
52
+ vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), loading: vi.fn() } }))
53
+
54
+ const { SeoLinkingSection } = await import('../../components/seo/SeoLinkingSection.js')
55
+
56
+ beforeEach(() => {
57
+ fetchLinkSuggestions.mockClear()
58
+ applySeoInternalLink.mockClear()
59
+ fetchPlanInfo.mockClear()
60
+ fetchPlanInfo.mockResolvedValue(null)
61
+ })
62
+
63
+ describe('SeoLinkingSection approve UX', () => {
64
+ it('shows Approve link on wrappable rows and Open in editor on the rest', async () => {
65
+ render(
66
+ <SeoLinkingSection
67
+ entityType="page"
68
+ entityId="tgt-1"
69
+ internalLinks={0}
70
+ externalLinks={0}
71
+ internalLinkOk={false}
72
+ externalLinkOk={false}
73
+ onNavigate={() => {}}
74
+ />,
75
+ )
76
+
77
+ expect(await screen.findByRole('button', { name: 'Approve link' })).toBeTruthy()
78
+
79
+ const wrappableRow = screen.getByText('Related guide').closest('li') as HTMLElement
80
+ expect(within(wrappableRow).getByRole('button', { name: 'Approve link' })).toBeTruthy()
81
+ expect(within(wrappableRow).queryByRole('button', { name: 'Open in editor' })).toBeNull()
82
+
83
+ const otherRow = screen.getByText('Other post').closest('li') as HTMLElement
84
+ expect(within(otherRow).getByRole('button', { name: 'Open in editor' })).toBeTruthy()
85
+ expect(within(otherRow).queryByRole('button', { name: 'Approve link' })).toBeNull()
86
+
87
+ expect(screen.queryByText(/apply links in the content editor/i)).toBeNull()
88
+ })
89
+
90
+ it('hides Approve link and shows upgrade callout when seo.inlineApply is off', async () => {
91
+ render(
92
+ <SeoLinkingSection
93
+ entityType="page"
94
+ entityId="tgt-1"
95
+ internalLinks={0}
96
+ externalLinks={0}
97
+ internalLinkOk={false}
98
+ externalLinkOk={false}
99
+ onNavigate={() => {}}
100
+ planInfo={{
101
+ tier: 'starter',
102
+ features: ['seo.contentBrief'],
103
+ upgradeUrl: 'https://example.com/upgrade',
104
+ }}
105
+ />,
106
+ )
107
+
108
+ expect(await screen.findByText('Related guide')).toBeTruthy()
109
+ expect(screen.queryByRole('button', { name: 'Approve link' })).toBeNull()
110
+ expect(screen.getByText(/Upgrade to unlock SEO inline apply/i)).toBeTruthy()
111
+
112
+ const wrappableRow = screen.getByText('Related guide').closest('li') as HTMLElement
113
+ expect(within(wrappableRow).getByRole('button', { name: 'Open in editor' })).toBeTruthy()
114
+ })
115
+
116
+ it('opens a blog source in the post editor and drops the row after Approve', async () => {
117
+ const onNavigate = vi.fn()
118
+ render(
119
+ <SeoLinkingSection
120
+ entityType="page"
121
+ entityId="tgt-1"
122
+ internalLinks={0}
123
+ externalLinks={0}
124
+ internalLinkOk={false}
125
+ externalLinkOk={false}
126
+ onNavigate={onNavigate}
127
+ planInfo={{
128
+ tier: 'pro',
129
+ features: ['seo.inlineApply'],
130
+ upgradeUrl: null,
131
+ }}
132
+ />,
133
+ )
134
+
135
+ expect(await screen.findByRole('button', { name: 'Approve link' })).toBeTruthy()
136
+
137
+ fireEvent.click(screen.getByRole('button', { name: 'Open in editor' }))
138
+ expect(onNavigate).toHaveBeenCalledWith('/posts/blog/src-2/edit')
139
+
140
+ fireEvent.click(screen.getByRole('button', { name: 'Approve link' }))
141
+ await waitFor(() => {
142
+ expect(applySeoInternalLink).toHaveBeenCalled()
143
+ expect(screen.queryByRole('button', { name: 'Approve link' })).toBeNull()
144
+ })
145
+ })
146
+ })
@@ -1,6 +1,10 @@
1
1
  import { describe, expect, it } from 'vitest'
2
2
 
3
- import { editPathForDoc, newPathForCollection } from '../../lib/collection-routes.js'
3
+ import {
4
+ editPathForDoc,
5
+ newPathForCollection,
6
+ sourceEditPath,
7
+ } from '../../lib/collection-routes.js'
4
8
 
5
9
  describe('editPathForDoc', () => {
6
10
  it('routes post-type documents to the section editor (not the generic route)', () => {
@@ -22,6 +26,14 @@ describe('editPathForDoc', () => {
22
26
  })
23
27
  })
24
28
 
29
+ describe('sourceEditPath', () => {
30
+ it('routes a blog source through CollectionRouteMeta so posts open the post editor', () => {
31
+ expect(sourceEditPath('blog', 'src-2')).toBe('/posts/blog/src-2/edit')
32
+ expect(sourceEditPath('pages', 'abc')).toBe('/pages/abc/edit')
33
+ expect(sourceEditPath(undefined, 'abc')).toBe('/pages/abc/edit')
34
+ })
35
+ })
36
+
25
37
  describe('newPathForCollection', () => {
26
38
  it('routes new post documents to the post editor', () => {
27
39
  expect(newPathForCollection({ type: 'post' }, 'case-studies')).toBe('/posts/case-studies/new')
@@ -8,10 +8,12 @@ vi.mock('../../lib/api.js', () => ({
8
8
  }))
9
9
 
10
10
  const {
11
+ applySeoInternalLink,
11
12
  fetchSeoOverview,
12
13
  fetchSeoContentRecords,
13
14
  fetchSeoIssues,
14
15
  fetchRedirectRules,
16
+ isInlineSeoFixIssue,
15
17
  runSeoAudit,
16
18
  updateSeoFields,
17
19
  } = await import('../../lib/seo-service.js')
@@ -71,6 +73,33 @@ describe('SEO service read fetchers surface errors', () => {
71
73
  error: 'forbidden',
72
74
  })
73
75
  })
76
+
77
+ it('applySeoInternalLink POSTs the apply body and returns { error } on failure', async () => {
78
+ cmsApi.mockResolvedValue({ error: 'Not wrappable', status: 422 })
79
+ await expect(
80
+ applySeoInternalLink({
81
+ sourceEntityId: 'src-1',
82
+ targetEntityId: 'tgt-1',
83
+ anchorText: 'RankMath',
84
+ fingerprint: 'fp-1',
85
+ }),
86
+ ).resolves.toEqual({ error: 'Not wrappable' })
87
+ expect(cmsApi).toHaveBeenCalledWith('/seo/links/apply', {
88
+ method: 'POST',
89
+ body: JSON.stringify({
90
+ sourceEntityId: 'src-1',
91
+ targetEntityId: 'tgt-1',
92
+ anchorText: 'RankMath',
93
+ fingerprint: 'fp-1',
94
+ }),
95
+ })
96
+ })
97
+ })
98
+
99
+ describe('inline SEO fix issue types', () => {
100
+ it('treats orphan-page as an inline Approve issue', () => {
101
+ expect(isInlineSeoFixIssue('orphan-page')).toBe(true)
102
+ })
74
103
  })
75
104
 
76
105
  describe('SEO audit mutation contract', () => {
@@ -69,6 +69,7 @@ vi.mock('../../lib/seo-service.js', () => ({
69
69
  updateSeoFields: (t: string, i: string, p: unknown) => updateSeoFields(t, i, p),
70
70
  generateSeoField: vi.fn(async () => ({ unavailable: true })),
71
71
  fetchLinkSuggestions: vi.fn(async () => ({ data: { suggestions: [] } })),
72
+ applySeoInternalLink: vi.fn(async () => ({})),
72
73
  SEO_SCHEMA_TYPES: ['Article', 'WebPage'],
73
74
  applyContentSeoQuery: (
74
75
  records: Array<{ entityType: string; title: string }>,
@@ -162,6 +162,7 @@ export interface SeoEditorPaneProps {
162
162
  title?: string
163
163
  bodyHtml?: string
164
164
  featuredImage?: string
165
+ onNavigate?: (path: string) => void
165
166
  }
166
167
 
167
168
  export function SeoEditorPane({
@@ -178,6 +179,7 @@ export function SeoEditorPane({
178
179
  title,
179
180
  bodyHtml,
180
181
  featuredImage,
182
+ onNavigate,
181
183
  }: SeoEditorPaneProps) {
182
184
  const isDraft = !entityId
183
185
  const [record, setRecord] = useState<SeoContentRecord | null>(null)
@@ -994,6 +996,7 @@ export function SeoEditorPane({
994
996
  externalLinks={Number(externalLinks)}
995
997
  internalLinkOk={internalOk}
996
998
  externalLinkOk={externalOk}
999
+ onNavigate={onNavigate}
997
1000
  />
998
1001
  </SeoAccordionItem>
999
1002
  </SeoAccordion>
@@ -24,6 +24,38 @@ import { hasPlanFeature, type PlanInfo } from '../../lib/plan.js'
24
24
  import { PlanUpgradeCallout } from '../PlanUpgradeCallout.js'
25
25
  import { SeoErrorState, btnPrimary, btnSecondary } from './primitives.js'
26
26
 
27
+ function approveButtonLabel(strategy: SeoIssueFixSuggestion['fixStrategy']): string {
28
+ switch (strategy) {
29
+ case 'fix-link':
30
+ return 'Fix link in content'
31
+ case 'insert-link':
32
+ return 'Approve link'
33
+ case 'redirect':
34
+ case undefined:
35
+ return 'Approve redirect'
36
+ default: {
37
+ const _exhaustive: never = strategy
38
+ return _exhaustive
39
+ }
40
+ }
41
+ }
42
+
43
+ function approveSuccessToast(strategy: SeoIssueFixSuggestion['fixStrategy']): string {
44
+ switch (strategy) {
45
+ case 'fix-link':
46
+ return 'Link updated in content and issue resolved.'
47
+ case 'insert-link':
48
+ return 'Link added and issue resolved.'
49
+ case 'redirect':
50
+ case undefined:
51
+ return 'Redirect created and issue resolved.'
52
+ default: {
53
+ const _exhaustive: never = strategy
54
+ return _exhaustive
55
+ }
56
+ }
57
+ }
58
+
27
59
  function formatValue(value: string | boolean | null): string {
28
60
  if (value === null || value === '') return '—'
29
61
  if (typeof value === 'boolean') return value ? 'Yes' : 'No'
@@ -321,11 +353,7 @@ export function SeoIssueFixPanel({
321
353
  toast.error(res.error)
322
354
  return
323
355
  }
324
- toast.success(
325
- suggestion?.fixStrategy === 'fix-link'
326
- ? 'Link updated in content and issue resolved.'
327
- : 'Redirect created and issue resolved.',
328
- )
356
+ toast.success(approveSuccessToast(suggestion?.fixStrategy))
329
357
  onChanged?.()
330
358
  }
331
359
 
@@ -491,11 +519,7 @@ export function SeoIssueFixPanel({
491
519
  disabled={busy}
492
520
  >
493
521
  <Check className="h-4 w-4" aria-hidden />
494
- {busy
495
- ? 'Applying…'
496
- : suggestion.fixStrategy === 'fix-link'
497
- ? 'Fix link in content'
498
- : 'Approve redirect'}
522
+ {busy ? 'Applying…' : approveButtonLabel(suggestion.fixStrategy)}
499
523
  </button>
500
524
  ) : inlineFix && suggestion?.autoFixable && !inlineApplyEnabled ? (
501
525
  <PlanUpgradeCallout feature="seo.inlineApply" upgradeUrl={planInfo?.upgradeUrl} />
@@ -2,7 +2,21 @@
2
2
 
3
3
  import { useEffect, useState } from 'react'
4
4
  import { Link2, Loader2, Sparkles } from 'lucide-react'
5
- import { fetchLinkSuggestions, type LinkSuggestion } from '../../lib/seo-service.js'
5
+ import { toast } from 'sonner'
6
+ import { sourceEditPath } from '../../lib/collection-routes.js'
7
+ import {
8
+ applySeoInternalLink,
9
+ fetchLinkSuggestions,
10
+ type LinkSuggestion,
11
+ } from '../../lib/seo-service.js'
12
+ import { fetchPlanInfo, hasPlanFeature, type PlanInfo } from '../../lib/plan.js'
13
+ import { PlanUpgradeCallout } from '../PlanUpgradeCallout.js'
14
+
15
+ const approveBtnCls =
16
+ 'inline-flex items-center justify-center gap-1.5 rounded-[7px] bg-primary px-2.5 py-1.5 text-[11.5px] font-medium text-primary-foreground transition-colors hover:opacity-90 focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50'
17
+
18
+ const editorBtnCls =
19
+ 'inline-flex items-center justify-center gap-1.5 rounded-[7px] border border-[var(--bdr)] bg-[var(--card)] px-2.5 py-1.5 text-[11.5px] font-medium text-[var(--txt)] transition-colors hover:bg-[var(--acc-l)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none'
6
20
 
7
21
  export function SeoLinkingSection({
8
22
  entityType,
@@ -11,6 +25,8 @@ export function SeoLinkingSection({
11
25
  externalLinks,
12
26
  internalLinkOk,
13
27
  externalLinkOk,
28
+ onNavigate,
29
+ planInfo: planInfoProp,
14
30
  }: {
15
31
  entityType: 'page' | 'post'
16
32
  entityId: string | null
@@ -18,10 +34,31 @@ export function SeoLinkingSection({
18
34
  externalLinks: number
19
35
  internalLinkOk: boolean
20
36
  externalLinkOk: boolean
37
+ onNavigate?: (path: string) => void
38
+ /** When omitted (page/post editors), fetched on mount. */
39
+ planInfo?: PlanInfo | null
21
40
  }) {
22
41
  const [loading, setLoading] = useState(false)
23
42
  const [suggestions, setSuggestions] = useState<LinkSuggestion[]>([])
24
43
  const [error, setError] = useState<string | null>(null)
44
+ const [applyingKey, setApplyingKey] = useState<string | null>(null)
45
+ const [planInfo, setPlanInfo] = useState<PlanInfo | null | undefined>(planInfoProp)
46
+
47
+ useEffect(() => {
48
+ if (planInfoProp !== undefined) {
49
+ setPlanInfo(planInfoProp)
50
+ return
51
+ }
52
+ let alive = true
53
+ void fetchPlanInfo().then((info) => {
54
+ if (alive) setPlanInfo(info)
55
+ })
56
+ return () => {
57
+ alive = false
58
+ }
59
+ }, [planInfoProp])
60
+
61
+ const inlineApplyEnabled = hasPlanFeature(planInfo, 'seo.inlineApply')
25
62
 
26
63
  useEffect(() => {
27
64
  if (!entityId) {
@@ -48,6 +85,33 @@ export function SeoLinkingSection({
48
85
  }
49
86
  }, [entityType, entityId])
50
87
 
88
+ async function handleApprove(suggestion: LinkSuggestion) {
89
+ if (!entityId) return
90
+ const key = `${suggestion.sourceEntityId}-${suggestion.fingerprint}`
91
+ setApplyingKey(key)
92
+ const res = await applySeoInternalLink({
93
+ sourceEntityId: suggestion.sourceEntityId,
94
+ targetEntityId: entityId,
95
+ anchorText: suggestion.anchorText,
96
+ fingerprint: suggestion.fingerprint,
97
+ })
98
+ setApplyingKey(null)
99
+ if (res.error) {
100
+ toast.error(res.error)
101
+ return
102
+ }
103
+ toast.success('Link added.')
104
+ setSuggestions((prev) =>
105
+ prev.filter(
106
+ (row) =>
107
+ !(
108
+ row.fingerprint === suggestion.fingerprint &&
109
+ row.sourceEntityId === suggestion.sourceEntityId
110
+ ),
111
+ ),
112
+ )
113
+ }
114
+
51
115
  return (
52
116
  <div className="space-y-4">
53
117
  <div className="grid grid-cols-2 gap-3">
@@ -90,22 +154,56 @@ export function SeoLinkingSection({
90
154
  <Sparkles className="h-3.5 w-3.5 text-[var(--acc)]" aria-hidden />
91
155
  Link opportunities
92
156
  </div>
157
+ {!inlineApplyEnabled && suggestions.some((s) => s.wrappable) ? (
158
+ <div className="mb-2">
159
+ <PlanUpgradeCallout feature="seo.inlineApply" upgradeUrl={planInfo?.upgradeUrl} />
160
+ </div>
161
+ ) : null}
93
162
  <ul className="space-y-2">
94
- {suggestions.map((s) => (
95
- <li
96
- key={`${s.sourceEntityId}-${s.anchorText}`}
97
- className="rounded-[7px] border border-[var(--bdr)] bg-[var(--card)] p-2.5"
98
- >
99
- <div className="text-[12.5px] font-medium text-[var(--txt)]">{s.sourceTitle}</div>
100
- <p className="mt-0.5 text-[11px] text-[var(--muted)]">{s.sourceUrl}</p>
101
- <p className="mt-1 text-[11.5px] text-[var(--sub)]">
102
- Suggested anchor: <span className="text-[var(--txt)]">{s.anchorText}</span>
103
- </p>
104
- {s.excerpt && (
105
- <p className="mt-1 line-clamp-2 text-[11px] text-[var(--muted)]">{s.excerpt}</p>
106
- )}
107
- </li>
108
- ))}
163
+ {suggestions.map((s) => {
164
+ const key = `${s.sourceEntityId}-${s.fingerprint || s.anchorText}`
165
+ const busy = applyingKey === key
166
+ return (
167
+ <li
168
+ key={key}
169
+ className="rounded-[7px] border border-[var(--bdr)] bg-[var(--card)] p-2.5"
170
+ >
171
+ <div className="text-[12.5px] font-medium text-[var(--txt)]">{s.sourceTitle}</div>
172
+ <p className="mt-0.5 text-[11px] text-[var(--muted)]">{s.sourceUrl}</p>
173
+ <p className="mt-1 text-[11.5px] text-[var(--sub)]">
174
+ Suggested anchor: <span className="text-[var(--txt)]">{s.anchorText}</span>
175
+ </p>
176
+ {s.excerpt && (
177
+ <p className="mt-1 line-clamp-2 text-[11px] text-[var(--muted)]">{s.excerpt}</p>
178
+ )}
179
+ {s.wrappable && inlineApplyEnabled ? (
180
+ <div className="mt-2">
181
+ <button
182
+ type="button"
183
+ className={approveBtnCls}
184
+ disabled={busy}
185
+ onClick={() => void handleApprove(s)}
186
+ >
187
+ {busy ? <Loader2 className="h-3.5 w-3.5 animate-spin" aria-hidden /> : null}
188
+ Approve link
189
+ </button>
190
+ </div>
191
+ ) : onNavigate ? (
192
+ <div className="mt-2">
193
+ <button
194
+ type="button"
195
+ className={editorBtnCls}
196
+ onClick={() =>
197
+ onNavigate(sourceEditPath(s.sourceCollection, s.sourceEntityId))
198
+ }
199
+ >
200
+ Open in editor
201
+ </button>
202
+ </div>
203
+ ) : null}
204
+ </li>
205
+ )
206
+ })}
109
207
  </ul>
110
208
  </div>
111
209
  ) : (
@@ -118,8 +216,8 @@ export function SeoLinkingSection({
118
216
  <div className="flex items-start gap-2 rounded-[7px] border border-[var(--bdr)] bg-[var(--bg)] p-2.5 text-[11px] text-[var(--sub)]">
119
217
  <Link2 className="mt-0.5 h-3.5 w-3.5 shrink-0 text-[var(--acc)]" aria-hidden />
120
218
  <span>
121
- Best practice: mix internal links (site structure + crawl paths) with selective outbound
122
- links (trust signals). We flag counts here; apply links in the content editor.
219
+ Wrappable suggestions can be approved here. Others need an editor pass so we do not invent
220
+ a sentence.
123
221
  </span>
124
222
  </div>
125
223
  </div>