@actuate-media/cms-admin 0.36.0 → 0.37.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.
- package/dist/__tests__/views/appearance-settings.render.test.js +4 -4
- package/dist/__tests__/views/updates-tab.render.test.d.ts +2 -0
- package/dist/__tests__/views/updates-tab.render.test.d.ts.map +1 -0
- package/dist/__tests__/views/updates-tab.render.test.js +132 -0
- package/dist/__tests__/views/updates-tab.render.test.js.map +1 -0
- package/dist/actuate-admin.css +1 -1
- package/dist/views/ApiKeys.d.ts.map +1 -1
- package/dist/views/ApiKeys.js +14 -13
- package/dist/views/ApiKeys.js.map +1 -1
- package/dist/views/Profile.d.ts.map +1 -1
- package/dist/views/Profile.js +1 -1
- package/dist/views/Profile.js.map +1 -1
- package/dist/views/Settings.d.ts.map +1 -1
- package/dist/views/Settings.js +16 -119
- package/dist/views/Settings.js.map +1 -1
- package/dist/views/Users.js +1 -1
- package/dist/views/Users.js.map +1 -1
- package/dist/views/settings/AISettingsTab.js +40 -42
- package/dist/views/settings/AISettingsTab.js.map +1 -1
- package/dist/views/settings/AdminThemeCard.js +1 -1
- package/dist/views/settings/AiFeaturesCard.d.ts.map +1 -1
- package/dist/views/settings/AiFeaturesCard.js +2 -3
- package/dist/views/settings/AiFeaturesCard.js.map +1 -1
- package/dist/views/settings/BrandPreviewCard.js +1 -1
- package/dist/views/settings/BrandVoiceCard.d.ts.map +1 -1
- package/dist/views/settings/BrandVoiceCard.js +2 -4
- package/dist/views/settings/BrandVoiceCard.js.map +1 -1
- package/dist/views/settings/BrandingCard.d.ts.map +1 -1
- package/dist/views/settings/BrandingCard.js +34 -19
- package/dist/views/settings/BrandingCard.js.map +1 -1
- package/dist/views/settings/GeneralSettingsTab.js +1 -1
- package/dist/views/settings/LanguageRegionCard.d.ts.map +1 -1
- package/dist/views/settings/LanguageRegionCard.js +2 -1
- package/dist/views/settings/LanguageRegionCard.js.map +1 -1
- package/dist/views/settings/MonthlyUsageCard.d.ts.map +1 -1
- package/dist/views/settings/MonthlyUsageCard.js +3 -3
- package/dist/views/settings/MonthlyUsageCard.js.map +1 -1
- package/dist/views/settings/ProviderConnectionCard.js +1 -1
- package/dist/views/settings/ProviderConnectionCard.js.map +1 -1
- package/dist/views/settings/SecurityStatusCard.d.ts.map +1 -1
- package/dist/views/settings/SecurityStatusCard.js +2 -3
- package/dist/views/settings/SecurityStatusCard.js.map +1 -1
- package/dist/views/settings/SecurityTab.js +1 -1
- package/dist/views/settings/SeoRobotsDefaultsCard.d.ts.map +1 -1
- package/dist/views/settings/SeoRobotsDefaultsCard.js +3 -4
- package/dist/views/settings/SeoRobotsDefaultsCard.js.map +1 -1
- package/dist/views/settings/SeoSettingsTab.d.ts.map +1 -1
- package/dist/views/settings/SeoSettingsTab.js +5 -8
- package/dist/views/settings/SeoSettingsTab.js.map +1 -1
- package/dist/views/settings/SiteIndexStatusCard.d.ts.map +1 -1
- package/dist/views/settings/SiteIndexStatusCard.js +3 -2
- package/dist/views/settings/SiteIndexStatusCard.js.map +1 -1
- package/dist/views/settings/SiteInformationCard.d.ts.map +1 -1
- package/dist/views/settings/SiteInformationCard.js +4 -4
- package/dist/views/settings/SiteInformationCard.js.map +1 -1
- package/dist/views/settings/TypographyMotionCard.js +1 -1
- package/dist/views/settings/UpdatesTab.d.ts +6 -0
- package/dist/views/settings/UpdatesTab.d.ts.map +1 -0
- package/dist/views/settings/UpdatesTab.js +80 -0
- package/dist/views/settings/UpdatesTab.js.map +1 -0
- package/dist/views/settings/components.d.ts +51 -1
- package/dist/views/settings/components.d.ts.map +1 -1
- package/dist/views/settings/components.js +33 -0
- package/dist/views/settings/components.js.map +1 -1
- package/dist/views/settings/securityPrimitives.d.ts +11 -3
- package/dist/views/settings/securityPrimitives.d.ts.map +1 -1
- package/dist/views/settings/securityPrimitives.js +10 -3
- package/dist/views/settings/securityPrimitives.js.map +1 -1
- package/dist/views/settings/useUpdates.d.ts +67 -0
- package/dist/views/settings/useUpdates.d.ts.map +1 -0
- package/dist/views/settings/useUpdates.js +127 -0
- package/dist/views/settings/useUpdates.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/views/appearance-settings.render.test.tsx +4 -4
- package/src/__tests__/views/updates-tab.render.test.tsx +161 -0
- package/src/views/ApiKeys.tsx +190 -154
- package/src/views/Profile.tsx +4 -2
- package/src/views/Settings.tsx +26 -451
- package/src/views/Users.tsx +1 -1
- package/src/views/settings/AISettingsTab.tsx +64 -76
- package/src/views/settings/AdminThemeCard.tsx +1 -1
- package/src/views/settings/AiFeaturesCard.tsx +6 -12
- package/src/views/settings/BrandPreviewCard.tsx +1 -1
- package/src/views/settings/BrandVoiceCard.tsx +6 -19
- package/src/views/settings/BrandingCard.tsx +179 -180
- package/src/views/settings/GeneralSettingsTab.tsx +1 -1
- package/src/views/settings/LanguageRegionCard.tsx +5 -7
- package/src/views/settings/MonthlyUsageCard.tsx +6 -10
- package/src/views/settings/ProviderConnectionCard.tsx +1 -1
- package/src/views/settings/SecurityStatusCard.tsx +8 -11
- package/src/views/settings/SecurityTab.tsx +1 -1
- package/src/views/settings/SeoRobotsDefaultsCard.tsx +7 -14
- package/src/views/settings/SeoSettingsTab.tsx +17 -26
- package/src/views/settings/SiteIndexStatusCard.tsx +10 -22
- package/src/views/settings/SiteInformationCard.tsx +3 -9
- package/src/views/settings/TypographyMotionCard.tsx +1 -1
- package/src/views/settings/UpdatesTab.tsx +545 -0
- package/src/views/settings/components.tsx +123 -1
- package/src/views/settings/securityPrimitives.tsx +14 -9
- package/src/views/settings/useUpdates.ts +183 -0
package/src/views/Settings.tsx
CHANGED
|
@@ -3,16 +3,9 @@
|
|
|
3
3
|
import * as Tabs from '@radix-ui/react-tabs'
|
|
4
4
|
import {
|
|
5
5
|
Bot,
|
|
6
|
-
Eye,
|
|
7
|
-
EyeOff,
|
|
8
6
|
Loader2,
|
|
9
7
|
AlertTriangle,
|
|
10
8
|
Download,
|
|
11
|
-
CheckCircle2,
|
|
12
|
-
ArrowUpCircle,
|
|
13
|
-
ExternalLink,
|
|
14
|
-
RefreshCw,
|
|
15
|
-
GitPullRequest,
|
|
16
9
|
Layers,
|
|
17
10
|
Users as UsersIcon,
|
|
18
11
|
KeyRound,
|
|
@@ -27,6 +20,8 @@ import { SeoSettingsTab } from './settings/SeoSettingsTab.js'
|
|
|
27
20
|
import { AISettingsTab } from './settings/AISettingsTab.js'
|
|
28
21
|
import { AppearanceTab } from './settings/AppearanceTab.js'
|
|
29
22
|
import { SecurityTab } from './settings/SecurityTab.js'
|
|
23
|
+
import { SettingsCard } from './settings/components.js'
|
|
24
|
+
import { UpdatesTab } from './settings/UpdatesTab.js'
|
|
30
25
|
import { Users as UsersView } from './Users.js'
|
|
31
26
|
import { ApiKeys as ApiKeysView } from './ApiKeys.js'
|
|
32
27
|
|
|
@@ -165,12 +160,15 @@ export function Settings({
|
|
|
165
160
|
return (
|
|
166
161
|
<div className="p-3 pr-6 sm:p-4 sm:pr-8">
|
|
167
162
|
{error && (
|
|
168
|
-
<div
|
|
169
|
-
|
|
170
|
-
|
|
163
|
+
<div
|
|
164
|
+
role="alert"
|
|
165
|
+
className="border-destructive/30 bg-destructive/10 text-destructive mb-4 flex items-center gap-3 rounded-lg border p-3 text-sm"
|
|
166
|
+
>
|
|
167
|
+
<AlertTriangle size={20} className="shrink-0" aria-hidden="true" />
|
|
168
|
+
<span className="flex-1">{error}</span>
|
|
171
169
|
<button
|
|
172
170
|
onClick={refetch}
|
|
173
|
-
className="rounded-
|
|
171
|
+
className="border-destructive/40 rounded-md border px-3 py-1 transition-colors hover:opacity-80"
|
|
174
172
|
>
|
|
175
173
|
Retry
|
|
176
174
|
</button>
|
|
@@ -178,12 +176,12 @@ export function Settings({
|
|
|
178
176
|
)}
|
|
179
177
|
|
|
180
178
|
<div className="mb-4">
|
|
181
|
-
<h1 className="mb-1 text-2xl font-
|
|
182
|
-
<p className="text-
|
|
179
|
+
<h1 className="text-foreground mb-1 text-2xl font-medium">Settings</h1>
|
|
180
|
+
<p className="text-muted-foreground text-sm">Manage your CMS configuration</p>
|
|
183
181
|
</div>
|
|
184
182
|
|
|
185
183
|
<Tabs.Root value={activeTab} onValueChange={changeTab}>
|
|
186
|
-
<Tabs.List className="mb-4 flex gap-1 overflow-x-auto border-b
|
|
184
|
+
<Tabs.List className="border-border mb-4 flex gap-1 overflow-x-auto border-b">
|
|
187
185
|
<Tabs.Trigger value="general" className={tabTriggerClass}>
|
|
188
186
|
General
|
|
189
187
|
</Tabs.Trigger>
|
|
@@ -240,12 +238,10 @@ export function Settings({
|
|
|
240
238
|
|
|
241
239
|
{hasLayoutRegions && (
|
|
242
240
|
<Tabs.Content value="layout" className="space-y-4">
|
|
243
|
-
<
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
can override these individually or inherit from parent pages.
|
|
248
|
-
</p>
|
|
241
|
+
<SettingsCard
|
|
242
|
+
title="Default Layout Variants"
|
|
243
|
+
description="Select the default header, footer, and other layout variants used site-wide. Pages can override these individually or inherit from parent pages."
|
|
244
|
+
>
|
|
249
245
|
<div className="space-y-4">
|
|
250
246
|
{layoutRegions.map((region) => (
|
|
251
247
|
<RelationshipField
|
|
@@ -268,14 +264,11 @@ export function Settings({
|
|
|
268
264
|
/>
|
|
269
265
|
))}
|
|
270
266
|
</div>
|
|
271
|
-
</
|
|
272
|
-
<
|
|
273
|
-
<
|
|
274
|
-
How Layout Inheritance Works
|
|
275
|
-
</h3>
|
|
276
|
-
<ul className="space-y-1.5 text-xs text-gray-600">
|
|
267
|
+
</SettingsCard>
|
|
268
|
+
<SettingsCard title="How Layout Inheritance Works">
|
|
269
|
+
<ul className="text-muted-foreground space-y-1.5 text-sm">
|
|
277
270
|
<li className="flex items-start gap-2">
|
|
278
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full
|
|
271
|
+
<span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
|
|
279
272
|
1
|
|
280
273
|
</span>
|
|
281
274
|
<span>
|
|
@@ -284,20 +277,20 @@ export function Settings({
|
|
|
284
277
|
</span>
|
|
285
278
|
</li>
|
|
286
279
|
<li className="flex items-start gap-2">
|
|
287
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full
|
|
280
|
+
<span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
|
|
288
281
|
2
|
|
289
282
|
</span>
|
|
290
283
|
<span>
|
|
291
284
|
Child pages automatically inherit their parent's layout. For example,{' '}
|
|
292
|
-
<code className="
|
|
285
|
+
<code className="bg-muted rounded px-1 font-mono">
|
|
293
286
|
/hampton-roads/thank-you
|
|
294
287
|
</code>{' '}
|
|
295
288
|
inherits from{' '}
|
|
296
|
-
<code className="
|
|
289
|
+
<code className="bg-muted rounded px-1 font-mono">/hampton-roads</code>.
|
|
297
290
|
</span>
|
|
298
291
|
</li>
|
|
299
292
|
<li className="flex items-start gap-2">
|
|
300
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full
|
|
293
|
+
<span className="bg-brand/10 text-brand mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full text-[10px] font-medium">
|
|
301
294
|
3
|
|
302
295
|
</span>
|
|
303
296
|
<span>
|
|
@@ -306,7 +299,7 @@ export function Settings({
|
|
|
306
299
|
</span>
|
|
307
300
|
</li>
|
|
308
301
|
</ul>
|
|
309
|
-
</
|
|
302
|
+
</SettingsCard>
|
|
310
303
|
</Tabs.Content>
|
|
311
304
|
)}
|
|
312
305
|
|
|
@@ -331,7 +324,7 @@ export function Settings({
|
|
|
331
324
|
</Tabs.Content>
|
|
332
325
|
|
|
333
326
|
<Tabs.Content value="updates" className="space-y-4">
|
|
334
|
-
<
|
|
327
|
+
<UpdatesTab role={session?.user?.role} />
|
|
335
328
|
</Tabs.Content>
|
|
336
329
|
</Tabs.Root>
|
|
337
330
|
|
|
@@ -350,421 +343,3 @@ export function Settings({
|
|
|
350
343
|
</div>
|
|
351
344
|
)
|
|
352
345
|
}
|
|
353
|
-
|
|
354
|
-
// ---------------------------------------------------------------------------
|
|
355
|
-
// Updates Panel
|
|
356
|
-
// ---------------------------------------------------------------------------
|
|
357
|
-
|
|
358
|
-
interface UpdateInfo {
|
|
359
|
-
current: string
|
|
360
|
-
latest: string
|
|
361
|
-
updateAvailable: boolean
|
|
362
|
-
severity?: 'patch' | 'minor' | 'major'
|
|
363
|
-
releaseDate?: string
|
|
364
|
-
changelog?: Array<{ version: string; date: string; summary: string }>
|
|
365
|
-
updateCommand?: string
|
|
366
|
-
hasGithubToken?: boolean
|
|
367
|
-
githubRepo?: string
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
function UpdatesPanel() {
|
|
371
|
-
const [updateInfo, setUpdateInfo] = useState<UpdateInfo | null>(null)
|
|
372
|
-
const [checking, setChecking] = useState(false)
|
|
373
|
-
const [checkError, setCheckError] = useState('')
|
|
374
|
-
const [applying, setApplying] = useState(false)
|
|
375
|
-
const [prResult, setPrResult] = useState<{ prUrl: string; prNumber: number } | null>(null)
|
|
376
|
-
const [hasChecked, setHasChecked] = useState(false)
|
|
377
|
-
|
|
378
|
-
// GitHub config
|
|
379
|
-
const [ghToken, setGhToken] = useState('')
|
|
380
|
-
const [ghRepo, setGhRepo] = useState('')
|
|
381
|
-
const [showGhToken, setShowGhToken] = useState(false)
|
|
382
|
-
const [savingConfig, setSavingConfig] = useState(false)
|
|
383
|
-
const [configSaved, setConfigSaved] = useState(false)
|
|
384
|
-
|
|
385
|
-
const checkForUpdates = async () => {
|
|
386
|
-
setChecking(true)
|
|
387
|
-
setCheckError('')
|
|
388
|
-
setPrResult(null)
|
|
389
|
-
|
|
390
|
-
try {
|
|
391
|
-
const res = await cmsApi<UpdateInfo>('/updates/check')
|
|
392
|
-
if (res.error) {
|
|
393
|
-
setCheckError(res.error)
|
|
394
|
-
} else if (res.data) {
|
|
395
|
-
setUpdateInfo(res.data)
|
|
396
|
-
if (res.data.githubRepo) setGhRepo(res.data.githubRepo)
|
|
397
|
-
}
|
|
398
|
-
} catch {
|
|
399
|
-
setCheckError('Unable to check for updates. Please try again.')
|
|
400
|
-
} finally {
|
|
401
|
-
setChecking(false)
|
|
402
|
-
setHasChecked(true)
|
|
403
|
-
}
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
const saveGitHubConfig = async () => {
|
|
407
|
-
setSavingConfig(true)
|
|
408
|
-
setConfigSaved(false)
|
|
409
|
-
try {
|
|
410
|
-
const res = await cmsApi('/updates/config', {
|
|
411
|
-
method: 'PUT',
|
|
412
|
-
body: JSON.stringify({
|
|
413
|
-
...(ghToken ? { githubToken: ghToken } : {}),
|
|
414
|
-
...(ghRepo ? { githubRepo: ghRepo } : {}),
|
|
415
|
-
}),
|
|
416
|
-
})
|
|
417
|
-
if (res.error) {
|
|
418
|
-
toast.error(res.error)
|
|
419
|
-
} else {
|
|
420
|
-
toast.success('GitHub configuration saved and encrypted.')
|
|
421
|
-
setConfigSaved(true)
|
|
422
|
-
setGhToken('')
|
|
423
|
-
if (updateInfo) {
|
|
424
|
-
setUpdateInfo({ ...updateInfo, hasGithubToken: true, githubRepo: ghRepo })
|
|
425
|
-
}
|
|
426
|
-
}
|
|
427
|
-
} catch {
|
|
428
|
-
toast.error('Failed to save configuration.')
|
|
429
|
-
} finally {
|
|
430
|
-
setSavingConfig(false)
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
const applyUpdate = async () => {
|
|
435
|
-
if (!updateInfo?.latest) return
|
|
436
|
-
setApplying(true)
|
|
437
|
-
|
|
438
|
-
try {
|
|
439
|
-
const res = await cmsApi<{ prUrl: string; prNumber: number }>('/updates/apply', {
|
|
440
|
-
method: 'POST',
|
|
441
|
-
body: JSON.stringify({ targetVersion: updateInfo.latest }),
|
|
442
|
-
})
|
|
443
|
-
|
|
444
|
-
if (res.error) {
|
|
445
|
-
toast.error(res.error)
|
|
446
|
-
} else if (res.data) {
|
|
447
|
-
setPrResult(res.data)
|
|
448
|
-
toast.success('Update PR created successfully!')
|
|
449
|
-
}
|
|
450
|
-
} catch {
|
|
451
|
-
toast.error('Failed to create update PR. Check your GitHub configuration.')
|
|
452
|
-
} finally {
|
|
453
|
-
setApplying(false)
|
|
454
|
-
}
|
|
455
|
-
}
|
|
456
|
-
|
|
457
|
-
useEffect(() => {
|
|
458
|
-
checkForUpdates()
|
|
459
|
-
}, [])
|
|
460
|
-
|
|
461
|
-
const severityColors: Record<
|
|
462
|
-
string,
|
|
463
|
-
{ bg: string; text: string; border: string; label: string }
|
|
464
|
-
> = {
|
|
465
|
-
patch: { bg: 'bg-blue-50', text: 'text-blue-700', border: 'border-blue-200', label: 'Patch' },
|
|
466
|
-
minor: {
|
|
467
|
-
bg: 'bg-yellow-50',
|
|
468
|
-
text: 'text-yellow-700',
|
|
469
|
-
border: 'border-yellow-200',
|
|
470
|
-
label: 'Minor',
|
|
471
|
-
},
|
|
472
|
-
major: { bg: 'bg-red-50', text: 'text-red-700', border: 'border-red-200', label: 'Major' },
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
return (
|
|
476
|
-
<>
|
|
477
|
-
{/* Current Version Card */}
|
|
478
|
-
<div className="rounded-lg border border-gray-200 bg-white p-4">
|
|
479
|
-
<div className="flex items-center justify-between">
|
|
480
|
-
<div>
|
|
481
|
-
<h3 className="text-sm font-semibold text-gray-900">Actuate CMS</h3>
|
|
482
|
-
<p className="mt-1 text-sm text-gray-600">
|
|
483
|
-
Current version:{' '}
|
|
484
|
-
<span className="font-mono font-medium">{updateInfo?.current ?? '...'}</span>
|
|
485
|
-
</p>
|
|
486
|
-
</div>
|
|
487
|
-
<button
|
|
488
|
-
type="button"
|
|
489
|
-
onClick={checkForUpdates}
|
|
490
|
-
disabled={checking}
|
|
491
|
-
className="flex items-center gap-2 rounded-lg border border-gray-300 px-4 py-2 text-sm font-medium text-gray-700 transition-colors hover:bg-gray-50 disabled:opacity-50"
|
|
492
|
-
>
|
|
493
|
-
<RefreshCw className={`h-4 w-4 ${checking ? 'animate-spin' : ''}`} />
|
|
494
|
-
{checking ? 'Checking...' : 'Check for Updates'}
|
|
495
|
-
</button>
|
|
496
|
-
</div>
|
|
497
|
-
</div>
|
|
498
|
-
|
|
499
|
-
{/* Error State */}
|
|
500
|
-
{checkError && (
|
|
501
|
-
<div className="flex items-center gap-3 rounded-lg border border-red-200 bg-red-50 p-3">
|
|
502
|
-
<AlertTriangle className="h-5 w-5 shrink-0 text-red-600" />
|
|
503
|
-
<span className="flex-1 text-sm text-red-800">{checkError}</span>
|
|
504
|
-
<button
|
|
505
|
-
onClick={checkForUpdates}
|
|
506
|
-
className="rounded-lg border border-red-300 px-3 py-1 text-sm text-red-700 transition-colors hover:bg-red-100"
|
|
507
|
-
>
|
|
508
|
-
Retry
|
|
509
|
-
</button>
|
|
510
|
-
</div>
|
|
511
|
-
)}
|
|
512
|
-
|
|
513
|
-
{/* Up to Date */}
|
|
514
|
-
{hasChecked && updateInfo && !updateInfo.updateAvailable && !checkError && (
|
|
515
|
-
<div className="flex items-center gap-3 rounded-lg border border-green-200 bg-green-50 p-4">
|
|
516
|
-
<CheckCircle2 className="h-6 w-6 shrink-0 text-green-600" />
|
|
517
|
-
<div>
|
|
518
|
-
<h3 className="text-sm font-semibold text-green-900">You're up to date!</h3>
|
|
519
|
-
<p className="mt-0.5 text-sm text-green-700">
|
|
520
|
-
Actuate CMS <span className="font-mono">{updateInfo.current}</span> is the latest
|
|
521
|
-
version.
|
|
522
|
-
</p>
|
|
523
|
-
</div>
|
|
524
|
-
</div>
|
|
525
|
-
)}
|
|
526
|
-
|
|
527
|
-
{/* Update Available */}
|
|
528
|
-
{updateInfo?.updateAvailable && (
|
|
529
|
-
<>
|
|
530
|
-
<div
|
|
531
|
-
className={`rounded-lg border p-4 ${severityColors[updateInfo.severity ?? 'patch']?.border ?? 'border-blue-200'} ${severityColors[updateInfo.severity ?? 'patch']?.bg ?? 'bg-blue-50'}`}
|
|
532
|
-
>
|
|
533
|
-
<div className="flex items-start gap-3">
|
|
534
|
-
<ArrowUpCircle
|
|
535
|
-
className={`mt-0.5 h-6 w-6 shrink-0 ${severityColors[updateInfo.severity ?? 'patch']?.text ?? 'text-blue-700'}`}
|
|
536
|
-
/>
|
|
537
|
-
<div className="flex-1">
|
|
538
|
-
<div className="flex items-center gap-2">
|
|
539
|
-
<h3
|
|
540
|
-
className={`text-sm font-semibold ${severityColors[updateInfo.severity ?? 'patch']?.text ?? 'text-blue-700'}`}
|
|
541
|
-
>
|
|
542
|
-
Update Available
|
|
543
|
-
</h3>
|
|
544
|
-
<span
|
|
545
|
-
className={`inline-flex items-center rounded px-2 py-0.5 text-xs font-medium ${severityColors[updateInfo.severity ?? 'patch']?.bg ?? 'bg-blue-50'} ${severityColors[updateInfo.severity ?? 'patch']?.text ?? 'text-blue-700'} border ${severityColors[updateInfo.severity ?? 'patch']?.border ?? 'border-blue-200'}`}
|
|
546
|
-
>
|
|
547
|
-
{severityColors[updateInfo.severity ?? 'patch']?.label ?? 'Update'}
|
|
548
|
-
</span>
|
|
549
|
-
</div>
|
|
550
|
-
<p className="mt-1 text-sm" style={{ color: 'inherit' }}>
|
|
551
|
-
<span className="font-mono">{updateInfo.current}</span> →{' '}
|
|
552
|
-
<span className="font-mono font-semibold">{updateInfo.latest}</span>
|
|
553
|
-
{updateInfo.releaseDate && (
|
|
554
|
-
<span className="ml-2 text-xs opacity-70">
|
|
555
|
-
Released {updateInfo.releaseDate}
|
|
556
|
-
</span>
|
|
557
|
-
)}
|
|
558
|
-
</p>
|
|
559
|
-
</div>
|
|
560
|
-
</div>
|
|
561
|
-
|
|
562
|
-
<div className="mt-4 flex items-center gap-3">
|
|
563
|
-
<button
|
|
564
|
-
type="button"
|
|
565
|
-
onClick={applyUpdate}
|
|
566
|
-
disabled={applying}
|
|
567
|
-
className="flex items-center gap-2 rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:opacity-50"
|
|
568
|
-
>
|
|
569
|
-
{applying ? (
|
|
570
|
-
<>
|
|
571
|
-
<Loader2 className="h-4 w-4 animate-spin" />
|
|
572
|
-
Creating PR...
|
|
573
|
-
</>
|
|
574
|
-
) : (
|
|
575
|
-
<>
|
|
576
|
-
<GitPullRequest className="h-4 w-4" />
|
|
577
|
-
Create Update PR
|
|
578
|
-
</>
|
|
579
|
-
)}
|
|
580
|
-
</button>
|
|
581
|
-
<span className="text-xs text-gray-500">Opens a pull request on your repository</span>
|
|
582
|
-
</div>
|
|
583
|
-
|
|
584
|
-
{updateInfo.updateCommand && (
|
|
585
|
-
<div className="mt-3 rounded border border-gray-200 bg-white p-3">
|
|
586
|
-
<p className="mb-1 text-xs text-gray-500">Or update manually:</p>
|
|
587
|
-
<code className="block rounded bg-gray-50 px-2 py-1.5 font-mono text-xs text-gray-800 select-all">
|
|
588
|
-
{updateInfo.updateCommand}
|
|
589
|
-
</code>
|
|
590
|
-
</div>
|
|
591
|
-
)}
|
|
592
|
-
</div>
|
|
593
|
-
|
|
594
|
-
{/* Changelog */}
|
|
595
|
-
{updateInfo.changelog && updateInfo.changelog.length > 0 && (
|
|
596
|
-
<div className="rounded-lg border border-gray-200 bg-white p-4">
|
|
597
|
-
<h3 className="mb-3 text-sm font-semibold text-gray-900">Changelog</h3>
|
|
598
|
-
<div className="max-h-64 space-y-2 overflow-y-auto">
|
|
599
|
-
{updateInfo.changelog.map((entry) => (
|
|
600
|
-
<div key={entry.version} className="flex items-baseline gap-3 text-sm">
|
|
601
|
-
<span className="w-14 shrink-0 font-mono text-xs text-gray-500">
|
|
602
|
-
{entry.version}
|
|
603
|
-
</span>
|
|
604
|
-
<span className="w-20 shrink-0 text-xs text-gray-400">{entry.date}</span>
|
|
605
|
-
<span className="text-gray-700">{entry.summary}</span>
|
|
606
|
-
</div>
|
|
607
|
-
))}
|
|
608
|
-
</div>
|
|
609
|
-
</div>
|
|
610
|
-
)}
|
|
611
|
-
</>
|
|
612
|
-
)}
|
|
613
|
-
|
|
614
|
-
{/* PR Created */}
|
|
615
|
-
{prResult && (
|
|
616
|
-
<div className="rounded-lg border border-green-200 bg-green-50 p-4">
|
|
617
|
-
<div className="flex items-start gap-3">
|
|
618
|
-
<GitPullRequest className="mt-0.5 h-5 w-5 shrink-0 text-green-600" />
|
|
619
|
-
<div>
|
|
620
|
-
<h3 className="text-sm font-semibold text-green-900">Pull Request Created</h3>
|
|
621
|
-
<p className="mt-1 text-sm text-green-700">
|
|
622
|
-
PR #{prResult.prNumber} has been created on your repository. Review and merge it to
|
|
623
|
-
apply the update, then run{' '}
|
|
624
|
-
<code className="rounded bg-green-100 px-1 font-mono text-xs">
|
|
625
|
-
npx prisma migrate deploy
|
|
626
|
-
</code>
|
|
627
|
-
.
|
|
628
|
-
</p>
|
|
629
|
-
<a
|
|
630
|
-
href={prResult.prUrl}
|
|
631
|
-
target="_blank"
|
|
632
|
-
rel="noopener noreferrer"
|
|
633
|
-
className="mt-2 inline-flex items-center gap-1.5 text-sm font-medium text-green-700 hover:text-green-800"
|
|
634
|
-
>
|
|
635
|
-
<ExternalLink className="h-4 w-4" />
|
|
636
|
-
View Pull Request
|
|
637
|
-
</a>
|
|
638
|
-
</div>
|
|
639
|
-
</div>
|
|
640
|
-
</div>
|
|
641
|
-
)}
|
|
642
|
-
|
|
643
|
-
{/* GitHub Configuration */}
|
|
644
|
-
<div className="rounded-lg border border-gray-200 bg-white p-4">
|
|
645
|
-
<h3 className="mb-1 text-sm font-semibold text-gray-900">GitHub Integration</h3>
|
|
646
|
-
<p className="mb-4 text-xs text-gray-500">
|
|
647
|
-
Connect your repository to enable one-click update PRs. Credentials are encrypted at rest
|
|
648
|
-
(AES-256-GCM).
|
|
649
|
-
</p>
|
|
650
|
-
|
|
651
|
-
<div className="space-y-4">
|
|
652
|
-
<div>
|
|
653
|
-
<label className="mb-1 block text-sm font-medium text-gray-700">Repository</label>
|
|
654
|
-
<input
|
|
655
|
-
type="text"
|
|
656
|
-
value={ghRepo}
|
|
657
|
-
onChange={(e) => setGhRepo(e.target.value)}
|
|
658
|
-
placeholder="owner/repo"
|
|
659
|
-
className="w-full rounded-lg border border-gray-300 px-3 py-2 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
660
|
-
/>
|
|
661
|
-
<p className="mt-1 text-xs text-gray-500">
|
|
662
|
-
e.g.{' '}
|
|
663
|
-
<code className="rounded bg-gray-100 px-1 font-mono">
|
|
664
|
-
actuate-media/my-client-site
|
|
665
|
-
</code>
|
|
666
|
-
</p>
|
|
667
|
-
</div>
|
|
668
|
-
<div>
|
|
669
|
-
<label className="mb-1 block text-sm font-medium text-gray-700">
|
|
670
|
-
GitHub Token
|
|
671
|
-
{updateInfo?.hasGithubToken && !ghToken && (
|
|
672
|
-
<span className="ml-2 text-xs font-normal text-green-600">Saved</span>
|
|
673
|
-
)}
|
|
674
|
-
</label>
|
|
675
|
-
<div className="flex gap-2">
|
|
676
|
-
<div className="relative flex-1">
|
|
677
|
-
<input
|
|
678
|
-
type={showGhToken ? 'text' : 'password'}
|
|
679
|
-
value={ghToken}
|
|
680
|
-
onChange={(e) => setGhToken(e.target.value)}
|
|
681
|
-
placeholder={
|
|
682
|
-
updateInfo?.hasGithubToken ? '••••••••••••••••' : 'ghp_... or github_pat_...'
|
|
683
|
-
}
|
|
684
|
-
className="w-full rounded-lg border border-gray-300 px-3 py-2 pr-10 text-sm focus:ring-2 focus:ring-blue-500 focus:outline-none"
|
|
685
|
-
/>
|
|
686
|
-
<button
|
|
687
|
-
type="button"
|
|
688
|
-
onClick={() => setShowGhToken(!showGhToken)}
|
|
689
|
-
className="absolute top-1/2 right-2 -translate-y-1/2 p-1 text-gray-400 hover:text-gray-600"
|
|
690
|
-
>
|
|
691
|
-
{showGhToken ? <EyeOff className="h-4 w-4" /> : <Eye className="h-4 w-4" />}
|
|
692
|
-
</button>
|
|
693
|
-
</div>
|
|
694
|
-
</div>
|
|
695
|
-
<p className="mt-1 text-xs text-gray-500">
|
|
696
|
-
Needs <code className="rounded bg-gray-100 px-1 font-mono">repo</code> scope. Create
|
|
697
|
-
at{' '}
|
|
698
|
-
<a
|
|
699
|
-
href="https://github.com/settings/tokens"
|
|
700
|
-
target="_blank"
|
|
701
|
-
rel="noopener noreferrer"
|
|
702
|
-
className="text-blue-600 hover:underline"
|
|
703
|
-
>
|
|
704
|
-
github.com/settings/tokens
|
|
705
|
-
</a>
|
|
706
|
-
</p>
|
|
707
|
-
</div>
|
|
708
|
-
|
|
709
|
-
<button
|
|
710
|
-
type="button"
|
|
711
|
-
onClick={saveGitHubConfig}
|
|
712
|
-
disabled={savingConfig || (!ghToken && !ghRepo)}
|
|
713
|
-
className="flex items-center gap-2 rounded-lg bg-gray-900 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-gray-800 disabled:opacity-50"
|
|
714
|
-
>
|
|
715
|
-
{savingConfig ? (
|
|
716
|
-
<>
|
|
717
|
-
<Loader2 className="h-4 w-4 animate-spin" />
|
|
718
|
-
Encrypting & Saving...
|
|
719
|
-
</>
|
|
720
|
-
) : (
|
|
721
|
-
'Save Configuration'
|
|
722
|
-
)}
|
|
723
|
-
</button>
|
|
724
|
-
</div>
|
|
725
|
-
</div>
|
|
726
|
-
|
|
727
|
-
{/* Help Text */}
|
|
728
|
-
<div className="rounded-lg border border-gray-200 bg-gray-50 p-4">
|
|
729
|
-
<h3 className="mb-2 text-sm font-semibold text-gray-700">How Updates Work</h3>
|
|
730
|
-
<ul className="space-y-1.5 text-xs text-gray-600">
|
|
731
|
-
<li className="flex items-start gap-2">
|
|
732
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-blue-100 text-[10px] font-bold text-blue-600">
|
|
733
|
-
1
|
|
734
|
-
</span>
|
|
735
|
-
<span>
|
|
736
|
-
Click "Check for Updates" to see if a new version is available on npm.
|
|
737
|
-
</span>
|
|
738
|
-
</li>
|
|
739
|
-
<li className="flex items-start gap-2">
|
|
740
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-blue-100 text-[10px] font-bold text-blue-600">
|
|
741
|
-
2
|
|
742
|
-
</span>
|
|
743
|
-
<span>
|
|
744
|
-
Add your GitHub token and repository above. They're encrypted at rest — never
|
|
745
|
-
stored in plaintext.
|
|
746
|
-
</span>
|
|
747
|
-
</li>
|
|
748
|
-
<li className="flex items-start gap-2">
|
|
749
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-blue-100 text-[10px] font-bold text-blue-600">
|
|
750
|
-
3
|
|
751
|
-
</span>
|
|
752
|
-
<span>
|
|
753
|
-
Click "Create Update PR" to open a pull request that bumps your CMS packages
|
|
754
|
-
automatically.
|
|
755
|
-
</span>
|
|
756
|
-
</li>
|
|
757
|
-
<li className="flex items-start gap-2">
|
|
758
|
-
<span className="mt-0.5 flex h-4 w-4 shrink-0 items-center justify-center rounded-full bg-blue-100 text-[10px] font-bold text-blue-600">
|
|
759
|
-
4
|
|
760
|
-
</span>
|
|
761
|
-
<span>
|
|
762
|
-
Review and merge the PR, then deploy. Database migrations run automatically via{' '}
|
|
763
|
-
<code className="rounded bg-gray-200 px-1 font-mono">prisma migrate deploy</code>.
|
|
764
|
-
</span>
|
|
765
|
-
</li>
|
|
766
|
-
</ul>
|
|
767
|
-
</div>
|
|
768
|
-
</>
|
|
769
|
-
)
|
|
770
|
-
}
|
package/src/views/Users.tsx
CHANGED
|
@@ -923,7 +923,7 @@ export function Users({ embedded = false }: UsersProps = {}) {
|
|
|
923
923
|
{/* Header */}
|
|
924
924
|
<div className="border-border flex flex-col gap-3 border-b p-4 lg:flex-row lg:items-center lg:justify-between">
|
|
925
925
|
<div>
|
|
926
|
-
<h2 className="text-card-foreground text-
|
|
926
|
+
<h2 className="text-card-foreground text-lg font-medium">Team members</h2>
|
|
927
927
|
<p className="text-muted-foreground text-sm">
|
|
928
928
|
{peopleCount} {peopleCount === 1 ? 'person has' : 'people have'} access to this
|
|
929
929
|
workspace
|