sidekick-docker 0.2.0 → 0.2.2
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 +2 -0
- package/dist/sidekick-docker.mjs +160 -89
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -97,6 +97,7 @@ The dashboard has 5 panels, each mapped to a number key:
|
|
|
97
97
|
| `r` | Restart |
|
|
98
98
|
| `R` | Remove (with confirmation) |
|
|
99
99
|
| `e` | Exec into container |
|
|
100
|
+
| `c` | Copy logs to clipboard |
|
|
100
101
|
|
|
101
102
|
### Compose Actions (via context menu)
|
|
102
103
|
|
|
@@ -106,6 +107,7 @@ The dashboard has 5 panels, each mapped to a number key:
|
|
|
106
107
|
| `d` | Down (stop project) |
|
|
107
108
|
| `r` | Restart |
|
|
108
109
|
| `S` | Stop |
|
|
110
|
+
| `c` | Copy logs to clipboard |
|
|
109
111
|
|
|
110
112
|
## Features
|
|
111
113
|
|
package/dist/sidekick-docker.mjs
CHANGED
|
@@ -56086,7 +56086,7 @@ var require_ComposeClient = __commonJS({
|
|
|
56086
56086
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
56087
56087
|
exports2.ComposeClient = void 0;
|
|
56088
56088
|
var child_process_1 = __require("child_process");
|
|
56089
|
-
var
|
|
56089
|
+
var ComposeClient3 = class {
|
|
56090
56090
|
async exec(args, cwd2) {
|
|
56091
56091
|
return new Promise((resolve, reject) => {
|
|
56092
56092
|
const proc = (0, child_process_1.spawn)("docker", ["compose", ...args], {
|
|
@@ -56224,7 +56224,7 @@ var require_ComposeClient = __commonJS({
|
|
|
56224
56224
|
}
|
|
56225
56225
|
}
|
|
56226
56226
|
};
|
|
56227
|
-
exports2.ComposeClient =
|
|
56227
|
+
exports2.ComposeClient = ComposeClient3;
|
|
56228
56228
|
}
|
|
56229
56229
|
});
|
|
56230
56230
|
|
|
@@ -56511,7 +56511,7 @@ var require_LogFilter = __commonJS({
|
|
|
56511
56511
|
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
56512
56512
|
exports2.exactMatch = exactMatch;
|
|
56513
56513
|
exports2.fuzzyMatch = fuzzyMatch;
|
|
56514
|
-
exports2.filterLine =
|
|
56514
|
+
exports2.filterLine = filterLine3;
|
|
56515
56515
|
function exactMatch(line, query) {
|
|
56516
56516
|
if (!query)
|
|
56517
56517
|
return { matched: true, matches: [] };
|
|
@@ -56546,7 +56546,7 @@ var require_LogFilter = __commonJS({
|
|
|
56546
56546
|
matches.sort((a, b) => a.start - b.start);
|
|
56547
56547
|
return { matched: true, matches };
|
|
56548
56548
|
}
|
|
56549
|
-
function
|
|
56549
|
+
function filterLine3(line, query, mode) {
|
|
56550
56550
|
return mode === "exact" ? exactMatch(line, query) : fuzzyMatch(line, query);
|
|
56551
56551
|
}
|
|
56552
56552
|
}
|
|
@@ -94249,7 +94249,7 @@ var {
|
|
|
94249
94249
|
|
|
94250
94250
|
// src/commands/dashboard.ts
|
|
94251
94251
|
var import_react37 = __toESM(require_react(), 1);
|
|
94252
|
-
var
|
|
94252
|
+
var import_sidekick_docker_shared14 = __toESM(require_dist(), 1);
|
|
94253
94253
|
import { spawnSync } from "child_process";
|
|
94254
94254
|
|
|
94255
94255
|
// src/utils/clipboard.ts
|
|
@@ -94732,9 +94732,7 @@ var ContainersPanel = class {
|
|
|
94732
94732
|
if (c.state !== "running") return "Container is not running.";
|
|
94733
94733
|
const latest = metrics.statsCollector.getLatest(c.id);
|
|
94734
94734
|
if (!latest) {
|
|
94735
|
-
|
|
94736
|
-
const idx = Math.floor(Date.now() / 200) % frames.length;
|
|
94737
|
-
return `${frames[idx]} Loading stats...`;
|
|
94735
|
+
return "Loading stats...";
|
|
94738
94736
|
}
|
|
94739
94737
|
const cpuSeries = metrics.statsCollector.getCpuSeries(c.id);
|
|
94740
94738
|
const memSeries = metrics.statsCollector.getMemorySeries(c.id);
|
|
@@ -94967,6 +94965,7 @@ var ContainersPanel = class {
|
|
|
94967
94965
|
};
|
|
94968
94966
|
|
|
94969
94967
|
// src/dashboard/panels/ServicesPanel.ts
|
|
94968
|
+
var import_sidekick_docker_shared5 = __toESM(require_dist(), 1);
|
|
94970
94969
|
function getProjectName(d) {
|
|
94971
94970
|
return d.type === "project" ? d.project.name : d.service.projectName;
|
|
94972
94971
|
}
|
|
@@ -94978,12 +94977,17 @@ var ServicesPanel = class {
|
|
|
94978
94977
|
onAction;
|
|
94979
94978
|
onError;
|
|
94980
94979
|
cwd;
|
|
94980
|
+
onCopyLogs;
|
|
94981
|
+
lastMetrics = null;
|
|
94981
94982
|
constructor(composeClient, onAction, cwd2, onError) {
|
|
94982
94983
|
this.composeClient = composeClient;
|
|
94983
94984
|
this.onAction = onAction;
|
|
94984
94985
|
this.onError = onError ?? defaultOnError;
|
|
94985
94986
|
this.cwd = cwd2;
|
|
94986
94987
|
}
|
|
94988
|
+
setOnCopyLogs(handler) {
|
|
94989
|
+
this.onCopyLogs = handler;
|
|
94990
|
+
}
|
|
94987
94991
|
detailTabs = [
|
|
94988
94992
|
{
|
|
94989
94993
|
label: "Info",
|
|
@@ -95023,6 +95027,7 @@ var ServicesPanel = class {
|
|
|
95023
95027
|
}
|
|
95024
95028
|
];
|
|
95025
95029
|
getItems(metrics) {
|
|
95030
|
+
this.lastMetrics = metrics;
|
|
95026
95031
|
const items = [];
|
|
95027
95032
|
let sortKey = 0;
|
|
95028
95033
|
for (const project of metrics.composeProjects) {
|
|
@@ -95117,6 +95122,23 @@ var ServicesPanel = class {
|
|
|
95117
95122
|
});
|
|
95118
95123
|
},
|
|
95119
95124
|
condition: (item) => item.data !== null
|
|
95125
|
+
},
|
|
95126
|
+
{
|
|
95127
|
+
key: "c",
|
|
95128
|
+
label: "Copy Logs",
|
|
95129
|
+
handler: () => {
|
|
95130
|
+
if (!this.lastMetrics || !this.onCopyLogs) return;
|
|
95131
|
+
const logs = this.lastMetrics.selectedComposeLogs;
|
|
95132
|
+
const query = this.lastMetrics.logFilterString;
|
|
95133
|
+
const mode = this.lastMetrics.logFilterMode;
|
|
95134
|
+
let lines;
|
|
95135
|
+
if (query) {
|
|
95136
|
+
lines = logs.filter((l) => (0, import_sidekick_docker_shared5.filterLine)(l.message, query, mode).matched).map((l) => l.message);
|
|
95137
|
+
} else {
|
|
95138
|
+
lines = logs.map((l) => l.message);
|
|
95139
|
+
}
|
|
95140
|
+
this.onCopyLogs(lines.join("\n"));
|
|
95141
|
+
}
|
|
95120
95142
|
}
|
|
95121
95143
|
];
|
|
95122
95144
|
}
|
|
@@ -95402,15 +95424,15 @@ var NetworksPanel = class {
|
|
|
95402
95424
|
};
|
|
95403
95425
|
|
|
95404
95426
|
// src/dashboard/LogStreamManager.ts
|
|
95405
|
-
var
|
|
95427
|
+
var import_sidekick_docker_shared7 = __toESM(require_dist(), 1);
|
|
95406
95428
|
|
|
95407
95429
|
// src/dashboard/BaseStreamManager.ts
|
|
95408
|
-
var
|
|
95430
|
+
var import_sidekick_docker_shared6 = __toESM(require_dist(), 1);
|
|
95409
95431
|
var BaseStreamManager = class {
|
|
95410
95432
|
currentId;
|
|
95411
95433
|
aborted = false;
|
|
95412
95434
|
streamPromise = null;
|
|
95413
|
-
reconnect = new
|
|
95435
|
+
reconnect = new import_sidekick_docker_shared6.ReconnectScheduler();
|
|
95414
95436
|
onChange;
|
|
95415
95437
|
constructor(onChange) {
|
|
95416
95438
|
this.onChange = onChange;
|
|
@@ -95437,7 +95459,7 @@ var BaseStreamManager = class {
|
|
|
95437
95459
|
}
|
|
95438
95460
|
this.reconnect.reset();
|
|
95439
95461
|
} catch (err) {
|
|
95440
|
-
console.debug(`${this.streamLabel} stream error:`, (0,
|
|
95462
|
+
console.debug(`${this.streamLabel} stream error:`, (0, import_sidekick_docker_shared6.errorMessage)(err));
|
|
95441
95463
|
}
|
|
95442
95464
|
if (!this.aborted && this.isSameId(id, this.currentId)) {
|
|
95443
95465
|
const scheduled = this.reconnect.schedule(() => {
|
|
@@ -95474,9 +95496,9 @@ var BaseStreamManager = class {
|
|
|
95474
95496
|
var LogStreamManager = class extends BaseStreamManager {
|
|
95475
95497
|
client;
|
|
95476
95498
|
logs = [];
|
|
95477
|
-
analytics = new
|
|
95478
|
-
timeSeries = new
|
|
95479
|
-
templateEngine = new
|
|
95499
|
+
analytics = new import_sidekick_docker_shared7.LogAnalytics();
|
|
95500
|
+
timeSeries = new import_sidekick_docker_shared7.LogSeverityTimeSeries();
|
|
95501
|
+
templateEngine = new import_sidekick_docker_shared7.LogTemplateEngine();
|
|
95480
95502
|
streamLabel = "log";
|
|
95481
95503
|
constructor(client, onChange) {
|
|
95482
95504
|
super(onChange);
|
|
@@ -95502,7 +95524,7 @@ var LogStreamManager = class extends BaseStreamManager {
|
|
|
95502
95524
|
const severity = this.analytics.push(entry.message);
|
|
95503
95525
|
this.timeSeries.push(severity);
|
|
95504
95526
|
this.templateEngine.push(entry.message);
|
|
95505
|
-
if (this.logs.length >
|
|
95527
|
+
if (this.logs.length > import_sidekick_docker_shared7.MAX_LOG_LINES) {
|
|
95506
95528
|
this.logs.shift();
|
|
95507
95529
|
}
|
|
95508
95530
|
}
|
|
@@ -95533,7 +95555,6 @@ var LogStreamManager = class extends BaseStreamManager {
|
|
|
95533
95555
|
var StatsStreamManager = class extends BaseStreamManager {
|
|
95534
95556
|
client;
|
|
95535
95557
|
collector;
|
|
95536
|
-
loadingInterval = null;
|
|
95537
95558
|
streamLabel = "stats";
|
|
95538
95559
|
constructor(client, collector, onChange) {
|
|
95539
95560
|
super(onChange);
|
|
@@ -95557,21 +95578,11 @@ var StatsStreamManager = class extends BaseStreamManager {
|
|
|
95557
95578
|
}
|
|
95558
95579
|
processItem(id, stats) {
|
|
95559
95580
|
this.collector.push(id, stats);
|
|
95560
|
-
this.clearLoadingInterval();
|
|
95561
95581
|
}
|
|
95562
95582
|
onClear() {
|
|
95563
95583
|
}
|
|
95564
95584
|
onBeforeStream() {
|
|
95565
|
-
this.
|
|
95566
|
-
}
|
|
95567
|
-
onStop() {
|
|
95568
|
-
this.clearLoadingInterval();
|
|
95569
|
-
}
|
|
95570
|
-
clearLoadingInterval() {
|
|
95571
|
-
if (this.loadingInterval) {
|
|
95572
|
-
clearInterval(this.loadingInterval);
|
|
95573
|
-
this.loadingInterval = null;
|
|
95574
|
-
}
|
|
95585
|
+
this.onChange();
|
|
95575
95586
|
}
|
|
95576
95587
|
getCollector() {
|
|
95577
95588
|
return this.collector;
|
|
@@ -95582,7 +95593,7 @@ var StatsStreamManager = class extends BaseStreamManager {
|
|
|
95582
95593
|
};
|
|
95583
95594
|
|
|
95584
95595
|
// src/dashboard/ComposeLogStreamManager.ts
|
|
95585
|
-
var
|
|
95596
|
+
var import_sidekick_docker_shared8 = __toESM(require_dist(), 1);
|
|
95586
95597
|
var ComposeLogStreamManager = class extends BaseStreamManager {
|
|
95587
95598
|
composeClient;
|
|
95588
95599
|
logs = [];
|
|
@@ -95608,7 +95619,7 @@ var ComposeLogStreamManager = class extends BaseStreamManager {
|
|
|
95608
95619
|
}
|
|
95609
95620
|
processItem(_id, entry) {
|
|
95610
95621
|
this.logs.push(entry);
|
|
95611
|
-
if (this.logs.length >
|
|
95622
|
+
if (this.logs.length > import_sidekick_docker_shared8.MAX_LOG_LINES) {
|
|
95612
95623
|
this.logs.shift();
|
|
95613
95624
|
}
|
|
95614
95625
|
}
|
|
@@ -96229,8 +96240,7 @@ function DetailTabBar({ tabs, activeIndex }) {
|
|
|
96229
96240
|
// src/dashboard/ink/DetailPane.tsx
|
|
96230
96241
|
await init_build2();
|
|
96231
96242
|
var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1);
|
|
96232
|
-
function DetailPane({
|
|
96233
|
-
const lines = content.split("\n");
|
|
96243
|
+
function DetailPane({ lines, scrollOffset, viewportHeight, focused }) {
|
|
96234
96244
|
const visibleLines = lines.slice(scrollOffset, scrollOffset + viewportHeight);
|
|
96235
96245
|
const hasScrollUp = scrollOffset > 0;
|
|
96236
96246
|
const hasScrollDown = scrollOffset + viewportHeight < lines.length;
|
|
@@ -96246,7 +96256,7 @@ function DetailPane({ content, scrollOffset, viewportHeight, focused }) {
|
|
|
96246
96256
|
// src/dashboard/ink/StatusBar.tsx
|
|
96247
96257
|
var import_react32 = __toESM(require_react(), 1);
|
|
96248
96258
|
await init_build2();
|
|
96249
|
-
var
|
|
96259
|
+
var import_sidekick_docker_shared9 = __toESM(require_dist(), 1);
|
|
96250
96260
|
var import_jsx_runtime5 = __toESM(require_jsx_runtime(), 1);
|
|
96251
96261
|
function formatAgo(date) {
|
|
96252
96262
|
const secs = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
@@ -96259,13 +96269,13 @@ var SEP2 = "\u2502";
|
|
|
96259
96269
|
function StatusBar({ daemonConnected, focusTarget, panelActionHints, filterString, containerCount, runningCount, version: version2, matchCount, totalCount, lastRefresh, contextHint }) {
|
|
96260
96270
|
const [, setTick] = (0, import_react32.useState)(0);
|
|
96261
96271
|
(0, import_react32.useEffect)(() => {
|
|
96262
|
-
const timer = setInterval(() => setTick((t) => t + 1),
|
|
96272
|
+
const timer = setInterval(() => setTick((t) => t + 1), 3e4);
|
|
96263
96273
|
return () => clearInterval(timer);
|
|
96264
96274
|
}, []);
|
|
96265
96275
|
const ago = lastRefresh ? formatAgo(lastRefresh) : null;
|
|
96266
96276
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { children: [
|
|
96267
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, color: "magenta", children: ` \u26A1 ${
|
|
96268
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "gray", dimColor: true, children: ` ${
|
|
96277
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { bold: true, color: "magenta", children: ` \u26A1 ${import_sidekick_docker_shared9.BRAND_INLINE}` }),
|
|
96278
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "gray", dimColor: true, children: ` ${import_sidekick_docker_shared9.BRAND_TAGLINE} v${version2}` }),
|
|
96269
96279
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: "gray", dimColor: true, children: ` ${SEP2} ` }),
|
|
96270
96280
|
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: daemonConnected ? "green" : "red", children: daemonConnected ? `\u25CF ${runningCount ?? 0}/${containerCount ?? 0}` : "\u25CB disconnected" }),
|
|
96271
96281
|
ago && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { color: ago.stale ? "yellow" : "gray", dimColor: !ago.stale, children: ` \u21BB ${ago.text}` }),
|
|
@@ -96288,7 +96298,7 @@ function StatusBar({ daemonConnected, focusTarget, panelActionHints, filterStrin
|
|
|
96288
96298
|
|
|
96289
96299
|
// src/dashboard/ink/HelpOverlay.tsx
|
|
96290
96300
|
await init_build2();
|
|
96291
|
-
var
|
|
96301
|
+
var import_sidekick_docker_shared10 = __toESM(require_dist(), 1);
|
|
96292
96302
|
var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
|
|
96293
96303
|
var GLOBAL_BINDINGS = [
|
|
96294
96304
|
{ key: "1-5", label: "Switch panel" },
|
|
@@ -96314,7 +96324,7 @@ function HelpOverlay({ panels, activePanelIndex, version: version2 }) {
|
|
|
96314
96324
|
const actions = panel.getActions();
|
|
96315
96325
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
96316
96326
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Box_default, { children: [
|
|
96317
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { bold: true, color: "magenta", children: `\u26A1 ${
|
|
96327
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { bold: true, color: "magenta", children: `\u26A1 ${import_sidekick_docker_shared10.BRAND_INLINE} ${import_sidekick_docker_shared10.BRAND_TAGLINE}` }),
|
|
96318
96328
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { color: "gray", dimColor: true, children: ` v${version2}` })
|
|
96319
96329
|
] }),
|
|
96320
96330
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Text, { children: "" }),
|
|
@@ -96483,7 +96493,7 @@ function ToastNotification({ toast }) {
|
|
|
96483
96493
|
|
|
96484
96494
|
// src/dashboard/ink/TooSmallOverlay.tsx
|
|
96485
96495
|
await init_build2();
|
|
96486
|
-
var
|
|
96496
|
+
var import_sidekick_docker_shared11 = __toESM(require_dist(), 1);
|
|
96487
96497
|
var import_jsx_runtime11 = __toESM(require_jsx_runtime(), 1);
|
|
96488
96498
|
function TooSmallOverlay({ columns, rows }) {
|
|
96489
96499
|
const needWidth = Math.max(0, 60 - columns);
|
|
@@ -96492,7 +96502,7 @@ function TooSmallOverlay({ columns, rows }) {
|
|
|
96492
96502
|
if (needWidth > 0) hints.push(`${needWidth} col${needWidth > 1 ? "s" : ""} wider`);
|
|
96493
96503
|
if (needHeight > 0) hints.push(`${needHeight} row${needHeight > 1 ? "s" : ""} taller`);
|
|
96494
96504
|
return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(Box_default, { flexDirection: "column", justifyContent: "center", alignItems: "center", height: rows, width: columns, children: [
|
|
96495
|
-
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { bold: true, color: "magenta", children: `\u26A1 ${
|
|
96505
|
+
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { bold: true, color: "magenta", children: `\u26A1 ${import_sidekick_docker_shared11.BRAND_INLINE}` }),
|
|
96496
96506
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { children: "" }),
|
|
96497
96507
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { color: "yellow", bold: true, children: "Terminal too small" }),
|
|
96498
96508
|
/* @__PURE__ */ (0, import_jsx_runtime11.jsx)(Text, { color: "gray", children: `${columns}\xD7${rows} \u2192 need ${hints.join(" and ")}` }),
|
|
@@ -96632,13 +96642,13 @@ function LogFilterOverlay({ filterString, filterMode }) {
|
|
|
96632
96642
|
// src/dashboard/ink/VersionOverlay.tsx
|
|
96633
96643
|
var import_react35 = __toESM(require_react(), 1);
|
|
96634
96644
|
await init_build2();
|
|
96635
|
-
var
|
|
96645
|
+
var import_sidekick_docker_shared12 = __toESM(require_dist(), 1);
|
|
96636
96646
|
var import_jsx_runtime15 = __toESM(require_jsx_runtime(), 1);
|
|
96637
96647
|
function VersionOverlay({ version: version2 }) {
|
|
96638
|
-
const phrase = import_react35.default.useMemo(() => (0,
|
|
96648
|
+
const phrase = import_react35.default.useMemo(() => (0, import_sidekick_docker_shared12.getRandomPhrase)(), []);
|
|
96639
96649
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)(Box_default, { flexDirection: "column", flexGrow: 1, padding: 1, children: [
|
|
96640
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { bold: true, color: "magenta", children: `\u26A1 ${
|
|
96641
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: "#2B4C7E", bold: true, children: `${
|
|
96650
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { bold: true, color: "magenta", children: `\u26A1 ${import_sidekick_docker_shared12.BRAND_INLINE}` }),
|
|
96651
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: "#2B4C7E", bold: true, children: `${import_sidekick_docker_shared12.BRAND_TAGLINE} v${version2}` }),
|
|
96642
96652
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: "" }),
|
|
96643
96653
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { color: "gray", dimColor: true, children: "\u2500".repeat(40) }),
|
|
96644
96654
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(Text, { children: "" }),
|
|
@@ -96697,7 +96707,7 @@ function SortOverlay({ selectedIndex, currentField, reversed }) {
|
|
|
96697
96707
|
}
|
|
96698
96708
|
|
|
96699
96709
|
// src/dashboard/ink/Dashboard.tsx
|
|
96700
|
-
var
|
|
96710
|
+
var import_sidekick_docker_shared13 = __toESM(require_dist(), 1);
|
|
96701
96711
|
|
|
96702
96712
|
// src/dashboard/ExecManager.ts
|
|
96703
96713
|
var ExecManager = class {
|
|
@@ -96885,16 +96895,16 @@ var initialState = {
|
|
|
96885
96895
|
sortReversed: false,
|
|
96886
96896
|
sortMenuIndex: 0
|
|
96887
96897
|
};
|
|
96888
|
-
function Dashboard({ panels, metrics,
|
|
96898
|
+
function Dashboard({ panels, metrics, onViewStateChange, execTriggerRef, onExecFallback }) {
|
|
96889
96899
|
const [state, dispatch] = (0, import_react36.useReducer)(reducer, initialState);
|
|
96890
96900
|
const { columns, rows } = useTerminalSize();
|
|
96891
96901
|
const toastIdRef = (0, import_react36.useRef)(0);
|
|
96892
96902
|
const execManagerRef = (0, import_react36.useRef)(null);
|
|
96893
|
-
const [phrase, setPhrase] = import_react36.default.useState(() => (0,
|
|
96903
|
+
const [phrase, setPhrase] = import_react36.default.useState(() => (0, import_sidekick_docker_shared13.getRandomPhrase)());
|
|
96894
96904
|
const phraseTimerRef = (0, import_react36.useRef)(null);
|
|
96895
96905
|
const rotatePhraseRef = (0, import_react36.useRef)(void 0);
|
|
96896
96906
|
rotatePhraseRef.current = () => {
|
|
96897
|
-
setPhrase((0,
|
|
96907
|
+
setPhrase((0, import_sidekick_docker_shared13.getRandomPhrase)());
|
|
96898
96908
|
if (phraseTimerRef.current) clearTimeout(phraseTimerRef.current);
|
|
96899
96909
|
phraseTimerRef.current = setTimeout(() => rotatePhraseRef.current?.(), 7e3);
|
|
96900
96910
|
};
|
|
@@ -97047,11 +97057,16 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
|
|
|
97047
97057
|
}
|
|
97048
97058
|
}, [state.selectedItemIndex]);
|
|
97049
97059
|
const selectedItem = currentItems[clampedSelection];
|
|
97050
|
-
(0, import_react36.useEffect)(() => {
|
|
97051
|
-
onSelectionChange?.(panel.id, selectedItem?.id ?? null);
|
|
97052
|
-
}, [panel.id, selectedItem?.id]);
|
|
97053
97060
|
const detailTabs = panel.detailTabs;
|
|
97054
97061
|
const tabIdx = Math.min(state.detailTabIndex, detailTabs.length - 1);
|
|
97062
|
+
(0, import_react36.useEffect)(() => {
|
|
97063
|
+
onViewStateChange?.({
|
|
97064
|
+
panelId: panel.id,
|
|
97065
|
+
itemId: selectedItem?.id ?? null,
|
|
97066
|
+
detailTabIndex: tabIdx,
|
|
97067
|
+
sortField: state.sortField
|
|
97068
|
+
});
|
|
97069
|
+
}, [panel.id, selectedItem?.id, tabIdx, state.sortField]);
|
|
97055
97070
|
const enrichedMetrics = {
|
|
97056
97071
|
...metrics,
|
|
97057
97072
|
logFilterString: state.logFilterString,
|
|
@@ -97160,7 +97175,7 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
|
|
|
97160
97175
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
97161
97176
|
DetailPane,
|
|
97162
97177
|
{
|
|
97163
|
-
|
|
97178
|
+
lines: detailLines,
|
|
97164
97179
|
scrollOffset: state.detailScrollOffset,
|
|
97165
97180
|
viewportHeight: detailViewportHeight,
|
|
97166
97181
|
focused: state.focusTarget === "detail"
|
|
@@ -97168,8 +97183,8 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
|
|
|
97168
97183
|
)
|
|
97169
97184
|
] })
|
|
97170
97185
|
] }),
|
|
97171
|
-
state.overlay === "help" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(HelpOverlay, { panels, activePanelIndex: state.activePanelIndex, version: "0.2.
|
|
97172
|
-
state.overlay === "version" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VersionOverlay, { version: "0.2.
|
|
97186
|
+
state.overlay === "help" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(HelpOverlay, { panels, activePanelIndex: state.activePanelIndex, version: "0.2.2" }),
|
|
97187
|
+
state.overlay === "version" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(VersionOverlay, { version: "0.2.2" }),
|
|
97173
97188
|
state.overlay === "exec" && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
97174
97189
|
ExecOverlay,
|
|
97175
97190
|
{
|
|
@@ -97186,7 +97201,7 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
|
|
|
97186
97201
|
filterString: state.filterString,
|
|
97187
97202
|
containerCount: metrics.containers.length,
|
|
97188
97203
|
runningCount,
|
|
97189
|
-
version: "0.2.
|
|
97204
|
+
version: "0.2.2",
|
|
97190
97205
|
matchCount: state.filterString ? currentItems.length : void 0,
|
|
97191
97206
|
totalCount: state.filterString ? totalItemCount : void 0,
|
|
97192
97207
|
lastRefresh: metrics.lastRefresh,
|
|
@@ -97231,7 +97246,7 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
|
|
|
97231
97246
|
async function dashboardAction(_opts, cmd) {
|
|
97232
97247
|
const globalOpts = cmd.parent?.opts() ?? cmd.opts();
|
|
97233
97248
|
const socketPath = globalOpts.socket;
|
|
97234
|
-
const client = new
|
|
97249
|
+
const client = new import_sidekick_docker_shared14.DockerClient(socketPath ? { socketPath } : void 0);
|
|
97235
97250
|
const ok = await client.ping();
|
|
97236
97251
|
if (!ok) {
|
|
97237
97252
|
console.error("Error: Cannot connect to Docker daemon. Is Docker running?");
|
|
@@ -97240,34 +97255,68 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97240
97255
|
const cwd2 = process.cwd();
|
|
97241
97256
|
const state = new DockerState(client, cwd2);
|
|
97242
97257
|
await state.refresh();
|
|
97243
|
-
const composeClient = new
|
|
97258
|
+
const composeClient = new import_sidekick_docker_shared14.ComposeClient();
|
|
97244
97259
|
const onAction = () => {
|
|
97245
97260
|
state.refresh().then(() => scheduleRender()).catch((e) => console.debug("refresh failed:", e));
|
|
97246
97261
|
};
|
|
97247
97262
|
const onError = (msg) => {
|
|
97248
97263
|
console.debug("panel action failed:", msg);
|
|
97249
97264
|
};
|
|
97265
|
+
let logFlushTimer = null;
|
|
97266
|
+
let composeLogFlushTimer = null;
|
|
97250
97267
|
const logManager = new LogStreamManager(client, () => {
|
|
97268
|
+
if (logFlushTimer) return;
|
|
97269
|
+
logFlushTimer = setTimeout(() => {
|
|
97270
|
+
logFlushTimer = null;
|
|
97271
|
+
state.setSelectedLogs(logManager.getLogs());
|
|
97272
|
+
logSeverityCounts = logManager.getSeverityCounts();
|
|
97273
|
+
scheduleRender();
|
|
97274
|
+
}, 100);
|
|
97275
|
+
});
|
|
97276
|
+
const flushLogsNow = () => {
|
|
97277
|
+
if (logFlushTimer) {
|
|
97278
|
+
clearTimeout(logFlushTimer);
|
|
97279
|
+
logFlushTimer = null;
|
|
97280
|
+
}
|
|
97251
97281
|
state.setSelectedLogs(logManager.getLogs());
|
|
97252
97282
|
logSeverityCounts = logManager.getSeverityCounts();
|
|
97253
97283
|
scheduleRender();
|
|
97254
|
-
}
|
|
97284
|
+
};
|
|
97255
97285
|
let logSeverityCounts = logManager.getSeverityCounts();
|
|
97256
97286
|
const statsManager = new StatsStreamManager(client, state.getStatsCollector(), () => {
|
|
97257
97287
|
scheduleRender();
|
|
97258
97288
|
});
|
|
97259
97289
|
const composeLogManager = new ComposeLogStreamManager(composeClient, () => {
|
|
97290
|
+
if (composeLogFlushTimer) return;
|
|
97291
|
+
composeLogFlushTimer = setTimeout(() => {
|
|
97292
|
+
composeLogFlushTimer = null;
|
|
97293
|
+
state.clearComposeLogs();
|
|
97294
|
+
for (const entry of composeLogManager.getLogs()) {
|
|
97295
|
+
state.appendComposeLog(entry);
|
|
97296
|
+
}
|
|
97297
|
+
scheduleRender();
|
|
97298
|
+
}, 100);
|
|
97299
|
+
});
|
|
97300
|
+
const flushComposeLogsNow = () => {
|
|
97301
|
+
if (composeLogFlushTimer) {
|
|
97302
|
+
clearTimeout(composeLogFlushTimer);
|
|
97303
|
+
composeLogFlushTimer = null;
|
|
97304
|
+
}
|
|
97260
97305
|
state.clearComposeLogs();
|
|
97261
97306
|
for (const entry of composeLogManager.getLogs()) {
|
|
97262
97307
|
state.appendComposeLog(entry);
|
|
97263
97308
|
}
|
|
97264
97309
|
scheduleRender();
|
|
97265
|
-
}
|
|
97266
|
-
const
|
|
97310
|
+
};
|
|
97311
|
+
const onViewStateChange = (viewState) => {
|
|
97312
|
+
const { panelId, itemId, detailTabIndex, sortField } = viewState;
|
|
97313
|
+
const wantsLiveStats = sortField === "cpu" || sortField === "mem" || sortField === "net" || sortField === "io" || sortField === "pids";
|
|
97267
97314
|
if (panelId === "containers") {
|
|
97268
|
-
logManager.select(itemId);
|
|
97269
|
-
statsManager.select(itemId);
|
|
97270
|
-
composeLogManager.selectCompose(null, null);
|
|
97315
|
+
void logManager.select(detailTabIndex === 0 ? itemId : null);
|
|
97316
|
+
void statsManager.select(itemId && (detailTabIndex === 1 || wantsLiveStats) ? itemId : null);
|
|
97317
|
+
void composeLogManager.selectCompose(null, null);
|
|
97318
|
+
flushLogsNow();
|
|
97319
|
+
flushComposeLogsNow();
|
|
97271
97320
|
if (itemId && !state.getInspectedEnv(itemId)) {
|
|
97272
97321
|
client.getContainerEnv(itemId).then((env3) => {
|
|
97273
97322
|
state.setInspectedEnv(itemId, env3);
|
|
@@ -97281,18 +97330,26 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97281
97330
|
}).catch((e) => console.debug("getContainerChanges failed:", e));
|
|
97282
97331
|
}
|
|
97283
97332
|
} else if (panelId === "services" && itemId) {
|
|
97284
|
-
logManager.select(null);
|
|
97285
|
-
statsManager.select(null);
|
|
97286
|
-
|
|
97287
|
-
|
|
97288
|
-
|
|
97289
|
-
|
|
97290
|
-
|
|
97333
|
+
void logManager.select(null);
|
|
97334
|
+
void statsManager.select(null);
|
|
97335
|
+
if (detailTabIndex === 1) {
|
|
97336
|
+
const parts = itemId.split(":");
|
|
97337
|
+
if (parts[0] === "project") {
|
|
97338
|
+
void composeLogManager.selectCompose(parts.slice(1).join(":"), null);
|
|
97339
|
+
} else if (parts[0] === "service") {
|
|
97340
|
+
void composeLogManager.selectCompose(parts[1], parts.slice(2).join(":"));
|
|
97341
|
+
}
|
|
97342
|
+
} else {
|
|
97343
|
+
void composeLogManager.selectCompose(null, null);
|
|
97291
97344
|
}
|
|
97345
|
+
flushLogsNow();
|
|
97346
|
+
flushComposeLogsNow();
|
|
97292
97347
|
} else if (panelId === "images") {
|
|
97293
|
-
logManager.select(null);
|
|
97294
|
-
statsManager.select(null);
|
|
97295
|
-
composeLogManager.selectCompose(null, null);
|
|
97348
|
+
void logManager.select(null);
|
|
97349
|
+
void statsManager.select(null);
|
|
97350
|
+
void composeLogManager.selectCompose(null, null);
|
|
97351
|
+
flushLogsNow();
|
|
97352
|
+
flushComposeLogsNow();
|
|
97296
97353
|
if (itemId && !state.getImageLayers(itemId)) {
|
|
97297
97354
|
client.getImageHistory(itemId).then((layers) => {
|
|
97298
97355
|
state.setImageLayers(itemId, layers);
|
|
@@ -97300,9 +97357,11 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97300
97357
|
}).catch((e) => console.debug("getImageHistory failed:", e));
|
|
97301
97358
|
}
|
|
97302
97359
|
} else {
|
|
97303
|
-
logManager.select(null);
|
|
97304
|
-
statsManager.select(null);
|
|
97305
|
-
composeLogManager.selectCompose(null, null);
|
|
97360
|
+
void logManager.select(null);
|
|
97361
|
+
void statsManager.select(null);
|
|
97362
|
+
void composeLogManager.selectCompose(null, null);
|
|
97363
|
+
flushLogsNow();
|
|
97364
|
+
flushComposeLogsNow();
|
|
97306
97365
|
}
|
|
97307
97366
|
};
|
|
97308
97367
|
const panels = [
|
|
@@ -97312,7 +97371,7 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97312
97371
|
new VolumesPanel(client, onAction, onError),
|
|
97313
97372
|
new NetworksPanel(client, onAction, onError)
|
|
97314
97373
|
];
|
|
97315
|
-
const watcher = new
|
|
97374
|
+
const watcher = new import_sidekick_docker_shared14.EventWatcher(client, {
|
|
97316
97375
|
onEvent: (event) => {
|
|
97317
97376
|
state.processEvent(event);
|
|
97318
97377
|
scheduleRender();
|
|
@@ -97337,7 +97396,7 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97337
97396
|
import_react37.default.createElement(Dashboard, {
|
|
97338
97397
|
panels,
|
|
97339
97398
|
metrics: getEnrichedMetrics(),
|
|
97340
|
-
|
|
97399
|
+
onViewStateChange,
|
|
97341
97400
|
execTriggerRef,
|
|
97342
97401
|
onExecFallback
|
|
97343
97402
|
})
|
|
@@ -97349,7 +97408,7 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97349
97408
|
import_react37.default.createElement(Dashboard, {
|
|
97350
97409
|
panels,
|
|
97351
97410
|
metrics: getEnrichedMetrics(),
|
|
97352
|
-
|
|
97411
|
+
onViewStateChange,
|
|
97353
97412
|
execTriggerRef,
|
|
97354
97413
|
onExecFallback
|
|
97355
97414
|
})
|
|
@@ -97357,7 +97416,7 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97357
97416
|
const containersPanel = panels[0];
|
|
97358
97417
|
containersPanel.setOnExec((containerId) => {
|
|
97359
97418
|
const container = state.getMetrics().containers.find((c) => c.id === containerId);
|
|
97360
|
-
const name = container?.name ?? (0,
|
|
97419
|
+
const name = container?.name ?? (0, import_sidekick_docker_shared14.shortId)(containerId);
|
|
97361
97420
|
if (execTriggerRef.current) {
|
|
97362
97421
|
execTriggerRef.current(containerId, name);
|
|
97363
97422
|
} else {
|
|
@@ -97367,6 +97426,10 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97367
97426
|
containersPanel.setOnCopyLogs((text) => {
|
|
97368
97427
|
copyToClipboard(text);
|
|
97369
97428
|
});
|
|
97429
|
+
const servicesPanel = panels[1];
|
|
97430
|
+
servicesPanel.setOnCopyLogs((text) => {
|
|
97431
|
+
copyToClipboard(text);
|
|
97432
|
+
});
|
|
97370
97433
|
let renderTimer = null;
|
|
97371
97434
|
function getEnrichedMetrics() {
|
|
97372
97435
|
const m = state.getMetrics();
|
|
@@ -97383,7 +97446,7 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97383
97446
|
import_react37.default.createElement(Dashboard, {
|
|
97384
97447
|
panels,
|
|
97385
97448
|
metrics: getEnrichedMetrics(),
|
|
97386
|
-
|
|
97449
|
+
onViewStateChange,
|
|
97387
97450
|
execTriggerRef,
|
|
97388
97451
|
onExecFallback
|
|
97389
97452
|
})
|
|
@@ -97406,6 +97469,14 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97406
97469
|
composeLogManager.dispose();
|
|
97407
97470
|
} catch {
|
|
97408
97471
|
}
|
|
97472
|
+
try {
|
|
97473
|
+
if (logFlushTimer) clearTimeout(logFlushTimer);
|
|
97474
|
+
} catch {
|
|
97475
|
+
}
|
|
97476
|
+
try {
|
|
97477
|
+
if (composeLogFlushTimer) clearTimeout(composeLogFlushTimer);
|
|
97478
|
+
} catch {
|
|
97479
|
+
}
|
|
97409
97480
|
try {
|
|
97410
97481
|
clearInterval(refreshInterval);
|
|
97411
97482
|
} catch {
|
|
@@ -97430,9 +97501,9 @@ async function dashboardAction(_opts, cmd) {
|
|
|
97430
97501
|
}
|
|
97431
97502
|
|
|
97432
97503
|
// src/commands/ps.ts
|
|
97433
|
-
var
|
|
97504
|
+
var import_sidekick_docker_shared15 = __toESM(require_dist(), 1);
|
|
97434
97505
|
async function psAction(opts) {
|
|
97435
|
-
const client = new
|
|
97506
|
+
const client = new import_sidekick_docker_shared15.DockerClient();
|
|
97436
97507
|
const ok = await client.ping();
|
|
97437
97508
|
if (!ok) {
|
|
97438
97509
|
console.error("Error: Cannot connect to Docker daemon. Is Docker running?");
|
|
@@ -97448,7 +97519,7 @@ async function psAction(opts) {
|
|
|
97448
97519
|
console.log("-".repeat(100));
|
|
97449
97520
|
for (const c of containers) {
|
|
97450
97521
|
const row = [
|
|
97451
|
-
(0,
|
|
97522
|
+
(0, import_sidekick_docker_shared15.shortId)(c.id).padEnd(20),
|
|
97452
97523
|
`${(0, import_sidekick_docker_shared3.stateIcon)(c.state)} ${c.name}`.padEnd(20),
|
|
97453
97524
|
c.image.padEnd(20),
|
|
97454
97525
|
formatUptime(c.status).padEnd(20),
|
|
@@ -97459,9 +97530,9 @@ async function psAction(opts) {
|
|
|
97459
97530
|
}
|
|
97460
97531
|
|
|
97461
97532
|
// src/commands/logs.ts
|
|
97462
|
-
var
|
|
97533
|
+
var import_sidekick_docker_shared16 = __toESM(require_dist(), 1);
|
|
97463
97534
|
async function logsAction(container, opts) {
|
|
97464
|
-
const client = new
|
|
97535
|
+
const client = new import_sidekick_docker_shared16.DockerClient();
|
|
97465
97536
|
const ok = await client.ping();
|
|
97466
97537
|
if (!ok) {
|
|
97467
97538
|
console.error("Error: Cannot connect to Docker daemon. Is Docker running?");
|
|
@@ -97472,13 +97543,13 @@ async function logsAction(container, opts) {
|
|
|
97472
97543
|
follow: opts.follow ?? true,
|
|
97473
97544
|
tail: parseInt(opts.tail || "100", 10)
|
|
97474
97545
|
})) {
|
|
97475
|
-
const ts = entry.timestamp ? (0,
|
|
97546
|
+
const ts = entry.timestamp ? (0, import_sidekick_docker_shared16.formatTimestampTime)(entry.timestamp) : "";
|
|
97476
97547
|
const prefix = entry.stream === "stderr" ? "\x1B[31m" : "";
|
|
97477
97548
|
const reset = entry.stream === "stderr" ? "\x1B[0m" : "";
|
|
97478
97549
|
console.log(`${prefix}${ts} ${entry.message}${reset}`);
|
|
97479
97550
|
}
|
|
97480
97551
|
} catch (err) {
|
|
97481
|
-
const msg = (0,
|
|
97552
|
+
const msg = (0, import_sidekick_docker_shared16.errorMessage)(err);
|
|
97482
97553
|
if (msg.includes("no such container") || msg.includes("No such container")) {
|
|
97483
97554
|
console.error(`Error: Container "${container}" not found.`);
|
|
97484
97555
|
} else {
|
|
@@ -97490,7 +97561,7 @@ async function logsAction(container, opts) {
|
|
|
97490
97561
|
|
|
97491
97562
|
// src/cli.ts
|
|
97492
97563
|
var program2 = new Command();
|
|
97493
|
-
program2.name("sidekick-docker").description("Docker management TUI dashboard").version("0.2.
|
|
97564
|
+
program2.name("sidekick-docker").description("Docker management TUI dashboard").version("0.2.2").option("--socket <path>", "Docker socket path").action(async (_opts, cmd) => {
|
|
97494
97565
|
await dashboardAction(_opts, cmd);
|
|
97495
97566
|
});
|
|
97496
97567
|
program2.command("ps").description("List containers").option("-a, --all", "Show all containers (default: running only)", false).action(async (opts) => {
|