@prenta/admin 1.13.0 → 1.15.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 (100) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/__tests__/lib/api.test.d.ts +2 -0
  3. package/dist/__tests__/lib/api.test.d.ts.map +1 -0
  4. package/dist/__tests__/lib/api.test.js +58 -0
  5. package/dist/__tests__/lib/api.test.js.map +1 -0
  6. package/dist/__tests__/lib/seo-service-autopilot.test.d.ts +2 -0
  7. package/dist/__tests__/lib/seo-service-autopilot.test.d.ts.map +1 -0
  8. package/dist/__tests__/lib/seo-service-autopilot.test.js +171 -0
  9. package/dist/__tests__/lib/seo-service-autopilot.test.js.map +1 -0
  10. package/dist/__tests__/lib/seo-service-proposals.test.d.ts +2 -0
  11. package/dist/__tests__/lib/seo-service-proposals.test.d.ts.map +1 -0
  12. package/dist/__tests__/lib/seo-service-proposals.test.js +99 -0
  13. package/dist/__tests__/lib/seo-service-proposals.test.js.map +1 -0
  14. package/dist/__tests__/router/seo-tab-for-path.test.js +1 -0
  15. package/dist/__tests__/router/seo-tab-for-path.test.js.map +1 -1
  16. package/dist/__tests__/views/redirects-pane.render.test.js +30 -12
  17. package/dist/__tests__/views/redirects-pane.render.test.js.map +1 -1
  18. package/dist/__tests__/views/seo-autopilot-applied.render.test.d.ts +2 -0
  19. package/dist/__tests__/views/seo-autopilot-applied.render.test.d.ts.map +1 -0
  20. package/dist/__tests__/views/seo-autopilot-applied.render.test.js +330 -0
  21. package/dist/__tests__/views/seo-autopilot-applied.render.test.js.map +1 -0
  22. package/dist/__tests__/views/seo-autopilot-card.render.test.d.ts +2 -0
  23. package/dist/__tests__/views/seo-autopilot-card.render.test.d.ts.map +1 -0
  24. package/dist/__tests__/views/seo-autopilot-card.render.test.js +512 -0
  25. package/dist/__tests__/views/seo-autopilot-card.render.test.js.map +1 -0
  26. package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts +2 -0
  27. package/dist/__tests__/views/seo-proposals-tab.render.test.d.ts.map +1 -0
  28. package/dist/__tests__/views/seo-proposals-tab.render.test.js +431 -0
  29. package/dist/__tests__/views/seo-proposals-tab.render.test.js.map +1 -0
  30. package/dist/__tests__/views/seo-settings.render.test.js +41 -4
  31. package/dist/__tests__/views/seo-settings.render.test.js.map +1 -1
  32. package/dist/components/seo/ChangePreview.d.ts +6 -0
  33. package/dist/components/seo/ChangePreview.d.ts.map +1 -0
  34. package/dist/components/seo/ChangePreview.js +18 -0
  35. package/dist/components/seo/ChangePreview.js.map +1 -0
  36. package/dist/components/seo/SeoIssueFixPanel.d.ts.map +1 -1
  37. package/dist/components/seo/SeoIssueFixPanel.js +1 -14
  38. package/dist/components/seo/SeoIssueFixPanel.js.map +1 -1
  39. package/dist/lib/api.d.ts +13 -2
  40. package/dist/lib/api.d.ts.map +1 -1
  41. package/dist/lib/api.js +1 -2
  42. package/dist/lib/api.js.map +1 -1
  43. package/dist/lib/seo-service.d.ts +293 -2
  44. package/dist/lib/seo-service.d.ts.map +1 -1
  45. package/dist/lib/seo-service.js +170 -0
  46. package/dist/lib/seo-service.js.map +1 -1
  47. package/dist/prenta-admin.css +1 -1
  48. package/dist/views/SEO.d.ts +5 -1
  49. package/dist/views/SEO.d.ts.map +1 -1
  50. package/dist/views/SEO.js +28 -9
  51. package/dist/views/SEO.js.map +1 -1
  52. package/dist/views/seo/AutopilotAppliedSection.d.ts +10 -0
  53. package/dist/views/seo/AutopilotAppliedSection.d.ts.map +1 -0
  54. package/dist/views/seo/AutopilotAppliedSection.js +295 -0
  55. package/dist/views/seo/AutopilotAppliedSection.js.map +1 -0
  56. package/dist/views/seo/ProposalsTab.d.ts +7 -0
  57. package/dist/views/seo/ProposalsTab.d.ts.map +1 -0
  58. package/dist/views/seo/ProposalsTab.js +334 -0
  59. package/dist/views/seo/ProposalsTab.js.map +1 -0
  60. package/dist/views/seo/RedirectsTab.d.ts +3 -1
  61. package/dist/views/seo/RedirectsTab.d.ts.map +1 -1
  62. package/dist/views/seo/RedirectsTab.js +14 -19
  63. package/dist/views/seo/RedirectsTab.js.map +1 -1
  64. package/dist/views/seo/relative-age.d.ts +7 -0
  65. package/dist/views/seo/relative-age.d.ts.map +1 -0
  66. package/dist/views/seo/relative-age.js +20 -0
  67. package/dist/views/seo/relative-age.js.map +1 -0
  68. package/dist/views/settings/SeoAutopilotCard.d.ts +30 -0
  69. package/dist/views/settings/SeoAutopilotCard.d.ts.map +1 -0
  70. package/dist/views/settings/SeoAutopilotCard.js +375 -0
  71. package/dist/views/settings/SeoAutopilotCard.js.map +1 -0
  72. package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
  73. package/dist/views/settings/SeoSettingsTab.js +2 -1
  74. package/dist/views/settings/SeoSettingsTab.js.map +1 -1
  75. package/dist/views/settings/components.d.ts +3 -1
  76. package/dist/views/settings/components.d.ts.map +1 -1
  77. package/dist/views/settings/components.js +2 -2
  78. package/dist/views/settings/components.js.map +1 -1
  79. package/package.json +3 -3
  80. package/src/__tests__/lib/api.test.ts +76 -0
  81. package/src/__tests__/lib/seo-service-autopilot.test.ts +196 -0
  82. package/src/__tests__/lib/seo-service-proposals.test.ts +108 -0
  83. package/src/__tests__/router/seo-tab-for-path.test.ts +1 -0
  84. package/src/__tests__/views/redirects-pane.render.test.tsx +36 -16
  85. package/src/__tests__/views/seo-autopilot-applied.render.test.tsx +382 -0
  86. package/src/__tests__/views/seo-autopilot-card.render.test.tsx +610 -0
  87. package/src/__tests__/views/seo-proposals-tab.render.test.tsx +531 -0
  88. package/src/__tests__/views/seo-settings.render.test.tsx +47 -7
  89. package/src/components/seo/ChangePreview.tsx +47 -0
  90. package/src/components/seo/SeoIssueFixPanel.tsx +1 -44
  91. package/src/lib/api.ts +19 -3
  92. package/src/lib/seo-service.ts +455 -2
  93. package/src/views/SEO.tsx +41 -8
  94. package/src/views/seo/AutopilotAppliedSection.tsx +597 -0
  95. package/src/views/seo/ProposalsTab.tsx +761 -0
  96. package/src/views/seo/RedirectsTab.tsx +39 -60
  97. package/src/views/seo/relative-age.ts +15 -0
  98. package/src/views/settings/SeoAutopilotCard.tsx +826 -0
  99. package/src/views/settings/SeoSettingsTab.tsx +2 -0
  100. package/src/views/settings/components.tsx +10 -1
