adonisjs-server-stats 1.10.0 → 1.11.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/README.md +23 -14
- package/dist/core/config-utils.d.ts +8 -0
- package/dist/core/constants.d.ts +4 -0
- package/dist/core/dashboard-data-controller.d.ts +16 -0
- package/dist/core/dashboard-data-helpers.d.ts +12 -0
- package/dist/core/debug-data-controller.d.ts +4 -0
- package/dist/core/define-config-helpers.d.ts +25 -0
- package/dist/core/feature-detect-helpers.d.ts +36 -0
- package/dist/core/field-resolvers.d.ts +64 -0
- package/dist/core/formatters-helpers.d.ts +23 -0
- package/dist/core/formatters.d.ts +15 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.js +599 -509
- package/dist/core/log-utils-helpers.d.ts +13 -0
- package/dist/core/metrics.d.ts +3 -28
- package/dist/core/pagination.d.ts +0 -9
- package/dist/core/server-stats-controller.d.ts +6 -0
- package/dist/core/transmit-helpers.d.ts +7 -0
- package/dist/core/types-dashboard.d.ts +178 -0
- package/dist/core/types-diagnostics.d.ts +85 -0
- package/dist/core/types.d.ts +10 -442
- package/dist/react/CacheSection-BYN53kYO.js +135 -0
- package/dist/react/CacheStatsBar-CRodCOeP.js +27 -0
- package/dist/react/CacheTab-DOhuK05d.js +106 -0
- package/dist/react/{ConfigSection-DfFd-WRq.js → ConfigSection-B9EHh4Rp.js} +1 -1
- package/dist/react/{ConfigTab-Bdg8YMer.js → ConfigTab-C8kriE2b.js} +1 -1
- package/dist/react/CustomPaneTab-CvzQS_Wh.js +99 -0
- package/dist/react/EmailPreviewOverlay-BmXOAvqG.js +58 -0
- package/dist/react/EmailsSection-BJyFJf7A.js +226 -0
- package/dist/react/EmailsTab-Ch8jp10B.js +110 -0
- package/dist/react/{EventsSection-ByQ-9blq.js → EventsSection-DJPwHeT8.js} +28 -27
- package/dist/react/EventsTab-B-FoehXC.js +58 -0
- package/dist/react/{FilterBar-DQRXpWrb.js → FilterBar-CQ7bD669.js} +15 -15
- package/dist/react/{InternalsContent-DBzsI0CG.js → InternalsContent-O8ino9oM.js} +133 -109
- package/dist/react/InternalsSection-B6VlVx5f.js +22 -0
- package/dist/react/InternalsTab-CkEKpRMU.js +17 -0
- package/dist/react/JobStatsBar-C7RslAFE.js +30 -0
- package/dist/react/JobsSection-DWF4i1t_.js +167 -0
- package/dist/react/JobsTab-DqnifQXV.js +129 -0
- package/dist/react/LogEntryRow-CMMkqA9M.js +43 -0
- package/dist/react/LogsSection-C1xC5aP4.js +198 -0
- package/dist/react/LogsTab-CS4sLfLw.js +79 -0
- package/dist/react/{OverviewSection-C4T1ur51.js → OverviewSection-CxvfOR0v.js} +70 -80
- package/dist/react/QueriesSection-CrMdU5Ax.js +458 -0
- package/dist/react/{QueriesTab-osLUWd4L.js → QueriesTab-x85PjkyS.js} +38 -40
- package/dist/react/RequestsSection-DETN9oZb.js +321 -0
- package/dist/react/{RoutesSection-BUSkM6PY.js → RoutesSection-CmorkJeC.js} +2 -2
- package/dist/react/RoutesTab-CbzBOzpc.js +68 -0
- package/dist/react/SplitPaneWrapper-BiIgT4ND.js +49 -0
- package/dist/react/TimeAgoCell-o3KigGfM.js +8 -0
- package/dist/react/{TimelineTab-Covg5weo.js → TimelineTab-Ue9tUD_n.js} +76 -102
- package/dist/react/index-DwDK-4oX.js +1121 -0
- package/dist/react/index.js +6 -6
- package/dist/react/react/components/shared/CacheStatsBar.d.ts +13 -0
- package/dist/react/react/components/shared/EmailPreviewOverlay.d.ts +29 -0
- package/dist/react/react/components/{Dashboard/shared → shared}/FilterBar.d.ts +4 -3
- package/dist/react/react/components/shared/JobStatsBar.d.ts +12 -0
- package/dist/react/react/components/shared/LogEntryRow.d.ts +9 -0
- package/dist/react/react/components/shared/RelatedLogs.d.ts +2 -2
- package/dist/react/react/components/shared/SplitPaneWrapper.d.ts +7 -0
- package/dist/react/react/components/shared/TimeAgoCell.d.ts +17 -0
- package/dist/react/react/hooks/useDashboardData.d.ts +4 -8
- package/dist/react/react/hooks/useDiagnosticsData.d.ts +14 -0
- package/dist/react/style.css +1 -1
- package/dist/src/collectors/app_collector.d.ts +0 -8
- package/dist/src/collectors/app_collector.js +45 -52
- package/dist/src/collectors/auto_detect.d.ts +0 -23
- package/dist/src/collectors/auto_detect.js +33 -55
- package/dist/src/collectors/db_pool_collector.d.ts +14 -16
- package/dist/src/collectors/db_pool_collector.js +72 -57
- package/dist/src/collectors/log_collector.d.ts +0 -47
- package/dist/src/collectors/log_collector.js +36 -65
- package/dist/src/collectors/queue_collector.d.ts +0 -20
- package/dist/src/collectors/queue_collector.js +60 -76
- package/dist/src/collectors/redis_collector.d.ts +10 -10
- package/dist/src/collectors/redis_collector.js +69 -66
- package/dist/src/config/deprecation_migration.d.ts +7 -0
- package/dist/src/config/deprecation_migration.js +201 -0
- package/dist/src/controller/debug_controller.d.ts +1 -1
- package/dist/src/controller/debug_controller.js +87 -81
- package/dist/src/dashboard/cache_handlers.d.ts +14 -0
- package/dist/src/dashboard/cache_handlers.js +52 -0
- package/dist/src/dashboard/chart_aggregator.d.ts +0 -7
- package/dist/src/dashboard/chart_aggregator.js +68 -50
- package/dist/src/dashboard/coalesce_cache.d.ts +25 -0
- package/dist/src/dashboard/coalesce_cache.js +47 -0
- package/dist/src/dashboard/dashboard_controller.d.ts +11 -37
- package/dist/src/dashboard/dashboard_controller.js +51 -544
- package/dist/src/dashboard/dashboard_page_assets.d.ts +17 -0
- package/dist/src/dashboard/dashboard_page_assets.js +51 -0
- package/dist/src/dashboard/dashboard_store.d.ts +19 -218
- package/dist/src/dashboard/dashboard_store.js +115 -1116
- package/dist/src/dashboard/dashboard_types.d.ts +83 -0
- package/dist/src/dashboard/dashboard_types.js +4 -0
- package/dist/src/dashboard/detail_queries.d.ts +19 -0
- package/dist/src/dashboard/detail_queries.js +98 -0
- package/dist/src/dashboard/email_event_builder.d.ts +8 -0
- package/dist/src/dashboard/email_event_builder.js +65 -0
- package/dist/src/dashboard/explain_query.d.ts +8 -0
- package/dist/src/dashboard/explain_query.js +22 -0
- package/dist/src/dashboard/filter_handlers.d.ts +23 -0
- package/dist/src/dashboard/filter_handlers.js +56 -0
- package/dist/src/dashboard/filtered_queries.d.ts +15 -0
- package/dist/src/dashboard/filtered_queries.js +155 -0
- package/dist/src/dashboard/flush_manager.d.ts +25 -0
- package/dist/src/dashboard/flush_manager.js +107 -0
- package/dist/src/dashboard/format_helpers.d.ts +126 -0
- package/dist/src/dashboard/format_helpers.js +140 -0
- package/dist/src/dashboard/inspector_manager.d.ts +36 -0
- package/dist/src/dashboard/inspector_manager.js +102 -0
- package/dist/src/dashboard/integrations/config_inspector.js +11 -13
- package/dist/src/dashboard/integrations/queue_inspector.d.ts +3 -3
- package/dist/src/dashboard/integrations/queue_inspector.js +13 -10
- package/dist/src/dashboard/jobs_handlers.d.ts +14 -0
- package/dist/src/dashboard/jobs_handlers.js +61 -0
- package/dist/src/dashboard/knex_factory.d.ts +18 -0
- package/dist/src/dashboard/knex_factory.js +91 -0
- package/dist/src/dashboard/migrator.js +30 -159
- package/dist/src/dashboard/migrator_tables.d.ts +19 -0
- package/dist/src/dashboard/migrator_tables.js +153 -0
- package/dist/src/dashboard/overview_queries.d.ts +66 -0
- package/dist/src/dashboard/overview_queries.js +155 -0
- package/dist/src/dashboard/overview_query_runners.d.ts +25 -0
- package/dist/src/dashboard/overview_query_runners.js +84 -0
- package/dist/src/dashboard/overview_store_queries.d.ts +40 -0
- package/dist/src/dashboard/overview_store_queries.js +69 -0
- package/dist/src/dashboard/paginate_helper.d.ts +12 -0
- package/dist/src/dashboard/paginate_helper.js +33 -0
- package/dist/src/dashboard/query_explain_handler.d.ts +10 -0
- package/dist/src/dashboard/query_explain_handler.js +80 -0
- package/dist/src/dashboard/read_queries.d.ts +32 -0
- package/dist/src/dashboard/read_queries.js +107 -0
- package/dist/src/dashboard/saved_filter_queries.d.ts +10 -0
- package/dist/src/dashboard/saved_filter_queries.js +24 -0
- package/dist/src/dashboard/storage_stats.d.ts +41 -0
- package/dist/src/dashboard/storage_stats.js +81 -0
- package/dist/src/dashboard/write_queue.d.ts +106 -0
- package/dist/src/dashboard/write_queue.js +225 -0
- package/dist/src/data/data_access.d.ts +2 -39
- package/dist/src/data/data_access.js +17 -193
- package/dist/src/data/data_access_helpers.d.ts +130 -0
- package/dist/src/data/data_access_helpers.js +212 -0
- package/dist/src/debug/debug_store.js +37 -32
- package/dist/src/debug/email_collector.d.ts +1 -10
- package/dist/src/debug/email_collector.js +78 -81
- package/dist/src/debug/event_collector.d.ts +0 -9
- package/dist/src/debug/event_collector.js +79 -62
- package/dist/src/debug/query_collector.js +23 -19
- package/dist/src/debug/route_inspector.d.ts +1 -5
- package/dist/src/debug/route_inspector.js +50 -51
- package/dist/src/debug/trace_collector.d.ts +9 -1
- package/dist/src/debug/trace_collector.js +21 -15
- package/dist/src/debug/types.d.ts +1 -1
- package/dist/src/define_config.d.ts +0 -65
- package/dist/src/define_config.js +93 -333
- package/dist/src/edge/client/dashboard.js +2 -2
- package/dist/src/edge/client/debug-panel-deferred.js +1 -1
- package/dist/src/edge/client/stats-bar.js +1 -1
- package/dist/src/edge/client-vue/dashboard.js +5 -5
- package/dist/src/edge/client-vue/debug-panel-deferred.js +4 -4
- package/dist/src/edge/client-vue/stats-bar.js +3 -3
- package/dist/src/edge/plugin.d.ts +0 -16
- package/dist/src/edge/plugin.js +57 -64
- package/dist/src/engine/request_metrics.d.ts +1 -0
- package/dist/src/engine/request_metrics.js +32 -42
- package/dist/src/middleware/request_tracking_middleware.d.ts +2 -8
- package/dist/src/middleware/request_tracking_middleware.js +65 -93
- package/dist/src/provider/auth_middleware_detector.d.ts +16 -0
- package/dist/src/provider/auth_middleware_detector.js +97 -0
- package/dist/src/provider/boot_helpers.d.ts +20 -0
- package/dist/src/provider/boot_helpers.js +91 -0
- package/dist/src/provider/boot_initializer.d.ts +28 -0
- package/dist/src/provider/boot_initializer.js +35 -0
- package/dist/src/provider/dashboard_init.d.ts +30 -0
- package/dist/src/provider/dashboard_init.js +138 -0
- package/dist/src/provider/dashboard_setup.d.ts +25 -0
- package/dist/src/provider/dashboard_setup.js +78 -0
- package/dist/src/provider/diagnostics.d.ts +134 -0
- package/dist/src/provider/diagnostics.js +127 -0
- package/dist/src/provider/email_bridge.d.ts +43 -0
- package/dist/src/provider/email_bridge.js +80 -0
- package/dist/src/provider/email_helpers.d.ts +13 -0
- package/dist/src/provider/email_helpers.js +68 -0
- package/dist/src/provider/pino_hook.d.ts +17 -0
- package/dist/src/provider/pino_hook.js +35 -0
- package/dist/src/provider/provider_helpers_extra.d.ts +47 -0
- package/dist/src/provider/provider_helpers_extra.js +177 -0
- package/dist/src/provider/server_stats_provider.d.ts +39 -85
- package/dist/src/provider/server_stats_provider.js +132 -951
- package/dist/src/provider/shutdown_helpers.d.ts +43 -0
- package/dist/src/provider/shutdown_helpers.js +70 -0
- package/dist/src/provider/toolbar_setup.d.ts +57 -0
- package/dist/src/provider/toolbar_setup.js +141 -0
- package/dist/src/routes/dashboard_routes.d.ts +14 -0
- package/dist/src/routes/dashboard_routes.js +197 -0
- package/dist/src/routes/debug_routes.d.ts +14 -0
- package/dist/src/routes/debug_routes.js +101 -0
- package/dist/src/routes/register_routes.d.ts +0 -78
- package/dist/src/routes/register_routes.js +22 -352
- package/dist/src/routes/stats_routes.d.ts +5 -0
- package/dist/src/routes/stats_routes.js +14 -0
- package/dist/src/styles/components.css +163 -0
- package/dist/src/styles/dashboard.css +13 -105
- package/dist/src/styles/debug-panel.css +2 -53
- package/dist/src/styles/utilities.css +3 -1
- package/dist/src/types.d.ts +305 -14
- package/dist/vue/{CacheSection-oFAJL3mo.js → CacheSection-DT2Mwf_s.js} +1 -1
- package/dist/vue/{ConfigSection-BhfJ4KqL.js → ConfigSection-BwKwS9lh.js} +1 -1
- package/dist/vue/CustomPaneTab-Hr1IBHfz.js +172 -0
- package/dist/vue/{EmailsSection-BcNyhyHs.js → EmailsSection-B65g0FVS.js} +1 -1
- package/dist/vue/{EventsSection-r60Q5Lmu.js → EventsSection-CxqtVF-o.js} +1 -1
- package/dist/vue/{JobsSection-BHL-hkQw.js → JobsSection-rMIyMb-g.js} +1 -1
- package/dist/vue/{LogsSection-DRMGzJmg.js → LogsSection-DmmZVJ7D.js} +9 -3
- package/dist/vue/{LogsTab-Bg3o0Mm6.js → LogsTab-47zEK7jL.js} +4 -1
- package/dist/vue/{OverviewSection-CXh6Ja1B.js → OverviewSection-BMabyqw-.js} +49 -50
- package/dist/vue/{QueriesSection-IodIsCJ-.js → QueriesSection-BfDFwGqH.js} +44 -45
- package/dist/vue/{QueriesTab-C8_7oprC.js → QueriesTab-DuTG7cpC.js} +30 -31
- package/dist/vue/RelatedLogs.vue_vue_type_script_setup_true_lang-Py1iu9GU.js +77 -0
- package/dist/vue/{RequestsSection-BPuMdmMc.js → RequestsSection-CTu4jPZ_.js} +143 -147
- package/dist/vue/{RoutesSection-NKo3Rbq3.js → RoutesSection-zQZDedL7.js} +1 -1
- package/dist/vue/TimelineTab-DHfXsX7t.js +334 -0
- package/dist/vue/components/shared/RelatedLogs.vue.d.ts +1 -4
- package/dist/vue/composables/useDashboardData.d.ts +12 -23
- package/dist/vue/index-CM3yNVUR.js +1232 -0
- package/dist/vue/index.js +1 -1
- package/dist/vue/style.css +1 -1
- package/package.json +1 -1
- package/dist/react/CacheSection-UCMptWyn.js +0 -146
- package/dist/react/CacheTab-CA8LB1J5.js +0 -123
- package/dist/react/CustomPaneTab-Bxtv_8Rw.js +0 -104
- package/dist/react/EmailsSection-CM7stSyh.js +0 -262
- package/dist/react/EmailsTab-BDhEiomM.js +0 -153
- package/dist/react/EventsTab-CMfY98Rl.js +0 -63
- package/dist/react/InternalsSection-t7ihcWO-.js +0 -32
- package/dist/react/InternalsTab-Oij0A2fN.js +0 -30
- package/dist/react/JobsSection-DF3qEv9O.js +0 -187
- package/dist/react/JobsTab-BbrBWIOb.js +0 -141
- package/dist/react/LogsSection-DcFTZY7b.js +0 -227
- package/dist/react/LogsTab-CicucmVk.js +0 -103
- package/dist/react/QueriesSection-PswteoF9.js +0 -461
- package/dist/react/RelatedLogs-DFDOyUMr.js +0 -40
- package/dist/react/RequestsSection-Nag30rEA.js +0 -341
- package/dist/react/RoutesTab-DgVzd2PZ.js +0 -74
- package/dist/react/index-Cflz9Ebj.js +0 -1069
- package/dist/vue/CustomPaneTab-BJxT5Dp7.js +0 -172
- package/dist/vue/RelatedLogs.vue_vue_type_script_setup_true_lang-CB2_TzYW.js +0 -84
- package/dist/vue/TimelineTab-zj5Z5OdT.js +0 -338
- package/dist/vue/index-Dtgysd26.js +0 -1229
|
@@ -6,97 +6,19 @@ import type { AdonisRouter } from './router_types.js';
|
|
|
6
6
|
import type { HttpContext } from '@adonisjs/core/http';
|
|
7
7
|
/**
|
|
8
8
|
* Options for the unified route registration function.
|
|
9
|
-
*
|
|
10
|
-
* Brings together stats, debug, and dashboard route registration
|
|
11
|
-
* into a single call with all required dependencies declared upfront.
|
|
12
9
|
*/
|
|
13
10
|
export interface RegisterRoutesOptions {
|
|
14
|
-
/** The AdonisJS router instance. */
|
|
15
11
|
router: AdonisRouter;
|
|
16
|
-
/**
|
|
17
|
-
* The unified API controller that serves all data resource endpoints
|
|
18
|
-
* (queries, events, emails, traces, routes, logs).
|
|
19
|
-
*
|
|
20
|
-
* Pass `null` during early boot — routes will return 503 until the
|
|
21
|
-
* controller is wired up.
|
|
22
|
-
*/
|
|
23
12
|
getApiController: () => ApiController | null;
|
|
24
|
-
/**
|
|
25
|
-
* Lazy getter for the stats bar controller.
|
|
26
|
-
*
|
|
27
|
-
* The controller is created during `ready()`, but routes are
|
|
28
|
-
* registered during `boot()`, so a lazy getter is required.
|
|
29
|
-
*/
|
|
30
13
|
getStatsController: () => ServerStatsController | null;
|
|
31
|
-
/**
|
|
32
|
-
* Lazy getter for the debug controller.
|
|
33
|
-
*
|
|
34
|
-
* Handles non-data debug endpoints: `/config` and `/diagnostics`.
|
|
35
|
-
*/
|
|
36
14
|
getDebugController: () => DebugController | null;
|
|
37
|
-
/**
|
|
38
|
-
* Lazy getter for the dashboard controller.
|
|
39
|
-
*
|
|
40
|
-
* Handles dashboard-specific endpoints that are **not** data
|
|
41
|
-
* resources: page rendering, overview, requests, cache, jobs,
|
|
42
|
-
* config, saved filters, grouped queries, and query explain.
|
|
43
|
-
*/
|
|
44
15
|
getDashboardController: () => DashboardController | null;
|
|
45
|
-
/**
|
|
46
|
-
* Stats polling endpoint path (e.g. `'/admin/api/server-stats'`).
|
|
47
|
-
*
|
|
48
|
-
* Set to `false` to skip registering the stats endpoint entirely.
|
|
49
|
-
*/
|
|
50
16
|
statsEndpoint?: string | false;
|
|
51
|
-
/**
|
|
52
|
-
* Base path for debug panel API routes (e.g. `'/admin/api/debug'`).
|
|
53
|
-
*
|
|
54
|
-
* When omitted, debug routes are **not** registered.
|
|
55
|
-
*/
|
|
56
17
|
debugEndpoint?: string;
|
|
57
|
-
/**
|
|
58
|
-
* Base path for the full-page dashboard (e.g. `'/__stats'`).
|
|
59
|
-
*
|
|
60
|
-
* When omitted, dashboard routes are **not** registered.
|
|
61
|
-
*/
|
|
62
18
|
dashboardPath?: string;
|
|
63
|
-
/**
|
|
64
|
-
* Optional access-control callback applied to **all** registered
|
|
65
|
-
* routes as middleware. When it returns `false`, the request
|
|
66
|
-
* receives a 403 Forbidden response.
|
|
67
|
-
*/
|
|
68
19
|
shouldShow?: (ctx: HttpContext) => boolean;
|
|
69
20
|
}
|
|
70
21
|
/**
|
|
71
22
|
* Register all server-stats routes in a single call.
|
|
72
|
-
*
|
|
73
|
-
* This is the unified replacement for the three separate registrars:
|
|
74
|
-
*
|
|
75
|
-
* - `registerStatsRoutes` — stats bar polling endpoint
|
|
76
|
-
* - `registerDebugRoutes` — debug panel API endpoints
|
|
77
|
-
* - `registerDashboardRoutes` — full-page dashboard endpoints
|
|
78
|
-
*
|
|
79
|
-
* **Data resource** endpoints (queries, events, emails, traces, routes,
|
|
80
|
-
* logs) are routed through the unified {@link ApiController} so that
|
|
81
|
-
* both the debug panel and the dashboard read from the same handler.
|
|
82
|
-
*
|
|
83
|
-
* **Non-data** endpoints (stats polling, config, diagnostics, overview,
|
|
84
|
-
* requests, cache, jobs, saved filters, grouped queries, query explain,
|
|
85
|
-
* and the dashboard HTML page) continue to use their original controllers.
|
|
86
|
-
*
|
|
87
|
-
* @example
|
|
88
|
-
* ```ts
|
|
89
|
-
* registerAllRoutes({
|
|
90
|
-
* router,
|
|
91
|
-
* getApiController: () => apiController,
|
|
92
|
-
* getStatsController: () => statsController,
|
|
93
|
-
* getDebugController: () => debugController,
|
|
94
|
-
* getDashboardController: () => dashboardController,
|
|
95
|
-
* statsEndpoint: '/admin/api/server-stats',
|
|
96
|
-
* debugEndpoint: '/admin/api/debug',
|
|
97
|
-
* dashboardPath: '/__stats',
|
|
98
|
-
* shouldShow: (ctx) => ctx.auth?.user?.role === 'admin',
|
|
99
|
-
* })
|
|
100
|
-
* ```
|
|
101
23
|
*/
|
|
102
24
|
export declare function registerAllRoutes(options: RegisterRoutesOptions): void;
|
|
@@ -1,361 +1,31 @@
|
|
|
1
1
|
import { createAccessMiddleware } from './access_middleware.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
import { registerDashboardRoutes } from './dashboard_routes.js';
|
|
3
|
+
import { registerDebugRoutes } from './debug_routes.js';
|
|
4
|
+
import { registerStatsRoute } from './stats_routes.js';
|
|
5
5
|
/**
|
|
6
6
|
* Register all server-stats routes in a single call.
|
|
7
|
-
*
|
|
8
|
-
* This is the unified replacement for the three separate registrars:
|
|
9
|
-
*
|
|
10
|
-
* - `registerStatsRoutes` — stats bar polling endpoint
|
|
11
|
-
* - `registerDebugRoutes` — debug panel API endpoints
|
|
12
|
-
* - `registerDashboardRoutes` — full-page dashboard endpoints
|
|
13
|
-
*
|
|
14
|
-
* **Data resource** endpoints (queries, events, emails, traces, routes,
|
|
15
|
-
* logs) are routed through the unified {@link ApiController} so that
|
|
16
|
-
* both the debug panel and the dashboard read from the same handler.
|
|
17
|
-
*
|
|
18
|
-
* **Non-data** endpoints (stats polling, config, diagnostics, overview,
|
|
19
|
-
* requests, cache, jobs, saved filters, grouped queries, query explain,
|
|
20
|
-
* and the dashboard HTML page) continue to use their original controllers.
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* registerAllRoutes({
|
|
25
|
-
* router,
|
|
26
|
-
* getApiController: () => apiController,
|
|
27
|
-
* getStatsController: () => statsController,
|
|
28
|
-
* getDebugController: () => debugController,
|
|
29
|
-
* getDashboardController: () => dashboardController,
|
|
30
|
-
* statsEndpoint: '/admin/api/server-stats',
|
|
31
|
-
* debugEndpoint: '/admin/api/debug',
|
|
32
|
-
* dashboardPath: '/__stats',
|
|
33
|
-
* shouldShow: (ctx) => ctx.auth?.user?.role === 'admin',
|
|
34
|
-
* })
|
|
35
|
-
* ```
|
|
36
7
|
*/
|
|
37
8
|
export function registerAllRoutes(options) {
|
|
38
|
-
const
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// Stats polling endpoint
|
|
42
|
-
// =========================================================================
|
|
43
|
-
if (typeof statsEndpoint === 'string') {
|
|
44
|
-
router
|
|
45
|
-
.get(statsEndpoint, async (ctx) => {
|
|
46
|
-
const controller = getStatsController();
|
|
47
|
-
if (!controller) {
|
|
48
|
-
return ctx.response.serviceUnavailable({
|
|
49
|
-
error: 'Stats engine is starting up, please retry',
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return controller.index(ctx);
|
|
53
|
-
})
|
|
54
|
-
.as('server-stats.api')
|
|
55
|
-
.use(middleware);
|
|
9
|
+
const middleware = options.shouldShow ? [createAccessMiddleware(options.shouldShow)] : [];
|
|
10
|
+
if (typeof options.statsEndpoint === 'string') {
|
|
11
|
+
registerStatsRoute(options.router, options.statsEndpoint, options.getStatsController, middleware);
|
|
56
12
|
}
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
*/
|
|
66
|
-
const bindDebug = (method) => {
|
|
67
|
-
return async (ctx) => {
|
|
68
|
-
const controller = getDebugController();
|
|
69
|
-
if (!controller) {
|
|
70
|
-
return ctx.response.serviceUnavailable({
|
|
71
|
-
error: 'Debug toolbar is starting up, please retry',
|
|
72
|
-
});
|
|
73
|
-
}
|
|
74
|
-
return controller[method].call(controller, ctx);
|
|
75
|
-
};
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Wrap an ApiController method as an HTTP handler with lazy
|
|
79
|
-
* initialization and 503 fallback.
|
|
80
|
-
*/
|
|
81
|
-
const bindApi = (fn) => {
|
|
82
|
-
return async (ctx) => {
|
|
83
|
-
const api = getApiController();
|
|
84
|
-
if (!api) {
|
|
85
|
-
return ctx.response.serviceUnavailable({
|
|
86
|
-
error: 'Debug toolbar is starting up, please retry',
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
return fn(api, ctx);
|
|
90
|
-
};
|
|
91
|
-
};
|
|
92
|
-
router
|
|
93
|
-
.group(() => {
|
|
94
|
-
// Non-data endpoints — stay with DebugController
|
|
95
|
-
router.get('/config', bindDebug('config')).as('server-stats.debug.config');
|
|
96
|
-
router.get('/diagnostics', bindDebug('diagnostics')).as('server-stats.debug.diagnostics');
|
|
97
|
-
// Data endpoints — unified through ApiController
|
|
98
|
-
// Queries, events, and traces read from ring buffers (source: 'memory')
|
|
99
|
-
// because SQLite column names (snake_case) differ from the
|
|
100
|
-
// camelCase QueryRecord/EventRecord/etc. shapes the frontend expects.
|
|
101
|
-
// Logs and emails use 'auto' (SQLite when available) since the
|
|
102
|
-
// frontend resolvers handle both snake_case and camelCase fields.
|
|
103
|
-
router
|
|
104
|
-
.get('/queries', bindApi(async (api, ctx) => {
|
|
105
|
-
const queries = await api.getQueries({ source: 'memory' });
|
|
106
|
-
const summary = api.getQuerySummary();
|
|
107
|
-
return ctx.response.json({ queries: queries.data, summary });
|
|
108
|
-
}))
|
|
109
|
-
.as('server-stats.debug.queries');
|
|
110
|
-
router
|
|
111
|
-
.get('/events', bindApi(async (api, ctx) => {
|
|
112
|
-
const result = await api.getEvents({ source: 'memory' });
|
|
113
|
-
return ctx.response.json({ events: result.data, total: result.meta.total });
|
|
114
|
-
}))
|
|
115
|
-
.as('server-stats.debug.events');
|
|
116
|
-
router
|
|
117
|
-
.get('/routes', bindApi((api, ctx) => {
|
|
118
|
-
const result = api.getRoutes();
|
|
119
|
-
return ctx.response.json({ routes: result.data, total: result.meta.total });
|
|
120
|
-
}))
|
|
121
|
-
.as('server-stats.debug.routes');
|
|
122
|
-
router
|
|
123
|
-
.get('/logs', bindApi(async (api, ctx) => {
|
|
124
|
-
// Request up to 200 entries so the debug panel frontend
|
|
125
|
-
// (which caps at `.slice(0, 200)`) always has enough
|
|
126
|
-
// recent logs instead of the default 50-row page.
|
|
127
|
-
const result = await api.getLogs({ source: 'auto', perPage: 200 });
|
|
128
|
-
return ctx.response.json(result.data);
|
|
129
|
-
}))
|
|
130
|
-
.as('server-stats.debug.logs');
|
|
131
|
-
router
|
|
132
|
-
.get('/emails', bindApi(async (api, ctx) => {
|
|
133
|
-
const result = await api.getEmails({});
|
|
134
|
-
return ctx.response.json({ emails: result.data, total: result.meta.total });
|
|
135
|
-
}))
|
|
136
|
-
.as('server-stats.debug.emails');
|
|
137
|
-
router
|
|
138
|
-
.get('/emails/:id/preview', bindApi(async (api, ctx) => {
|
|
139
|
-
const id = Number(ctx.params.id);
|
|
140
|
-
const html = await api.getEmailPreview(id);
|
|
141
|
-
if (!html) {
|
|
142
|
-
return ctx.response.notFound({ error: 'Email not found' });
|
|
143
|
-
}
|
|
144
|
-
return ctx.response.header('Content-Type', 'text/html; charset=utf-8').send(html);
|
|
145
|
-
}))
|
|
146
|
-
.as('server-stats.debug.emailPreview');
|
|
147
|
-
router
|
|
148
|
-
.get('/traces', bindApi(async (api, ctx) => {
|
|
149
|
-
const result = await api.getTraces({ source: 'memory' });
|
|
150
|
-
return ctx.response.json({ traces: result.data, total: result.meta.total });
|
|
151
|
-
}))
|
|
152
|
-
.as('server-stats.debug.traces');
|
|
153
|
-
router
|
|
154
|
-
.get('/traces/:id', bindApi(async (api, ctx) => {
|
|
155
|
-
const id = Number(ctx.params.id);
|
|
156
|
-
const trace = await api.getTraceDetail(id, 'memory');
|
|
157
|
-
if (!trace) {
|
|
158
|
-
return ctx.response.notFound({ error: 'Trace not found' });
|
|
159
|
-
}
|
|
160
|
-
return ctx.response.json(trace);
|
|
161
|
-
}))
|
|
162
|
-
.as('server-stats.debug.traceDetail');
|
|
163
|
-
})
|
|
164
|
-
.prefix(base)
|
|
165
|
-
.use(middleware);
|
|
13
|
+
if (options.debugEndpoint) {
|
|
14
|
+
registerDebugRoutes({
|
|
15
|
+
router: options.router,
|
|
16
|
+
debugEndpoint: options.debugEndpoint,
|
|
17
|
+
getDebugController: options.getDebugController,
|
|
18
|
+
getApiController: options.getApiController,
|
|
19
|
+
middleware,
|
|
20
|
+
});
|
|
166
21
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
*/
|
|
176
|
-
const bindDash = (method) => {
|
|
177
|
-
return async (ctx) => {
|
|
178
|
-
const controller = getDashboardController();
|
|
179
|
-
if (!controller) {
|
|
180
|
-
return ctx.response.serviceUnavailable({
|
|
181
|
-
error: 'Dashboard is starting up, please retry',
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
return controller[method].call(controller, ctx);
|
|
185
|
-
};
|
|
186
|
-
};
|
|
187
|
-
/**
|
|
188
|
-
* Wrap an ApiController method as a dashboard HTTP handler with
|
|
189
|
-
* lazy initialization and 503 fallback.
|
|
190
|
-
*/
|
|
191
|
-
const bindApi = (fn) => {
|
|
192
|
-
return async (ctx) => {
|
|
193
|
-
const api = getApiController();
|
|
194
|
-
if (!api) {
|
|
195
|
-
return ctx.response.serviceUnavailable({
|
|
196
|
-
error: 'Dashboard is starting up, please retry',
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
return fn(api, ctx);
|
|
200
|
-
};
|
|
201
|
-
};
|
|
202
|
-
router
|
|
203
|
-
.group(() => {
|
|
204
|
-
// ── Page ────────────────────────────────────────────────────
|
|
205
|
-
router.get('/', bindDash('page')).as('server-stats.dashboard');
|
|
206
|
-
// ── Overview (dashboard-only) ───────────────────────────────
|
|
207
|
-
router.get('/api/overview', bindDash('overview')).as('server-stats.overview');
|
|
208
|
-
router
|
|
209
|
-
.get('/api/overview/chart', bindDash('overviewChart'))
|
|
210
|
-
.as('server-stats.overview.chart');
|
|
211
|
-
// ── Requests (dashboard-only) ───────────────────────────────
|
|
212
|
-
router.get('/api/requests', bindDash('requests')).as('server-stats.requests');
|
|
213
|
-
router.get('/api/requests/:id', bindDash('requestDetail')).as('server-stats.requests.show');
|
|
214
|
-
// ── Queries — unified data via ApiController ────────────────
|
|
215
|
-
router
|
|
216
|
-
.get('/api/queries', bindApi(async (api, ctx) => {
|
|
217
|
-
const qs = ctx.request.qs();
|
|
218
|
-
const result = await api.getQueries({
|
|
219
|
-
page: Number(qs.page) || 1,
|
|
220
|
-
perPage: Number(qs.perPage) || 25,
|
|
221
|
-
search: qs.search || undefined,
|
|
222
|
-
filters: {
|
|
223
|
-
durationMin: qs.duration_min ? Number(qs.duration_min) : undefined,
|
|
224
|
-
model: qs.model || undefined,
|
|
225
|
-
method: qs.method || undefined,
|
|
226
|
-
connection: qs.connection || undefined,
|
|
227
|
-
},
|
|
228
|
-
});
|
|
229
|
-
return ctx.response.json(result);
|
|
230
|
-
}))
|
|
231
|
-
.as('server-stats.queries');
|
|
232
|
-
// Grouped queries and explain stay on DashboardController
|
|
233
|
-
router
|
|
234
|
-
.get('/api/queries/grouped', bindDash('queriesGrouped'))
|
|
235
|
-
.as('server-stats.queries.grouped');
|
|
236
|
-
router
|
|
237
|
-
.get('/api/queries/:id/explain', bindDash('queryExplain'))
|
|
238
|
-
.as('server-stats.queries.explain');
|
|
239
|
-
// ── Events — unified data via ApiController ─────────────────
|
|
240
|
-
router
|
|
241
|
-
.get('/api/events', bindApi(async (api, ctx) => {
|
|
242
|
-
const qs = ctx.request.qs();
|
|
243
|
-
const result = await api.getEvents({
|
|
244
|
-
page: Number(qs.page) || 1,
|
|
245
|
-
perPage: Number(qs.perPage) || 25,
|
|
246
|
-
search: qs.search || undefined,
|
|
247
|
-
filters: {
|
|
248
|
-
eventName: qs.event_name || undefined,
|
|
249
|
-
},
|
|
250
|
-
});
|
|
251
|
-
return ctx.response.json(result);
|
|
252
|
-
}))
|
|
253
|
-
.as('server-stats.events');
|
|
254
|
-
// ── Routes — unified data via ApiController ─────────────────
|
|
255
|
-
router
|
|
256
|
-
.get('/api/routes', bindApi((api, ctx) => {
|
|
257
|
-
const qs = ctx.request.qs();
|
|
258
|
-
const result = api.getRoutes(qs.search || undefined);
|
|
259
|
-
return ctx.response.json(result);
|
|
260
|
-
}))
|
|
261
|
-
.as('server-stats.routes');
|
|
262
|
-
// ── Logs — unified data via ApiController ───────────────────
|
|
263
|
-
router
|
|
264
|
-
.get('/api/logs', bindApi(async (api, ctx) => {
|
|
265
|
-
const qs = ctx.request.qs();
|
|
266
|
-
const result = await api.getLogs({
|
|
267
|
-
page: Number(qs.page) || 1,
|
|
268
|
-
perPage: Number(qs.perPage) || 50,
|
|
269
|
-
search: qs.message || qs.search || undefined,
|
|
270
|
-
filters: {
|
|
271
|
-
level: qs.level || undefined,
|
|
272
|
-
requestId: qs.request_id || qs.requestId || undefined,
|
|
273
|
-
},
|
|
274
|
-
});
|
|
275
|
-
return ctx.response.json(result);
|
|
276
|
-
}))
|
|
277
|
-
.as('server-stats.logs');
|
|
278
|
-
// ── Emails — unified data via ApiController ─────────────────
|
|
279
|
-
router
|
|
280
|
-
.get('/api/emails', bindApi(async (api, ctx) => {
|
|
281
|
-
const qs = ctx.request.qs();
|
|
282
|
-
const result = await api.getEmails({
|
|
283
|
-
page: Number(qs.page) || 1,
|
|
284
|
-
perPage: Number(qs.perPage) || 25,
|
|
285
|
-
search: qs.search || undefined,
|
|
286
|
-
filters: {
|
|
287
|
-
from: qs.from || undefined,
|
|
288
|
-
to: qs.to || undefined,
|
|
289
|
-
subject: qs.subject || undefined,
|
|
290
|
-
status: qs.status || undefined,
|
|
291
|
-
mailer: qs.mailer || undefined,
|
|
292
|
-
},
|
|
293
|
-
});
|
|
294
|
-
return ctx.response.json(result);
|
|
295
|
-
}))
|
|
296
|
-
.as('server-stats.emails');
|
|
297
|
-
router
|
|
298
|
-
.get('/api/emails/:id/preview', bindApi(async (api, ctx) => {
|
|
299
|
-
const id = Number(ctx.params.id);
|
|
300
|
-
const html = await api.getEmailPreview(id);
|
|
301
|
-
if (!html) {
|
|
302
|
-
return ctx.response.notFound({ error: 'Email not found' });
|
|
303
|
-
}
|
|
304
|
-
return ctx.response.header('Content-Type', 'text/html; charset=utf-8').send(html);
|
|
305
|
-
}))
|
|
306
|
-
.as('server-stats.emails.preview');
|
|
307
|
-
// ── Traces — unified data via ApiController ─────────────────
|
|
308
|
-
router
|
|
309
|
-
.get('/api/traces', bindApi(async (api, ctx) => {
|
|
310
|
-
const qs = ctx.request.qs();
|
|
311
|
-
const result = await api.getTraces({
|
|
312
|
-
page: Number(qs.page) || 1,
|
|
313
|
-
perPage: Number(qs.perPage) || 25,
|
|
314
|
-
search: qs.search || undefined,
|
|
315
|
-
filters: {
|
|
316
|
-
method: qs.method ? qs.method.toUpperCase() : undefined,
|
|
317
|
-
url: qs.url || undefined,
|
|
318
|
-
statusMin: qs.status_min ? Number(qs.status_min) : undefined,
|
|
319
|
-
statusMax: qs.status_max ? Number(qs.status_max) : undefined,
|
|
320
|
-
},
|
|
321
|
-
});
|
|
322
|
-
return ctx.response.json(result);
|
|
323
|
-
}))
|
|
324
|
-
.as('server-stats.traces');
|
|
325
|
-
router
|
|
326
|
-
.get('/api/traces/:id', bindApi(async (api, ctx) => {
|
|
327
|
-
const id = Number(ctx.params.id);
|
|
328
|
-
const trace = await api.getTraceDetail(id);
|
|
329
|
-
if (!trace) {
|
|
330
|
-
return ctx.response.notFound({ error: 'Trace not found' });
|
|
331
|
-
}
|
|
332
|
-
return ctx.response.json(trace);
|
|
333
|
-
}))
|
|
334
|
-
.as('server-stats.traces.show');
|
|
335
|
-
// ── Cache (dashboard-only) ──────────────────────────────────
|
|
336
|
-
router.get('/api/cache', bindDash('cacheStats')).as('server-stats.cache');
|
|
337
|
-
router
|
|
338
|
-
.get('/api/cache/:key', bindDash('cacheKey'))
|
|
339
|
-
.as('server-stats.cache.show')
|
|
340
|
-
.where('key', /.*/);
|
|
341
|
-
router
|
|
342
|
-
.delete('/api/cache/:key', bindDash('cacheKeyDelete'))
|
|
343
|
-
.as('server-stats.cache.delete')
|
|
344
|
-
.where('key', /.*/);
|
|
345
|
-
// ── Jobs / Queue (dashboard-only) ───────────────────────────
|
|
346
|
-
router.get('/api/jobs', bindDash('jobs')).as('server-stats.jobs');
|
|
347
|
-
router.get('/api/jobs/:id', bindDash('jobDetail')).as('server-stats.jobs.show');
|
|
348
|
-
router.post('/api/jobs/:id/retry', bindDash('jobRetry')).as('server-stats.jobs.retry');
|
|
349
|
-
// ── Config (dashboard-only) ─────────────────────────────────
|
|
350
|
-
router.get('/api/config', bindDash('config')).as('server-stats.config');
|
|
351
|
-
// ── Saved Filters (dashboard-only) ──────────────────────────
|
|
352
|
-
router.get('/api/filters', bindDash('savedFilters')).as('server-stats.filters');
|
|
353
|
-
router.post('/api/filters', bindDash('createSavedFilter')).as('server-stats.filters.create');
|
|
354
|
-
router
|
|
355
|
-
.delete('/api/filters/:id', bindDash('deleteSavedFilter'))
|
|
356
|
-
.as('server-stats.filters.delete');
|
|
357
|
-
})
|
|
358
|
-
.prefix(base)
|
|
359
|
-
.use(middleware);
|
|
22
|
+
if (options.dashboardPath) {
|
|
23
|
+
registerDashboardRoutes({
|
|
24
|
+
router: options.router,
|
|
25
|
+
dashboardPath: options.dashboardPath,
|
|
26
|
+
getDashboardController: options.getDashboardController,
|
|
27
|
+
getApiController: options.getApiController,
|
|
28
|
+
middleware,
|
|
29
|
+
});
|
|
360
30
|
}
|
|
361
31
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type ServerStatsController from '../controller/server_stats_controller.js';
|
|
2
|
+
import type { AdonisRouter } from './router_types.js';
|
|
3
|
+
import type { HttpContext } from '@adonisjs/core/http';
|
|
4
|
+
/** Register the stats polling endpoint. */
|
|
5
|
+
export declare function registerStatsRoute(router: AdonisRouter, endpoint: string, getController: () => ServerStatsController | null, middleware: Array<(ctx: HttpContext, next: () => Promise<void>) => Promise<void>>): void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Register the stats polling endpoint. */
|
|
2
|
+
export function registerStatsRoute(router, endpoint, getController, middleware) {
|
|
3
|
+
router
|
|
4
|
+
.get(endpoint, async (ctx) => {
|
|
5
|
+
const controller = getController();
|
|
6
|
+
if (!controller)
|
|
7
|
+
return ctx.response.serviceUnavailable({
|
|
8
|
+
error: 'Stats engine is starting up, please retry',
|
|
9
|
+
});
|
|
10
|
+
return controller.index(ctx);
|
|
11
|
+
})
|
|
12
|
+
.as('server-stats.api')
|
|
13
|
+
.use(middleware);
|
|
14
|
+
}
|
|
@@ -309,6 +309,102 @@
|
|
|
309
309
|
color: var(--ss-border);
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
+
/* ── Filter / Search Bar ─────────────────────────────────────── */
|
|
313
|
+
/* Padding can be overridden via --ss-filter-px (debug: 12px, dashboard: 16px). */
|
|
314
|
+
.ss-filter-bar,
|
|
315
|
+
.ss-dash-filter-bar,
|
|
316
|
+
.ss-dash-search-bar,
|
|
317
|
+
.ss-dbg-filter-bar,
|
|
318
|
+
.ss-dbg-search-bar {
|
|
319
|
+
display: flex;
|
|
320
|
+
align-items: center;
|
|
321
|
+
gap: 8px;
|
|
322
|
+
padding: 8px var(--ss-filter-px, 12px);
|
|
323
|
+
border-bottom: 1px solid var(--ss-border-dim);
|
|
324
|
+
background: var(--ss-surface-alt);
|
|
325
|
+
flex-shrink: 0;
|
|
326
|
+
flex-wrap: wrap;
|
|
327
|
+
}
|
|
328
|
+
.ss-search-wrapper,
|
|
329
|
+
.ss-dash-search-wrapper,
|
|
330
|
+
.ss-dbg-search-wrapper {
|
|
331
|
+
position: relative;
|
|
332
|
+
flex: 1;
|
|
333
|
+
min-width: 180px;
|
|
334
|
+
}
|
|
335
|
+
.ss-search-icon,
|
|
336
|
+
.ss-dash-search-icon,
|
|
337
|
+
.ss-dbg-search-icon {
|
|
338
|
+
position: absolute;
|
|
339
|
+
left: 8px;
|
|
340
|
+
top: 50%;
|
|
341
|
+
transform: translateY(-50%);
|
|
342
|
+
width: 14px;
|
|
343
|
+
height: 14px;
|
|
344
|
+
color: var(--ss-dim);
|
|
345
|
+
pointer-events: none;
|
|
346
|
+
}
|
|
347
|
+
.ss-search,
|
|
348
|
+
.ss-dash-search,
|
|
349
|
+
.ss-dbg-search {
|
|
350
|
+
flex: 1;
|
|
351
|
+
width: 100%;
|
|
352
|
+
padding: var(--ss-search-py, 4px) var(--ss-search-px, 8px);
|
|
353
|
+
padding-left: 28px;
|
|
354
|
+
padding-right: 24px;
|
|
355
|
+
font-size: 11px;
|
|
356
|
+
color: var(--ss-text);
|
|
357
|
+
background: var(--ss-input-bg);
|
|
358
|
+
border: 1px solid var(--ss-border);
|
|
359
|
+
border-radius: 4px;
|
|
360
|
+
outline: none;
|
|
361
|
+
}
|
|
362
|
+
.ss-search:focus,
|
|
363
|
+
.ss-dash-search:focus,
|
|
364
|
+
.ss-dbg-search:focus {
|
|
365
|
+
border-color: var(--ss-accent);
|
|
366
|
+
}
|
|
367
|
+
.ss-search::placeholder,
|
|
368
|
+
.ss-dash-search::placeholder,
|
|
369
|
+
.ss-dbg-search::placeholder {
|
|
370
|
+
color: var(--ss-dim);
|
|
371
|
+
}
|
|
372
|
+
.ss-search-clear,
|
|
373
|
+
.ss-dash-search-clear,
|
|
374
|
+
.ss-dbg-search-clear {
|
|
375
|
+
position: absolute;
|
|
376
|
+
right: 6px;
|
|
377
|
+
top: 50%;
|
|
378
|
+
transform: translateY(-50%);
|
|
379
|
+
background: none;
|
|
380
|
+
border: none;
|
|
381
|
+
color: var(--ss-dim);
|
|
382
|
+
cursor: pointer;
|
|
383
|
+
font-size: 14px;
|
|
384
|
+
padding: 2px 4px;
|
|
385
|
+
line-height: 1;
|
|
386
|
+
}
|
|
387
|
+
.ss-search-clear:hover,
|
|
388
|
+
.ss-dash-search-clear:hover,
|
|
389
|
+
.ss-dbg-search-clear:hover {
|
|
390
|
+
color: var(--ss-text);
|
|
391
|
+
}
|
|
392
|
+
.ss-filter-controls,
|
|
393
|
+
.ss-dash-filter-controls,
|
|
394
|
+
.ss-dbg-filter-controls {
|
|
395
|
+
display: flex;
|
|
396
|
+
align-items: center;
|
|
397
|
+
gap: 6px;
|
|
398
|
+
margin-left: auto;
|
|
399
|
+
}
|
|
400
|
+
.ss-summary,
|
|
401
|
+
.ss-dash-summary,
|
|
402
|
+
.ss-dbg-summary {
|
|
403
|
+
font-size: 11px;
|
|
404
|
+
color: var(--ss-muted);
|
|
405
|
+
white-space: nowrap;
|
|
406
|
+
}
|
|
407
|
+
|
|
312
408
|
/* ═══════════════════════════════════════════════════════════════
|
|
313
409
|
* Phase 4: Full Component Unification
|
|
314
410
|
* ═══════════════════════════════════════════════════════════════ */
|
|
@@ -1211,3 +1307,70 @@ tr:hover .ss-dbg-copy-row-btn,
|
|
|
1211
1307
|
font-weight: 400;
|
|
1212
1308
|
color: var(--ss-dim);
|
|
1213
1309
|
}
|
|
1310
|
+
|
|
1311
|
+
/* ── Cache stats bar ─────────────────────────────────────────── */
|
|
1312
|
+
/* Shared between Dashboard CacheSection and DebugPanel CacheTab.
|
|
1313
|
+
* Gap/padding differ slightly — override via --ss-cache-stats-gap
|
|
1314
|
+
* and --ss-cache-stats-px / --ss-cache-stats-py. */
|
|
1315
|
+
.ss-cache-stats,
|
|
1316
|
+
.ss-dash-cache-stats,
|
|
1317
|
+
.ss-dbg-cache-stats {
|
|
1318
|
+
display: flex;
|
|
1319
|
+
gap: var(--ss-cache-stats-gap, 16px);
|
|
1320
|
+
padding: var(--ss-cache-stats-py, 8px) var(--ss-cache-stats-px, 12px);
|
|
1321
|
+
border-bottom: 1px solid var(--ss-border-dim);
|
|
1322
|
+
background: var(--ss-surface-alt);
|
|
1323
|
+
font-size: 11px;
|
|
1324
|
+
flex-shrink: 0;
|
|
1325
|
+
}
|
|
1326
|
+
.ss-cache-stat,
|
|
1327
|
+
.ss-dash-cache-stat,
|
|
1328
|
+
.ss-dbg-cache-stat {
|
|
1329
|
+
display: inline-flex;
|
|
1330
|
+
align-items: center;
|
|
1331
|
+
gap: 4px;
|
|
1332
|
+
}
|
|
1333
|
+
.ss-cache-stat-label,
|
|
1334
|
+
.ss-dash-cache-stat-label,
|
|
1335
|
+
.ss-dbg-cache-stat-label {
|
|
1336
|
+
color: var(--ss-muted);
|
|
1337
|
+
}
|
|
1338
|
+
.ss-cache-stat-value,
|
|
1339
|
+
.ss-dash-cache-stat-value,
|
|
1340
|
+
.ss-dbg-cache-stat-value {
|
|
1341
|
+
color: var(--ss-text);
|
|
1342
|
+
font-weight: 600;
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
/* ── Job stats bar ──────────────────────────────────────────── */
|
|
1346
|
+
/* Shared between Dashboard JobsSection and DebugPanel JobsTab.
|
|
1347
|
+
* Gap/padding differ slightly — override via --ss-job-stats-gap
|
|
1348
|
+
* and --ss-job-stats-px / --ss-job-stats-py. */
|
|
1349
|
+
.ss-job-stats,
|
|
1350
|
+
.ss-dash-job-stats,
|
|
1351
|
+
.ss-dbg-job-stats {
|
|
1352
|
+
display: flex;
|
|
1353
|
+
gap: var(--ss-job-stats-gap, 16px);
|
|
1354
|
+
padding: var(--ss-job-stats-py, 8px) var(--ss-job-stats-px, 12px);
|
|
1355
|
+
background: var(--ss-surface-alt);
|
|
1356
|
+
font-size: 11px;
|
|
1357
|
+
flex-shrink: 0;
|
|
1358
|
+
}
|
|
1359
|
+
.ss-job-stat,
|
|
1360
|
+
.ss-dash-job-stat,
|
|
1361
|
+
.ss-dbg-job-stat {
|
|
1362
|
+
display: inline-flex;
|
|
1363
|
+
align-items: center;
|
|
1364
|
+
gap: 4px;
|
|
1365
|
+
}
|
|
1366
|
+
.ss-job-stat-label,
|
|
1367
|
+
.ss-dash-job-stat-label,
|
|
1368
|
+
.ss-dbg-job-stat-label {
|
|
1369
|
+
color: var(--ss-muted);
|
|
1370
|
+
}
|
|
1371
|
+
.ss-job-stat-value,
|
|
1372
|
+
.ss-dash-job-stat-value,
|
|
1373
|
+
.ss-dbg-job-stat-value {
|
|
1374
|
+
color: var(--ss-text);
|
|
1375
|
+
font-weight: 600;
|
|
1376
|
+
}
|