sidekick-docker 0.1.3 → 0.1.4

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.
@@ -77965,6 +77965,29 @@ var import_react37 = __toESM(require_react(), 1);
77965
77965
  var import_sidekick_docker_shared13 = __toESM(require_dist(), 1);
77966
77966
  import { spawnSync } from "child_process";
77967
77967
 
77968
+ // src/utils/clipboard.ts
77969
+ import { execSync } from "child_process";
77970
+ function copyToClipboard(text) {
77971
+ try {
77972
+ if (process.platform === "darwin") {
77973
+ execSync("pbcopy", { input: text });
77974
+ } else {
77975
+ try {
77976
+ execSync("xclip -selection clipboard", { input: text });
77977
+ } catch {
77978
+ try {
77979
+ execSync("xsel --clipboard --input", { input: text });
77980
+ } catch {
77981
+ execSync("wl-copy", { input: text });
77982
+ }
77983
+ }
77984
+ }
77985
+ return true;
77986
+ } catch {
77987
+ return false;
77988
+ }
77989
+ }
77990
+
77968
77991
  // src/dashboard/DockerState.ts
77969
77992
  var import_sidekick_docker_shared = __toESM(require_dist(), 1);
77970
77993
  var DockerState = class {
@@ -78316,6 +78339,8 @@ var ContainersPanel = class {
78316
78339
  onAction;
78317
78340
  onError;
78318
78341
  onExec;
78342
+ onCopyLogs;
78343
+ lastMetrics = null;
78319
78344
  constructor(client, onAction, onError) {
78320
78345
  this.client = client;
78321
78346
  this.onAction = onAction;
@@ -78324,6 +78349,9 @@ var ContainersPanel = class {
78324
78349
  setOnExec(handler) {
78325
78350
  this.onExec = handler;
78326
78351
  }
78352
+ setOnCopyLogs(handler) {
78353
+ this.onCopyLogs = handler;
78354
+ }
78327
78355
  detailTabs = [
78328
78356
  {
78329
78357
  label: "Logs",
@@ -78453,10 +78481,11 @@ var ContainersPanel = class {
78453
78481
  }
78454
78482
  ];
78455
78483
  getItems(metrics) {
78484
+ this.lastMetrics = metrics;
78456
78485
  return metrics.containers.map((c) => {
78457
78486
  const uptime = compactUptime(c.status);
78458
78487
  const portHint = c.state === "running" && c.ports.length > 0 ? `:${c.ports[0].hostPort || c.ports[0].containerPort}` : "";
78459
- const namePart = portHint ? `${(0, import_sidekick_docker_shared3.truncate)(c.name, 16)} ${portHint}` : (0, import_sidekick_docker_shared3.truncate)(c.name, 20);
78488
+ const namePart = portHint ? `${(0, import_sidekick_docker_shared3.truncate)(c.name, 34)} ${portHint}` : (0, import_sidekick_docker_shared3.truncate)(c.name, 38);
78460
78489
  return {
78461
78490
  id: c.id,
78462
78491
  label: `${(0, import_sidekick_docker_shared3.stateIcon)(c.state)} ${namePart}`,
@@ -78515,6 +78544,23 @@ var ContainersPanel = class {
78515
78544
  this.onExec?.(c.id);
78516
78545
  },
78517
78546
  condition: (item) => item.data.state === "running"
78547
+ },
78548
+ {
78549
+ key: "c",
78550
+ label: "Copy Logs",
78551
+ handler: () => {
78552
+ if (!this.lastMetrics || !this.onCopyLogs) return;
78553
+ const logs = this.lastMetrics.selectedContainerLogs;
78554
+ const query = this.lastMetrics.logFilterString;
78555
+ const mode = this.lastMetrics.logFilterMode;
78556
+ let lines;
78557
+ if (query) {
78558
+ lines = logs.filter((l) => (0, import_sidekick_docker_shared4.filterLine)(l.message, query, mode).matched).map((l) => l.message);
78559
+ } else {
78560
+ lines = logs.map((l) => l.message);
78561
+ }
78562
+ this.onCopyLogs(lines.join("\n"));
78563
+ }
78518
78564
  }
78519
78565
  ];
78520
78566
  }
@@ -78600,7 +78646,7 @@ var ServicesPanel = class {
78600
78646
  const icon = (0, import_sidekick_docker_shared3.stateIcon)(service.state);
78601
78647
  items.push({
78602
78648
  id: `service:${project.name}:${service.name}`,
78603
- label: ` ${icon} ${(0, import_sidekick_docker_shared3.truncate)(service.name, 18)}`,
78649
+ label: ` ${icon} ${(0, import_sidekick_docker_shared3.truncate)(service.name, 36)}`,
78604
78650
  sortKey: sortKey++,
78605
78651
  data: { type: "service", service },
78606
78652
  iconColor: (0, import_sidekick_docker_shared3.stateColor)(service.state)
@@ -78709,7 +78755,7 @@ var ImagesPanel = class {
78709
78755
  const icon = img.isDangling ? "\u25CB" : "\u25CF";
78710
78756
  return {
78711
78757
  id: img.id,
78712
- label: `${icon} ${(0, import_sidekick_docker_shared3.truncate)(tag, 20)}`,
78758
+ label: `${icon} ${(0, import_sidekick_docker_shared3.truncate)(tag, 38)}`,
78713
78759
  sortKey: img.isDangling ? 1 : 0,
78714
78760
  data: img,
78715
78761
  iconColor: img.isDangling ? "gray" : "#2B4C7E",
@@ -78780,7 +78826,7 @@ var VolumesPanel = class {
78780
78826
  const icon = vol.isInUse ? "\u25CF" : "\u25CB";
78781
78827
  return {
78782
78828
  id: vol.name,
78783
- label: `${icon} ${(0, import_sidekick_docker_shared3.truncate)(vol.name, 20)}`,
78829
+ label: `${icon} ${(0, import_sidekick_docker_shared3.truncate)(vol.name, 38)}`,
78784
78830
  sortKey: vol.isInUse ? 0 : 1,
78785
78831
  data: vol,
78786
78832
  iconColor: vol.isInUse ? "green" : "gray",
@@ -78862,7 +78908,7 @@ var NetworksPanel = class {
78862
78908
  const countLabel = net.containers.length > 0 ? `${net.containers.length}` : "";
78863
78909
  return {
78864
78910
  id: net.id,
78865
- label: `${icon} ${(0, import_sidekick_docker_shared3.truncate)(net.name, 20)}`,
78911
+ label: `${icon} ${(0, import_sidekick_docker_shared3.truncate)(net.name, 38)}`,
78866
78912
  sortKey: net.isDefault ? 0 : 1,
78867
78913
  data: net,
78868
78914
  iconColor: net.isDefault ? "#2B4C7E" : "gray",
@@ -79362,7 +79408,8 @@ function useKeyboardHandler(ctx) {
79362
79408
  }
79363
79409
  if (input === "z") {
79364
79410
  dispatch({ type: "CYCLE_LAYOUT" });
79365
- addToast(`Layout: ${state.layoutMode === "normal" ? "Expanded" : "Normal"}`, "info");
79411
+ const nextMode = state.layoutMode === "normal" ? "Wide" : state.layoutMode === "wide" ? "Expanded" : "Normal";
79412
+ addToast(`Layout: ${nextMode}`, "info");
79366
79413
  return;
79367
79414
  }
79368
79415
  if (input === "/") {
@@ -79573,7 +79620,7 @@ function TabBar({ panels, activeIndex, layoutMode, phrase, panelCounts }) {
79573
79620
  ] }, panel.id);
79574
79621
  }),
79575
79622
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Box_default, { flexGrow: 1, marginLeft: 1, children: phrase && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: "gray", wrap: "truncate", children: phrase }) }),
79576
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: layoutMode === "expanded" ? "#2B4C7E" : "gray", children: `z: ${layoutMode === "expanded" ? "Expanded" : "Normal"} \u25B8` })
79623
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Text, { color: layoutMode !== "normal" ? "#2B4C7E" : "gray", children: `z: ${layoutMode === "expanded" ? "Expanded" : layoutMode === "wide" ? "Wide" : "Normal"} \u25B8` })
79577
79624
  ] });
79578
79625
  }
79579
79626
 
@@ -79746,7 +79793,7 @@ var GLOBAL_BINDINGS = [
79746
79793
  { key: "g/G", label: "Jump to first / last" },
79747
79794
  { key: "Tab", label: "Toggle focus" },
79748
79795
  { key: "[/]", label: "Cycle detail tabs" },
79749
- { key: "z", label: "Toggle expanded layout" },
79796
+ { key: "z", label: "Cycle layout (Normal/Wide/Expanded)" },
79750
79797
  { key: "/", label: "Filter items" },
79751
79798
  { key: "x", label: "Actions menu" },
79752
79799
  { key: "V", label: "Version info" },
@@ -80147,6 +80194,7 @@ var ExecManager = class {
80147
80194
  // src/dashboard/ink/Dashboard.tsx
80148
80195
  var import_jsx_runtime16 = __toESM(require_jsx_runtime(), 1);
80149
80196
  var SIDE_PANEL_WIDTH = 28;
80197
+ var SIDE_PANEL_WIDTH_WIDE = 42;
80150
80198
  var MIN_SCREEN_WIDTH = 60;
80151
80199
  var MIN_SCREEN_HEIGHT = 15;
80152
80200
  var RESERVED_UI_ROWS = 5;
@@ -80174,7 +80222,7 @@ function reducer(state, action) {
80174
80222
  return { ...state, detailTabIndex: next, detailScrollOffset: 0 };
80175
80223
  }
80176
80224
  case "CYCLE_LAYOUT": {
80177
- const next = state.layoutMode === "normal" ? "expanded" : "normal";
80225
+ const next = state.layoutMode === "normal" ? "wide" : state.layoutMode === "wide" ? "expanded" : "normal";
80178
80226
  return { ...state, layoutMode: next, focusTarget: next === "expanded" ? "detail" : state.focusTarget };
80179
80227
  }
80180
80228
  case "TOGGLE_FOCUS":
@@ -80261,17 +80309,19 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
80261
80309
  const execManagerRef = (0, import_react36.useRef)(null);
80262
80310
  const [phrase, setPhrase] = import_react36.default.useState(() => (0, import_sidekick_docker_shared12.getRandomPhrase)());
80263
80311
  const phraseTimerRef = (0, import_react36.useRef)(null);
80264
- const rotatePhrase = (0, import_react36.useCallback)(() => {
80312
+ const rotatePhraseRef = (0, import_react36.useRef)(void 0);
80313
+ rotatePhraseRef.current = () => {
80265
80314
  setPhrase((0, import_sidekick_docker_shared12.getRandomPhrase)());
80266
80315
  if (phraseTimerRef.current) clearTimeout(phraseTimerRef.current);
80267
- phraseTimerRef.current = setTimeout(rotatePhrase, 7e3);
80268
- }, []);
80316
+ phraseTimerRef.current = setTimeout(() => rotatePhraseRef.current?.(), 7e3);
80317
+ };
80318
+ const rotatePhrase = (0, import_react36.useCallback)(() => rotatePhraseRef.current?.(), []);
80269
80319
  (0, import_react36.useEffect)(() => {
80270
- phraseTimerRef.current = setTimeout(rotatePhrase, 7e3);
80320
+ phraseTimerRef.current = setTimeout(() => rotatePhraseRef.current?.(), 7e3);
80271
80321
  return () => {
80272
80322
  if (phraseTimerRef.current) clearTimeout(phraseTimerRef.current);
80273
80323
  };
80274
- }, [rotatePhrase]);
80324
+ }, []);
80275
80325
  (0, import_react36.useEffect)(() => {
80276
80326
  if (!execTriggerRef) return;
80277
80327
  execTriggerRef.current = (containerId, containerName) => {
@@ -80336,7 +80386,7 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
80336
80386
  }, []);
80337
80387
  const panel = panels[state.activePanelIndex];
80338
80388
  const tooSmall = columns < MIN_SCREEN_WIDTH || rows < MIN_SCREEN_HEIGHT;
80339
- const sideWidth = state.layoutMode === "expanded" ? 0 : SIDE_PANEL_WIDTH;
80389
+ const sideWidth = state.layoutMode === "expanded" ? 0 : state.layoutMode === "wide" ? SIDE_PANEL_WIDTH_WIDE : SIDE_PANEL_WIDTH;
80340
80390
  const allItems = panel.getItems(metrics);
80341
80391
  const totalItemCount = allItems.length;
80342
80392
  const currentItems = (() => {
@@ -80473,8 +80523,8 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
80473
80523
  )
80474
80524
  ] })
80475
80525
  ] }),
