opendocker 0.1.1 → 0.1.3

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.
@@ -0,0 +1,68 @@
1
+
2
+ export class Docker {
3
+ private socket = "/var/run/docker.sock";
4
+
5
+ private async request(path: string) {
6
+ try {
7
+ const process = Bun.spawn([
8
+ "curl", "-s", "--unix-socket", this.socket,
9
+ `http://localhost${path}`
10
+ ], { stdout: "pipe", stderr: "pipe" });
11
+
12
+ const output = await new Response(process.stdout).text();
13
+ process.kill();
14
+
15
+ return JSON.parse(output);
16
+ } catch (error) {
17
+ console.error('Docker socket request failed:', error);
18
+ throw error;
19
+ }
20
+ }
21
+
22
+ async getContainers() {
23
+ return this.request("/v1.41/containers/json?all=true");
24
+ }
25
+
26
+ async watch(callback: (containers: any[]) => void) {
27
+ try {
28
+ let containers = await this.getContainers();
29
+ callback(containers);
30
+
31
+ const process = Bun.spawn([
32
+ "curl", "-s", "--no-buffer", "--unix-socket", this.socket,
33
+ "http://localhost/v1.41/events"
34
+ ], { stdout: "pipe", stderr: "pipe" });
35
+
36
+ const reader = process.stdout.getReader();
37
+ const decoder = new TextDecoder();
38
+ let buffer = "";
39
+
40
+ while (true) {
41
+ const { value, done } = await reader.read();
42
+ if (done) break;
43
+
44
+ buffer += decoder.decode(value, { stream: true });
45
+ const lines = buffer.split('\n');
46
+ buffer = lines.pop() || "";
47
+
48
+ for (const line of lines) {
49
+ if (line.trim()) {
50
+ try {
51
+ const event = JSON.parse(line);
52
+ if (event.Type === "container") {
53
+ containers = await this.getContainers();
54
+ callback(containers);
55
+ }
56
+ } catch (parseError) {
57
+ console.error('Failed to parse event:', line, parseError);
58
+ }
59
+ }
60
+ }
61
+ }
62
+
63
+ } catch (error) {
64
+ console.error('Docker watch failed', error);
65
+ throw error;
66
+ }
67
+ }
68
+ }
package/src/main.tsx ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env bun
2
+
3
+ import { createRoot, useKeyboard, useRenderer } from "@opentui/react";
4
+ import { createCliRenderer } from "@opentui/core";
5
+ import ContainersPane from "./components/ContainersPane";
6
+ import LogsPane from "./components/LogsPane";
7
+ import BaseLayout from "./layouts/BaseLayout";
8
+
9
+ function App() {
10
+ const renderer = useRenderer();
11
+
12
+ useKeyboard((key) => {
13
+ if (key.name === "q") {
14
+ process.exit(0);
15
+ }
16
+
17
+ if (key.ctrl && key.name === "d") {
18
+ renderer?.console.toggle()
19
+ renderer?.toggleDebugOverlay()
20
+ }
21
+ })
22
+
23
+ return (
24
+ <BaseLayout>
25
+ <box
26
+ flexDirection="column"
27
+ width="30%"
28
+ gap={1}
29
+ >
30
+ <ContainersPane />
31
+ </box>
32
+ <LogsPane />
33
+ </BaseLayout>
34
+ )
35
+ }
36
+
37
+ async function main() {
38
+ const renderer = await createCliRenderer();
39
+ const root = createRoot(renderer);
40
+ root.render(<App />);
41
+ }
42
+
43
+ main();
@@ -0,0 +1,11 @@
1
+ import { create } from "zustand";
2
+
3
+ interface ApplicationStore {
4
+ activePane: string;
5
+ setActivePane: (activePane: string) => void;
6
+ }
7
+
8
+ export const useApplicationStore = create<ApplicationStore>((set) => ({
9
+ activePane: "containers",
10
+ setActivePane: (activePane) => set({ activePane }),
11
+ }));
@@ -0,0 +1,22 @@
1
+ import { create } from "zustand";
2
+
3
+ export type Container = {
4
+ name: string;
5
+ status: string;
6
+ health: string;
7
+ state: string;
8
+ }
9
+
10
+ interface ContainerStore {
11
+ containers: Container[];
12
+ activeContainer: Container;
13
+ setContainers: (containers: Container[]) => void;
14
+ setActiveContainer: (activeContainer: Container) => void;
15
+ }
16
+
17
+ export const useContainerStore = create<ContainerStore>((set) => ({
18
+ containers: [],
19
+ activeContainer: null,
20
+ setContainers: (containers: Container[]) => set({ containers }),
21
+ setActiveContainer: (activeContainer) => set({ activeContainer }),
22
+ }));
@@ -0,0 +1,11 @@
1
+ import { create } from "zustand";
2
+
3
+ export interface ImageStore {
4
+ images: string[];
5
+ setImages: (images: string[]) => void;
6
+ }
7
+
8
+ export const useImageStore = create<ImageStore>((set) => ({
9
+ images: [],
10
+ setImages: (images: string[]) => set({ images }),
11
+ }));
@@ -0,0 +1,11 @@
1
+ import { create } from "zustand";
2
+
3
+ interface VolumeStore {
4
+ volumes: string[];
5
+ setVolumes: (volumes: string[]) => void;
6
+ }
7
+
8
+ export const useVolumeStore = create<VolumeStore>((set) => ({
9
+ volumes: [],
10
+ setVolumes: (volumes: string[]) => set({ volumes }),
11
+ }));
@@ -0,0 +1,198 @@
1
+ export const colors = {
2
+ primary: '#fab283',
3
+ secondary: '#5c9cf5',
4
+ accent: '#9d7cd8',
5
+ error: '#e06c75',
6
+ warning: '#f5a742',
7
+ success: '#7fd88f',
8
+ info: '#56b6c2',
9
+ text: '#eeeeee',
10
+ textMuted: '#808080',
11
+ background: '#0a0a0a',
12
+ backgroundPanel: '#141414',
13
+ backgroundElement: '#1e1e1e',
14
+ border: '#484848',
15
+ borderActive: '#606060',
16
+ borderSubtle: '#3c3c3c',
17
+ }
18
+
19
+ export const padding = {
20
+ paddingTop: 1,
21
+ paddingBottom: 1,
22
+ paddingLeft: 2,
23
+ paddingRight: 2,
24
+ }
25
+
26
+ export const termColors = {
27
+ gray01: "#111111",
28
+ gray02: "#191919",
29
+ gray03: "#222222",
30
+ gray04: "#2a2a2a",
31
+ gray05: "#313131",
32
+ gray06: "#3a3a3a",
33
+ gray07: "#484848",
34
+ gray08: "#606060",
35
+ gray09: "#6e6e6e",
36
+ gray10: "#7b7b7b",
37
+ gray11: "#b4b4b4",
38
+ gray12: "#eeeeee",
39
+ gray13: "#ffffff",
40
+ gray1: "#0b0b0b",
41
+ gray00: "#0d0d0d",
42
+ red01: "#191111",
43
+ red02: "#201314",
44
+ red03: "#3b1219",
45
+ red04: "#500f1c",
46
+ red05: "#611623",
47
+ red06: "#72232d",
48
+ red07: "#8c333a",
49
+ red08: "#b54548",
50
+ red09: "#e5484d",
51
+ red10: "#ec5d5e",
52
+ red11: "#ff9592",
53
+ red12: "#ffd1d9",
54
+ green01: "#0e1512",
55
+ green02: "#121b17",
56
+ green03: "#132d21",
57
+ green04: "#113b29",
58
+ green05: "#174933",
59
+ green06: "#20573e",
60
+ green07: "#28684a",
61
+ green08: "#2f7c57",
62
+ green09: "#30a46c",
63
+ green10: "#33b074",
64
+ green11: "#3dd68c",
65
+ green12: "#b1f1cb",
66
+ blue01: "#0d1520",
67
+ blue02: "#111927",
68
+ blue03: "#0d2847",
69
+ blue04: "#003362",
70
+ blue05: "#004074",
71
+ blue06: "#104d87",
72
+ blue07: "#205d9e",
73
+ blue08: "#2870bd",
74
+ blue09: "#0090ff",
75
+ blue10: "#3b9eff",
76
+ blue11: "#70b8ff",
77
+ blue12: "#c2e6ff",
78
+ orange01: "#17120e",
79
+ orange02: "#1e160f",
80
+ orange03: "#331e0b",
81
+ orange04: "#462100",
82
+ orange05: "#562800",
83
+ orange06: "#66350c",
84
+ orange07: "#7e451d",
85
+ orange08: "#a35829",
86
+ orange09: "#f76b15",
87
+ orange10: "#ff801f",
88
+ orange11: "#ffa057",
89
+ orange12: "#ffe0c2",
90
+ purple01: "#18111b",
91
+ purple02: "#1e1523",
92
+ purple03: "#301c3b",
93
+ purple04: "#3d224e",
94
+ purple05: "#48295c",
95
+ purple06: "#54346b",
96
+ purple07: "#664282",
97
+ purple08: "#8457aa",
98
+ purple09: "#8e4ec6",
99
+ purple10: "#9a5cd0",
100
+ purple11: "#d19dff",
101
+ purple12: "#ecd9fa",
102
+ teal01: "#0d1514",
103
+ teal02: "#111c1b",
104
+ teal03: "#0d2d2a",
105
+ teal04: "#023b37",
106
+ teal05: "#084843",
107
+ teal06: "#145750",
108
+ teal07: "#1c6961",
109
+ teal08: "#207e73",
110
+ teal09: "#12a594",
111
+ teal10: "#0eb39e",
112
+ teal11: "#0bd8b6",
113
+ teal12: "#adf0dd",
114
+ yellow01: "#14120b",
115
+ yellow02: "#1b180f",
116
+ yellow03: "#2d2305",
117
+ yellow04: "#362b00",
118
+ yellow05: "#433500",
119
+ yellow06: "#524202",
120
+ yellow07: "#665417",
121
+ yellow08: "#836a21",
122
+ yellow09: "#ffe629",
123
+ yellow10: "#ffff57",
124
+ yellow11: "#f5e147",
125
+ yellow12: "#f6eeb4",
126
+ pink01: "#191117",
127
+ pink02: "#21121d",
128
+ pink03: "#37172f",
129
+ pink04: "#4b143d",
130
+ pink05: "#591c47",
131
+ pink06: "#692955",
132
+ pink07: "#833869",
133
+ pink08: "#a84885",
134
+ pink09: "#d6409f",
135
+ pink10: "#de51a8",
136
+ pink11: "#ff8dcc",
137
+ pink12: "#fdd1ea",
138
+ brown01: "#12110f",
139
+ brown02: "#1c1816",
140
+ brown03: "#28211d",
141
+ brown04: "#322922",
142
+ brown05: "#3e3128",
143
+ brown06: "#4d3c2f",
144
+ brown07: "#614a39",
145
+ brown08: "#7c5f46",
146
+ brown09: "#ad7f58",
147
+ brown10: "#b88c67",
148
+ brown11: "#dbb594",
149
+ brown12: "#f2e1ca",
150
+ iris01: "#13131e",
151
+ iris02: "#171625",
152
+ iris03: "#202248",
153
+ iris04: "#262a65",
154
+ iris05: "#303374",
155
+ iris06: "#3d3e82",
156
+ iris07: "#4a4a95",
157
+ iris08: "#5958b1",
158
+ iris09: "#5b5bd6",
159
+ iris10: "#6e6ade",
160
+ iris11: "#b1a9ff",
161
+ iris12: "#e0dffe",
162
+ lime01: "#11130c",
163
+ lime02: "#151a10",
164
+ lime03: "#1f2917",
165
+ lime04: "#29371d",
166
+ lime05: "#334423",
167
+ lime06: "#3d522a",
168
+ lime07: "#496231",
169
+ lime08: "#577538",
170
+ lime09: "#bdee63",
171
+ lime10: "#d4ff70",
172
+ lime11: "#bde56c",
173
+ lime12: "#e3f7ba",
174
+ amber01: "#16120c",
175
+ amber02: "#1d180f",
176
+ amber03: "#302008",
177
+ amber04: "#3f2700",
178
+ amber05: "#4d3000",
179
+ amber06: "#5c3d05",
180
+ amber07: "#714f19",
181
+ amber08: "#8f6424",
182
+ amber09: "#ffc53d",
183
+ amber10: "#ffd60a",
184
+ amber11: "#ffca16",
185
+ amber12: "#ffe7b3",
186
+ tomato01: "#181111",
187
+ tomato02: "#1f1513",
188
+ tomato03: "#391714",
189
+ tomato04: "#4e1511",
190
+ tomato05: "#5e1c16",
191
+ tomato06: "#6e2920",
192
+ tomato07: "#853a2d",
193
+ tomato08: "#ac4d39",
194
+ tomato09: "#e54d2e",
195
+ tomato10: "#ec6142",
196
+ tomato11: "#ff977d",
197
+ tomato12: "#fbd3cb",
198
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,15 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/tsconfig",
3
+ "extends": "@tsconfig/bun/tsconfig.json",
4
+ "compilerOptions": {
5
+ "jsx": "preserve",
6
+ "jsxImportSource": "@opentui/react",
7
+ "lib": ["ESNext", "DOM", "DOM.Iterable"],
8
+ "customConditions": ["browser"],
9
+ "baseUrl": ".",
10
+ "paths": {
11
+ "@/*": ["./src/*"],
12
+ "@tui/*": ["./src/cli/cmd/tui/*"]
13
+ }
14
+ }
15
+ }