Files
Gnuboard7/templates/_bundled/sirsoft-admin_basic/layouts/admin_dashboard.json
T
HeuJung b6c5e1f323 feat(core): 리버스 프록시 신뢰 설정 지원 및 미설정 진단
TLS 가 앞단에서 종단되고 앱에는 HTTP 로 전달되는 구성에서 X-Forwarded-* 가 전부
무시되어 화면 백지·IP 왜곡·webhook 403 이 함께 발생했다. 코어에 신뢰 프록시 설정
지점이 아예 없던 것이 원인이다.

- config/trustedproxy.php 로 내장 TrustProxies 미들웨어에 값을 공급한다.
 bootstrap/app.php 는 건드리지 않는다 — withMiddleware 클로저는 .env 로드 전에
 평가되어 env 가 항상 null 이 되는 조용한 no-op 이다.
- 판정은 App\Support\TrustedProxyDiagnostic 단일 SSoT 에서 계산하고 대시보드
 알림·환경설정 고급 탭·설치 마법사·trusted-proxy:status 네 면이 소비한다.
 판정식은 "HTTPS 인식 실패" 가 아니라 "X-Forwarded-* 수신 중 AND 신뢰 프록시
 미설정" 이다 — HTTP 전용 사이트가 프록시 뒤에 있으면 화면은 정상인 채로
 나머지만 조용히 어긋나기 때문이다.
- 값 편집 UI 와 쓰기 엔드포인트는 두지 않는다(잠금 역설 + XFF 위조 경로).
- 혼합 콘텐츠 차단을 부트스트랩 폴백의 별도 사유로 가른다. 새로고침으로 낫지
 않으므로 버튼을 렌더하지 않고, 원인·조치는 콘솔로 운영자에게 보낸다.
- 대시보드 알림을 심각도로 배치한다 — warning 은 상단 배너, 그 외는 하단 카드.
 같은 알림이 두 곳에 뜨지 않으며, 여러 건은 간격을 두고 쌓인다.

공개 이슈: (@lyg-kaban 제보)
2026-08-28 18:09:27 +09:00

1848 lines
114 KiB
JSON

