@pixelated-tech/components 3.3.5 → 3.4.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 (158) hide show
  1. package/README.COMPONENTS.md +126 -0
  2. package/README.md +15 -9
  3. package/dist/components/admin/componentusage/componentAnalysis.js +144 -0
  4. package/dist/components/admin/componentusage/componentDiscovery.js +85 -0
  5. package/dist/components/admin/deploy/deployment.integration.js +170 -0
  6. package/dist/components/admin/site-health/google-api-auth.js +69 -0
  7. package/dist/components/admin/site-health/seo-metrics.config.json +265 -0
  8. package/dist/components/admin/site-health/site-health-accessibility.js +158 -0
  9. package/dist/components/admin/site-health/site-health-axe-core.integration.js +119 -0
  10. package/dist/components/admin/site-health/site-health-axe-core.js +53 -0
  11. package/dist/components/admin/site-health/site-health-cache.js +23 -0
  12. package/dist/components/admin/site-health/site-health-core-web-vitals.integration.js +208 -0
  13. package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +38 -0
  14. package/dist/components/admin/site-health/site-health-github.integration.js +81 -0
  15. package/dist/components/admin/site-health/site-health-github.js +34 -0
  16. package/dist/components/admin/site-health/site-health-google-analytics.integration.js +112 -0
  17. package/dist/components/admin/site-health/site-health-google-analytics.js +43 -0
  18. package/dist/components/admin/site-health/site-health-google-search-console.integration.js +118 -0
  19. package/dist/components/admin/site-health/site-health-google-search-console.js +43 -0
  20. package/dist/components/admin/site-health/site-health-indicators.js +71 -0
  21. package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +578 -0
  22. package/dist/components/admin/site-health/site-health-on-site-seo.js +204 -0
  23. package/dist/components/admin/site-health/site-health-overview.js +65 -0
  24. package/dist/components/admin/site-health/site-health-performance.js +191 -0
  25. package/dist/components/admin/site-health/site-health-security.integration.js +109 -0
  26. package/dist/components/admin/site-health/site-health-security.js +169 -0
  27. package/dist/components/admin/site-health/site-health-seo.js +124 -0
  28. package/dist/components/admin/site-health/site-health-template.js +62 -0
  29. package/dist/components/admin/site-health/site-health-types.js +1 -0
  30. package/dist/components/admin/site-health/site-health-uptime.integration.js +29 -0
  31. package/dist/components/admin/site-health/site-health-uptime.js +30 -0
  32. package/dist/components/admin/site-health/site-health.css +427 -0
  33. package/dist/components/admin/sites/sites.integration.js +117 -0
  34. package/dist/components/cms/contentful.management.js +104 -0
  35. package/dist/components/cms/hubspot.components.js +3 -3
  36. package/dist/components/config/config.client.js +21 -10
  37. package/dist/components/general/table.js +3 -1
  38. package/dist/components/seo/googleanalytics.js +1 -2
  39. package/dist/components/shoppingcart/shipping.from.json +101 -0
  40. package/dist/components/shoppingcart/shipping.parcel.json +112 -0
  41. package/dist/components/shoppingcart/shipping.to.json +422 -0
  42. package/dist/components/shoppingcart/shoppingCartDiscountCodes.json +26 -0
  43. package/dist/components/shoppingcart/shoppingcart.components.js +1 -1
  44. package/dist/components/sitebuilder/config/ConfigBuilder.js +36 -140
  45. package/dist/components/sitebuilder/config/siteinfo-form.json +200 -0
  46. package/dist/components/sitebuilder/config/visualdesignform.json +244 -0
  47. package/dist/components/structured/buzzwordbingo.js +3 -2
  48. package/dist/data/404-data.json +128 -102
  49. package/dist/data/flickr.json +25 -0
  50. package/dist/data/form.json +368 -368
  51. package/dist/data/recipes.json +3251 -3251
  52. package/dist/data/references.json +138 -137
  53. package/dist/data/requestform.json +111 -0
  54. package/dist/data/requests.json +136 -135
  55. package/dist/data/resume.json +2573 -2575
  56. package/dist/data/routes.json +238 -238
  57. package/dist/data/routes2.json +141 -140
  58. package/dist/index.js +16 -3
  59. package/dist/index.server.js +36 -15
  60. package/dist/types/components/admin/componentusage/componentAnalysis.d.ts +35 -0
  61. package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -0
  62. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts +10 -0
  63. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts.map +1 -0
  64. package/dist/types/components/admin/deploy/deployment.integration.d.ts +26 -0
  65. package/dist/types/components/admin/deploy/deployment.integration.d.ts.map +1 -0
  66. package/dist/types/components/admin/site-health/google-api-auth.d.ts +37 -0
  67. package/dist/types/components/admin/site-health/google-api-auth.d.ts.map +1 -0
  68. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts +6 -0
  69. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts.map +1 -0
  70. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts +6 -0
  71. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts.map +1 -0
  72. package/dist/types/components/admin/site-health/site-health-axe-core.integration.d.ts +63 -0
  73. package/dist/types/components/admin/site-health/site-health-axe-core.integration.d.ts.map +1 -0
  74. package/dist/types/components/admin/site-health/site-health-cache.d.ts +12 -0
  75. package/dist/types/components/admin/site-health/site-health-cache.d.ts.map +1 -0
  76. package/dist/types/components/admin/site-health/site-health-core-web-vitals.integration.d.ts +3 -0
  77. package/dist/types/components/admin/site-health/site-health-core-web-vitals.integration.d.ts.map +1 -0
  78. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts +6 -0
  79. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts.map +1 -0
  80. package/dist/types/components/admin/site-health/site-health-github.d.ts +8 -0
  81. package/dist/types/components/admin/site-health/site-health-github.d.ts.map +1 -0
  82. package/dist/types/components/admin/site-health/site-health-github.integration.d.ts +26 -0
  83. package/dist/types/components/admin/site-health/site-health-github.integration.d.ts.map +1 -0
  84. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts +8 -0
  85. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts.map +1 -0
  86. package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts +26 -0
  87. package/dist/types/components/admin/site-health/site-health-google-analytics.integration.d.ts.map +1 -0
  88. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts +8 -0
  89. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts.map +1 -0
  90. package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts +46 -0
  91. package/dist/types/components/admin/site-health/site-health-google-search-console.integration.d.ts.map +1 -0
  92. package/dist/types/components/admin/site-health/site-health-indicators.d.ts +73 -0
  93. package/dist/types/components/admin/site-health/site-health-indicators.d.ts.map +1 -0
  94. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts +4 -0
  95. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts.map +1 -0
  96. package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts +34 -0
  97. package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -0
  98. package/dist/types/components/admin/site-health/site-health-overview.d.ts +6 -0
  99. package/dist/types/components/admin/site-health/site-health-overview.d.ts.map +1 -0
  100. package/dist/types/components/admin/site-health/site-health-performance.d.ts +6 -0
  101. package/dist/types/components/admin/site-health/site-health-performance.d.ts.map +1 -0
  102. package/dist/types/components/admin/site-health/site-health-security.d.ts +6 -0
  103. package/dist/types/components/admin/site-health/site-health-security.d.ts.map +1 -0
  104. package/dist/types/components/admin/site-health/site-health-security.integration.d.ts +29 -0
  105. package/dist/types/components/admin/site-health/site-health-security.integration.d.ts.map +1 -0
  106. package/dist/types/components/admin/site-health/site-health-seo.d.ts +6 -0
  107. package/dist/types/components/admin/site-health/site-health-seo.d.ts.map +1 -0
  108. package/dist/types/components/admin/site-health/site-health-template.d.ts +12 -0
  109. package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -0
  110. package/dist/types/components/admin/site-health/site-health-types.d.ts +186 -0
  111. package/dist/types/components/admin/site-health/site-health-types.d.ts.map +1 -0
  112. package/dist/types/components/admin/site-health/site-health-uptime.d.ts +6 -0
  113. package/dist/types/components/admin/site-health/site-health-uptime.d.ts.map +1 -0
  114. package/dist/types/components/admin/site-health/site-health-uptime.integration.d.ts +10 -0
  115. package/dist/types/components/admin/site-health/site-health-uptime.integration.d.ts.map +1 -0
  116. package/dist/types/components/admin/sites/sites.integration.d.ts +40 -0
  117. package/dist/types/components/admin/sites/sites.integration.d.ts.map +1 -0
  118. package/dist/types/components/cms/contentful.management.d.ts +41 -0
  119. package/dist/types/components/cms/contentful.management.d.ts.map +1 -1
  120. package/dist/types/components/config/config.client.d.ts +1 -2
  121. package/dist/types/components/config/config.client.d.ts.map +1 -1
  122. package/dist/types/components/general/table.d.ts +1 -0
  123. package/dist/types/components/general/table.d.ts.map +1 -1
  124. package/dist/types/components/seo/googleanalytics.d.ts +1 -1
  125. package/dist/types/components/seo/googleanalytics.d.ts.map +1 -1
  126. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +4 -4
  127. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -1
  128. package/dist/types/components/structured/buzzwordbingo.d.ts +1 -1
  129. package/dist/types/components/structured/buzzwordbingo.d.ts.map +1 -1
  130. package/dist/types/components/structured/buzzwordbingo.words.d.ts +2 -0
  131. package/dist/types/components/structured/buzzwordbingo.words.d.ts.map +1 -0
  132. package/dist/types/index.d.ts +16 -3
  133. package/dist/types/index.server.d.ts +36 -13
  134. package/dist/types/stories/admin/preview.d.ts +12 -0
  135. package/dist/types/stories/admin/preview.d.ts.map +1 -0
  136. package/dist/types/stories/admin/site-health.stories.d.ts +65 -0
  137. package/dist/types/stories/admin/site-health.stories.d.ts.map +1 -0
  138. package/dist/types/stories/structured/buzzword-bingo.stories.d.ts +1 -1
  139. package/dist/types/stories/structured/buzzword-bingo.stories.d.ts.map +1 -1
  140. package/dist/types/tests/site-health-axe-core.test.d.ts +2 -0
  141. package/dist/types/tests/site-health-axe-core.test.d.ts.map +1 -0
  142. package/dist/types/tests/site-health-cache.test.d.ts +2 -0
  143. package/dist/types/tests/site-health-cache.test.d.ts.map +1 -0
  144. package/dist/types/tests/site-health-indicators.test.d.ts +2 -0
  145. package/dist/types/tests/site-health-indicators.test.d.ts.map +1 -0
  146. package/dist/types/tests/site-health-overview.test.d.ts +2 -0
  147. package/dist/types/tests/site-health-overview.test.d.ts.map +1 -0
  148. package/dist/types/tests/site-health-template.test.d.ts +2 -0
  149. package/dist/types/tests/site-health-template.test.d.ts.map +1 -0
  150. package/dist/types/tests/sites.integration.test.d.ts +2 -0
  151. package/dist/types/tests/sites.integration.test.d.ts.map +1 -0
  152. package/package.json +15 -9
  153. package/dist/data/shipping.to.json +0 -422
  154. package/dist/data/siteinfo-form.json +0 -200
  155. package/dist/data/visualdesignform.json +0 -244
  156. package/dist/types/data/buzzwords.d.ts +0 -2
  157. package/dist/types/data/buzzwords.d.ts.map +0 -1
  158. /package/dist/{data/buzzwords.js → components/structured/buzzwordbingo.words.js} +0 -0