80476
- state.overlay === "help" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HelpOverlay, { panels, activePanelIndex: state.activePanelIndex, version: "0.1.3" }),
80477
- state.overlay === "version" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VersionOverlay, { version: "0.1.3" }),
80526
+ state.overlay === "help" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(HelpOverlay, { panels, activePanelIndex: state.activePanelIndex, version: "0.1.4" }),
80527
+ state.overlay === "version" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(VersionOverlay, { version: "0.1.4" }),
80478
80528
  state.overlay === "exec" && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
80479
80529
  ExecOverlay,
80480
80530
  {
@@ -80491,7 +80541,7 @@ function Dashboard({ panels, metrics, onSelectionChange, execTriggerRef, onExecF
80491
80541
  filterString: state.filterString,
80492
80542
  containerCount: metrics.containers.length,
80493
80543
  runningCount,
80494
- version: "0.1.3",
80544
+ version: "0.1.4",
80495
80545
  matchCount: state.filterString ? currentItems.length : void 0,
80496
80546
  totalCount: state.filterString ? totalItemCount : void 0,
80497
80547
  lastRefresh: metrics.lastRefresh
@@ -80650,6 +80700,9 @@ async function dashboardAction(_opts, cmd) {
80650
80700
  onExecFallback(containerId);
80651
80701
  }
80652
80702
  });
80703
+ containersPanel.setOnCopyLogs((text) => {
80704
+ copyToClipboard(text);
80705
+ });
80653
80706
  let renderTimer = null;
80654
80707
  function getEnrichedMetrics() {
80655
80708
  const m = state.getMetrics();
@@ -80773,7 +80826,7 @@ async function logsAction(container, opts) {
80773
80826
 
80774
80827
  // src/cli.ts
80775
80828
  var program2 = new Command();
80776
- program2.name("sidekick-docker").description("Docker management TUI dashboard").version("0.1.3").option("--socket <path>", "Docker socket path").action(async (_opts, cmd) => {
80829
+ program2.name("sidekick-docker").description("Docker management TUI dashboard").version("0.1.4").option("--socket <path>", "Docker socket path").action(async (_opts, cmd) => {
80777
80830
  await dashboardAction(_opts, cmd);
80778
80831
  });
80779
80832
  program2.command("ps").description("List containers").option("-a, --all", "Show all containers (default: running only)", false).action(async (opts) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sidekick-docker",
3
- "version": "0.1.3",
3
+ "version": "0.1.4",
4
4
  "description": "Docker management TUI dashboard",
5
5
  "author": "Cesar Andres Lopez <cesarandreslopez@gmail.com>",
6
6
  "repository": {