package/src/views/SEO.tsx CHANGED
@@ -1,10 +1,11 @@
1
1
  'use client'
2
2
 
3
3
  /**
4
- * SEO Operations Center — five-tab workflow surface (Overview / Content /
5
- * Technical / Redirects / Audit). Tab + deep-link state is driven by the
6
- * `?tab=` query string so audits, issues, redirects, and content editors are
7
- * all linkable. All data flows through `lib/seo-service.ts`.
4
+ * SEO Operations Center — seven-tab workflow surface (Overview / Content /
5
+ * Links / Technical / Redirects / Audit / Proposals). Tab + deep-link state is
6
+ * driven by the `?tab=` query string so audits, issues, redirects, proposals,
7
+ * and content editors are all linkable. All data flows through
8
+ * `lib/seo-service.ts`.
8
9
  */
9
10
  import * as Tabs from '@radix-ui/react-tabs'
10
11
  import {
@@ -16,6 +17,7 @@ import {
16
17
  RefreshCw,
17
18
  Bot,
18
19
  Link2,
20
+ Inbox,
19
21
  } from 'lucide-react'
20
22
  import { useCallback, useEffect, useMemo, useState } from 'react'
21
23
  import { toast } from 'sonner'
@@ -32,6 +34,7 @@ import { TechnicalTab } from './seo/TechnicalTab.js'
32
34
  import { RedirectsTab } from './seo/RedirectsTab.js'
33
35
  import { AuditTab } from './seo/AuditTab.js'
34
36
  import { LinksTab } from './seo/LinksTab.js'
37
+ import { ProposalsTab } from './seo/ProposalsTab.js'
35
38
 
36
39
  export interface SEOProps {
37
40
  onNavigate?: (path: string) => void
@@ -45,6 +48,7 @@ const TABS = [
45
48
  { id: 'technical', label: 'Technical', icon: Settings2 },
46
49
  { id: 'redirects', label: 'Redirects', icon: ArrowRightLeft },
47
50
  { id: 'audit', label: 'Audit', icon: ClipboardCheck },
51
+ { id: 'proposals', label: 'Proposals', icon: Inbox },
48
52
  ] as const
49
53
 
50
54
  type TabId = (typeof TABS)[number]['id']
@@ -69,6 +73,7 @@ export const SEO_DEEP_PATHS = [
69
73
  '/seo/technical',
70
74
  '/seo/links',
71
75
  '/seo/audit',
76
+ '/seo/proposals',
72
77
  '/seo',
73
78
  ] as const
74
79
 
@@ -89,6 +94,8 @@ export function seoTabForPath(pathname: string): TabId | null {
89
94
  return 'technical'
90
95
  case '/seo/audit':
91
96
  return 'audit'
97
+ case '/seo/proposals':
98
+ return 'proposals'
92
99
  case '/seo':
93
100
  return 'overview'
94
101
  default:
@@ -177,7 +184,11 @@ export function SEO({ onNavigate, initialTab = 'overview' }: SEOProps) {
177
184
 
178
185
  const badgeCounts = useMemo(() => {
179
186
  const summary = overviewResource.data?.issuesSummary
180
- return { audit: summary ? summary.critical + summary.warning : 0 }
187
+ const pending = overviewResource.data?.pendingProposals
188
+ return {
189
+ audit: summary ? summary.critical + summary.warning : 0,
190
+ proposals: pending ? pending.issueFixes + pending.redirects : 0,
191
+ }
181
192
  }, [overviewResource.data])
182
193
 
183
194
  return (
@@ -215,7 +226,18 @@ export function SEO({ onNavigate, initialTab = 'overview' }: SEOProps) {
215
226
  >
216
227
  {TABS.map((t) => {
217
228
  const Icon = t.icon
218
- const badge = t.id === 'audit' ? badgeCounts.audit : 0
229
+ const badge =
230
+ t.id === 'audit'
231
+ ? badgeCounts.audit
232
+ : t.id === 'proposals'
233
+ ? badgeCounts.proposals
234
+ : 0
235
+ // The proposals count is informational (items awaiting review),
236
+ // not a warning like the audit issue count.
237
+ const badgeClass =
238
+ t.id === 'proposals'
239
+ ? 'bg-muted text-muted-foreground'
240
+ : 'bg-destructive/10 text-destructive'
219
241
  return (
220
242
  <Tabs.Trigger
221
243
  key={t.id}
@@ -225,7 +247,9 @@ export function SEO({ onNavigate, initialTab = 'overview' }: SEOProps) {
225
247
  <Icon className="h-4 w-4" aria-hidden />
226
248
  {t.label}
227
249
  {badge > 0 && (
228
- <span className="bg-destructive/10 text-destructive ml-1 rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums">
250
+ <span
251
+ className={`${badgeClass} ml-1 rounded-full px-1.5 py-0.5 text-xs font-medium tabular-nums`}
252
+ >
229
253
  {badge}
230
254
  </span>
231
255
  )}
@@ -260,7 +284,7 @@ export function SEO({ onNavigate, initialTab = 'overview' }: SEOProps) {
260
284
  {activeTab === 'technical' && <TechnicalTab />}
261
285
  </Tabs.Content>
262
286
  <Tabs.Content value="redirects" tabIndex={-1}>
263
- {activeTab === 'redirects' && <RedirectsTab />}
287
+ {activeTab === 'redirects' && <RedirectsTab onNavigate={onNavigate} />}
264
288
  </Tabs.Content>
265
289
  <Tabs.Content value="audit" tabIndex={-1}>
266
290
  {activeTab === 'audit' && (
@@ -272,6 +296,15 @@ export function SEO({ onNavigate, initialTab = 'overview' }: SEOProps) {
272
296
  />
273
297
  )}
274
298
  </Tabs.Content>
299
+ <Tabs.Content value="proposals" tabIndex={-1}>
300
+ {activeTab === 'proposals' && (
301
+ <ProposalsTab
302
+ planInfo={planInfo}
303
+ onChanged={() => setRefetchKey((k) => k + 1)}
304
+ onNavigate={onNavigate}
305
+ />
306
+ )}
307
+ </Tabs.Content>
275
308
  </ErrorBoundary>
276
309
  </div>
277
310
  </Tabs.Root>