{
"version": "1.0.0",
"layout_name": "admin_dashboard",
"permissions": [
"core.dashboard.read"
],
"extends": "_admin_base",
"meta": {
"title": "$t:admin.dashboard.title",
"description": "$t:admin.dashboard.description",
"auth_required": true
},
"init_actions": [
{
"handler": "checkAssetUrlModeDrift"
}
],
"data_sources": [
{
"id": "dashboard_stats",
"label_key": "$t:editor.data_source.dashboard_stats",
"type": "api",
"endpoint": "/api/admin/dashboard/stats",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "progressive",
"fallback": {
"data": {
"total_users": {
"count": 0,
"change_display": "-"
},
"installed_modules": {
"total": 0,
"active": 0
},
"active_plugins": {
"total": 0,
"active": 0
},
"installed_templates": {
"total": 0,
"active": 0
},
"language_packs": {
"total": 0,
"active": 0
},
"system_status": {
"label": "-"
}
}
}
},
{
"id": "dashboard_activities",
"label_key": "$t:editor.data_source.dashboard_activities",
"type": "api",
"endpoint": "/api/admin/dashboard/activities",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "progressive",
"fallback": {
"data": []
}
},
{
"id": "dashboard_modules",
"label_key": "$t:editor.data_source.dashboard_modules",
"type": "api",
"endpoint": "/api/admin/modules/installed",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "progressive",
"params": {
"per_page": "5"
},
"fallback": {
"data": {
"data": [],
"current_page": 1,
"last_page": 1,
"per_page": 5,
"total": 0
}
}
},
{
"id": "dashboard_plugins",
"label_key": "$t:editor.data_source.dashboard_plugins",
"type": "api",
"endpoint": "/api/admin/plugins/installed",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "progressive",
"params": {
"per_page": "5"
},
"fallback": {
"data": {
"data": [],
"current_page": 1,
"last_page": 1,
"per_page": 5,
"total": 0
}
}
},
{
"id": "dashboard_templates",
"label_key": "$t:editor.data_source.dashboard_templates",
"type": "api",
"endpoint": "/api/admin/templates",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "progressive",
"params": {
"per_page": "5"
},
"fallback": {
"data": {
"data": [],
"current_page": 1,
"last_page": 1,
"per_page": 5,
"total": 0
}
}
},
{
"id": "dashboard_alerts",
"label_key": "$t:editor.data_source.dashboard_alerts",
"type": "api",
"endpoint": "/api/admin/dashboard/alerts",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "background",
"fallback": {
"data": []
}
},
{
"id": "dashboard_recent_notifications",
"label_key": "$t:editor.data_source.dashboard_recent_notifications",
"type": "api",
"endpoint": "/api/admin/dashboard/recent-notifications",
"method": "GET",
"auto_fetch": true,
"auth_required": true,
"loading_strategy": "progressive",
"fallback": {
"data": []
}
},
{
"id": "dashboard_stats_ws",
"label_key": "$t:editor.data_source.dashboard_stats_ws",
"type": "websocket",
"channel": "core.admin.dashboard",
"event": "dashboard.stats.updated",
"channel_type": "private",
"target_source": "dashboard_stats"
}
],
"slots": {
"content": [
{
"id": "dashboard_content",
"type": "basic",
"name": "Div",
"props": {
"className": "admin-page-content-responsive-fluid"
},
"children": [
{
"id": "page_header",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between mb-6"
},
"children": [
{
"id": "page_title",
"type": "basic",
"name": "H1",
"props": {
"className": "text-primary text-xl sm:text-2xl font-semibold"
},
"text": "$t:admin.dashboard.title"
},
{
"id": "refresh_button",
"type": "basic",
"name": "Button",
"props": {
"className": "btn-icon",
"aria-label": "$t:admin.dashboard.refresh"
},
"actions": [
{
"type": "click",
"handler": "sequence",
"params": {
"actions": [
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_stats"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_activities"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_modules"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_plugins"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_templates"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_alerts"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_recent_notifications"
}
},
{
"handler": "toast",
"params": {
"type": "success",
"message": "$t:admin.dashboard.refreshed"
}
}
]
}
}
],
"children": [
{
"id": "refresh_icon",
"type": "basic",
"name": "Icon",
"props": {
"name": "refresh",
"size": "md"
}
}
]
}
]
},
{
"id": "asset_url_mode_drift_alert",
"type": "basic",
"name": "Div",
"if": "{{_global.assetUrlModeDrift}}",
"props": {
"className": "flex items-start gap-3 p-4 mb-6 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800"
},
"children": [
{
"id": "asset_url_mode_drift_icon",
"type": "basic",
"name": "Icon",
"props": {
"name": "triangle-exclamation",
"className": "text-base text-amber-600 dark:text-amber-400 mt-0.5"
}
},
{
"id": "asset_url_mode_drift_body",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-1 min-w-0"
},
"children": [
{
"id": "asset_url_mode_drift_title",
"type": "basic",
"name": "Div",
"props": {
"className": "text-sm font-semibold text-amber-900 dark:text-amber-200"
},
"text": "$t:admin.dashboard.asset_url_mode_drift_title"
},
{
"id": "asset_url_mode_drift_desc",
"type": "basic",
"name": "P",
"props": {
"className": "mt-1 text-sm text-amber-800 dark:text-amber-300"
},
"text": "$t:admin.dashboard.asset_url_mode_drift_description"
},
{
"id": "asset_url_mode_drift_link",
"type": "basic",
"name": "Button",
"props": {
"type": "button",
"className": "mt-2 inline-flex items-center gap-1.5 text-sm font-medium text-amber-900 dark:text-amber-200 underline hover:no-underline cursor-pointer"
},
"text": "$t:admin.dashboard.asset_url_mode_drift_action",
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/settings",
"query": {
"tab": "general"
}
}
}
]
}
]
}
]
},
{
"id": "dashboard_alert_banners",
"if": "{{((dashboard_alerts?.data?.data ? dashboard_alerts.data.data : (dashboard_alerts?.data ?? [])).filter(a => a.type === 'warning').length) > 0}}",
"permissions": [
"core.dashboard.alerts"
],
"type": "basic",
"name": "Div",
"props": {
"className": "space-y-3 mb-6"
},
"children": [
{
"id": "top_alert_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "{{alert.type === 'warning' ? 'flex items-start gap-3 p-4 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800' : (alert.type === 'info' ? 'flex items-start gap-3 p-4 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800' : 'flex items-start gap-3 p-4 rounded-lg bg-gray-50 dark:bg-gray-700')}}"
},
"iteration": {
"source": "{{(dashboard_alerts?.data?.data ? dashboard_alerts.data.data : (dashboard_alerts?.data ?? [])).filter(a => a.type === 'warning')}}",
"item_var": "alert",
"index_var": "$idx"
},
"children": [
{
"id": "top_alert_icon_{{$idx}}",
"type": "basic",
"name": "Icon",
"props": {
"name": "{{alert.icon ?? 'info-circle'}}",
"className": "{{alert.type === 'warning' ? 'text-amber-600 dark:text-amber-400 mt-0.5 shrink-0' : (alert.type === 'info' ? 'text-blue-600 dark:text-blue-400 mt-0.5 shrink-0' : 'text-gray-500 dark:text-gray-400 mt-0.5 shrink-0')}}"
}
},
{
"id": "top_alert_content_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-1 min-w-0"
},
"children": [
{
"id": "top_alert_title_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading"
},
"text": "{{alert.title ?? ''}}"
},
{
"id": "top_alert_message_{{$idx}}",
"type": "basic",
"name": "P",
"if": "{{alert.message}}",
"props": {
"className": "text-secondary text-xs mt-0.5"
},
"text": "{{alert.message ?? ''}}"
},
{
"id": "top_alert_time_{{$idx}}",
"type": "basic",
"name": "P",
"if": "{{alert.time}}",
"props": {
"className": "form-hint"
},
"text": "{{alert.time ?? ''}}"
},
{
"id": "top_alert_actions_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-center gap-2 mt-2"
},
"children": [
{
"id": "top_alert_recover_button_{{$idx}}",
"type": "basic",
"name": "Button",
"if": "{{alert.subtype === 'recovery_available'}}",
"props": {
"type": "button",
"className": "inline-flex items-center gap-1 px-3 py-1 text-xs bg-blue-600 dark:bg-blue-500 hover:bg-blue-700 dark:hover:bg-blue-600 text-white rounded"
},
"actions": [
{
"type": "click",
"handler": "apiCall",
"auth_required": true,
"target": "{{alert.recover_endpoint}}",
"params": {
"method": "POST"
},
"onSuccess": [
{
"handler": "toast",
"params": {
"type": "success",
"message": "$t:extensions.alerts.recovered_success"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_alerts"
}
}
],
"onError": [
{
"handler": "toast",
"params": {
"type": "error",
"message": "{{error.message}}"
}
}
]
}
],
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "check-circle",
"size": "xs"
}
},
{
"type": "basic",
"name": "Span",
"text": "$t:extensions.alerts.recover_action"
}
]
},
{
"id": "top_alert_dismiss_button_{{$idx}}",
"type": "basic",
"name": "Button",
"if": "{{alert.extension_type && alert.identifier}}",
"props": {
"type": "button",
"className": "inline-flex items-center gap-1 px-3 py-1 text-xs text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600 rounded",
"aria-label": "$t:extensions.alerts.dismiss_action"
},
"actions": [
{
"type": "click",
"handler": "apiCall",
"auth_required": true,
"target": "/api/admin/extensions/{{alert.extension_type}}/{{alert.identifier}}/dismiss",
"params": {
"method": "POST"
},
"onSuccess": [
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_alerts"
}
}
],
"onError": [
{
"handler": "toast",
"params": {
"type": "error",
"message": "{{error.message}}"
}
}
]
}
],
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "times",
"size": "xs"
}
},
{
"type": "basic",
"name": "Span",
"text": "$t:extensions.alerts.dismiss_action"
}
]
}
]
}
]
}
]
}
]
},
{
"id": "quick_menu",
"type": "basic",
"name": "Div",
"props": {
"className": "flex flex-wrap gap-2 md:gap-3 mb-4 md:mb-6 lg:mb-8"
},
"children": [
{
"id": "qm_users",
"type": "basic",
"name": "A",
"props": {
"href": "/admin/users",
"className": "flex-center flex-col justify-center gap-1 w-16 h-16 md:w-20 md:h-20 text-[10px] md:text-xs font-medium rounded-xl bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 hover:bg-slate-700 hover:text-white dark:hover:bg-slate-200 dark:hover:text-slate-800 hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-slate-400 dark:focus:ring-slate-500 transition-all duration-200"
},
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "users",
"className": "text-lg md:text-xl"
}
},
{
"type": "basic",
"name": "Span",
"props": {
"className": "text-center leading-tight"
},
"text": "$t:admin.dashboard.quick_menu.users"
}
]
},
{
"id": "qm_settings",
"type": "basic",
"name": "A",
"props": {
"href": "/admin/settings",
"className": "flex-center flex-col justify-center gap-1 w-16 h-16 md:w-20 md:h-20 text-[10px] md:text-xs font-medium rounded-xl bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 hover:bg-slate-700 hover:text-white dark:hover:bg-slate-200 dark:hover:text-slate-800 hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-slate-400 dark:focus:ring-slate-500 transition-all duration-200"
},
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "cog",
"className": "text-lg md:text-xl"
}
},
{
"type": "basic",
"name": "Span",
"props": {
"className": "text-center leading-tight"
},
"text": "$t:admin.dashboard.quick_menu.settings"
}
]
},
{
"id": "qm_modules",
"type": "basic",
"name": "A",
"props": {
"href": "/admin/modules",
"className": "flex-center flex-col justify-center gap-1 w-16 h-16 md:w-20 md:h-20 text-[10px] md:text-xs font-medium rounded-xl bg-slate-100 dark:bg-slate-700 text-slate-600 dark:text-slate-300 hover:bg-slate-700 hover:text-white dark:hover:bg-slate-200 dark:hover:text-slate-800 hover:-translate-y-0.5 focus:outline-none focus:ring-2 focus:ring-slate-400 dark:focus:ring-slate-500 transition-all duration-200"
},
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "puzzle-piece",
"className": "text-lg md:text-xl"
}
},
{
"type": "basic",
"name": "Span",
"props": {
"className": "text-center leading-tight"
},
"text": "$t:admin.dashboard.quick_menu.modules"
}
]
},
{
"type": "extension_point",
"name": "admin_dashboard_quick_menu",
"default": [],
"props": {
"className": "contents"
}
}
]
},
{
"type": "extension_point",
"name": "admin_dashboard_commerce",
"default": []
},
{
"type": "extension_point",
"name": "admin_dashboard_community",
"default": []
},
{
"id": "secondary_stats_badges",
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_stats"
},
"props": {
"className": "flex-center flex-wrap gap-2 md:gap-3 mb-2"
},
"children": [
{
"id": "modules_badge",
"permissions": [
"core.modules.read"
],
"type": "basic",
"name": "Div",
"props": {
"className": "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-white dark:bg-slate-700 text-sm font-medium text-slate-700 dark:text-slate-300 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-600 transition-colors"
},
"children": [
{
"id": "modules_badge_icon",
"type": "basic",
"name": "Icon",
"props": {
"name": "cube",
"size": "sm"
}
},
{
"id": "modules_badge_label",
"type": "basic",
"name": "Span",
"text": "$t:admin.dashboard.stats.installed_modules"
},
{
"id": "modules_badge_value",
"type": "basic",
"name": "Span",
"props": {
"className": "font-bold"
},
"text": "{{dashboard_stats?.data?.installed_modules?.active ?? 0}}/{{dashboard_stats?.data?.installed_modules?.total ?? 0}}"
}
],
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/modules"
}
}
]
},
{
"id": "plugins_badge",
"permissions": [
"core.plugins.read"
],
"type": "basic",
"name": "Div",
"props": {
"className": "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-white dark:bg-slate-700 text-sm font-medium text-slate-700 dark:text-slate-300 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-600 transition-colors"
},
"children": [
{
"id": "plugins_badge_icon",
"type": "basic",
"name": "Icon",
"props": {
"name": "puzzle-piece",
"size": "sm"
}
},
{
"id": "plugins_badge_label",
"type": "basic",
"name": "Span",
"text": "$t:admin.dashboard.stats.active_plugins"
},
{
"id": "plugins_badge_value",
"type": "basic",
"name": "Span",
"props": {
"className": "font-bold"
},
"text": "{{dashboard_stats?.data?.active_plugins?.active ?? 0}}/{{dashboard_stats?.data?.active_plugins?.total ?? 0}}"
}
],
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/plugins"
}
}
]
},
{
"id": "templates_badge",
"permissions": [
"core.templates.read"
],
"type": "basic",
"name": "Div",
"props": {
"className": "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-white dark:bg-slate-700 text-sm font-medium text-slate-700 dark:text-slate-300 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-600 transition-colors"
},
"children": [
{
"id": "templates_badge_icon",
"type": "basic",
"name": "Icon",
"props": {
"name": "palette",
"size": "sm"
}
},
{
"id": "templates_badge_label",
"type": "basic",
"name": "Span",
"text": "$t:admin.dashboard.stats.active_templates"
},
{
"id": "templates_badge_value",
"type": "basic",
"name": "Span",
"props": {
"className": "font-bold"
},
"text": "{{dashboard_stats?.data?.installed_templates?.active ?? 0}}/{{dashboard_stats?.data?.installed_templates?.total ?? 0}}"
}
],
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/templates/admin"
}
}
]
},
{
"id": "language_packs_badge",
"permissions": [
"core.language_packs.read"
],
"type": "basic",
"name": "Div",
"props": {
"className": "inline-flex items-center gap-1.5 px-3 py-1.5 rounded-full bg-white dark:bg-slate-700 text-sm font-medium text-slate-700 dark:text-slate-300 cursor-pointer hover:bg-slate-50 dark:hover:bg-slate-600 transition-colors"
},
"children": [
{
"id": "language_packs_badge_icon",
"type": "basic",
"name": "Icon",
"props": {
"name": "language",
"size": "sm"
}
},
{
"id": "language_packs_badge_label",
"type": "basic",
"name": "Span",
"text": "$t:admin.dashboard.stats.active_language_packs"
},
{
"id": "language_packs_badge_value",
"type": "basic",
"name": "Span",
"props": {
"className": "font-bold"
},
"text": "{{dashboard_stats?.data?.language_packs?.active ?? 0}}/{{dashboard_stats?.data?.language_packs?.total ?? 0}}"
}
],
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/settings?tab=language_packs"
}
}
]
}
]
},
{
"id": "middle_section_grid",
"type": "basic",
"name": "Div",
"props": {
"className": "grid grid-cols-1 lg:grid-cols-2 gap-4 sm:gap-6 mb-6"
},
"children": [
{
"id": "recent_notifications_card",
"permissions": [
"core.notification-logs.read"
],
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_recent_notifications"
},
"props": {
"className": "bg-slate-100 dark:bg-slate-800 rounded-xl md:rounded-2xl p-4 md:p-6"
},
"children": [
{
"id": "recent_notifications_header",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-start justify-between mb-4"
},
"children": [
{
"type": "basic",
"name": "Div",
"children": [
{
"id": "recent_notifications_title",
"type": "basic",
"name": "H2",
"props": {
"className": "section-heading"
},
"text": "$t:admin.dashboard.recent_notifications.title"
},
{
"id": "recent_notifications_subtitle",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "$t:admin.dashboard.recent_notifications.subtitle"
}
]
},
{
"id": "recent_notifications_more_btn",
"type": "basic",
"name": "Button",
"props": {
"type": "button",
"className": "text-tertiary hover:text-gray-700 dark:hover:text-gray-200 transition-colors cursor-pointer"
},
"text": "$t:admin.dashboard.extension_status.more",
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/notification-logs"
}
}
]
}
]
},
{
"id": "recent_notifications_empty",
"type": "basic",
"name": "P",
"if": "{{(dashboard_recent_notifications?.data ?? []).length === 0}}",
"props": {
"className": "text-sm text-slate-500 dark:text-slate-400 text-center py-6"
},
"text": "$t:admin.dashboard.recent_notifications.empty"
},
{
"id": "recent_notifications_list",
"type": "basic",
"name": "Div",
"if": "{{(dashboard_recent_notifications?.data ?? []).length > 0}}",
"props": {
"className": "mb-4"
},
"children": [
{
"id": "recent_notification_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-start gap-3"
},
"iteration": {
"source": "dashboard_recent_notifications?.data",
"item_var": "notification",
"index_var": "$idx"
},
"children": [
{
"id": "recent_notification_dot_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "{{notification?.status === 'failed' ? 'w-2 h-2 mt-2 rounded-full bg-rose-500 dark:bg-rose-400 flex-shrink-0' : (notification?.status === 'skipped' ? 'w-2 h-2 mt-2 rounded-full bg-slate-400 dark:bg-slate-300 flex-shrink-0' : 'w-2 h-2 mt-2 rounded-full bg-emerald-500 dark:bg-emerald-400 flex-shrink-0')}}"
}
},
{
"id": "recent_notification_content_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-1 min-w-0"
},
"children": [
{
"id": "recent_notification_subject_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading truncate"
},
"text": "{{notification?.subject ?? ''}}"
},
{
"id": "recent_notification_recipient_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle truncate"
},
"text": "{{notification?.recipient ?? ''}}"
}
]
},
{
"id": "recent_notification_time_{{$idx}}",
"type": "basic",
"name": "Span",
"props": {
"className": "text-hint whitespace-nowrap"
},
"text": "{{notification?.time ?? ''}}"
}
]
}
]
}
]
},
{
"id": "recent_activity_card",
"permissions": [
"core.dashboard.activities"
],
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_activities"
},
"props": {
"className": "bg-slate-100 dark:bg-slate-800 rounded-xl md:rounded-2xl p-4 md:p-6"
},
"children": [
{
"id": "recent_activity_header",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-start justify-between mb-4"
},
"children": [
{
"type": "basic",
"name": "Div",
"children": [
{
"id": "recent_activity_title",
"type": "basic",
"name": "H2",
"props": {
"className": "section-heading"
},
"text": "$t:admin.dashboard.recent_activity.title"
},
{
"id": "recent_activity_subtitle",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "$t:admin.dashboard.recent_activity.subtitle"
}
]
},
{
"id": "activity_more_btn",
"type": "basic",
"name": "Button",
"props": {
"type": "button",
"className": "text-tertiary hover:text-gray-700 dark:hover:text-gray-200 transition-colors cursor-pointer"
},
"text": "$t:admin.dashboard.extension_status.more",
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/activity-logs"
}
}
]
}
]
},
{
"id": "activity_list",
"type": "basic",
"name": "Div",
"props": {},
"children": [
{
"id": "activity_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-start gap-3"
},
"iteration": {
"source": "dashboard_activities?.data",
"item_var": "activity",
"index_var": "$idx"
},
"children": [
{
"id": "activity_dot_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "w-2 h-2 mt-2 rounded-full bg-blue-500 dark:bg-blue-400 flex-shrink-0"
}
},
{
"id": "activity_content_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-1 min-w-0"
},
"children": [
{
"id": "activity_title_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading"
},
"text": "{{activity.title}}"
},
{
"id": "activity_desc_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "{{activity.description}}"
}
]
},
{
"id": "activity_time_{{$idx}}",
"type": "basic",
"name": "Span",
"props": {
"className": "text-hint whitespace-nowrap"
},
"text": "{{activity.time}}"
}
]
}
]
}
]
}
]
},
{
"id": "extension_status_grid",
"type": "basic",
"name": "Div",
"props": {
"className": "grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4 sm:gap-6"
},
"children": [
{
"id": "module_status_card",
"permissions": [
"core.modules.read"
],
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_modules"
},
"props": {
"className": "bg-slate-100 dark:bg-slate-800 rounded-xl md:rounded-2xl p-4 md:p-6"
},
"children": [
{
"id": "module_status_header",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between mb-4"
},
"children": [
{
"id": "module_header_left",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-center gap-2"
},
"children": [
{
"id": "module_header_text",
"type": "basic",
"name": "Div",
"children": [
{
"id": "module_status_title",
"type": "basic",
"name": "H2",
"props": {
"className": "section-heading"
},
"text": "$t:admin.dashboard.module_status.title"
},
{
"id": "module_status_subtitle",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "$t:admin.dashboard.module_status.subtitle"
}
]
}
]
},
{
"id": "module_more_btn",
"type": "basic",
"name": "Button",
"props": {
"type": "button",
"className": "text-tertiary hover:text-gray-700 dark:hover:text-gray-200 transition-colors cursor-pointer"
},
"text": "$t:admin.dashboard.extension_status.more",
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/modules"
}
}
]
}
]
},
{
"id": "module_list",
"type": "basic",
"name": "Div",
"props": {},
"children": [
{
"id": "module_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between py-2"
},
"iteration": {
"source": "dashboard_modules?.data?.data",
"item_var": "module",
"index_var": "$idx"
},
"children": [
{
"id": "module_info_{{$idx}}",
"type": "basic",
"name": "Div",
"children": [
{
"id": "module_name_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading"
},
"text": "{{module.name}}"
},
{
"id": "module_version_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-tertiary"
},
"text": "v{{module.version}}"
}
]
},
{
"id": "module_badge_{{$idx}}",
"type": "basic",
"name": "Span",
"props": {
"className": "{{module.status === 'active' ? 'badge badge-green' : 'badge badge-gray'}}"
},
"text": "{{module.status === 'active' ? '$t:admin.dashboard.module_status.active' : '$t:admin.dashboard.module_status.inactive'}}"
}
]
}
]
}
]
},
{
"id": "plugin_status_card",
"permissions": [
"core.plugins.read"
],
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_plugins"
},
"props": {
"className": "bg-slate-100 dark:bg-slate-800 rounded-xl md:rounded-2xl p-4 md:p-6"
},
"children": [
{
"id": "plugin_status_header",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between mb-4"
},
"children": [
{
"id": "plugin_header_left",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-center gap-2"
},
"children": [
{
"id": "plugin_header_text",
"type": "basic",
"name": "Div",
"children": [
{
"id": "plugin_status_title",
"type": "basic",
"name": "H2",
"props": {
"className": "section-heading"
},
"text": "$t:admin.dashboard.plugin_status.title"
},
{
"id": "plugin_status_subtitle",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "$t:admin.dashboard.plugin_status.subtitle"
}
]
}
]
},
{
"id": "plugin_more_btn",
"type": "basic",
"name": "Button",
"props": {
"type": "button",
"className": "text-tertiary hover:text-gray-700 dark:hover:text-gray-200 transition-colors cursor-pointer"
},
"text": "$t:admin.dashboard.extension_status.more",
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/plugins"
}
}
]
}
]
},
{
"id": "plugin_list",
"type": "basic",
"name": "Div",
"props": {},
"children": [
{
"id": "plugin_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between py-2"
},
"iteration": {
"source": "dashboard_plugins?.data?.data",
"item_var": "plugin",
"index_var": "$idx"
},
"children": [
{
"id": "plugin_info_{{$idx}}",
"type": "basic",
"name": "Div",
"children": [
{
"id": "plugin_name_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading"
},
"text": "{{plugin.name}}"
},
{
"id": "plugin_version_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-tertiary"
},
"text": "v{{plugin.version}}"
}
]
},
{
"id": "plugin_badge_{{$idx}}",
"type": "basic",
"name": "Span",
"props": {
"className": "{{plugin.status === 'active' ? 'badge badge-green' : 'badge badge-gray'}}"
},
"text": "{{plugin.status === 'active' ? '$t:admin.dashboard.plugin_status.active' : '$t:admin.dashboard.plugin_status.inactive'}}"
}
]
}
]
}
]
},
{
"id": "template_status_card",
"permissions": [
"core.templates.read"
],
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_templates"
},
"props": {
"className": "bg-slate-100 dark:bg-slate-800 rounded-xl md:rounded-2xl p-4 md:p-6"
},
"children": [
{
"id": "template_status_header",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between mb-4"
},
"children": [
{
"id": "template_header_left",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-center gap-2"
},
"children": [
{
"id": "template_header_text",
"type": "basic",
"name": "Div",
"children": [
{
"id": "template_status_title",
"type": "basic",
"name": "H2",
"props": {
"className": "section-heading"
},
"text": "$t:admin.dashboard.template_status.title"
},
{
"id": "template_status_subtitle",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "$t:admin.dashboard.template_status.subtitle"
}
]
}
]
},
{
"id": "template_more_btn",
"type": "basic",
"name": "Button",
"props": {
"type": "button",
"className": "text-tertiary hover:text-gray-700 dark:hover:text-gray-200 transition-colors cursor-pointer"
},
"text": "$t:admin.dashboard.extension_status.more",
"actions": [
{
"type": "click",
"handler": "navigate",
"params": {
"path": "/admin/templates/admin"
}
}
]
}
]
},
{
"id": "template_list",
"type": "basic",
"name": "Div",
"props": {},
"children": [
{
"id": "template_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-between py-2"
},
"iteration": {
"source": "dashboard_templates?.data?.data",
"item_var": "template",
"index_var": "$idx"
},
"children": [
{
"id": "template_info_{{$idx}}",
"type": "basic",
"name": "Div",
"children": [
{
"id": "template_name_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading"
},
"text": "{{template.name}}"
},
{
"id": "template_version_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-tertiary"
},
"text": "v{{template.version}}"
}
]
},
{
"id": "template_badge_{{$idx}}",
"type": "basic",
"name": "Span",
"props": {
"className": "{{template.status === 'active' ? 'badge badge-green' : 'badge badge-gray'}}"
},
"text": "{{template.status === 'active' ? '$t:admin.dashboard.template_status.active' : '$t:admin.dashboard.template_status.inactive'}}"
}
]
}
]
}
]
}
]
},
{
"id": "bottom_section_grid",
"type": "basic",
"name": "Div",
"props": {
"className": "mt-4 sm:mt-6"
},
"children": [
{
"id": "system_alerts_card",
"if": "{{((dashboard_alerts?.data?.data ? dashboard_alerts.data.data : (dashboard_alerts?.data ?? [])).filter(a => a.type !== 'warning').length) > 0}}",
"permissions": [
"core.dashboard.alerts"
],
"type": "basic",
"name": "Div",
"blur_until_loaded": {
"enabled": true,
"data_sources": "dashboard_alerts"
},
"props": {
"className": "bg-slate-100 dark:bg-slate-800 rounded-xl md:rounded-2xl p-4 md:p-6"
},
"children": [
{
"id": "system_alerts_header",
"type": "basic",
"name": "Div",
"props": {
"className": "mb-4"
},
"children": [
{
"id": "system_alerts_title",
"type": "basic",
"name": "H2",
"props": {
"className": "section-heading"
},
"text": "$t:admin.dashboard.system_alerts.title"
},
{
"id": "system_alerts_subtitle",
"type": "basic",
"name": "P",
"props": {
"className": "text-label-subtle"
},
"text": "$t:admin.dashboard.system_alerts.subtitle"
}
]
},
{
"id": "alerts_list",
"type": "basic",
"name": "Div",
"props": {
"className": "space-y-3"
},
"children": [
{
"id": "alert_item_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "{{alert.type === 'warning' ? 'flex items-start gap-3 p-3 rounded-lg bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-800' : (alert.type === 'info' ? 'flex items-start gap-3 p-3 rounded-lg bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800' : 'flex items-start gap-3 p-3 rounded-lg bg-gray-50 dark:bg-gray-700')}}"
},
"iteration": {
"source": "{{(dashboard_alerts?.data?.data ? dashboard_alerts.data.data : (dashboard_alerts?.data ?? [])).filter(a => a.type !== 'warning')}}",
"item_var": "alert",
"index_var": "$idx"
},
"children": [
{
"id": "alert_icon_{{$idx}}",
"type": "basic",
"name": "Icon",
"props": {
"name": "{{alert.icon ?? 'info-circle'}}",
"className": "{{alert.type === 'warning' ? 'text-amber-600 dark:text-amber-400 mt-0.5 shrink-0' : (alert.type === 'info' ? 'text-blue-600 dark:text-blue-400 mt-0.5 shrink-0' : 'text-gray-500 dark:text-gray-400 mt-0.5 shrink-0')}}"
}
},
{
"id": "alert_content_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-1 min-w-0"
},
"children": [
{
"id": "alert_title_{{$idx}}",
"type": "basic",
"name": "P",
"props": {
"className": "text-heading"
},
"text": "{{alert.title ?? ''}}"
},
{
"id": "alert_message_{{$idx}}",
"type": "basic",
"name": "P",
"if": "{{alert.message}}",
"props": {
"className": "text-secondary text-xs mt-0.5"
},
"text": "{{alert.message ?? ''}}"
},
{
"id": "alert_time_{{$idx}}",
"type": "basic",
"name": "P",
"if": "{{alert.time}}",
"props": {
"className": "form-hint"
},
"text": "{{alert.time ?? ''}}"
},
{
"id": "alert_actions_{{$idx}}",
"type": "basic",
"name": "Div",
"props": {
"className": "flex-center gap-2 mt-2"
},
"children": [
{
"id": "alert_recover_button_{{$idx}}",
"type": "basic",
"name": "Button",
"if": "{{alert.subtype === 'recovery_available'}}",
"props": {
"type": "button",
"className": "inline-flex items-center gap-1 px-3 py-1 text-xs bg-blue-600 dark:bg-blue-500 hover:bg-blue-700 dark:hover:bg-blue-600 text-white rounded"
},
"actions": [
{
"type": "click",
"handler": "apiCall",
"auth_required": true,
"target": "{{alert.recover_endpoint}}",
"params": {
"method": "POST"
},
"onSuccess": [
{
"handler": "toast",
"params": {
"type": "success",
"message": "$t:extensions.alerts.recovered_success"
}
},
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_alerts"
}
}
],
"onError": [
{
"handler": "toast",
"params": {
"type": "error",
"message": "{{error.message}}"
}
}
]
}
],
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "check-circle",
"size": "xs"
}
},
{
"type": "basic",
"name": "Span",
"text": "$t:extensions.alerts.recover_action"
}
]
},
{
"id": "alert_dismiss_button_{{$idx}}",
"type": "basic",
"name": "Button",
"if": "{{alert.extension_type && alert.identifier}}",
"props": {
"type": "button",
"className": "inline-flex items-center gap-1 px-3 py-1 text-xs text-gray-600 dark:text-gray-300 hover:bg-gray-200 dark:hover:bg-gray-600 rounded",
"aria-label": "$t:extensions.alerts.dismiss_action"
},
"actions": [
{
"type": "click",
"handler": "apiCall",
"auth_required": true,
"target": "/api/admin/extensions/{{alert.extension_type}}/{{alert.identifier}}/dismiss",
"params": {
"method": "POST"
},
"onSuccess": [
{
"handler": "refetchDataSource",
"params": {
"dataSourceId": "dashboard_alerts"
}
}
],
"onError": [
{
"handler": "toast",
"params": {
"type": "error",
"message": "{{error.message}}"
}
}
]
}
],
"children": [
{
"type": "basic",
"name": "Icon",
"props": {
"name": "times",
"size": "xs"
}
},
{
"type": "basic",
"name": "Span",
"text": "$t:extensions.alerts.dismiss_action"
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
}
]
},
"transition_overlay": {
"wait_for": [
"dashboard_stats",
"dashboard_activities",
"dashboard_modules",
"dashboard_plugins",
"dashboard_templates",
"dashboard_recent_notifications"
]
}
}