Sources: container labels in one field, colored by compose project

- One label per container (project/service) in a single field, like
  tag pickers: followed ones in the project color, a separator, then the
  others in grey; a click switches a label. Excluded ones last, locked.
- Stopped containers hidden by default, shown dashed and still editable
  with 'Show stopped containers'; filter box; enable/disable all apply to
  the labels shown.
- Docker app names in the log list use their compose project color.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
cedricandClaude Opus 5.5 committed 2026-09-28 17:18:27 +02:00
1 parent cd0307f6f6
commit d751fb54ae
4 files changed
+150 -68

No files matched your search

+43 -20
View File
@@ -11,6 +11,7 @@
--row-hover: #f5f6fa;
--hit: rgba(99, 102, 241, .18);
--shadow: 0 10px 30px rgba(15, 23, 42, .12);
--chip-l: 38%; /* lightness of project-colored text (labels, Docker apps) */
--sev-crit: #be123c;
--sev-err: #dc2626;
@@ -45,6 +46,7 @@
--row-hover: #1a1f26;
--hit: rgba(129, 140, 248, .28);
--shadow: 0 10px 30px rgba(0, 0, 0, .5);
--chip-l: 70%;
--sev-crit: #fb7185;
--sev-err: #f87171;
--sev-warning: #fbbf24;
@@ -67,6 +69,7 @@
--row-hover: #1a1f26;
--hit: rgba(129, 140, 248, .28);
--shadow: 0 10px 30px rgba(0, 0, 0, .5);
--chip-l: 70%;
--sev-crit: #fb7185;
--sev-err: #f87171;
--sev-warning: #fbbf24;
@@ -220,6 +223,9 @@ body.busy .progress::after {
/* Docker logs */
.src-ico { width: 1em; height: 1em; vertical-align: -.15em; margin-right: 4px; color: #2496ed; }
/* Docker app names take the color of their compose project (see hueOf in app.js) */
.row .app.proj { color: hsl(var(--h) 55% var(--chip-l)); }
.row .app.proj .src-ico { color: inherit; }
/* ---------- Histogram ---------- */
.histo { padding: 0 20px 6px; }
@@ -418,28 +424,45 @@ select.field:focus { outline: 0; border-color: var(--accent); box-shadow: 0 0 0
.docker-status.good::before, .docker-status.bad::before { content: "●"; margin-right: 6px; }
.docker-status.good::before { color: var(--sev-info); }
.docker-status.bad { color: var(--sev-err); }
.switch-row { display: flex; align-items: center; gap: 10px; font-size: 13.5px; font-weight: 550; cursor: pointer; }
.docker-actions { display: flex; gap: 8px; margin: 12px 0; }
.docker-list { display: flex; flex-direction: column; gap: 14px; margin-bottom: 12px; }
.dk-group { border: 1px solid var(--border); border-radius: 10px; overflow: hidden; }
.dk-group-title {
padding: 7px 12px; background: var(--panel-2);
font-size: 12px; font-weight: 650; text-transform: uppercase; letter-spacing: .04em; color: var(--muted);
.switch-row { display: flex; align-items: center; gap: 10px; font-size: 13px; font-weight: 550; cursor: pointer; }
.dk-opts { display: flex; flex-direction: column; gap: 8px; }
.dk-toolbar { display: flex; align-items: center; gap: 12px; margin: 14px 0 6px; }
.dk-filter {
flex: 1; min-width: 0; height: 28px; padding: 0 10px;
border: 1px solid var(--border); border-radius: 7px; background: var(--panel);
font: 12px var(--mono); outline: 0;
}
.dk-row {
display: grid; grid-template-columns: auto minmax(0, 1fr) auto; align-items: center; gap: 12px;
padding: 8px 12px; border-top: 1px solid var(--border); cursor: pointer;
.dk-filter:focus { border-color: var(--accent); box-shadow: 0 0 0 3px var(--accent-soft); }
.link-btn { border: 0; background: none; padding: 0; font-size: 12px; font-weight: 550; color: var(--accent); white-space: nowrap; }
.link-btn:hover { text-decoration: underline; }
.dk-legend { font-size: 11.5px; color: var(--muted); margin: 8px 0 12px !important; }
/* Container labels (Settings > Sources) */
.chip-field {
display: flex; flex-wrap: wrap; align-items: center; gap: 5px;
padding: 8px; min-height: 40px;
border: 1px solid var(--border); border-radius: 10px; background: var(--panel);
}
.dk-row:hover { background: var(--row-hover); }
.dk-row.locked { cursor: default; opacity: .65; }
.dk-main { display: flex; flex-direction: column; min-width: 0; }
.dk-main strong { font-size: 13.5px; font-weight: 600; }
.dk-main small { font-size: 12px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dk-state { font-size: 12px; white-space: nowrap; color: var(--muted); }
.dk-state::before { content: "●"; margin-right: 5px; }
.dk-state.following { color: var(--sev-info); }
.dk-state.ignored::before { color: var(--sev-warning); }
.dk-state.stopped::before, .dk-state.locked::before { opacity: .4; }
.chip {
display: inline-flex; align-items: center; gap: 4px;
height: 22px; padding: 0 7px;
border: 1px solid var(--border); border-radius: 5px; background: transparent;
color: var(--muted); font: 11px/1 var(--mono); white-space: nowrap; cursor: pointer;
}
.chip:hover { color: var(--text); border-color: var(--muted); }
.chip.on {
color: hsl(var(--h) 55% var(--chip-l));
border-color: hsl(var(--h) 50% var(--chip-l) / .7);
background: hsl(var(--h) 60% 50% / .13);
}
.chip.on:hover { background: hsl(var(--h) 60% 50% / .22); }
.chip.stopped { border-style: dashed; }
.chip.stopped:not(.on) { opacity: .7; }
.chip.locked { opacity: .45; cursor: not-allowed; }
.chip svg { width: 10px; height: 10px; }
.chip:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
.chip-sep { width: 1px; height: 18px; margin: 0 4px; background: var(--border); }
.chip-empty { font-size: 12px; color: var(--muted); padding: 0 4px; }
/* Toggle switch */
input.switch {