good_pipeline 0.4.0 → 0.6.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/Appraisals +25 -0
- data/CHANGELOG.md +58 -0
- data/README.md +67 -11
- data/app/controllers/good_pipeline/frontends_controller.rb +18 -1
- data/app/controllers/good_pipeline/pipelines_controller.rb +254 -36
- data/app/controllers/good_pipeline/themes_controller.rb +15 -0
- data/app/frontend/good_pipeline/dashboard.css +407 -0
- data/app/frontend/good_pipeline/dashboard.js +542 -0
- data/app/helpers/good_pipeline/mermaid_diagram_builder.rb +225 -66
- data/app/helpers/good_pipeline/pipelines_helper.rb +89 -5
- data/app/jobs/good_pipeline/pipeline_callback_job.rb +2 -2
- data/app/jobs/good_pipeline/pipeline_reconciliation_job.rb +1 -2
- data/app/jobs/good_pipeline/step_finished_job.rb +6 -2
- data/app/models/good_pipeline/pipeline_record.rb +7 -4
- data/app/models/good_pipeline/step_record.rb +6 -3
- data/app/views/good_pipeline/pipelines/_actions.html.erb +28 -0
- data/app/views/good_pipeline/pipelines/_chain_links.html.erb +17 -29
- data/app/views/good_pipeline/pipelines/_diagram.html.erb +101 -0
- data/app/views/good_pipeline/pipelines/_filter_bar.html.erb +51 -0
- data/app/views/good_pipeline/pipelines/_kpi_strip.html.erb +74 -0
- data/app/views/good_pipeline/pipelines/_pager.html.erb +31 -0
- data/app/views/good_pipeline/pipelines/_row.html.erb +103 -0
- data/app/views/good_pipeline/pipelines/_row_detail.html.erb +93 -0
- data/app/views/good_pipeline/pipelines/_sidebar.html.erb +115 -0
- data/app/views/good_pipeline/pipelines/_steps_table.html.erb +46 -33
- data/app/views/good_pipeline/pipelines/_table.html.erb +33 -0
- data/app/views/good_pipeline/pipelines/_timeline.html.erb +55 -0
- data/app/views/good_pipeline/pipelines/_topbar.html.erb +54 -0
- data/app/views/good_pipeline/pipelines/definitions.html.erb +88 -55
- data/app/views/good_pipeline/pipelines/index.html.erb +31 -42
- data/app/views/good_pipeline/pipelines/show.html.erb +54 -47
- data/app/views/layouts/good_pipeline/application.html.erb +24 -153
- data/config/routes.rb +4 -0
- data/demo/config/environments/development.rb +3 -0
- data/demo/config/environments/test.rb +2 -1
- data/demo/db/migrate/20260319205325_create_good_jobs.rb +1 -1
- data/demo/db/migrate/20260319205326_create_good_pipeline_tables.rb +1 -1
- data/demo/db/migrate/20260810000000_add_good_pipeline_dashboard_indexes.rb +20 -0
- data/demo/db/seeds.rb +325 -11
- data/demo/docs/screenshots/definitions.png +0 -0
- data/demo/docs/screenshots/show.png +0 -0
- data/demo/test/good_pipeline/test_bulk_enqueue.rb +54 -1
- data/demo/test/good_pipeline/test_cancellation.rb +312 -0
- data/demo/test/good_pipeline/test_cleanup.rb +31 -1
- data/demo/test/good_pipeline/test_coordinator.rb +39 -0
- data/demo/test/good_pipeline/test_dashboard.rb +667 -0
- data/demo/test/good_pipeline/test_dashboard_rerun.rb +244 -0
- data/demo/test/good_pipeline/test_pipeline_callback_job.rb +11 -0
- data/demo/test/good_pipeline/test_pipeline_record.rb +30 -0
- data/demo/test/good_pipeline/test_runner.rb +40 -1
- data/demo/test/good_pipeline/test_step_record.rb +37 -0
- data/demo/test/integration/test_barrier_execution.rb +502 -0
- data/demo/test/integration/test_chain_locking.rb +54 -0
- data/demo/test/integration/test_pipeline_chaining.rb +96 -0
- data/demo/test/test_helper.rb +20 -0
- data/docs/architecture.md +45 -29
- data/docs/branching.md +4 -0
- data/docs/callbacks.md +9 -7
- data/docs/cleanup.md +2 -2
- data/docs/dag-validation.md +16 -0
- data/docs/dashboard.md +84 -22
- data/docs/defining-pipelines.md +34 -1
- data/docs/failure-strategies.md +24 -1
- data/docs/getting-started.md +9 -1
- data/docs/index.md +1 -1
- data/docs/introduction.md +4 -4
- data/docs/monitoring.md +8 -3
- data/docs/pipeline-chaining.md +17 -9
- data/docs/public/screenshots/definitions.png +0 -0
- data/docs/public/screenshots/index.png +0 -0
- data/docs/public/screenshots/show.png +0 -0
- data/docs/screenshots/definitions.png +0 -0
- data/docs/screenshots/index.png +0 -0
- data/docs/screenshots/show.png +0 -0
- data/gemfiles/rails_7_2.gemfile +24 -0
- data/gemfiles/rails_7_2.gemfile.lock +412 -0
- data/gemfiles/rails_8_0.gemfile +24 -0
- data/gemfiles/rails_8_0.gemfile.lock +411 -0
- data/gemfiles/rails_8_1.gemfile +24 -0
- data/gemfiles/rails_8_1.gemfile.lock +415 -0
- data/lib/generators/good_pipeline/install/templates/create_good_pipeline_tables.rb.erb +9 -0
- data/lib/generators/good_pipeline/upgrade/templates/add_good_pipeline_dashboard_indexes.rb.erb +27 -0
- data/lib/generators/good_pipeline/upgrade/upgrade_generator.rb +32 -0
- data/lib/good_pipeline/barrier_compiler.rb +106 -0
- data/lib/good_pipeline/chain_coordinator.rb +9 -5
- data/lib/good_pipeline/constants.rb +2 -0
- data/lib/good_pipeline/coordinator.rb +269 -140
- data/lib/good_pipeline/dashboard/connection_info.rb +67 -0
- data/lib/good_pipeline/dashboard/definition_stages.rb +59 -0
- data/lib/good_pipeline/dashboard/filter_set.rb +77 -0
- data/lib/good_pipeline/dashboard/kpi_calculator.rb +143 -0
- data/lib/good_pipeline/dashboard/sparkline.rb +73 -0
- data/lib/good_pipeline/dashboard/stage_lanes.rb +307 -0
- data/lib/good_pipeline/dashboard/step_timings.rb +50 -0
- data/lib/good_pipeline/dashboard.rb +21 -0
- data/lib/good_pipeline/errors.rb +11 -0
- data/lib/good_pipeline/pipeline.rb +14 -2
- data/lib/good_pipeline/step_definition.rb +16 -1
- data/lib/good_pipeline/version.rb +1 -1
- data/lib/good_pipeline.rb +7 -1
- data/mise.toml +1 -1
- metadata +48 -13
- data/app/frontend/good_pipeline/style.css +0 -597
- data/app/views/good_pipeline/pipelines/_pagination.html.erb +0 -24
- data/app/views/good_pipeline/pipelines/_pipeline_row.html.erb +0 -7
|
@@ -0,0 +1,407 @@
|
|
|
1
|
+
:root[data-gp-theme="dark"] {
|
|
2
|
+
--bg:#0c0d10;--bg-1:#111317;--bg-2:#15181d;--bg-3:#1a1e24;
|
|
3
|
+
--bg-row-hover:#16191f;--bg-row-open:#14171c;--bg-detail:#0e1014;
|
|
4
|
+
--border:#20242c;--border-strong:#2a2f38;
|
|
5
|
+
--fg:#e6e9ef;--fg-1:#c2c8d2;--fg-2:#8a92a0;--fg-3:#5d6573;--fg-4:#3f4651;
|
|
6
|
+
--accent:#d6deea;--selected:#1d2530;--selected-bar:#2c3a52;--conn:#4ea36b;
|
|
7
|
+
--st-succeeded:#4ea36b;--st-running:#6694e8;--st-failed:#d96565;
|
|
8
|
+
--st-halted:#c98a3f;--st-canceling:#d79a4a;--st-canceled:#929baa;--st-skipped:#6b7384;--st-pending:#6b7384;
|
|
9
|
+
--strat-halt:#d96565;--strat-continue:#6694e8;--strat-ignore:#6b7384;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
:root[data-gp-theme="light"] {
|
|
13
|
+
--bg:#f5f6f8;--bg-1:#ffffff;--bg-2:#fafbfc;--bg-3:#eef0f4;
|
|
14
|
+
--bg-row-hover:#f3f5f8;--bg-row-open:#f3f5f8;--bg-detail:#f9fafc;
|
|
15
|
+
--border:#e3e6eb;--border-strong:#cdd2da;
|
|
16
|
+
--fg:#0f1216;--fg-1:#2a2f38;--fg-2:#5b6471;--fg-3:#8a92a0;--fg-4:#b6bcc7;
|
|
17
|
+
--accent:#1a1d22;--selected:#e7eef9;--selected-bar:#c5d4ee;--conn:#2f8a52;
|
|
18
|
+
--st-succeeded:#2f8a52;--st-running:#2563d4;--st-failed:#c43a3a;
|
|
19
|
+
--st-halted:#b16a1f;--st-canceling:#874b0f;--st-canceled:#4f5867;--st-skipped:#6b7384;--st-pending:#6b7384;
|
|
20
|
+
--strat-halt:#c43a3a;--strat-continue:#2563d4;--strat-ignore:#6b7384;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
html[data-gp-theme], html[data-gp-theme] body { height:100%; margin:0; }
|
|
24
|
+
html[data-gp-theme] body {
|
|
25
|
+
color:var(--fg); background:var(--bg);
|
|
26
|
+
font:12.5px/1.4 "Inter",system-ui,-apple-system,"Segoe UI",sans-serif;
|
|
27
|
+
-webkit-font-smoothing:antialiased; font-feature-settings:"cv11","ss01";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.gp-app, .gp-app * { box-sizing:border-box; }
|
|
31
|
+
.gp-app { width:100%; height:100vh; color:var(--fg); background:var(--bg); }
|
|
32
|
+
/* Element resets are wrapped in :where() so they carry zero specificity and can
|
|
33
|
+
never outrank a single-class component rule. Without this, `.gp-app button`
|
|
34
|
+
(0,1,1) silently beats every component font-size such as `.gp-action` (0,1,0). */
|
|
35
|
+
:where(.gp-app) a { color:var(--fg-1); text-decoration:none; }
|
|
36
|
+
:where(.gp-app) a:hover { color:var(--fg); }
|
|
37
|
+
:where(.gp-app) :where(button, input) { font:inherit; }
|
|
38
|
+
.gp-app .mono, .gp-app code, .gp-app pre, .gp-app input, .gp-app .data {
|
|
39
|
+
font-family:"JetBrains Mono",ui-monospace,"SFMono-Regular",Menlo,monospace;
|
|
40
|
+
}
|
|
41
|
+
.gp-app button { cursor:pointer; }
|
|
42
|
+
.gp-app button:disabled { cursor:not-allowed; opacity:.52; }
|
|
43
|
+
.gp-app table { border-spacing:0; }
|
|
44
|
+
.gp-app ::-webkit-scrollbar { width:8px; height:8px; }
|
|
45
|
+
.gp-app ::-webkit-scrollbar-thumb { background:var(--border-strong); border-radius:4px; }
|
|
46
|
+
.gp-app ::-webkit-scrollbar-track { background:transparent; }
|
|
47
|
+
.gp-sr-only {
|
|
48
|
+
position:absolute!important; width:1px!important; height:1px!important; padding:0!important;
|
|
49
|
+
margin:-1px!important; overflow:hidden!important; clip:rect(0,0,0,0)!important;
|
|
50
|
+
white-space:nowrap!important; border:0!important;
|
|
51
|
+
}
|
|
52
|
+
.gp-flash {
|
|
53
|
+
position:fixed; z-index:1000; top:10px; right:12px; max-width:min(420px,calc(100vw - 24px));
|
|
54
|
+
box-sizing:border-box;
|
|
55
|
+
padding:8px 12px; border:1px solid var(--border-strong); border-radius:4px;
|
|
56
|
+
color:var(--fg); background:var(--bg-2); box-shadow:0 6px 24px color-mix(in oklab,var(--bg) 75%,transparent);
|
|
57
|
+
font:11px/1.4 "JetBrains Mono",monospace;
|
|
58
|
+
}
|
|
59
|
+
.gp-flash--notice { border-color:color-mix(in oklab,var(--st-succeeded) 45%,var(--border)); }
|
|
60
|
+
.gp-flash--alert { border-color:color-mix(in oklab,var(--st-failed) 50%,var(--border)); color:var(--st-failed); }
|
|
61
|
+
|
|
62
|
+
/* Shell */
|
|
63
|
+
.gp-app--dashboard, .gp-app--definitions { display:grid; grid-template-columns:264px minmax(0,1fr); overflow:hidden; }
|
|
64
|
+
.gp-app--detail { display:flex; flex-direction:column; overflow:hidden; }
|
|
65
|
+
.gp-main { display:flex; flex-direction:column; min-width:0; min-height:0; overflow:hidden; }
|
|
66
|
+
#gp-dashboard, #gp-kpi, #gp-table { display:contents; }
|
|
67
|
+
#gp-filters { display:flex; align-items:center; gap:10px; min-width:0; flex-wrap:wrap; }
|
|
68
|
+
#gp-kpi.is-loading .gp-kpi-strip, #gp-filters.is-loading, #gp-table.is-loading .gp-table-wrap,
|
|
69
|
+
#gp-table.is-loading .gp-pager { opacity:.6; pointer-events:none; }
|
|
70
|
+
.gp-kpi-strip, #gp-filters, .gp-table-wrap, .gp-pager { transition:opacity 120ms ease-in; }
|
|
71
|
+
|
|
72
|
+
/* Sidebar */
|
|
73
|
+
.gp-sidebar {
|
|
74
|
+
display:flex; flex-direction:column; min-width:0; overflow:hidden;
|
|
75
|
+
background:var(--bg-1); border-right:1px solid var(--border);
|
|
76
|
+
}
|
|
77
|
+
.gp-sidebar-head { padding:12px 12px 10px; border-bottom:1px solid var(--border); }
|
|
78
|
+
.gp-brand { display:flex; align-items:center; gap:6px; min-width:0; }
|
|
79
|
+
.gp-brand-mark {
|
|
80
|
+
width:18px; height:18px; display:inline-flex; flex:none; align-items:center; justify-content:center;
|
|
81
|
+
border-radius:4px; color:var(--bg); background:var(--accent); font:500 9px/1 "JetBrains Mono",monospace;
|
|
82
|
+
}
|
|
83
|
+
.gp-brand-name { color:var(--fg); font-weight:600; letter-spacing:-.01em; line-height:1; }
|
|
84
|
+
.gp-brand-version { color:var(--fg-3); font:10px/1 "JetBrains Mono",monospace; }
|
|
85
|
+
.gp-sidebar-scroll { flex:1; overflow-y:auto; padding:4px 0 8px; }
|
|
86
|
+
.gp-sidebar-group { margin-top:10px; }
|
|
87
|
+
.gp-sidebar-group-head {
|
|
88
|
+
display:flex; align-items:center; justify-content:space-between; padding:4px 14px;
|
|
89
|
+
color:var(--fg-3); font-size:10px; letter-spacing:.06em; text-transform:uppercase;
|
|
90
|
+
}
|
|
91
|
+
.gp-sidebar-group-count { color:var(--fg-4); font-family:"JetBrains Mono",monospace; font-variant-numeric:tabular-nums; }
|
|
92
|
+
.gp-sidebar-row {
|
|
93
|
+
position:relative; display:flex; align-items:center; justify-content:space-between;
|
|
94
|
+
width:calc(100% - 12px); min-height:27px; margin:0 6px; padding:5px 8px;
|
|
95
|
+
overflow:hidden; border:0; border-radius:3px; color:var(--fg-1); background:transparent;
|
|
96
|
+
font-family:inherit; font-size:12px; line-height:1.4; text-align:left;
|
|
97
|
+
}
|
|
98
|
+
.gp-sidebar-all { margin-top:14px; }
|
|
99
|
+
.gp-sidebar-row:hover { color:var(--fg); background:var(--bg-row-hover); }
|
|
100
|
+
.gp-sidebar-row.is-active { color:var(--fg); background:var(--selected); }
|
|
101
|
+
.gp-sidebar-row.is-active::before {
|
|
102
|
+
content:""; position:absolute; z-index:2; left:0; top:4px; bottom:4px; width:2px;
|
|
103
|
+
border-radius:1px; background:var(--accent);
|
|
104
|
+
}
|
|
105
|
+
.gp-sidebar-bar {
|
|
106
|
+
position:absolute; inset:0 auto 0 0; z-index:0; width:var(--gp-width,0%);
|
|
107
|
+
pointer-events:none; opacity:.6; background:var(--bg-2);
|
|
108
|
+
}
|
|
109
|
+
.gp-sidebar-row.is-active .gp-sidebar-bar { opacity:.7; background:var(--selected-bar); }
|
|
110
|
+
.gp-sidebar-label, .gp-sidebar-count { position:relative; z-index:1; }
|
|
111
|
+
.gp-sidebar-label { display:flex; align-items:center; gap:6px; min-width:0; overflow:hidden; white-space:nowrap; }
|
|
112
|
+
.gp-sidebar-name { overflow:hidden; text-overflow:ellipsis; }
|
|
113
|
+
.gp-sidebar-count { color:var(--fg-3); font:11px "JetBrains Mono",monospace; font-variant-numeric:tabular-nums; }
|
|
114
|
+
.gp-sidebar-dot { width:6px; height:6px; flex:none; border-radius:50%; background:var(--accent); }
|
|
115
|
+
.gp-sidebar-dot.strategy-halt { background:var(--strat-halt); }
|
|
116
|
+
.gp-sidebar-dot.strategy-continue { background:var(--strat-continue); }
|
|
117
|
+
.gp-sidebar-dot.strategy-ignore { background:var(--strat-ignore); }
|
|
118
|
+
.gp-sidebar-tag {
|
|
119
|
+
display:inline-flex; align-items:center; height:14px; padding:0 4px; border:1px solid var(--border-strong);
|
|
120
|
+
border-radius:2px; color:var(--fg-3); background:var(--bg-2); font:9px "JetBrains Mono",monospace;
|
|
121
|
+
}
|
|
122
|
+
.gp-sidebar-tag--xl { color:var(--st-halted); border-color:color-mix(in oklab,var(--st-halted) 30%,var(--border)); }
|
|
123
|
+
.gp-sidebar-foot {
|
|
124
|
+
display:flex; flex-direction:column; gap:6px; padding:8px 12px;
|
|
125
|
+
border-top:1px solid var(--border); background:var(--bg-1);
|
|
126
|
+
}
|
|
127
|
+
.gp-legend { display:flex; gap:10px; color:var(--fg-3); font:10px "JetBrains Mono",monospace; }
|
|
128
|
+
.gp-legend span { display:inline-flex; align-items:center; gap:4px; }
|
|
129
|
+
.gp-legend i { width:6px; height:6px; border-radius:50%; }
|
|
130
|
+
.gp-retention { display:flex; align-items:baseline; justify-content:space-between; font-size:10.5px; }
|
|
131
|
+
.gp-retention-label { color:var(--fg-3); font-size:9.5px; letter-spacing:.06em; text-transform:uppercase; }
|
|
132
|
+
.gp-retention-value { color:var(--fg-2); font-family:"JetBrains Mono",monospace; }
|
|
133
|
+
|
|
134
|
+
/* Topbar */
|
|
135
|
+
.gp-topbar {
|
|
136
|
+
height:38px; flex:none; display:flex; align-items:center; justify-content:space-between;
|
|
137
|
+
gap:12px; padding:0 14px; border-bottom:1px solid var(--border); background:var(--bg-1);
|
|
138
|
+
}
|
|
139
|
+
.gp-crumbs { display:flex; align-items:center; gap:8px; min-width:0; overflow:hidden; white-space:nowrap; }
|
|
140
|
+
.gp-crumb { color:var(--fg-2); font-size:12px; }
|
|
141
|
+
.gp-crumb--active { color:var(--fg); font-weight:500; overflow:hidden; text-overflow:ellipsis; }
|
|
142
|
+
.gp-crumb-sep { color:var(--fg-4); font-size:12px; }
|
|
143
|
+
.gp-crumb-meta { color:var(--fg-3); font-size:11px; overflow:hidden; text-overflow:ellipsis; }
|
|
144
|
+
.gp-back {
|
|
145
|
+
display:inline-flex; align-items:center; height:22px; padding:0 8px; border:1px solid var(--border);
|
|
146
|
+
border-radius:3px; color:var(--fg-2); background:var(--bg-2); font-size:12px;
|
|
147
|
+
}
|
|
148
|
+
.gp-topbar-right { display:flex; align-items:center; gap:8px; flex:none; }
|
|
149
|
+
.gp-theme-btn, .gp-diagram-btn {
|
|
150
|
+
display:inline-flex; align-items:center; justify-content:center; height:22px;
|
|
151
|
+
border:1px solid var(--border); border-radius:3px; color:var(--fg-1); background:var(--bg-2);
|
|
152
|
+
}
|
|
153
|
+
.gp-theme-btn { width:22px; font-size:13px; line-height:1; }
|
|
154
|
+
.gp-theme-btn:hover, .gp-diagram-btn:hover { background:var(--bg-3); color:var(--fg); }
|
|
155
|
+
.gp-connection, .gp-clock {
|
|
156
|
+
display:inline-flex; align-items:center; gap:6px; height:22px; padding:0 8px;
|
|
157
|
+
border:1px solid var(--border); border-radius:3px; background:var(--bg-2); font-size:11px;
|
|
158
|
+
}
|
|
159
|
+
.gp-connection-dot { width:6px; height:6px; border-radius:50%; background:var(--conn); box-shadow:0 0 0 2px color-mix(in oklab,var(--conn) 22%,transparent); }
|
|
160
|
+
.gp-clock, .gp-connection-version { color:var(--fg-3); font-family:"JetBrains Mono",monospace; }
|
|
161
|
+
|
|
162
|
+
/* Pills */
|
|
163
|
+
/* text-transform:none keeps a pill identical wherever it is nested. Without it a
|
|
164
|
+
pill placed inside an uppercased section heading renders "ON_FAILURE: CONTINUE"
|
|
165
|
+
while the same component renders lowercase elsewhere. */
|
|
166
|
+
.gp-status, .gp-status-pill, .badge, .gp-strategy {
|
|
167
|
+
display:inline-flex; align-items:center; height:16px; padding:0 5px;
|
|
168
|
+
border:1px solid var(--border-strong); border-radius:2px; background:var(--bg-2);
|
|
169
|
+
font:10px "JetBrains Mono",monospace; letter-spacing:.02em; text-transform:none; white-space:nowrap;
|
|
170
|
+
}
|
|
171
|
+
.gp-status--pending,.gp-status-pending,.badge-pending { --gp-status:var(--st-pending); }
|
|
172
|
+
.gp-status--running,.gp-status--enqueued,.gp-status-running,.gp-status-enqueued,.badge-running,.badge-enqueued { --gp-status:var(--st-running); }
|
|
173
|
+
.gp-status--canceling,.gp-status-canceling,.badge-canceling { --gp-status:var(--st-canceling); }
|
|
174
|
+
.gp-status--canceled,.gp-status-canceled,.badge-canceled { --gp-status:var(--st-canceled); }
|
|
175
|
+
.gp-status--succeeded,.gp-status-succeeded,.badge-succeeded { --gp-status:var(--st-succeeded); }
|
|
176
|
+
.gp-status--failed,.gp-status-failed,.badge-failed { --gp-status:var(--st-failed); }
|
|
177
|
+
.gp-status--halted,.gp-status-halted,.badge-halted { --gp-status:var(--st-halted); }
|
|
178
|
+
.gp-status--skipped,.gp-status--skipped_by_branch,.gp-status-skipped,.gp-status-skipped_by_branch,.badge-skipped,.badge-skipped_by_branch { --gp-status:var(--st-skipped); }
|
|
179
|
+
.gp-status, .gp-status-pill, .badge { color:var(--gp-status,var(--fg-2)); border-color:color-mix(in oklab,var(--gp-status,var(--fg-2)) 35%,var(--border)); background:color-mix(in oklab,var(--gp-status,var(--fg-2)) 8%,var(--bg-2)); }
|
|
180
|
+
.gp-strategy--halt { --gp-strategy:var(--strat-halt); }
|
|
181
|
+
.gp-strategy--continue { --gp-strategy:var(--strat-continue); }
|
|
182
|
+
.gp-strategy--ignore { --gp-strategy:var(--strat-ignore); }
|
|
183
|
+
.gp-strategy { color:var(--gp-strategy,var(--fg-2)); border-color:color-mix(in oklab,var(--gp-strategy,var(--fg-2)) 35%,var(--border)); background:color-mix(in oklab,var(--gp-strategy,var(--fg-2)) 8%,var(--bg-2)); }
|
|
184
|
+
|
|
185
|
+
/* KPI strip */
|
|
186
|
+
.gp-kpi-strip { display:grid; grid-template-columns:repeat(5,minmax(0,1fr)) minmax(120px,1.4fr); border-bottom:1px solid var(--border); background:var(--bg-1); }
|
|
187
|
+
.gp-kpi { display:flex; flex-direction:column; gap:2px; min-width:0; padding:10px 14px; border-right:1px solid var(--border); }
|
|
188
|
+
.gp-kpi:last-child { border-right:0; }
|
|
189
|
+
.gp-kpi-label { color:var(--fg-3); font-size:9.5px; letter-spacing:.07em; text-transform:uppercase; white-space:nowrap; }
|
|
190
|
+
.gp-kpi-value { color:var(--fg); font:500 18px "JetBrains Mono",monospace; font-variant-numeric:tabular-nums; white-space:nowrap; }
|
|
191
|
+
.gp-kpi-value--running { color:var(--st-running); }
|
|
192
|
+
.gp-kpi-value--failed { color:var(--st-failed); }
|
|
193
|
+
.gp-kpi-sub { color:var(--fg-3); font:11px "JetBrains Mono",monospace; white-space:nowrap; }
|
|
194
|
+
.gp-spark { display:flex; align-items:flex-end; gap:2px; height:28px; margin-top:4px; }
|
|
195
|
+
.gp-spark-bar { flex:1; min-height:1px; height:var(--gp-height,1%); border-radius:1px; background:var(--fg-3); opacity:.7; }
|
|
196
|
+
.gp-spark-bar:nth-last-child(-n+3) { background:var(--accent); opacity:1; }
|
|
197
|
+
|
|
198
|
+
/* Filters */
|
|
199
|
+
.gp-filter-bar { display:flex; align-items:center; gap:10px; padding:8px 14px; border-bottom:1px solid var(--border); background:var(--bg-1); flex-wrap:wrap; }
|
|
200
|
+
.gp-search-form { flex:1 1 260px; min-width:220px; }
|
|
201
|
+
.gp-search {
|
|
202
|
+
display:flex; align-items:center; gap:6px; width:100%; height:26px; padding:4px 8px;
|
|
203
|
+
border:1px solid var(--border); border-radius:4px; color:var(--fg-3); background:var(--bg-2);
|
|
204
|
+
}
|
|
205
|
+
.gp-search svg { width:12px; height:12px; flex:none; }
|
|
206
|
+
.gp-search input { flex:1; min-width:0; padding:0; border:0; outline:0; color:var(--fg); background:transparent; font-size:11.5px; }
|
|
207
|
+
.gp-status-filter-scroll { flex:0 1 auto; min-width:0; max-width:100%; overflow-x:auto; overflow-y:hidden; }
|
|
208
|
+
/* Segment children use inline layout, not flex centring: a flex row would centre
|
|
209
|
+
the 11.5px label box against the 9.5px count box and their baselines would
|
|
210
|
+
diverge. `--gp-segment-line` is the segment's inner height (26px - 2px border),
|
|
211
|
+
so line-height alone centres a single shared baseline. */
|
|
212
|
+
.gp-segment { --gp-segment-line:24px; display:inline-flex; align-items:stretch; height:26px; border:1px solid var(--border); border-radius:4px; overflow:hidden; background:var(--bg-2); }
|
|
213
|
+
.gp-segment-label { display:block; padding:0 8px; border-right:1px solid var(--border); color:var(--fg-3); background:var(--bg-3); font-size:10px; line-height:var(--gp-segment-line); letter-spacing:.06em; text-transform:uppercase; }
|
|
214
|
+
.gp-segment-link { display:block; padding:0 9px; border-right:1px solid var(--border); color:var(--fg-2); font-size:11.5px; line-height:var(--gp-segment-line); white-space:nowrap; }
|
|
215
|
+
.gp-segment-count { margin-left:5px; color:var(--fg-3); font-family:"JetBrains Mono",monospace; font-size:9.5px; font-variant-numeric:tabular-nums; }
|
|
216
|
+
.gp-segment-link.is-active .gp-segment-count { color:var(--fg-1); }
|
|
217
|
+
.gp-segment-link:last-child { border-right:0; }
|
|
218
|
+
.gp-segment-link:hover { color:var(--fg); background:var(--bg-row-hover); }
|
|
219
|
+
.gp-segment-link.is-active { color:var(--fg); background:var(--selected); }
|
|
220
|
+
.gp-filter-clear { display:inline-flex; align-items:center; height:26px; padding:0 10px; border:1px solid var(--border); border-radius:4px; color:var(--fg-2); font-size:11.5px; }
|
|
221
|
+
.gp-filter-clear:hover { color:var(--fg); border-color:var(--border-strong); }
|
|
222
|
+
|
|
223
|
+
/* Execution table */
|
|
224
|
+
.gp-table-wrap { flex:1; min-height:0; overflow:auto; background:var(--bg); }
|
|
225
|
+
.gp-table { width:100%; border-collapse:collapse; table-layout:fixed; font-size:12px; }
|
|
226
|
+
.gp-table thead th {
|
|
227
|
+
position:sticky; top:0; z-index:3; padding:7px 10px; border-bottom:1px solid var(--border);
|
|
228
|
+
color:var(--fg-3); background:var(--bg-1); text-align:left; font-size:10px; font-weight:500;
|
|
229
|
+
letter-spacing:.07em; text-transform:uppercase;
|
|
230
|
+
}
|
|
231
|
+
.gp-table .gp-th-expand { width:24px; padding-right:0; }
|
|
232
|
+
/* Fits "YYYY-MM-DD HH:MM:SSZ" (135px at 10.5px JetBrains Mono) plus the cell's
|
|
233
|
+
20px horizontal padding, so the absolute timestamp is never ellipsised. */
|
|
234
|
+
.gp-table .gp-th-started { width:158px; }
|
|
235
|
+
.gp-table .gp-th-steps { width:160px; }
|
|
236
|
+
.gp-table .gp-th-status { width:110px; }
|
|
237
|
+
.gp-table .gp-th-duration { width:90px; }
|
|
238
|
+
.gp-row { cursor:pointer; }
|
|
239
|
+
.gp-row > td { padding:6px 10px; border-bottom:1px solid var(--border); vertical-align:middle; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; }
|
|
240
|
+
.gp-row > .gp-td-expand { padding-right:0; color:var(--fg-3); }
|
|
241
|
+
.gp-row:hover > td { background:var(--bg-row-hover); }
|
|
242
|
+
.gp-row.is-open > td { border-bottom-color:transparent; background:var(--bg-row-open); }
|
|
243
|
+
.gp-when-rel { color:var(--fg); font:11.5px "JetBrains Mono",monospace; font-variant-numeric:tabular-nums; }
|
|
244
|
+
.gp-when-abs { color:var(--fg-3); font:10.5px "JetBrains Mono",monospace; font-variant-numeric:tabular-nums; }
|
|
245
|
+
/* Only the pipeline name may truncate. The id and the two icon affordances are
|
|
246
|
+
flex:none so a long name can never clip the copy/open controls out of view. */
|
|
247
|
+
.gp-execution-cell { display:flex; align-items:center; min-width:0; }
|
|
248
|
+
.gp-execution-name { flex:0 1 auto; min-width:0; overflow:hidden; color:var(--fg); font-weight:500; text-overflow:ellipsis; white-space:nowrap; }
|
|
249
|
+
.gp-execution-id { flex:none; margin-left:6px; color:var(--fg-2); font:11.5px "JetBrains Mono",monospace; }
|
|
250
|
+
/* Both icon affordances share one fixed 14px box. Sizing them by their contents
|
|
251
|
+
gave the SVG an 11px box and the text glyph a 16.8px line box, so they sat on
|
|
252
|
+
visibly different centres. */
|
|
253
|
+
.gp-copy, .gp-open-detail {
|
|
254
|
+
display:inline-flex; align-items:center; justify-content:center; flex:none;
|
|
255
|
+
width:14px; height:14px; padding:0; margin-left:4px; line-height:1;
|
|
256
|
+
border:0; color:var(--fg-3); background:transparent; vertical-align:middle;
|
|
257
|
+
}
|
|
258
|
+
.gp-copy:hover, .gp-open-detail:hover { color:var(--fg); }
|
|
259
|
+
.gp-copy svg, .gp-open-detail svg { display:block; width:11px; height:11px; }
|
|
260
|
+
.gp-step-dots { display:inline-flex; align-items:center; gap:3px; margin-right:6px; vertical-align:middle; }
|
|
261
|
+
.gp-step-dot { display:inline-block; width:6px; height:6px; border-radius:50%; background:var(--gp-status); opacity:var(--gp-opacity,1); }
|
|
262
|
+
.gp-step-dot.is-branch { border-radius:1px; transform:rotate(45deg) scale(.9); }
|
|
263
|
+
.gp-step-dot.is-barrier { border-radius:1px; box-shadow:inset 1px 0 var(--bg),inset -1px 0 var(--bg); }
|
|
264
|
+
.gp-step-stack { display:inline-flex; align-items:center; width:84px; height:8px; margin-right:6px; overflow:hidden; border-radius:2px; vertical-align:middle; background:var(--bg-3); }
|
|
265
|
+
.gp-step-stack > span { display:block; height:100%; width:var(--gp-width); background:var(--gp-status); opacity:var(--gp-opacity,1); }
|
|
266
|
+
.gp-step-summary { color:var(--fg-3); font:10.5px "JetBrains Mono",monospace; font-variant-numeric:tabular-nums; }
|
|
267
|
+
.gp-params-preview { color:var(--fg-2); font:11px "JetBrains Mono",monospace; }
|
|
268
|
+
.gp-table-empty { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; padding:80px 20px; color:var(--fg-3); }
|
|
269
|
+
.gp-empty-mark { color:var(--fg-4); font:28px "JetBrains Mono",monospace; }
|
|
270
|
+
.gp-empty-title { color:var(--fg-1); font-weight:500; }
|
|
271
|
+
.gp-empty-sub { color:var(--fg-3); font:11px "JetBrains Mono",monospace; }
|
|
272
|
+
|
|
273
|
+
/* Expandable detail */
|
|
274
|
+
.gp-row-detail > td { padding:0; border-bottom:1px solid var(--border); background:var(--bg-detail); }
|
|
275
|
+
.gp-row-detail-inner { padding:12px 18px 14px; border-top:1px dashed var(--border-strong); }
|
|
276
|
+
.gp-detail-grid { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1fr); gap:14px 24px; }
|
|
277
|
+
.gp-detail-section { min-width:0; }
|
|
278
|
+
.gp-detail-wide { grid-column:1 / -1; }
|
|
279
|
+
.gp-section-heading { display:flex; align-items:center; gap:6px; min-height:21px; padding-bottom:6px; margin:0 0 6px; border-bottom:1px solid var(--border); color:var(--fg-3); font-size:10px; font-weight:400; letter-spacing:.08em; text-transform:uppercase; }
|
|
280
|
+
.gp-section-heading .gp-heading-meta { margin-left:auto; font-family:"JetBrains Mono",monospace; font-variant-numeric:tabular-nums; text-transform:none; letter-spacing:normal; }
|
|
281
|
+
.gp-section-heading .gp-strategy { margin-left:auto; }
|
|
282
|
+
.gp-scroll-steps { max-height:240px; overflow-y:auto; }
|
|
283
|
+
.gp-compact-table { width:100%; border-collapse:collapse; font-size:11.5px; }
|
|
284
|
+
.gp-compact-table td { padding:2.5px 0; vertical-align:top; }
|
|
285
|
+
.gp-compact-table .gp-step-key { color:var(--fg); font-family:"JetBrains Mono",monospace; white-space:nowrap; }
|
|
286
|
+
.gp-compact-table .gp-job-class { max-width:180px; padding-left:8px; padding-right:8px; overflow:hidden; color:var(--fg-3); font:10.5px "JetBrains Mono",monospace; text-overflow:ellipsis; white-space:nowrap; }
|
|
287
|
+
.gp-compact-table .gp-step-duration { padding-left:8px; color:var(--fg-2); font:10.5px "JetBrains Mono",monospace; text-align:right; white-space:nowrap; }
|
|
288
|
+
.gp-error { max-width:220px; overflow:hidden; color:var(--st-failed); text-overflow:ellipsis; white-space:nowrap; }
|
|
289
|
+
.gp-kv { width:100%; border-collapse:collapse; font-size:11.5px; }
|
|
290
|
+
.gp-kv td { padding:2px 0; vertical-align:top; }
|
|
291
|
+
.gp-kv-key { width:140px; color:var(--fg-3); font-family:"JetBrains Mono",monospace; white-space:nowrap; }
|
|
292
|
+
.gp-kv-value { color:var(--fg); font-family:"JetBrains Mono",monospace; overflow-wrap:anywhere; }
|
|
293
|
+
.gp-actions { display:flex; flex-wrap:wrap; gap:6px; margin-top:10px; }
|
|
294
|
+
.gp-action-form { display:inline-flex; margin:0; }
|
|
295
|
+
.gp-action {
|
|
296
|
+
display:inline-flex; align-items:center; height:22px; padding:0 10px; border:1px solid var(--border-strong);
|
|
297
|
+
border-radius:3px; color:var(--fg-1); background:var(--bg-2); font:11px "JetBrains Mono",monospace;
|
|
298
|
+
}
|
|
299
|
+
.gp-action--danger { border-color:color-mix(in oklab,var(--st-failed) 40%,var(--border)); color:var(--st-failed); background:transparent; }
|
|
300
|
+
.gp-action--ghost { border-color:var(--border); color:var(--fg-2); background:transparent; }
|
|
301
|
+
.gp-action:disabled { color:var(--fg-4); border-color:var(--border); }
|
|
302
|
+
|
|
303
|
+
/* Timeline */
|
|
304
|
+
.gp-timeline { display:flex; flex-direction:column; gap:3px; max-height:260px; overflow-y:auto; }
|
|
305
|
+
.gp-lane { display:flex; align-items:center; gap:8px; min-height:12px; }
|
|
306
|
+
.gp-lane-label { width:130px; flex:none; overflow:hidden; color:var(--fg-2); font:10.5px "JetBrains Mono",monospace; text-align:right; text-overflow:ellipsis; white-space:nowrap; }
|
|
307
|
+
.gp-lane-track { position:relative; flex:1; height:10px; overflow:hidden; border-radius:2px; background:var(--bg-2); }
|
|
308
|
+
.gp-lane-bar { position:absolute; inset:0 auto 0 var(--gp-left,0%); width:max(1.5%,var(--gp-width,1.5%)); border-radius:2px; background:var(--gp-status,var(--fg-3)); opacity:.85; }
|
|
309
|
+
.gp-lane-bar.is-running { background:repeating-linear-gradient(135deg,var(--gp-status,var(--st-running)) 0,var(--gp-status,var(--st-running)) 5px,color-mix(in oklab,var(--gp-status,var(--st-running)) 55%,var(--bg-2)) 5px,color-mix(in oklab,var(--gp-status,var(--st-running)) 55%,var(--bg-2)) 9px); }
|
|
310
|
+
.gp-lane-note { width:110px; flex:none; overflow:hidden; color:var(--fg-3); font:10.5px "JetBrains Mono",monospace; font-variant-numeric:tabular-nums; text-overflow:ellipsis; white-space:nowrap; }
|
|
311
|
+
.gp-stage-level { width:28px; flex:none; color:var(--fg-4); font:9.5px "JetBrains Mono",monospace; text-align:right; }
|
|
312
|
+
.gp-stage-role { width:var(--gp-width,12%); min-width:8px; height:10px; flex:none; border:1px solid var(--border-strong); border-radius:2px; background:var(--bg-3); }
|
|
313
|
+
.gp-stage-role--branch { background:color-mix(in oklab,var(--st-halted) 42%,var(--bg-3)); border-color:var(--st-halted); }
|
|
314
|
+
.gp-stage-role--barrier { background:var(--bg-2); border-width:2px; border-color:var(--fg-3); }
|
|
315
|
+
.gp-stage-role--terminal { background:var(--accent); border-color:var(--accent); }
|
|
316
|
+
.gp-stage-stack { display:inline-flex; flex:1; height:10px; overflow:hidden; border-radius:2px; background:var(--bg-2); }
|
|
317
|
+
.gp-stage-stack > span { display:block; width:var(--gp-width); height:100%; background:var(--gp-status); opacity:var(--gp-opacity,1); }
|
|
318
|
+
|
|
319
|
+
/* Code/requery */
|
|
320
|
+
.gp-code-wrap { position:relative; }
|
|
321
|
+
.gp-code {
|
|
322
|
+
margin:4px 0 0; padding:8px 36px 8px 10px; overflow-x:auto; border:1px solid var(--border);
|
|
323
|
+
border-radius:3px; color:var(--fg-1); background:var(--bg-2); font-size:11.5px; white-space:pre;
|
|
324
|
+
}
|
|
325
|
+
.gp-code-wrap > .gp-copy { position:absolute; z-index:1; top:6px; right:6px; width:22px; height:22px; margin:0; border:1px solid var(--border); border-radius:3px; background:var(--bg-3); }
|
|
326
|
+
|
|
327
|
+
/* Pager */
|
|
328
|
+
.gp-pager { height:36px; flex:none; display:flex; align-items:center; justify-content:space-between; padding:8px 14px; border-top:1px solid var(--border); background:var(--bg-1); font-size:11.5px; }
|
|
329
|
+
.gp-pager-info { color:var(--fg-2); }
|
|
330
|
+
.gp-pager-info .mono { color:var(--fg); font-variant-numeric:tabular-nums; }
|
|
331
|
+
.gp-pager-buttons { display:flex; align-items:center; gap:4px; }
|
|
332
|
+
.gp-page-button { width:24px; height:22px; display:inline-flex; align-items:center; justify-content:center; border:1px solid var(--border); border-radius:3px; color:var(--fg-1); background:var(--bg-2); }
|
|
333
|
+
.gp-page-button:hover { background:var(--bg-3); }
|
|
334
|
+
.gp-page-button:disabled { color:var(--fg-4); }
|
|
335
|
+
.gp-page-label { padding:0 8px; color:var(--fg-2); font-variant-numeric:tabular-nums; }
|
|
336
|
+
|
|
337
|
+
/* Detail screen and cards */
|
|
338
|
+
.gp-detail-header { flex:none; display:flex; align-items:center; gap:10px; padding:10px 16px; border-bottom:1px solid var(--border); background:var(--bg-1); flex-wrap:wrap; }
|
|
339
|
+
.gp-detail-title { color:var(--fg); font-size:14px; font-weight:600; }
|
|
340
|
+
.gp-detail-uuid { display:inline-flex; align-items:center; gap:2px; color:var(--fg-3); font:10.5px "JetBrains Mono",monospace; }
|
|
341
|
+
.gp-detail-header .gp-actions { margin:0 0 0 auto; }
|
|
342
|
+
.gp-detail-scroll { flex:1; min-height:0; overflow-y:auto; }
|
|
343
|
+
.gp-detail-columns { display:grid; grid-template-columns:minmax(0,1fr) minmax(0,1.15fr); gap:14px; align-items:start; padding:14px 16px; }
|
|
344
|
+
.gp-detail-column { display:flex; flex-direction:column; gap:14px; min-width:0; }
|
|
345
|
+
.gp-card { min-width:0; padding:10px 12px; border:1px solid var(--border); border-radius:4px; background:var(--bg-1); }
|
|
346
|
+
.gp-card .gp-scroll-steps { max-height:340px; }
|
|
347
|
+
.gp-chain { display:flex; align-items:center; flex-wrap:wrap; gap:6px; }
|
|
348
|
+
.gp-chain-chip { display:inline-flex; align-items:center; gap:6px; height:22px; padding:0 7px; border:1px solid var(--border); border-radius:3px; color:var(--fg-2); background:var(--bg-2); font-size:10.5px; }
|
|
349
|
+
.gp-chain-arrow { color:var(--fg-4); }
|
|
350
|
+
|
|
351
|
+
/* Diagrams */
|
|
352
|
+
.gp-diagram-container { min-width:0; }
|
|
353
|
+
.gp-diagram-toolbar { margin-left:auto; display:inline-flex; align-items:center; gap:4px; }
|
|
354
|
+
.gp-diagram-btn { min-width:20px; height:20px; padding:0 6px; color:var(--fg-2); font-size:10px; }
|
|
355
|
+
.gp-diagram-btn--icon { width:20px; padding:0; font-size:11px; }
|
|
356
|
+
.gp-diagram-btn[aria-pressed="true"] { color:var(--fg); background:var(--selected); }
|
|
357
|
+
.gp-diagram-viewport { min-height:280px; max-height:560px; overflow:hidden; cursor:grab; touch-action:none; }
|
|
358
|
+
.gp-diagram-viewport:active { cursor:grabbing; }
|
|
359
|
+
.gp-diagram-canvas { display:flex; justify-content:center; min-width:max-content; padding:6px 0; transform-origin:0 0; will-change:transform; }
|
|
360
|
+
.gp-diagram-canvas.is-dragging { cursor:grabbing; user-select:none; }
|
|
361
|
+
.gp-diagram-canvas svg { max-width:100%; height:auto; }
|
|
362
|
+
.gp-diagram-error, .gp-diagram-fallback { display:flex; min-height:200px; align-items:center; justify-content:center; padding:20px; color:var(--st-failed); font:11px "JetBrains Mono",monospace; text-align:center; }
|
|
363
|
+
.gp-diagram-fallback { color:var(--fg-3); }
|
|
364
|
+
.gp-graph-panel[hidden], .gp-stage-panel[hidden] { display:none; }
|
|
365
|
+
.gp-edge-warning { margin:6px 0 0; color:var(--st-halted); font:10.5px "JetBrains Mono",monospace; text-transform:none; letter-spacing:normal; }
|
|
366
|
+
.gp-diagram-container:fullscreen { padding:14px; overflow:auto; background:var(--bg); }
|
|
367
|
+
.gp-diagram-container:fullscreen .gp-diagram-viewport { max-height:none; height:calc(100vh - 50px); }
|
|
368
|
+
.gp-card:fullscreen { padding:14px; overflow:auto; background:var(--bg); }
|
|
369
|
+
.gp-card:fullscreen .gp-diagram-viewport { max-height:none; height:calc(100vh - 58px); }
|
|
370
|
+
|
|
371
|
+
/* Definitions */
|
|
372
|
+
.gp-definitions-scroll { flex:1; min-height:0; overflow-y:auto; }
|
|
373
|
+
.gp-definitions-content { width:100%; max-width:1100px; display:flex; flex-direction:column; gap:14px; padding:14px 16px; }
|
|
374
|
+
.gp-definition-panel { display:none; }
|
|
375
|
+
.gp-definition-panel.is-active { display:contents; }
|
|
376
|
+
.gp-definition-summary { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
|
|
377
|
+
.gp-definition-summary .gp-action { margin-left:auto; }
|
|
378
|
+
.gp-definition-title { color:var(--fg); font-size:14px; font-weight:600; }
|
|
379
|
+
.gp-definition-metrics { display:flex; flex-wrap:wrap; gap:18px; margin-top:8px; color:var(--fg-2); font:11px "JetBrains Mono",monospace; }
|
|
380
|
+
.gp-definition-metrics b { color:var(--fg-3); font-weight:400; }
|
|
381
|
+
.gp-definition-list-overflow { max-height:280px; overflow:auto; }
|
|
382
|
+
|
|
383
|
+
@media (max-width:1000px) {
|
|
384
|
+
.gp-app--dashboard, .gp-app--definitions { grid-template-columns:220px minmax(0,1fr); }
|
|
385
|
+
.gp-kpi-strip { grid-template-columns:repeat(3,minmax(0,1fr)); }
|
|
386
|
+
.gp-kpi:nth-child(3) { border-right:0; }
|
|
387
|
+
.gp-detail-columns { grid-template-columns:1fr; }
|
|
388
|
+
.gp-clock { display:none; }
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
@media (max-width:720px) {
|
|
392
|
+
.gp-app--dashboard, .gp-app--definitions { grid-template-columns:1fr; overflow:auto; }
|
|
393
|
+
.gp-sidebar { display:none; }
|
|
394
|
+
.gp-main { min-height:100vh; overflow:visible; }
|
|
395
|
+
.gp-topbar { position:sticky; top:0; z-index:10; }
|
|
396
|
+
.gp-connection { display:none; }
|
|
397
|
+
.gp-kpi-strip { grid-template-columns:repeat(2,minmax(0,1fr)); }
|
|
398
|
+
.gp-kpi:nth-child(odd) { border-right:1px solid var(--border); }
|
|
399
|
+
.gp-kpi:nth-child(even) { border-right:0; }
|
|
400
|
+
.gp-filter-bar { align-items:stretch; }
|
|
401
|
+
#gp-filters { width:100%; flex-wrap:wrap; }
|
|
402
|
+
.gp-table-wrap { min-height:480px; }
|
|
403
|
+
.gp-detail-grid { grid-template-columns:1fr; }
|
|
404
|
+
.gp-detail-wide { grid-column:auto; }
|
|
405
|
+
.gp-detail-columns { padding:10px; }
|
|
406
|
+
.gp-detail-header .gp-actions { width:100%; margin-left:0; }
|
|
407
|
+
}
|