@@ -0,0 +1,169 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useCallback } from 'react';
4
+ import { SiteHealthTemplate } from './site-health-template';
5
+ import { getScoreIndicator } from './site-health-indicators';
6
+ export function SiteHealthSecurity({ siteName }) {
7
+ const fetchSecurityData = useCallback(async (site) => {
8
+ // Fetch PSI data for best practices security audits
9
+ const psiResponse = await fetch(`/api/site-health/core-web-vitals?siteName=${encodeURIComponent(site)}`);
10
+ const psiResult = await psiResponse.json();
11
+ return {
12
+ psiData: psiResult.success ? psiResult.data : undefined
13
+ };
14
+ }, []);
15
+ return (_jsx(SiteHealthTemplate, { siteName: siteName, title: "PageSpeed - Site Security", fetchData: fetchSecurityData, children: (data) => {
16
+ const getScoreColor = (score) => {
17
+ return getScoreIndicator(score).color;
18
+ };
19
+ const getAuditScoreIcon = (score) => {
20
+ return getScoreIndicator(score).icon;
21
+ };
22
+ // Helper function to display audit item details
23
+ const formatAuditItem = (item, auditTitle) => {
24
+ // Handle URLs
25
+ if (item.url && typeof item.url === 'string') {
26
+ return item.url;
27
+ }
28
+ // Handle sources (like JavaScript files)
29
+ if (item.source && typeof item.source === 'string') {
30
+ return item.source;
31
+ }
32
+ // Handle text descriptions
33
+ if (item.text && typeof item.text === 'string') {
34
+ return item.text;
35
+ }
36
+ // Handle entities (like "Google Tag Manager")
37
+ if (item.entity && typeof item.entity === 'string') {
38
+ return item.entity;
39
+ }
40
+ // Handle nodes with selectors
41
+ if (item.node && typeof item.node === 'object' && 'selector' in item.node) {
42
+ return `Element: ${item.node.selector}`;
43
+ }
44
+ // Handle nodes with snippets
45
+ if (item.node && typeof item.node === 'object' && 'snippet' in item.node) {
46
+ const snippet = item.node.snippet;
47
+ return `Element: ${snippet.length > 50 ? snippet.substring(0, 50) + '...' : snippet}`;
48
+ }
49
+ // Handle origins (like domains)
50
+ if (item.origin && typeof item.origin === 'string') {
51
+ return item.origin;
52
+ }
53
+ // Handle labels
54
+ if (item.label && typeof item.label === 'string') {
55
+ return item.label;
56
+ }
57
+ // Handle numeric values with units
58
+ if (item.value && typeof item.value === 'object' && 'type' in item.value && item.value.type === 'numeric') {
59
+ const value = item.value;
60
+ return `${value.value}${item.unit || ''}`;
61
+ }
62
+ // Handle statistics
63
+ if (item.statistic && typeof item.statistic === 'string' && item.value) {
64
+ if (typeof item.value === 'object' && 'type' in item.value && item.value.type === 'numeric') {
65
+ const value = item.value;
66
+ return `${item.statistic}: ${value.value}`;
67
+ }
68
+ return item.statistic;
69
+ }
70
+ // Handle timing data with more context
71
+ if (item.duration && typeof item.duration === 'number') {
72
+ const duration = item.duration;
73
+ let context = '';
74
+ if (item.url && typeof item.url === 'string') {
75
+ context = ` for ${item.url}`;
76
+ }
77
+ else if (item.source && typeof item.source === 'string') {
78
+ context = ` for ${item.source}`;
79
+ }
80
+ else if (item.name && typeof item.name === 'string') {
81
+ context = ` for ${item.name}`;
82
+ }
83
+ return `${duration.toFixed(2)}ms${context}`;
84
+ }
85
+ // Handle response times
86
+ if (item.responseTime && typeof item.responseTime === 'number') {
87
+ const url = (item.url && typeof item.url === 'string') ? ` (${item.url})` : '';
88
+ return `${item.responseTime.toFixed(2)}ms response time${url}`;
89
+ }
90
+ // Handle start/end times
91
+ if ((item.startTime || item.endTime) && typeof (item.startTime || item.endTime) === 'number') {
92
+ const start = item.startTime && typeof item.startTime === 'number' ? item.startTime.toFixed(2) : '?';
93
+ const end = item.endTime && typeof item.endTime === 'number' ? item.endTime.toFixed(2) : '?';
94
+ const url = (item.url && typeof item.url === 'string') ? ` for ${item.url}` : '';
95
+ return `${start}ms - ${end}ms${url}`;
96
+ }
97
+ // Handle transfer size with timing
98
+ if (item.transferSize && typeof item.transferSize === 'number' && item.duration && typeof item.duration === 'number') {
99
+ const size = (item.transferSize / 1024).toFixed(1);
100
+ const time = item.duration.toFixed(2);
101
+ const url = (item.url && typeof item.url === 'string') ? ` (${item.url})` : '';
102
+ return `${size} KB in ${time}ms${url}`;
103
+ }
104
+ // Handle main thread time
105
+ if (item.mainThreadTime && typeof item.mainThreadTime === 'number') {
106
+ return `${item.mainThreadTime.toFixed(1)}ms`;
107
+ }
108
+ // For other objects, try to find a meaningful display
109
+ if (item.group && typeof item.group === 'string') {
110
+ return item.group;
111
+ }
112
+ if (item.type && typeof item.type === 'string') {
113
+ return item.type;
114
+ }
115
+ // If we can't find anything meaningful, provide a generic description
116
+ // This handles raw timing data that might be from various performance metrics
117
+ if (typeof item === 'number') {
118
+ let context = '';
119
+ if (auditTitle) {
120
+ if (auditTitle.toLowerCase().includes('server') || auditTitle.toLowerCase().includes('backend')) {
121
+ context = ' server response';
122
+ }
123
+ else if (auditTitle.toLowerCase().includes('network') || auditTitle.toLowerCase().includes('request')) {
124
+ context = ' network request';
125
+ }
126
+ else if (auditTitle.toLowerCase().includes('render') || auditTitle.toLowerCase().includes('blocking')) {
127
+ context = ' render blocking';
128
+ }
129
+ else if (auditTitle.toLowerCase().includes('javascript') || auditTitle.toLowerCase().includes('js')) {
130
+ context = ' JavaScript';
131
+ }
132
+ else if (auditTitle.toLowerCase().includes('image') || auditTitle.toLowerCase().includes('media')) {
133
+ context = ' media resource';
134
+ }
135
+ }
136
+ return `${item.toFixed(2)}ms${context}`;
137
+ }
138
+ if (item.value && typeof item.value === 'number') {
139
+ const unit = item.unit || 'ms';
140
+ let context = '';
141
+ if (auditTitle && unit === 'ms') {
142
+ if (auditTitle.toLowerCase().includes('server')) {
143
+ context = ' server time';
144
+ }
145
+ else if (auditTitle.toLowerCase().includes('network')) {
146
+ context = ' network time';
147
+ }
148
+ }
149
+ return `${item.value.toFixed(2)}${unit}${context}`;
150
+ }
151
+ return 'Details available';
152
+ };
153
+ const psiData = data?.psiData?.[0];
154
+ if (!psiData) {
155
+ return (_jsx("p", { style: { color: '#6b7280' }, children: "No security data available for this site." }));
156
+ }
157
+ if (psiData.status === 'error') {
158
+ return (_jsxs("p", { style: { color: '#ef4444', fontSize: '0.875rem' }, children: ["Error: ", psiData.error] }));
159
+ }
160
+ return (_jsxs(_Fragment, { children: [_jsx("h4", { className: "health-site-name", children: siteName.replace('-', ' ') }), _jsxs("p", { className: "health-site-url", children: ["URL: ", psiData.url] }), psiData.scores['best-practices'] !== null && (_jsx("div", { className: "health-score-container", children: _jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: "Best Practices Score" }), _jsxs("div", { className: "health-score-value", style: { color: getScoreColor(psiData.scores['best-practices']) }, children: [Math.round((psiData.scores['best-practices'] || 0) * 100), "%"] }), _jsx("div", { className: "health-score-bar", children: _jsx("div", { className: "health-score-fill", style: {
161
+ width: `${(psiData.scores['best-practices'] || 0) * 100}%`,
162
+ backgroundColor: getScoreColor(psiData.scores['best-practices'])
163
+ } }) })] }) })), psiData.categories['best-practices'] && psiData.categories['best-practices'].audits.length > 0 && (_jsxs("div", { children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "Security Best Practices" }), _jsx("div", { className: "space-y-2", children: psiData.categories['best-practices'].audits
164
+ .filter(audit => audit.scoreDisplayMode !== 'notApplicable')
165
+ .sort((a, b) => (b.score || 0) - (a.score || 0))
166
+ .slice(0, 20)
167
+ .map((audit) => (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", children: getAuditScoreIcon(audit.score) }), _jsxs("div", { className: "health-audit-content", children: [_jsxs("span", { className: "health-audit-title", children: ["(", Math.round((audit.score || 0) * 100), "%) ", audit.title] }), audit.displayValue && (_jsx("p", { className: "health-audit-description", children: audit.displayValue })), audit.details?.items && Array.isArray(audit.details.items) && audit.details.items.length > 0 && (audit.score || 0) < 0.9 && (_jsx("div", { className: "health-audit-details", children: _jsx("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: audit.details.items.map((item, idx) => (_jsx("div", { style: { marginBottom: '0.125rem' }, children: formatAuditItem(item, audit.title) }, idx))) }) }))] })] }, audit.id))) })] })), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(psiData.timestamp).toLocaleString()] })] }));
168
+ } }));
169
+ }
@@ -0,0 +1,124 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useCallback } from 'react';
4
+ import { SiteHealthTemplate } from './site-health-template';
5
+ import { getScoreIndicator } from './site-health-indicators';
6
+ export function SiteHealthSEO({ siteName }) {
7
+ const fetchSEOData = useCallback(async (site) => {
8
+ const response = await fetch(`/api/site-health/core-web-vitals?siteName=${encodeURIComponent(site)}`);
9
+ const result = await response.json();
10
+ if (!result.success) {
11
+ throw new Error(result.error || 'Failed to fetch SEO data');
12
+ }
13
+ return result;
14
+ }, []);
15
+ return (_jsx(SiteHealthTemplate, { siteName: siteName, title: "PageSpeed - SEO", fetchData: fetchSEOData, children: (data) => {
16
+ const getScoreColor = (score) => {
17
+ return getScoreIndicator(score).color;
18
+ };
19
+ const getAuditScoreIcon = (score) => {
20
+ return getScoreIndicator(score).icon;
21
+ };
22
+ // Helper function to display audit item details
23
+ const formatAuditItem = (item, auditTitle) => {
24
+ // Handle URLs
25
+ if (item.url && typeof item.url === 'string') {
26
+ return item.url;
27
+ }
28
+ // Handle sources (like JavaScript files)
29
+ if (item.source && typeof item.source === 'string') {
30
+ return item.source;
31
+ }
32
+ // Handle text descriptions
33
+ if (item.text && typeof item.text === 'string') {
34
+ return item.text;
35
+ }
36
+ // Handle entities (like "Google Tag Manager")
37
+ if (item.entity && typeof item.entity === 'string') {
38
+ return item.entity;
39
+ }
40
+ // Handle nodes with selectors
41
+ if (item.node && typeof item.node === 'object' && 'selector' in item.node) {
42
+ return `Element: ${item.node.selector}`;
43
+ }
44
+ // Handle nodes with snippets
45
+ if (item.node && typeof item.node === 'object' && 'snippet' in item.node) {
46
+ const snippet = item.node.snippet;
47
+ return `Element: ${snippet.length > 50 ? snippet.substring(0, 50) + '...' : snippet}`;
48
+ }
49
+ // Handle origins (like domains)
50
+ if (item.origin && typeof item.origin === 'string') {
51
+ return item.origin;
52
+ }
53
+ // Handle labels
54
+ if (item.label && typeof item.label === 'string') {
55
+ return item.label;
56
+ }
57
+ // Handle numeric values with units
58
+ if (item.value && typeof item.value === 'object' && 'type' in item.value && item.value.type === 'numeric') {
59
+ const value = item.value;
60
+ return `${value.value}${item.unit || ''}`;
61
+ }
62
+ // Handle statistics
63
+ if (item.statistic && typeof item.statistic === 'string' && item.value) {
64
+ if (typeof item.value === 'object' && 'type' in item.value && item.value.type === 'numeric') {
65
+ const value = item.value;
66
+ return `${item.statistic}: ${value.value}`;
67
+ }
68
+ return item.statistic;
69
+ }
70
+ // Handle timing data with audit context
71
+ if (typeof item === 'number') {
72
+ let context = '';
73
+ if (auditTitle) {
74
+ if (auditTitle.toLowerCase().includes('server') || auditTitle.toLowerCase().includes('backend')) {
75
+ context = ' server response';
76
+ }
77
+ else if (auditTitle.toLowerCase().includes('network') || auditTitle.toLowerCase().includes('request')) {
78
+ context = ' network request';
79
+ }
80
+ else if (auditTitle.toLowerCase().includes('render') || auditTitle.toLowerCase().includes('blocking')) {
81
+ context = ' render blocking';
82
+ }
83
+ else if (auditTitle.toLowerCase().includes('javascript') || auditTitle.toLowerCase().includes('js')) {
84
+ context = ' JavaScript';
85
+ }
86
+ else if (auditTitle.toLowerCase().includes('image') || auditTitle.toLowerCase().includes('media')) {
87
+ context = ' media resource';
88
+ }
89
+ }
90
+ return `${item.toFixed(2)}ms${context}`;
91
+ }
92
+ if (item.value && typeof item.value === 'number') {
93
+ const unit = item.unit || 'ms';
94
+ let context = '';
95
+ if (auditTitle && unit === 'ms') {
96
+ if (auditTitle.toLowerCase().includes('server')) {
97
+ context = ' server time';
98
+ }
99
+ else if (auditTitle.toLowerCase().includes('network')) {
100
+ context = ' network time';
101
+ }
102
+ }
103
+ return `${item.value.toFixed(2)}${unit}${context}`;
104
+ }
105
+ // If we can't find anything meaningful, show a generic message
106
+ return 'Details available';
107
+ };
108
+ if (!data?.data || data.data.length === 0) {
109
+ return (_jsx("p", { style: { color: '#6b7280' }, children: "No SEO data available for this site." }));
110
+ }
111
+ const siteData = data.data[0];
112
+ if (siteData.status === 'error') {
113
+ return (_jsxs("p", { style: { color: '#ef4444', fontSize: '0.875rem' }, children: ["Error: ", siteData.error] }));
114
+ }
115
+ return (_jsxs(_Fragment, { children: [_jsx("h4", { className: "health-site-name", children: siteData.site.replace('-', ' ') }), _jsxs("p", { className: "health-site-url", children: ["URL: ", siteData.url] }), siteData.scores.seo !== null && (_jsx("div", { className: "health-score-container", children: _jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: "SEO Score" }), _jsxs("div", { className: "health-score-value", style: { color: getScoreColor(siteData.scores.seo) }, children: [Math.round((siteData.scores.seo || 0) * 100), "%"] }), _jsx("div", { className: "health-score-bar", children: _jsx("div", { className: "health-score-fill", style: {
116
+ width: `${(siteData.scores.seo || 0) * 100}%`,
117
+ backgroundColor: getScoreColor(siteData.scores.seo)
118
+ } }) })] }) })), siteData.categories.seo && siteData.categories.seo.audits.length > 0 && (_jsxs("div", { children: [_jsx("h5", { style: { fontSize: '1rem', fontWeight: '600', marginBottom: '1rem' }, children: "SEO Issues & Recommendations" }), _jsx("div", { className: "space-y-2", children: siteData.categories.seo.audits
119
+ .filter(audit => audit.scoreDisplayMode !== 'notApplicable')
120
+ .sort((a, b) => (b.score || 0) - (a.score || 0))
121
+ .slice(0, 20)
122
+ .map((audit) => (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", children: getAuditScoreIcon(audit.score) }), _jsxs("div", { className: "health-audit-content", children: [_jsxs("span", { className: "health-audit-title", children: ["(", Math.round((audit.score || 0) * 100), "%) ", audit.title] }), audit.displayValue && (_jsx("p", { className: "health-audit-description", children: audit.displayValue })), audit.details?.items && Array.isArray(audit.details.items) && audit.details.items.length > 0 && (audit.score || 0) < 1.0 && (_jsx("div", { className: "health-audit-details", children: _jsx("div", { style: { fontSize: '0.75rem', color: '#6b7280', marginTop: '0.25rem' }, children: audit.details.items.map((item, idx) => (_jsx("div", { style: { marginBottom: '0.125rem' }, children: formatAuditItem(item, audit.title) }, idx))) }) }))] })] }, audit.id))) })] })), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(siteData.timestamp).toLocaleString()] })] }));
123
+ } }));
124
+ }
@@ -0,0 +1,62 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useState } from 'react';
4
+ import { PageGridItem } from '../../general/semantic';
5
+ export function SiteHealthTemplate({ siteName, title, children, fetchData, enableCacheControl = false, columnSpan = 1 }) {
6
+ const [data, setData] = useState(null);
7
+ const [loading, setLoading] = useState(false);
8
+ const [error, setError] = useState(null);
9
+ useEffect(() => {
10
+ let isMounted = true;
11
+ const loadData = async () => {
12
+ if (!siteName) {
13
+ if (isMounted) {
14
+ setData(null);
15
+ setLoading(false);
16
+ setError(null);
17
+ }
18
+ return;
19
+ }
20
+ if (isMounted) {
21
+ setLoading(true);
22
+ setError(null);
23
+ }
24
+ try {
25
+ // Check for cache control from URL query parameters
26
+ const urlParams = new URLSearchParams(window.location.search);
27
+ const cacheParam = urlParams.get('cache');
28
+ const useCache = enableCacheControl ? (cacheParam !== 'false') : true;
29
+ const result = await fetchData(siteName, useCache);
30
+ if (isMounted) {
31
+ setData(result);
32
+ setError(null);
33
+ }
34
+ }
35
+ catch (err) {
36
+ if (isMounted) {
37
+ setError(err instanceof Error ? err.message : 'Failed to load data');
38
+ setData(null);
39
+ }
40
+ }
41
+ finally {
42
+ if (isMounted) {
43
+ setLoading(false);
44
+ }
45
+ }
46
+ };
47
+ loadData();
48
+ return () => {
49
+ isMounted = false;
50
+ };
51
+ }, [siteName, fetchData]);
52
+ // If no site selected, show nothing
53
+ if (!siteName) {
54
+ return null;
55
+ }
56
+ // If title is provided, render the complete card structure
57
+ if (title) {
58
+ return (_jsxs(PageGridItem, { className: "health-card", columnSpan: columnSpan, children: [_jsx("h2", { className: "health-card-title", children: title }), _jsx("div", { className: "health-card-content", children: loading ? (_jsxs("div", { className: "health-loading", children: [_jsx("div", { className: "health-loading-spinner" }), _jsx("p", { className: "health-loading-text", children: "Loading..." })] })) : error ? (_jsx("div", { className: "health-error", children: _jsxs("p", { className: "health-error-text", children: ["Error: ", error] }) })) : (children(data)) })] }));
59
+ }
60
+ // Legacy mode: render content directly without wrapper
61
+ return (_jsx(_Fragment, { children: loading ? (_jsxs("div", { className: "health-loading", children: [_jsx("div", { className: "health-loading-spinner" }), _jsx("p", { className: "health-loading-text", children: "Loading..." })] })) : error ? (_jsx("div", { className: "health-error", children: _jsxs("p", { className: "health-error-text", children: ["Error: ", error] }) })) : (children(data)) }));
62
+ }
@@ -0,0 +1,29 @@
1
+ import { Route53Client, GetHealthCheckStatusCommand } from '@aws-sdk/client-route-53';
2
+ export async function checkUptimeHealth(healthCheckId) {
3
+ try {
4
+ // Simple Route 53 call (global service, no region needed)
5
+ const client = new Route53Client({});
6
+ const response = await client.send(new GetHealthCheckStatusCommand({
7
+ HealthCheckId: healthCheckId,
8
+ }));
9
+ const rawStatus = response.HealthCheckObservations?.[0]?.StatusReport?.Status;
10
+ const status = rawStatus?.toLowerCase().includes('success') ? 'Healthy' :
11
+ rawStatus?.toLowerCase().includes('failure') ? 'Unhealthy' : 'Unknown';
12
+ return {
13
+ status: 'success',
14
+ data: {
15
+ status
16
+ }
17
+ };
18
+ }
19
+ catch (error) {
20
+ console.error('Uptime check failed:', error);
21
+ return {
22
+ status: 'success', // Return success with unknown status to match API behavior
23
+ data: {
24
+ status: 'Unknown',
25
+ message: 'Check failed'
26
+ }
27
+ };
28
+ }
29
+ }
@@ -0,0 +1,30 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { SiteHealthTemplate } from './site-health-template';
4
+ export function SiteHealthUptime({ siteName }) {
5
+ const fetchUptimeData = async (site) => {
6
+ const response = await fetch(`/api/site-health/uptime?siteName=${encodeURIComponent(site)}`);
7
+ const result = await response.json();
8
+ if (!result.success) {
9
+ throw new Error('Failed to load health status');
10
+ }
11
+ return result;
12
+ };
13
+ return (_jsx(SiteHealthTemplate, { siteName: siteName, title: "Health Status", fetchData: fetchUptimeData, children: (data) => {
14
+ if (!data) {
15
+ return (_jsx("p", { style: { color: '#6b7280' }, children: "No uptime data available for this site." }));
16
+ }
17
+ return (_jsxs(_Fragment, { children: [_jsx("h4", { className: "health-site-name", children: siteName.replace('-', ' ') }), _jsxs("p", { className: "health-site-url", children: ["URL: ", data.url] }), _jsx("div", { className: "health-score-container", children: _jsxs("div", { className: "health-score-item", children: [_jsx("div", { className: "health-score-label", children: "Site Status" }), _jsx("div", { className: "health-score-value", style: {
18
+ color: data.status === 'Healthy' ? '#10b981' :
19
+ data.status === 'Unhealthy' ? '#ef4444' : '#f59e0b'
20
+ }, children: data.status }), _jsx("div", { className: "health-score-bar", children: _jsx("div", { className: "health-score-fill", style: {
21
+ width: data.status === 'Healthy' ? '100%' :
22
+ data.status === 'Unhealthy' ? '10%' : '50%',
23
+ backgroundColor: data.status === 'Healthy' ? '#10b981' :
24
+ data.status === 'Unhealthy' ? '#ef4444' : '#f59e0b'
25
+ } }) })] }) }), data.message && (_jsxs("div", { className: "health-audit-item", children: [_jsx("span", { className: "health-audit-icon", style: {
26
+ color: data.status === 'Healthy' ? '#10b981' :
27
+ data.status === 'Unhealthy' ? '#ef4444' : '#f59e0b'
28
+ }, children: data.status === 'Healthy' ? '✓' : data.status === 'Unhealthy' ? '✗' : '⚠' }), _jsx("div", { className: "health-audit-content", children: _jsx("span", { className: "health-audit-title", children: data.message }) })] })), _jsxs("p", { className: "health-timestamp", children: ["Last checked: ", new Date(data.timestamp).toLocaleString()] })] }));
29
+ } }));
30
+ }