pg_reports 0.8.1 → 0.9.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +23 -2
- data/app/controllers/pg_reports/dashboard_controller.rb +241 -24
- data/app/views/layouts/pg_reports/application.html.erb +616 -201
- data/app/views/pg_reports/dashboard/_database_selector.html.erb +2 -1
- data/app/views/pg_reports/dashboard/_show_modals.html.erb +10 -7
- data/app/views/pg_reports/dashboard/_show_scripts.html.erb +100 -51
- data/app/views/pg_reports/dashboard/_show_styles.html.erb +392 -476
- data/app/views/pg_reports/dashboard/index.html.erb +426 -335
- data/app/views/pg_reports/dashboard/show.html.erb +13 -11
- data/bin/pg_reports +28 -2
- data/config/brakeman.ignore +97 -0
- data/config/locales/en.yml +62 -47
- data/config/locales/ru.yml +62 -47
- data/config/locales/uk.yml +62 -47
- data/config/routes.rb +1 -0
- data/lib/pg_reports/configuration.rb +8 -0
- data/lib/pg_reports/connection/error_translator.rb +43 -0
- data/lib/pg_reports/dashboard/reports_registry.rb +10 -0
- data/lib/pg_reports/explain_analyzer.rb +0 -3
- data/lib/pg_reports/grafana/exporter.rb +5 -1
- data/lib/pg_reports/query_monitor.rb +15 -3
- data/lib/pg_reports/standalone.rb +59 -1
- data/lib/pg_reports/version.rb +1 -1
- data/lib/pg_reports.rb +5 -0
- metadata +2 -1
|
@@ -5,30 +5,69 @@
|
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
6
|
<meta name="pg-reports-root" content="<%= request.script_name.presence || PgReports::Engine.routes.url_helpers.root_path %>">
|
|
7
7
|
<title><%= t("pg_reports.ui.branding.page_title") %></title>
|
|
8
|
-
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%
|
|
8
|
+
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 32 32'%3E%3Crect width='32' height='32' rx='6' fill='%235561d4'/%3E%3Crect x='5' y='18' width='5' height='9' rx='1' fill='%23fff'/%3E%3Crect x='13.5' y='12' width='5' height='15' rx='1' fill='%23fff'/%3E%3Crect x='22' y='6' width='5' height='21' rx='1' fill='%23fff'/%3E%3C/svg%3E">
|
|
9
9
|
<% if PgReports.config.load_external_fonts %>
|
|
10
10
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
11
11
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
12
|
-
<link href="https://fonts.googleapis.com/css2?family=
|
|
12
|
+
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
13
13
|
<% end %>
|
|
14
14
|
<style>
|
|
15
15
|
:root {
|
|
16
|
-
--bg-primary: #
|
|
17
|
-
--bg-secondary: #
|
|
18
|
-
--bg-tertiary: #
|
|
19
|
-
--bg-card: #
|
|
20
|
-
--
|
|
21
|
-
--
|
|
22
|
-
--
|
|
23
|
-
|
|
16
|
+
--bg-primary: #141618;
|
|
17
|
+
--bg-secondary: #1a1d20;
|
|
18
|
+
--bg-tertiary: #212427;
|
|
19
|
+
--bg-card: #1a1d20;
|
|
20
|
+
--bg-hover: #272b2f;
|
|
21
|
+
--border-color: #2c3034;
|
|
22
|
+
--border-strong: #3b4045;
|
|
23
|
+
|
|
24
|
+
--text-primary: #d3d6d9;
|
|
25
|
+
--text-secondary: #8d9299;
|
|
26
|
+
--text-muted: #666b71;
|
|
27
|
+
--text-tertiary: #666b71;
|
|
28
|
+
|
|
24
29
|
--accent-purple: #7c8af6;
|
|
25
30
|
--accent-blue: #5c9eed;
|
|
26
31
|
--accent-green: #45a87a;
|
|
27
32
|
--accent-amber: #c89030;
|
|
28
33
|
--accent-rose: #d45d6e;
|
|
29
|
-
--accent-
|
|
30
|
-
|
|
31
|
-
|
|
34
|
+
--accent-red: #d45d6e;
|
|
35
|
+
|
|
36
|
+
/* Tints derived from the accents above. Every status surface uses these
|
|
37
|
+
two levels — fill and hairline — so tinted areas stay in one family. */
|
|
38
|
+
--purple-soft: rgba(124, 138, 246, 0.10);
|
|
39
|
+
--purple-line: rgba(124, 138, 246, 0.32);
|
|
40
|
+
--blue-soft: rgba(92, 158, 237, 0.10);
|
|
41
|
+
--blue-line: rgba(92, 158, 237, 0.32);
|
|
42
|
+
--green-soft: rgba(69, 168, 122, 0.10);
|
|
43
|
+
--green-line: rgba(69, 168, 122, 0.32);
|
|
44
|
+
--amber-soft: rgba(200, 144, 48, 0.10);
|
|
45
|
+
--amber-line: rgba(200, 144, 48, 0.34);
|
|
46
|
+
--rose-soft: rgba(212, 93, 110, 0.10);
|
|
47
|
+
--rose-line: rgba(212, 93, 110, 0.34);
|
|
48
|
+
|
|
49
|
+
--btn-primary-bg: #5561d4;
|
|
50
|
+
--btn-primary-bg-hover: #616de0;
|
|
51
|
+
--btn-primary-bg-active: #4a55c2;
|
|
52
|
+
--btn-danger-bg: #b64d5c;
|
|
53
|
+
--btn-danger-bg-hover: #c45a6a;
|
|
54
|
+
--btn-danger-bg-active: #a34351;
|
|
55
|
+
|
|
56
|
+
--flow-gap: 0.875rem;
|
|
57
|
+
--flow-gap-lg: 1.25rem;
|
|
58
|
+
|
|
59
|
+
--radius-sm: 4px;
|
|
60
|
+
--radius: 6px;
|
|
61
|
+
--radius-lg: 8px;
|
|
62
|
+
--control-h: 2.125rem;
|
|
63
|
+
--control-h-sm: 1.75rem;
|
|
64
|
+
|
|
65
|
+
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.3);
|
|
66
|
+
--shadow-2: 0 6px 20px rgba(0, 0, 0, 0.38);
|
|
67
|
+
--shadow-3: 0 12px 40px rgba(0, 0, 0, 0.45);
|
|
68
|
+
|
|
69
|
+
--font-sans: <%= PgReports.config.load_external_fonts ? "'Inter', " : "" %>-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif;
|
|
70
|
+
--font-mono: <%= PgReports.config.load_external_fonts ? "'JetBrains Mono', " : "" %>ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
|
|
32
71
|
}
|
|
33
72
|
|
|
34
73
|
* {
|
|
@@ -38,11 +77,28 @@
|
|
|
38
77
|
}
|
|
39
78
|
|
|
40
79
|
body {
|
|
41
|
-
font-family:
|
|
80
|
+
font-family: var(--font-sans);
|
|
42
81
|
background: var(--bg-primary);
|
|
43
82
|
color: var(--text-primary);
|
|
44
83
|
min-height: 100vh;
|
|
45
|
-
line-height: 1.
|
|
84
|
+
line-height: 1.5;
|
|
85
|
+
font-size: 0.875rem;
|
|
86
|
+
-webkit-font-smoothing: antialiased;
|
|
87
|
+
-moz-osx-font-smoothing: grayscale;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Numbers that refresh in place must not reflow as digits change. */
|
|
91
|
+
.results-table,
|
|
92
|
+
.query-results-table,
|
|
93
|
+
.metric-value,
|
|
94
|
+
.explain-stat-value {
|
|
95
|
+
font-variant-numeric: tabular-nums;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
:focus-visible {
|
|
99
|
+
outline: 2px solid var(--accent-blue);
|
|
100
|
+
outline-offset: 2px;
|
|
101
|
+
border-radius: var(--radius-sm);
|
|
46
102
|
}
|
|
47
103
|
|
|
48
104
|
.container {
|
|
@@ -62,89 +118,72 @@
|
|
|
62
118
|
}
|
|
63
119
|
|
|
64
120
|
.logo {
|
|
65
|
-
display: flex;
|
|
66
|
-
align-items: center;
|
|
67
|
-
gap: 0.75rem;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
.logo-icon {
|
|
71
|
-
width: 32px;
|
|
72
|
-
height: 32px;
|
|
73
|
-
background: var(--accent-purple);
|
|
74
|
-
border-radius: 6px;
|
|
75
|
-
display: flex;
|
|
76
|
-
align-items: center;
|
|
77
|
-
justify-content: center;
|
|
78
|
-
font-size: 1rem;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
.logo-text {
|
|
82
121
|
display: flex;
|
|
83
122
|
flex-direction: column;
|
|
84
|
-
gap:
|
|
85
|
-
|
|
123
|
+
gap: 0.125rem;
|
|
124
|
+
min-width: 0;
|
|
86
125
|
}
|
|
87
126
|
|
|
88
|
-
.logo
|
|
89
|
-
font-size: 1.1rem;
|
|
90
|
-
font-weight: 600;
|
|
91
|
-
color: var(--text-primary);
|
|
92
|
-
line-height: 1.15;
|
|
93
|
-
margin-top: -3px;
|
|
127
|
+
.logo h1 {
|
|
94
128
|
display: flex;
|
|
95
129
|
align-items: baseline;
|
|
96
130
|
gap: 0.5rem;
|
|
131
|
+
font-size: 1.0625rem;
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
letter-spacing: -0.01em;
|
|
134
|
+
color: var(--text-primary);
|
|
135
|
+
line-height: 1.2;
|
|
97
136
|
}
|
|
98
137
|
|
|
99
138
|
.logo-version {
|
|
100
|
-
font-
|
|
101
|
-
font-
|
|
139
|
+
font-family: var(--font-mono);
|
|
140
|
+
font-size: 0.6875rem;
|
|
141
|
+
font-weight: 400;
|
|
102
142
|
color: var(--text-muted);
|
|
103
|
-
letter-spacing: 0.02em;
|
|
104
143
|
}
|
|
105
144
|
|
|
106
145
|
.logo-subtitle {
|
|
107
|
-
font-size: 0.
|
|
146
|
+
font-size: 0.75rem;
|
|
108
147
|
color: var(--text-muted);
|
|
109
|
-
line-height: 1.
|
|
148
|
+
line-height: 1.2;
|
|
110
149
|
}
|
|
111
150
|
|
|
112
151
|
.header-badge {
|
|
113
|
-
display: flex;
|
|
152
|
+
display: inline-flex;
|
|
114
153
|
align-items: center;
|
|
115
154
|
gap: 0.4rem;
|
|
116
|
-
height:
|
|
155
|
+
height: var(--control-h);
|
|
117
156
|
padding: 0 0.75rem;
|
|
118
157
|
background: var(--bg-tertiary);
|
|
119
158
|
border: 1px solid var(--border-color);
|
|
120
|
-
border-radius:
|
|
159
|
+
border-radius: var(--radius-sm);
|
|
121
160
|
font-size: 0.75rem;
|
|
161
|
+
color: var(--text-secondary);
|
|
122
162
|
}
|
|
123
163
|
|
|
124
164
|
.header-badge-clickable {
|
|
125
165
|
cursor: pointer;
|
|
126
166
|
font-family: inherit;
|
|
127
|
-
|
|
128
|
-
transition: border-color 0.15s ease, background 0.15s ease;
|
|
167
|
+
transition: border-color 0.12s ease, background-color 0.12s ease;
|
|
129
168
|
}
|
|
130
169
|
|
|
131
170
|
.header-badge-clickable:hover {
|
|
132
|
-
background: var(--bg-
|
|
133
|
-
border-color: var(--
|
|
171
|
+
background: var(--bg-hover);
|
|
172
|
+
border-color: var(--border-strong);
|
|
173
|
+
color: var(--text-primary);
|
|
134
174
|
}
|
|
135
175
|
|
|
136
176
|
.badge-info-icon {
|
|
137
177
|
color: var(--text-muted);
|
|
138
|
-
|
|
139
|
-
line-height: 1;
|
|
178
|
+
line-height: 0;
|
|
140
179
|
}
|
|
141
180
|
|
|
142
181
|
.badge-dot {
|
|
143
|
-
width:
|
|
144
|
-
height:
|
|
182
|
+
width: 7px;
|
|
183
|
+
height: 7px;
|
|
184
|
+
flex: none;
|
|
145
185
|
border-radius: 50%;
|
|
146
186
|
background: var(--accent-green);
|
|
147
|
-
animation: pulse 2s infinite;
|
|
148
187
|
}
|
|
149
188
|
|
|
150
189
|
.badge-dot.warning {
|
|
@@ -153,13 +192,14 @@
|
|
|
153
192
|
|
|
154
193
|
@keyframes pulse {
|
|
155
194
|
0%, 100% { opacity: 1; }
|
|
156
|
-
50% { opacity: 0.
|
|
195
|
+
50% { opacity: 0.45; }
|
|
157
196
|
}
|
|
158
197
|
|
|
159
198
|
/* Categories Grid */
|
|
160
199
|
.categories-grid {
|
|
161
200
|
display: grid;
|
|
162
|
-
grid-template-columns: repeat(auto-fit, minmax(
|
|
201
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
202
|
+
align-items: start;
|
|
163
203
|
gap: 1rem;
|
|
164
204
|
margin-bottom: 1.5rem;
|
|
165
205
|
}
|
|
@@ -167,12 +207,13 @@
|
|
|
167
207
|
.category-card {
|
|
168
208
|
background: var(--bg-card);
|
|
169
209
|
border: 1px solid var(--border-color);
|
|
170
|
-
border-radius:
|
|
210
|
+
border-radius: var(--radius);
|
|
171
211
|
padding: 1rem;
|
|
212
|
+
transition: border-color 0.12s ease;
|
|
172
213
|
}
|
|
173
214
|
|
|
174
215
|
.category-card:hover {
|
|
175
|
-
border-color:
|
|
216
|
+
border-color: var(--border-strong);
|
|
176
217
|
}
|
|
177
218
|
|
|
178
219
|
.category-header {
|
|
@@ -183,28 +224,25 @@
|
|
|
183
224
|
}
|
|
184
225
|
|
|
185
226
|
.category-icon {
|
|
186
|
-
width:
|
|
187
|
-
height:
|
|
188
|
-
|
|
189
|
-
display: flex;
|
|
190
|
-
align-items: center;
|
|
191
|
-
justify-content: center;
|
|
192
|
-
font-size: 0.95rem;
|
|
193
|
-
background: transparent !important;
|
|
194
|
-
color: var(--text-secondary) !important;
|
|
227
|
+
width: 1rem;
|
|
228
|
+
height: 1rem;
|
|
229
|
+
color: var(--text-secondary);
|
|
195
230
|
}
|
|
196
231
|
|
|
197
232
|
.category-title {
|
|
198
|
-
font-size:
|
|
233
|
+
font-size: 0.9375rem;
|
|
199
234
|
font-weight: 600;
|
|
235
|
+
letter-spacing: -0.01em;
|
|
200
236
|
}
|
|
201
237
|
|
|
202
238
|
.category-count {
|
|
203
239
|
margin-left: auto;
|
|
204
|
-
padding: 0.
|
|
240
|
+
padding: 0.15rem 0.45rem;
|
|
205
241
|
background: var(--bg-tertiary);
|
|
206
|
-
border
|
|
207
|
-
|
|
242
|
+
border: 1px solid var(--border-color);
|
|
243
|
+
border-radius: var(--radius-sm);
|
|
244
|
+
font-size: 0.6875rem;
|
|
245
|
+
font-variant-numeric: tabular-nums;
|
|
208
246
|
color: var(--text-muted);
|
|
209
247
|
}
|
|
210
248
|
|
|
@@ -217,15 +255,16 @@
|
|
|
217
255
|
.report-link {
|
|
218
256
|
display: flex;
|
|
219
257
|
align-items: center;
|
|
258
|
+
gap: 0.75rem;
|
|
220
259
|
justify-content: space-between;
|
|
221
|
-
padding: 0.
|
|
260
|
+
padding: 0.4rem 0.6rem;
|
|
222
261
|
background: transparent;
|
|
223
262
|
border: 1px solid transparent;
|
|
224
|
-
border-radius:
|
|
263
|
+
border-radius: var(--radius-sm);
|
|
225
264
|
color: var(--text-secondary);
|
|
226
265
|
text-decoration: none;
|
|
227
|
-
font-size: 0.
|
|
228
|
-
transition: background 0.1s, color 0.1s;
|
|
266
|
+
font-size: 0.8125rem;
|
|
267
|
+
transition: background-color 0.1s ease, color 0.1s ease;
|
|
229
268
|
}
|
|
230
269
|
|
|
231
270
|
.report-link:hover {
|
|
@@ -234,26 +273,29 @@
|
|
|
234
273
|
}
|
|
235
274
|
|
|
236
275
|
.report-link .arrow {
|
|
276
|
+
width: 0.8125rem;
|
|
277
|
+
height: 0.8125rem;
|
|
278
|
+
color: var(--text-muted);
|
|
237
279
|
opacity: 0;
|
|
238
|
-
|
|
239
|
-
transition: all 0.15s ease;
|
|
280
|
+
transition: opacity 0.12s ease;
|
|
240
281
|
}
|
|
241
282
|
|
|
242
|
-
.report-link:hover .arrow
|
|
283
|
+
.report-link:hover .arrow,
|
|
284
|
+
.report-link:focus-visible .arrow {
|
|
243
285
|
opacity: 1;
|
|
244
|
-
transform: translateX(0);
|
|
245
286
|
}
|
|
246
287
|
|
|
247
288
|
.report-badge-new {
|
|
248
289
|
display: inline-block;
|
|
249
290
|
margin-left: 0.4rem;
|
|
250
|
-
padding: 0.
|
|
251
|
-
font-size: 0.
|
|
291
|
+
padding: 0.05rem 0.3rem;
|
|
292
|
+
font-size: 0.5625rem;
|
|
252
293
|
font-weight: 600;
|
|
253
|
-
letter-spacing: 0.
|
|
254
|
-
line-height: 1.
|
|
294
|
+
letter-spacing: 0.06em;
|
|
295
|
+
line-height: 1.4;
|
|
255
296
|
color: var(--accent-green);
|
|
256
|
-
background:
|
|
297
|
+
background: var(--green-soft);
|
|
298
|
+
border: 1px solid var(--green-line);
|
|
257
299
|
border-radius: 3px;
|
|
258
300
|
vertical-align: middle;
|
|
259
301
|
}
|
|
@@ -269,6 +311,7 @@
|
|
|
269
311
|
display: flex;
|
|
270
312
|
align-items: center;
|
|
271
313
|
gap: 0.4rem;
|
|
314
|
+
min-height: var(--control-h);
|
|
272
315
|
font-size: 0.75rem;
|
|
273
316
|
color: var(--text-muted);
|
|
274
317
|
}
|
|
@@ -276,13 +319,41 @@
|
|
|
276
319
|
.breadcrumb a {
|
|
277
320
|
color: var(--text-secondary);
|
|
278
321
|
text-decoration: none;
|
|
279
|
-
transition: color 0.
|
|
322
|
+
transition: color 0.12s ease, background-color 0.12s ease;
|
|
280
323
|
}
|
|
281
324
|
|
|
282
325
|
.breadcrumb a:hover {
|
|
283
326
|
color: var(--text-primary);
|
|
284
327
|
}
|
|
285
328
|
|
|
329
|
+
/* First crumb doubles as the back action — the arrow makes the affordance
|
|
330
|
+
explicit without a second control duplicating it in the header. */
|
|
331
|
+
.breadcrumb-back {
|
|
332
|
+
display: inline-flex;
|
|
333
|
+
align-items: center;
|
|
334
|
+
gap: 0.35rem;
|
|
335
|
+
margin-left: -0.4rem;
|
|
336
|
+
padding: 0.2rem 0.45rem;
|
|
337
|
+
border-radius: var(--radius-sm);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
.breadcrumb-back:hover {
|
|
341
|
+
background: var(--bg-tertiary);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
.breadcrumb-back .icon {
|
|
345
|
+
width: 0.8125rem;
|
|
346
|
+
height: 0.8125rem;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
.breadcrumb-sep {
|
|
350
|
+
color: var(--border-strong);
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
.breadcrumb-current {
|
|
354
|
+
color: var(--text-secondary);
|
|
355
|
+
}
|
|
356
|
+
|
|
286
357
|
.report-header {
|
|
287
358
|
display: flex;
|
|
288
359
|
align-items: flex-start;
|
|
@@ -306,62 +377,163 @@
|
|
|
306
377
|
gap: 0.5rem;
|
|
307
378
|
}
|
|
308
379
|
|
|
380
|
+
/* Buttons — one solid, classic control. Height, radius and weight come from
|
|
381
|
+
the tokens so every variant and every page lines up on the same grid. */
|
|
309
382
|
.btn {
|
|
310
383
|
display: inline-flex;
|
|
311
384
|
align-items: center;
|
|
312
385
|
justify-content: center;
|
|
313
386
|
gap: 0.4rem;
|
|
314
|
-
height:
|
|
315
|
-
padding: 0
|
|
387
|
+
height: var(--control-h);
|
|
388
|
+
padding: 0 0.875rem;
|
|
316
389
|
border: 1px solid transparent;
|
|
317
|
-
border-radius:
|
|
390
|
+
border-radius: var(--radius-sm);
|
|
318
391
|
font-family: inherit;
|
|
319
|
-
font-size: 0.
|
|
392
|
+
font-size: 0.8125rem;
|
|
320
393
|
font-weight: 500;
|
|
394
|
+
line-height: 1;
|
|
321
395
|
cursor: pointer;
|
|
322
|
-
|
|
396
|
+
user-select: none;
|
|
323
397
|
white-space: nowrap;
|
|
324
398
|
text-decoration: none;
|
|
399
|
+
transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
|
|
325
400
|
}
|
|
326
401
|
|
|
327
402
|
.btn-primary {
|
|
328
|
-
background:
|
|
329
|
-
color: var(--
|
|
330
|
-
|
|
403
|
+
background: var(--btn-primary-bg);
|
|
404
|
+
border-color: var(--btn-primary-bg);
|
|
405
|
+
color: #fff;
|
|
331
406
|
}
|
|
332
407
|
|
|
333
408
|
.btn-primary:hover {
|
|
334
|
-
background:
|
|
335
|
-
border-color:
|
|
409
|
+
background: var(--btn-primary-bg-hover);
|
|
410
|
+
border-color: var(--btn-primary-bg-hover);
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
.btn-primary:active {
|
|
414
|
+
background: var(--btn-primary-bg-active);
|
|
415
|
+
border-color: var(--btn-primary-bg-active);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
.btn-secondary,
|
|
419
|
+
.btn-telegram {
|
|
420
|
+
background: var(--bg-tertiary);
|
|
421
|
+
color: var(--text-primary);
|
|
422
|
+
border-color: var(--border-color);
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
.btn-secondary:hover,
|
|
426
|
+
.btn-telegram:hover {
|
|
427
|
+
background: var(--bg-hover);
|
|
428
|
+
border-color: var(--border-strong);
|
|
336
429
|
}
|
|
337
430
|
|
|
338
|
-
.btn-secondary
|
|
431
|
+
.btn-secondary:active,
|
|
432
|
+
.btn-telegram:active {
|
|
339
433
|
background: var(--bg-tertiary);
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
.btn-ghost {
|
|
437
|
+
background: transparent;
|
|
340
438
|
color: var(--text-secondary);
|
|
341
|
-
border:
|
|
439
|
+
border-color: transparent;
|
|
342
440
|
}
|
|
343
441
|
|
|
344
|
-
.btn-
|
|
345
|
-
background:
|
|
442
|
+
.btn-ghost:hover {
|
|
443
|
+
background: var(--bg-tertiary);
|
|
346
444
|
color: var(--text-primary);
|
|
347
445
|
}
|
|
348
446
|
|
|
349
|
-
.btn-
|
|
447
|
+
.btn-danger {
|
|
448
|
+
background: var(--btn-danger-bg);
|
|
449
|
+
border-color: var(--btn-danger-bg);
|
|
450
|
+
color: #fff;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
.btn-danger:hover {
|
|
454
|
+
background: var(--btn-danger-bg-hover);
|
|
455
|
+
border-color: var(--btn-danger-bg-hover);
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
.btn-danger:active {
|
|
459
|
+
background: var(--btn-danger-bg-active);
|
|
460
|
+
border-color: var(--btn-danger-bg-active);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
/* Destructive, but not the page's main action: neutral until hovered. */
|
|
464
|
+
.btn-muted {
|
|
350
465
|
background: var(--bg-tertiary);
|
|
466
|
+
border-color: var(--border-color);
|
|
351
467
|
color: var(--text-secondary);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
.btn-muted:hover {
|
|
471
|
+
background: var(--rose-soft);
|
|
472
|
+
border-color: var(--rose-line);
|
|
473
|
+
color: var(--accent-rose);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
.btn-small {
|
|
477
|
+
height: var(--control-h-sm);
|
|
478
|
+
padding: 0 0.625rem;
|
|
479
|
+
font-size: 0.75rem;
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
/* Square control sized to match .btn — for a lone icon with no label. */
|
|
483
|
+
.btn-icon {
|
|
484
|
+
width: var(--control-h);
|
|
485
|
+
height: var(--control-h);
|
|
486
|
+
padding: 0;
|
|
487
|
+
flex: none;
|
|
488
|
+
display: inline-flex;
|
|
489
|
+
align-items: center;
|
|
490
|
+
justify-content: center;
|
|
491
|
+
background: var(--bg-tertiary);
|
|
352
492
|
border: 1px solid var(--border-color);
|
|
493
|
+
border-radius: var(--radius-sm);
|
|
494
|
+
color: var(--text-secondary);
|
|
495
|
+
cursor: pointer;
|
|
496
|
+
transition: background-color 0.12s ease, border-color 0.12s ease, color 0.12s ease;
|
|
353
497
|
}
|
|
354
498
|
|
|
355
|
-
.btn-
|
|
356
|
-
background:
|
|
499
|
+
.btn-icon:hover {
|
|
500
|
+
background: var(--bg-hover);
|
|
501
|
+
border-color: var(--border-strong);
|
|
357
502
|
color: var(--text-primary);
|
|
358
503
|
}
|
|
359
504
|
|
|
360
|
-
.btn
|
|
361
|
-
|
|
505
|
+
.btn-small.btn-icon {
|
|
506
|
+
width: var(--control-h-sm);
|
|
507
|
+
height: var(--control-h-sm);
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
.btn:disabled,
|
|
511
|
+
.btn-icon:disabled {
|
|
512
|
+
opacity: 0.45;
|
|
362
513
|
cursor: not-allowed;
|
|
363
514
|
}
|
|
364
515
|
|
|
516
|
+
.btn:disabled:hover,
|
|
517
|
+
.btn-icon:disabled:hover {
|
|
518
|
+
background: inherit;
|
|
519
|
+
border-color: inherit;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
/* Icons — stroke-drawn, inherit the parent's colour and optical size. */
|
|
523
|
+
.icon {
|
|
524
|
+
width: 1em;
|
|
525
|
+
height: 1em;
|
|
526
|
+
flex: none;
|
|
527
|
+
fill: none;
|
|
528
|
+
stroke: currentColor;
|
|
529
|
+
stroke-width: 1.75;
|
|
530
|
+
stroke-linecap: round;
|
|
531
|
+
stroke-linejoin: round;
|
|
532
|
+
}
|
|
533
|
+
|
|
534
|
+
.icon-lg { width: 1.125rem; height: 1.125rem; }
|
|
535
|
+
.icon-sm { width: 0.875rem; height: 0.875rem; }
|
|
536
|
+
|
|
365
537
|
/* Results Table */
|
|
366
538
|
.results-container {
|
|
367
539
|
background: var(--bg-card);
|
|
@@ -468,63 +640,177 @@
|
|
|
468
640
|
}
|
|
469
641
|
|
|
470
642
|
/* Error state */
|
|
643
|
+
.error-title {
|
|
644
|
+
font-weight: 600;
|
|
645
|
+
color: var(--accent-rose);
|
|
646
|
+
}
|
|
647
|
+
|
|
471
648
|
.error-message {
|
|
472
|
-
padding: 0.875rem;
|
|
473
|
-
background:
|
|
474
|
-
border: 1px solid
|
|
475
|
-
border-radius:
|
|
649
|
+
padding: 0.875rem 1rem;
|
|
650
|
+
background: var(--rose-soft);
|
|
651
|
+
border: 1px solid var(--rose-line);
|
|
652
|
+
border-radius: var(--radius);
|
|
476
653
|
color: var(--accent-rose);
|
|
477
|
-
font-size: 0.
|
|
654
|
+
font-size: 0.8125rem;
|
|
655
|
+
line-height: 1.6;
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
.error-message .code-block {
|
|
659
|
+
color: var(--text-primary);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
/* Vertical rhythm. The global `* { margin: 0 }` reset leaves prose
|
|
663
|
+
containers with no spacing of their own, and per-element margins drifted
|
|
664
|
+
into asymmetric gaps (1rem above a code block, 0 below). One rule per
|
|
665
|
+
container spaces any two siblings identically, whatever their tags. */
|
|
666
|
+
.modal-body > * + *,
|
|
667
|
+
.modal-body li > * + *,
|
|
668
|
+
.error-message > * + *,
|
|
669
|
+
.problem-modal-body > * + *,
|
|
670
|
+
.doc-block > * + *,
|
|
671
|
+
.explain-query-section > * + *,
|
|
672
|
+
.explain-params-section > * + *,
|
|
673
|
+
#explain-content > * + *,
|
|
674
|
+
#run-query-content > * + *,
|
|
675
|
+
.callout-body > * + * {
|
|
676
|
+
margin-top: var(--flow-gap);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
.modal-body > ol > li + li {
|
|
680
|
+
margin-top: var(--flow-gap-lg);
|
|
478
681
|
}
|
|
479
682
|
|
|
480
|
-
|
|
683
|
+
.modal-body > .modal-actions,
|
|
684
|
+
.modal-body > .migration-actions {
|
|
685
|
+
margin-top: var(--flow-gap-lg);
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
/* Code block — one definition for every fenced snippet in the UI. */
|
|
689
|
+
.code-block,
|
|
690
|
+
.modal-body pre {
|
|
691
|
+
display: block;
|
|
692
|
+
padding: 0.6875rem 0.875rem;
|
|
693
|
+
background: var(--bg-primary);
|
|
694
|
+
border: 1px solid var(--border-color);
|
|
695
|
+
border-radius: var(--radius-sm);
|
|
696
|
+
font-family: var(--font-mono);
|
|
697
|
+
font-size: 0.78rem;
|
|
698
|
+
line-height: 1.6;
|
|
699
|
+
color: var(--text-primary);
|
|
700
|
+
white-space: pre;
|
|
701
|
+
overflow-x: auto;
|
|
702
|
+
tab-size: 2;
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
.code-block-wrap {
|
|
706
|
+
white-space: pre-wrap;
|
|
707
|
+
word-break: break-word;
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
/* Callout — an inline notice inside a panel or modal. */
|
|
711
|
+
.callout {
|
|
712
|
+
display: flex;
|
|
713
|
+
align-items: flex-start;
|
|
714
|
+
gap: 0.5rem;
|
|
715
|
+
padding: 0.75rem 0.875rem;
|
|
716
|
+
border: 1px solid var(--border-color);
|
|
717
|
+
border-radius: var(--radius-sm);
|
|
718
|
+
margin-bottom: 1rem;
|
|
719
|
+
font-size: 0.8125rem;
|
|
720
|
+
line-height: 1.6;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
.callout .icon {
|
|
724
|
+
margin-top: 0.22rem;
|
|
725
|
+
width: 0.875rem;
|
|
726
|
+
height: 0.875rem;
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
.callout p {
|
|
730
|
+
margin: 0.25rem 0 0;
|
|
731
|
+
color: var(--text-secondary);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
.callout-warning {
|
|
735
|
+
background: var(--amber-soft);
|
|
736
|
+
border-color: var(--amber-line);
|
|
737
|
+
color: var(--accent-amber);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
.callout-danger {
|
|
741
|
+
background: var(--rose-soft);
|
|
742
|
+
border-color: var(--rose-line);
|
|
743
|
+
color: var(--accent-rose);
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
/* Page-level flash sits above the header, like .db-error-banner. */
|
|
747
|
+
.page-notice {
|
|
748
|
+
margin-bottom: 1.25rem;
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
/* Toast notification — one definition for every page. */
|
|
481
752
|
.toast {
|
|
482
753
|
position: fixed;
|
|
483
754
|
bottom: 1.5rem;
|
|
484
755
|
right: 1.5rem;
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
border
|
|
756
|
+
max-width: 26rem;
|
|
757
|
+
padding: 0.625rem 0.875rem;
|
|
758
|
+
background: var(--bg-tertiary);
|
|
759
|
+
border: 1px solid var(--border-strong);
|
|
760
|
+
border-radius: var(--radius);
|
|
489
761
|
color: var(--text-primary);
|
|
490
|
-
font-size: 0.
|
|
491
|
-
box-shadow:
|
|
492
|
-
transform: translateY(
|
|
762
|
+
font-size: 0.8125rem;
|
|
763
|
+
box-shadow: var(--shadow-2);
|
|
764
|
+
transform: translateY(0.5rem);
|
|
493
765
|
opacity: 0;
|
|
494
|
-
|
|
495
|
-
|
|
766
|
+
visibility: hidden;
|
|
767
|
+
transition: opacity 0.18s ease, transform 0.18s ease, visibility 0.18s;
|
|
768
|
+
z-index: 2000;
|
|
496
769
|
}
|
|
497
770
|
|
|
498
771
|
.toast.show {
|
|
499
772
|
transform: translateY(0);
|
|
500
773
|
opacity: 1;
|
|
774
|
+
visibility: visible;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.toast.success,
|
|
778
|
+
.toast.toast-success {
|
|
779
|
+
border-color: var(--green-line);
|
|
780
|
+
background: var(--green-soft);
|
|
501
781
|
}
|
|
502
782
|
|
|
503
|
-
.toast.
|
|
504
|
-
|
|
783
|
+
.toast.error,
|
|
784
|
+
.toast.toast-error {
|
|
785
|
+
border-color: var(--rose-line);
|
|
786
|
+
background: var(--rose-soft);
|
|
505
787
|
}
|
|
506
788
|
|
|
507
|
-
.toast.
|
|
508
|
-
|
|
789
|
+
.toast.warning,
|
|
790
|
+
.toast.toast-warning {
|
|
791
|
+
border-color: var(--amber-line);
|
|
792
|
+
background: var(--amber-soft);
|
|
509
793
|
}
|
|
510
794
|
|
|
511
795
|
/* Modal */
|
|
512
796
|
.modal {
|
|
513
797
|
position: fixed;
|
|
514
798
|
inset: 0;
|
|
515
|
-
background: rgba(
|
|
799
|
+
background: rgba(10, 11, 12, 0.72);
|
|
516
800
|
display: flex;
|
|
517
801
|
align-items: center;
|
|
518
802
|
justify-content: center;
|
|
803
|
+
padding: 1.5rem;
|
|
519
804
|
z-index: 1000;
|
|
520
805
|
}
|
|
521
806
|
|
|
522
807
|
.modal-content {
|
|
523
808
|
background: var(--bg-card);
|
|
524
|
-
border: 1px solid var(--border-
|
|
525
|
-
border-radius:
|
|
809
|
+
border: 1px solid var(--border-strong);
|
|
810
|
+
border-radius: var(--radius);
|
|
811
|
+
box-shadow: var(--shadow-3);
|
|
526
812
|
max-width: 900px;
|
|
527
|
-
width:
|
|
813
|
+
width: 100%;
|
|
528
814
|
max-height: 90vh;
|
|
529
815
|
overflow: auto;
|
|
530
816
|
scrollbar-width: thin;
|
|
@@ -578,21 +864,25 @@
|
|
|
578
864
|
}
|
|
579
865
|
|
|
580
866
|
.modal-close {
|
|
581
|
-
width:
|
|
582
|
-
height:
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
867
|
+
width: 1.75rem;
|
|
868
|
+
height: 1.75rem;
|
|
869
|
+
display: inline-flex;
|
|
870
|
+
align-items: center;
|
|
871
|
+
justify-content: center;
|
|
872
|
+
background: transparent;
|
|
873
|
+
border: 1px solid transparent;
|
|
874
|
+
border-radius: var(--radius-sm);
|
|
586
875
|
color: var(--text-muted);
|
|
587
876
|
font-size: 1.125rem;
|
|
877
|
+
line-height: 1;
|
|
588
878
|
cursor: pointer;
|
|
589
|
-
transition:
|
|
879
|
+
transition: background-color 0.12s ease, color 0.12s ease;
|
|
590
880
|
}
|
|
591
881
|
|
|
592
882
|
.modal-close:hover {
|
|
593
|
-
background: var(--
|
|
594
|
-
border-color: var(--
|
|
595
|
-
color:
|
|
883
|
+
background: var(--bg-tertiary);
|
|
884
|
+
border-color: var(--border-color);
|
|
885
|
+
color: var(--text-primary);
|
|
596
886
|
}
|
|
597
887
|
|
|
598
888
|
.modal-body {
|
|
@@ -611,18 +901,66 @@
|
|
|
611
901
|
align-items: flex-start;
|
|
612
902
|
}
|
|
613
903
|
|
|
904
|
+
.header-actions {
|
|
905
|
+
width: 100%;
|
|
906
|
+
flex-wrap: wrap;
|
|
907
|
+
}
|
|
908
|
+
|
|
614
909
|
.report-header {
|
|
615
910
|
flex-direction: column;
|
|
911
|
+
gap: 0.75rem;
|
|
616
912
|
}
|
|
617
913
|
|
|
618
914
|
.report-actions {
|
|
619
915
|
width: 100%;
|
|
916
|
+
flex-wrap: wrap;
|
|
620
917
|
}
|
|
621
918
|
|
|
622
|
-
|
|
919
|
+
/* Only action bars stretch their buttons — elsewhere a stretched button
|
|
920
|
+
overruns the label sitting next to it. */
|
|
921
|
+
.header-actions .btn,
|
|
922
|
+
.report-actions .btn,
|
|
923
|
+
.modal-actions .btn {
|
|
623
924
|
flex: 1;
|
|
624
925
|
justify-content: center;
|
|
625
926
|
}
|
|
927
|
+
|
|
928
|
+
/* The selectors take a line of their own instead of squeezing the trail. */
|
|
929
|
+
.breadcrumb {
|
|
930
|
+
flex-wrap: wrap;
|
|
931
|
+
row-gap: 0.5rem;
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
.breadcrumb-spacer {
|
|
935
|
+
flex-basis: 100%;
|
|
936
|
+
}
|
|
937
|
+
|
|
938
|
+
.results-header {
|
|
939
|
+
flex-direction: column;
|
|
940
|
+
align-items: flex-start;
|
|
941
|
+
gap: 0.5rem;
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
.results-meta {
|
|
945
|
+
flex-wrap: wrap;
|
|
946
|
+
gap: 0.25rem 0.75rem;
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
.modal {
|
|
950
|
+
padding: 0.75rem;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
.modal-large {
|
|
954
|
+
width: 100%;
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
/* Placed by `right`, a toast wider than the screen hangs off the left. */
|
|
958
|
+
.toast {
|
|
959
|
+
left: 0.875rem;
|
|
960
|
+
right: 0.875rem;
|
|
961
|
+
bottom: 0.875rem;
|
|
962
|
+
max-width: none;
|
|
963
|
+
}
|
|
626
964
|
}
|
|
627
965
|
|
|
628
966
|
/* ============================================
|
|
@@ -677,7 +1015,7 @@
|
|
|
677
1015
|
color: var(--text-secondary);
|
|
678
1016
|
border: 1px solid var(--border-color);
|
|
679
1017
|
border-radius: 6px;
|
|
680
|
-
box-shadow:
|
|
1018
|
+
box-shadow: var(--shadow-2);
|
|
681
1019
|
font-size: 0.75rem;
|
|
682
1020
|
font-weight: 400;
|
|
683
1021
|
line-height: 1.5;
|
|
@@ -797,7 +1135,7 @@
|
|
|
797
1135
|
}
|
|
798
1136
|
|
|
799
1137
|
.query-item:hover {
|
|
800
|
-
border-color: var(--
|
|
1138
|
+
border-color: var(--border-strong);
|
|
801
1139
|
}
|
|
802
1140
|
|
|
803
1141
|
.query-item:last-child {
|
|
@@ -917,7 +1255,7 @@
|
|
|
917
1255
|
background: var(--bg-card);
|
|
918
1256
|
border: 1px solid var(--border-color);
|
|
919
1257
|
border-radius: 6px;
|
|
920
|
-
box-shadow:
|
|
1258
|
+
box-shadow: var(--shadow-2);
|
|
921
1259
|
z-index: 1000;
|
|
922
1260
|
min-width: 160px;
|
|
923
1261
|
overflow: hidden;
|
|
@@ -961,7 +1299,7 @@
|
|
|
961
1299
|
background: var(--bg-card);
|
|
962
1300
|
border: 1px solid var(--border-color);
|
|
963
1301
|
border-radius: 6px;
|
|
964
|
-
box-shadow:
|
|
1302
|
+
box-shadow: var(--shadow-2);
|
|
965
1303
|
z-index: 100;
|
|
966
1304
|
overflow: hidden;
|
|
967
1305
|
}
|
|
@@ -985,24 +1323,6 @@
|
|
|
985
1323
|
color: var(--text-primary);
|
|
986
1324
|
}
|
|
987
1325
|
|
|
988
|
-
.btn-small {
|
|
989
|
-
height: 30px;
|
|
990
|
-
padding: 0 0.875rem;
|
|
991
|
-
font-size: 0.75rem;
|
|
992
|
-
line-height: 1;
|
|
993
|
-
}
|
|
994
|
-
|
|
995
|
-
.btn-danger {
|
|
996
|
-
background: var(--accent-rose);
|
|
997
|
-
color: white;
|
|
998
|
-
border-color: var(--accent-rose);
|
|
999
|
-
}
|
|
1000
|
-
|
|
1001
|
-
.btn-danger:hover {
|
|
1002
|
-
opacity: 0.9;
|
|
1003
|
-
transform: translateY(-1px);
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
1326
|
/* IDE Settings Modal */
|
|
1007
1327
|
.settings-label {
|
|
1008
1328
|
color: var(--text-secondary);
|
|
@@ -1029,13 +1349,13 @@
|
|
|
1029
1349
|
}
|
|
1030
1350
|
|
|
1031
1351
|
.ide-option:hover {
|
|
1032
|
-
background: var(--bg-
|
|
1033
|
-
border-color: var(--
|
|
1352
|
+
background: var(--bg-hover);
|
|
1353
|
+
border-color: var(--border-strong);
|
|
1034
1354
|
}
|
|
1035
1355
|
|
|
1036
1356
|
.ide-option:has(input:checked) {
|
|
1037
|
-
background:
|
|
1038
|
-
border-color: var(--
|
|
1357
|
+
background: var(--purple-soft);
|
|
1358
|
+
border-color: var(--purple-line);
|
|
1039
1359
|
}
|
|
1040
1360
|
|
|
1041
1361
|
.ide-option input[type="radio"] {
|
|
@@ -1081,12 +1401,14 @@
|
|
|
1081
1401
|
}
|
|
1082
1402
|
|
|
1083
1403
|
.db-selector {
|
|
1084
|
-
background: var(--bg-
|
|
1404
|
+
background: var(--bg-tertiary);
|
|
1085
1405
|
color: var(--text-primary);
|
|
1086
|
-
border: 1px solid var(--border-color
|
|
1087
|
-
border-radius:
|
|
1088
|
-
|
|
1089
|
-
|
|
1406
|
+
border: 1px solid var(--border-color);
|
|
1407
|
+
border-radius: var(--radius-sm);
|
|
1408
|
+
height: var(--control-h-sm);
|
|
1409
|
+
padding: 0 0.5rem;
|
|
1410
|
+
font-family: inherit;
|
|
1411
|
+
font-size: 0.8125rem;
|
|
1090
1412
|
cursor: pointer;
|
|
1091
1413
|
width: auto;
|
|
1092
1414
|
max-width: 100%;
|
|
@@ -1098,13 +1420,12 @@
|
|
|
1098
1420
|
}
|
|
1099
1421
|
|
|
1100
1422
|
.db-selector:hover {
|
|
1101
|
-
border-color: var(--
|
|
1423
|
+
border-color: var(--border-strong);
|
|
1102
1424
|
}
|
|
1103
1425
|
|
|
1104
|
-
.db-selector:focus {
|
|
1105
|
-
outline:
|
|
1106
|
-
|
|
1107
|
-
box-shadow: 0 0 0 2px rgba(107, 159, 232, 0.2);
|
|
1426
|
+
.db-selector:focus-visible {
|
|
1427
|
+
outline: 2px solid var(--accent-blue);
|
|
1428
|
+
outline-offset: 1px;
|
|
1108
1429
|
}
|
|
1109
1430
|
|
|
1110
1431
|
.db-selector-static {
|
|
@@ -1124,11 +1445,11 @@
|
|
|
1124
1445
|
align-items: center;
|
|
1125
1446
|
gap: 0.375rem;
|
|
1126
1447
|
padding: 0.375rem 0.625rem;
|
|
1127
|
-
background:
|
|
1128
|
-
border: 1px solid
|
|
1129
|
-
border-radius:
|
|
1448
|
+
background: var(--rose-soft);
|
|
1449
|
+
border: 1px solid var(--rose-line);
|
|
1450
|
+
border-radius: var(--radius-sm);
|
|
1130
1451
|
font-size: 0.8125rem;
|
|
1131
|
-
color: var(--accent-red
|
|
1452
|
+
color: var(--accent-red);
|
|
1132
1453
|
cursor: help;
|
|
1133
1454
|
}
|
|
1134
1455
|
|
|
@@ -1136,47 +1457,123 @@
|
|
|
1136
1457
|
flex: 1;
|
|
1137
1458
|
}
|
|
1138
1459
|
|
|
1139
|
-
.breadcrumb {
|
|
1140
|
-
display: flex;
|
|
1141
|
-
align-items: center;
|
|
1142
|
-
gap: 0.5rem;
|
|
1143
|
-
}
|
|
1144
|
-
|
|
1145
1460
|
.db-error-banner {
|
|
1146
|
-
background:
|
|
1147
|
-
border: 1px solid
|
|
1148
|
-
border-radius:
|
|
1149
|
-
padding: 0.875rem
|
|
1461
|
+
background: var(--rose-soft);
|
|
1462
|
+
border: 1px solid var(--rose-line);
|
|
1463
|
+
border-radius: var(--radius);
|
|
1464
|
+
padding: 0.875rem 1rem;
|
|
1150
1465
|
margin-bottom: 1rem;
|
|
1151
1466
|
display: flex;
|
|
1152
1467
|
flex-direction: column;
|
|
1153
|
-
|
|
1468
|
+
align-items: flex-start;
|
|
1469
|
+
gap: var(--flow-gap);
|
|
1154
1470
|
}
|
|
1155
1471
|
|
|
1156
1472
|
.db-error-banner strong {
|
|
1157
|
-
color: var(--accent-red
|
|
1158
|
-
font-
|
|
1473
|
+
color: var(--accent-red);
|
|
1474
|
+
font-weight: 600;
|
|
1159
1475
|
}
|
|
1160
1476
|
|
|
1161
1477
|
.db-error-banner span {
|
|
1162
|
-
font-size: 0.875rem;
|
|
1163
1478
|
color: var(--text-secondary);
|
|
1164
1479
|
}
|
|
1165
1480
|
|
|
1166
1481
|
.db-error-banner code {
|
|
1167
|
-
font-family:
|
|
1168
|
-
font-size: 0.
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
border
|
|
1482
|
+
font-family: var(--font-mono);
|
|
1483
|
+
font-size: 0.78rem;
|
|
1484
|
+
line-height: 1.6;
|
|
1485
|
+
background: var(--bg-primary);
|
|
1486
|
+
border: 1px solid var(--border-color);
|
|
1487
|
+
padding: 0.5rem 0.75rem;
|
|
1488
|
+
border-radius: var(--radius-sm);
|
|
1172
1489
|
color: var(--text-primary);
|
|
1173
|
-
|
|
1174
|
-
|
|
1490
|
+
max-width: 100%;
|
|
1491
|
+
overflow-x: auto;
|
|
1492
|
+
}
|
|
1493
|
+
|
|
1494
|
+
/* Responsive, for the panels defined above this point. */
|
|
1495
|
+
@media (max-width: 768px) {
|
|
1496
|
+
.query-monitoring-header {
|
|
1497
|
+
flex-direction: column;
|
|
1498
|
+
align-items: flex-start;
|
|
1499
|
+
gap: 0.75rem;
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
.query-monitoring-title {
|
|
1503
|
+
flex-wrap: wrap;
|
|
1504
|
+
}
|
|
1505
|
+
|
|
1506
|
+
.query-monitoring-controls {
|
|
1507
|
+
width: 100%;
|
|
1508
|
+
flex-wrap: wrap;
|
|
1509
|
+
}
|
|
1510
|
+
|
|
1511
|
+
/* Anchored to its chip, this tooltip runs off the screen and stretches
|
|
1512
|
+
the page with it; on a phone it reads as a bottom sheet instead. */
|
|
1513
|
+
.query-monitoring-scope::after {
|
|
1514
|
+
position: fixed;
|
|
1515
|
+
inset: auto 0.875rem 0.875rem;
|
|
1516
|
+
width: auto;
|
|
1517
|
+
max-width: none;
|
|
1518
|
+
}
|
|
1175
1519
|
}
|
|
1176
1520
|
</style>
|
|
1177
1521
|
</head>
|
|
1178
1522
|
<body>
|
|
1523
|
+
<%# Icon sprite. One definition per glyph, referenced with
|
|
1524
|
+
<svg class="icon"><use href="#i-name"></use></svg>. Stroke-drawn and
|
|
1525
|
+
colourless so every icon inherits its context's colour and size. %>
|
|
1526
|
+
<svg width="0" height="0" aria-hidden="true" focusable="false" style="position:absolute">
|
|
1527
|
+
<defs>
|
|
1528
|
+
<symbol id="i-queries" viewBox="0 0 24 24"><path d="M13 2 4 14h7l-1 8 9-12h-7l1-8Z"/></symbol>
|
|
1529
|
+
<symbol id="i-indexes" viewBox="0 0 24 24"><path d="M8 6h13M8 12h13M8 18h13M3.5 6h.01M3.5 12h.01M3.5 18h.01"/></symbol>
|
|
1530
|
+
<symbol id="i-tables" viewBox="0 0 24 24"><rect x="3" y="4" width="18" height="16" rx="2"/><path d="M3 9.5h18M9 9.5V20"/></symbol>
|
|
1531
|
+
<symbol id="i-connections" viewBox="0 0 24 24"><path d="M9 2v6M15 2v6M6 8h12v4a6 6 0 0 1-12 0V8ZM12 18v4"/></symbol>
|
|
1532
|
+
<symbol id="i-system" viewBox="0 0 24 24"><rect x="2.5" y="4" width="19" height="12" rx="2"/><path d="M8 20h8M12 16v4"/></symbol>
|
|
1533
|
+
<symbol id="i-schema" viewBox="0 0 24 24"><circle cx="11" cy="11" r="7"/><path d="m20 20-4.2-4.2"/></symbol>
|
|
1534
|
+
<symbol id="i-link" viewBox="0 0 24 24"><path d="M10 13a5 5 0 0 0 7.5.5l3-3a5 5 0 0 0-7-7L11.8 5.2"/><path d="M14 11a5 5 0 0 0-7.5-.5l-3 3a5 5 0 0 0 7 7l1.7-1.7"/></symbol>
|
|
1535
|
+
<symbol id="i-activity" viewBox="0 0 24 24"><path d="M3 12h4l3 8 4-16 3 8h4"/></symbol>
|
|
1536
|
+
<symbol id="i-database" viewBox="0 0 24 24"><ellipse cx="12" cy="5.5" rx="8" ry="3.5"/><path d="M4 5.5v13c0 1.9 3.6 3.5 8 3.5s8-1.6 8-3.5v-13M4 12c0 1.9 3.6 3.5 8 3.5s8-1.6 8-3.5"/></symbol>
|
|
1537
|
+
<symbol id="i-clock" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 7v5.2l3.2 2"/></symbol>
|
|
1538
|
+
<symbol id="i-lock" viewBox="0 0 24 24"><rect x="4" y="10.5" width="16" height="10.5" rx="2"/><path d="M8 10.5V7a4 4 0 0 1 8 0v3.5"/></symbol>
|
|
1539
|
+
<symbol id="i-settings" viewBox="0 0 24 24"><circle cx="12" cy="12" r="3.2"/><path d="M19.4 14.6a1.7 1.7 0 0 0 .34 1.87l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.7 1.7 0 0 0-1.87-.34 1.7 1.7 0 0 0-1.03 1.56V21a2 2 0 1 1-4 0v-.1A1.7 1.7 0 0 0 8.9 19.3a1.7 1.7 0 0 0-1.87.34l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.7 1.7 0 0 0 .34-1.87 1.7 1.7 0 0 0-1.56-1.03H3a2 2 0 1 1 0-4h.1A1.7 1.7 0 0 0 4.7 8.9a1.7 1.7 0 0 0-.34-1.87l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.7 1.7 0 0 0 1.87.34H9.1A1.7 1.7 0 0 0 10.13 3V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1.03 1.56 1.7 1.7 0 0 0 1.87-.34l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.7 1.7 0 0 0-.34 1.87v.08A1.7 1.7 0 0 0 21 10.13H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1.03Z"/></symbol>
|
|
1540
|
+
<symbol id="i-check" viewBox="0 0 24 24"><path d="m4.5 12.5 5 5 10-11"/></symbol>
|
|
1541
|
+
<symbol id="i-alert" viewBox="0 0 24 24"><path d="M12 3.5 2.8 19.5h18.4L12 3.5Z"/><path d="M12 9.5v4.2M12 17h.01"/></symbol>
|
|
1542
|
+
<symbol id="i-info" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M12 11v5.5M12 7.8h.01"/></symbol>
|
|
1543
|
+
<symbol id="i-play" viewBox="0 0 24 24"><path d="M7 4.5v15l13-7.5-13-7.5Z"/></symbol>
|
|
1544
|
+
<symbol id="i-pause" viewBox="0 0 24 24"><path d="M9 4.5v15M15 4.5v15"/></symbol>
|
|
1545
|
+
<symbol id="i-chevron-right" viewBox="0 0 24 24"><path d="m9.5 5.5 6.5 6.5-6.5 6.5"/></symbol>
|
|
1546
|
+
<symbol id="i-arrow-left" viewBox="0 0 24 24"><path d="M20 12H4.5M10.5 5.5 4 12l6.5 6.5"/></symbol>
|
|
1547
|
+
<symbol id="i-download" viewBox="0 0 24 24"><path d="M12 3.5v12M7 11l5 5 5-5M4 20h16"/></symbol>
|
|
1548
|
+
<symbol id="i-copy" viewBox="0 0 24 24"><rect x="9" y="9" width="12" height="12" rx="2"/><path d="M15 6V5a2 2 0 0 0-2-2H5a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h1"/></symbol>
|
|
1549
|
+
<symbol id="i-send" viewBox="0 0 24 24"><path d="M21 3 3 10.5l7 3 3 7L21 3Z"/></symbol>
|
|
1550
|
+
<symbol id="i-trash" viewBox="0 0 24 24"><path d="M4 6.5h16M9.5 6.5V4h5v2.5M6.5 6.5 7.4 20a1 1 0 0 0 1 1h7.2a1 1 0 0 0 1-1l.9-13.5"/></symbol>
|
|
1551
|
+
<symbol id="i-pin" viewBox="0 0 24 24"><path d="M9 3.5h6l-.8 5.2 3.3 3.3H6.5l3.3-3.3L9 3.5ZM12 12v8.5"/></symbol>
|
|
1552
|
+
<symbol id="i-file" viewBox="0 0 24 24"><path d="M14 3H7a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V8l-5-5Z"/><path d="M14 3v5h5"/></symbol>
|
|
1553
|
+
<symbol id="i-book" viewBox="0 0 24 24"><path d="M4 4.5A1.5 1.5 0 0 1 5.5 3H19v15H5.5A1.5 1.5 0 0 0 4 19.5v-15ZM4 19.5A1.5 1.5 0 0 0 5.5 21H19v-3"/></symbol>
|
|
1554
|
+
<symbol id="i-external" viewBox="0 0 24 24"><path d="M14 4h6v6M20 4l-8.5 8.5"/><path d="M18 14v5a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h5"/></symbol>
|
|
1555
|
+
<symbol id="i-bulb" viewBox="0 0 24 24"><path d="M9.5 18h5M10 21h4"/><path d="M12 3a6 6 0 0 0-3.5 10.9c.6.5 1 1.3 1 2.1h5c0-.8.4-1.6 1-2.1A6 6 0 0 0 12 3Z"/></symbol>
|
|
1556
|
+
<symbol id="i-question" viewBox="0 0 24 24"><circle cx="12" cy="12" r="9"/><path d="M9.5 9.5a2.5 2.5 0 1 1 3.4 2.3c-.6.2-.9.8-.9 1.4v.6M12 16.8h.01"/></symbol>
|
|
1557
|
+
<symbol id="i-sliders" viewBox="0 0 24 24"><path d="M4 7h10M18 7h2M4 17h4M12 17h8"/><circle cx="16" cy="7" r="2"/><circle cx="10" cy="17" r="2"/></symbol>
|
|
1558
|
+
</defs>
|
|
1559
|
+
</svg>
|
|
1560
|
+
|
|
1179
1561
|
<div class="container">
|
|
1562
|
+
<%# Redirects out of an unavailable report set flash[:alert]; without this
|
|
1563
|
+
the user would just land back on the dashboard with no explanation. %>
|
|
1564
|
+
<% if flash[:alert].present? %>
|
|
1565
|
+
<div class="callout callout-warning page-notice" role="alert">
|
|
1566
|
+
<svg class="icon" aria-hidden="true"><use href="#i-alert"></use></svg>
|
|
1567
|
+
<span><%= flash[:alert] %></span>
|
|
1568
|
+
</div>
|
|
1569
|
+
<% end %>
|
|
1570
|
+
<% if flash[:notice].present? %>
|
|
1571
|
+
<div class="callout page-notice" role="status">
|
|
1572
|
+
<svg class="icon" aria-hidden="true"><use href="#i-info"></use></svg>
|
|
1573
|
+
<span><%= flash[:notice] %></span>
|
|
1574
|
+
</div>
|
|
1575
|
+
<% end %>
|
|
1576
|
+
|
|
1180
1577
|
<%= yield %>
|
|
1181
1578
|
</div>
|
|
1182
1579
|
|
|
@@ -1219,6 +1616,24 @@
|
|
|
1219
1616
|
}
|
|
1220
1617
|
});
|
|
1221
1618
|
|
|
1619
|
+
// The "feature is disabled, here is how to enable it" panel. Four callers
|
|
1620
|
+
// had drifted into hand-spaced copies of this markup (<br><br>,
|
|
1621
|
+
// indentation, inline styles); they all render through here now.
|
|
1622
|
+
window.pgReportsDisabledNotice = function(title) {
|
|
1623
|
+
const i18n = PG_REPORTS_I18N.modals;
|
|
1624
|
+
const esc = (t) => String(t == null ? '' : t)
|
|
1625
|
+
.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1626
|
+
return [
|
|
1627
|
+
'<div class="error-message">',
|
|
1628
|
+
'<p class="error-title">' + esc(title) + '</p>',
|
|
1629
|
+
'<p>' + esc(i18n.query_execution_disabled_intro) + '</p>',
|
|
1630
|
+
'<pre class="code-block">PgReports.configure do |config|\n config.allow_raw_query_execution = true\nend</pre>',
|
|
1631
|
+
'<p>' + esc(i18n.query_execution_disabled_env_note) + '</p>',
|
|
1632
|
+
'<pre class="code-block">PG_REPORTS_ALLOW_RAW_QUERY_EXECUTION=true</pre>',
|
|
1633
|
+
'</div>'
|
|
1634
|
+
].join('');
|
|
1635
|
+
};
|
|
1636
|
+
|
|
1222
1637
|
function showToast(message, type = 'success') {
|
|
1223
1638
|
const toast = document.getElementById('toast');
|
|
1224
1639
|
toast.textContent = message;
|