cdd-cli 3.1.2 → 3.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.
Files changed (33) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/FIXES_APPLIED.md +419 -0
  3. package/dist/App.js +7 -9
  4. package/dist/components/ContainerCreationPrompt.js +1 -1
  5. package/dist/components/ContainerList.js +2 -4
  6. package/dist/components/ContainerRow.js +20 -14
  7. package/dist/components/ContainerSection.js +1 -1
  8. package/dist/helpers/actionHelpers.js +14 -1
  9. package/dist/helpers/dockerService/dockerService.js +6 -3
  10. package/dist/helpers/dockerService/serviceComponents/containerActions.js +60 -10
  11. package/dist/helpers/dockerService/serviceComponents/containerList.js +7 -2
  12. package/dist/helpers/dockerService/serviceComponents/containerLogs.js +33 -20
  13. package/dist/helpers/dockerService/serviceComponents/containerStats.js +12 -3
  14. package/dist/helpers/dockerService/serviceComponents/imageUtils.js +12 -0
  15. package/dist/helpers/exitWithMessage.js +11 -0
  16. package/dist/helpers/validationHelpers.js +15 -2
  17. package/dist/hooks/creation/useContainerCreation.js +2 -6
  18. package/dist/hooks/useContainers.js +1 -3
  19. package/dist/hooks/useControls.js +27 -2
  20. package/dist/hooks/useLogsStream.js +6 -0
  21. package/dist/index.js +1 -4
  22. package/package.json +1 -1
  23. package/src/components/ContainerRow.jsx +17 -5
  24. package/src/helpers/actionHelpers.js +1 -1
  25. package/src/helpers/dockerService/dockerService.js +7 -1
  26. package/src/helpers/dockerService/serviceComponents/containerActions.js +25 -9
  27. package/src/helpers/dockerService/serviceComponents/containerList.js +1 -1
  28. package/src/helpers/dockerService/serviceComponents/containerLogs.js +19 -15
  29. package/src/helpers/dockerService/serviceComponents/containerStats.js +9 -1
  30. package/src/helpers/validationHelpers.js +14 -2
  31. package/src/hooks/creation/useContainerCreation.js +2 -6
  32. package/src/hooks/useControls.js +5 -1
  33. package/test/validationHelpers.test.js +32 -0
@@ -15,7 +15,15 @@ export async function getStats(containerId) {
15
15
  stream.precpu_stats.cpu_usage.total_usage;
16
16
  const systemDelta =
17
17
  stream.cpu_stats.system_cpu_usage - stream.precpu_stats.system_cpu_usage;
18
- const cpuPercent = systemDelta > 0 ? (cpuDelta / systemDelta) * 100 : 0;
18
+
19
+ // Get number of CPUs for proper normalization
20
+ const numCpus = stream.cpu_stats.online_cpus ||
21
+ stream.cpu_stats.cpu_usage.percpu_usage?.length || 1;
22
+
23
+ // Calculate normalized CPU percentage
24
+ const cpuPercent = systemDelta > 0
25
+ ? ((cpuDelta / systemDelta) * numCpus * 100)
26
+ : 0;
19
27
 
20
28
  const memUsage = stream.memory_stats.usage || 0;
21
29
  const memLimit = stream.memory_stats.limit || 1;
@@ -11,6 +11,18 @@ export function validatePorts(portInput) {
11
11
  }
12
12
 
13
13
  export function validateEnvVars(envInput) {
14
- // Future specific validations
15
- return true;
14
+ if (!envInput || !envInput.trim()) return true; // Empty is valid
15
+
16
+ const vars = envInput.split(",").map(v => v.trim()).filter(Boolean);
17
+ const invalid = vars.find(v => {
18
+ const parts = v.split("=");
19
+ // Must have at least VAR=value format
20
+ if (parts.length < 2) return true;
21
+ const varName = parts[0].trim();
22
+ // Variable names should be alphanumeric with underscores
23
+ if (!/^[A-Z_][A-Z0-9_]*$/i.test(varName)) return true;
24
+ return false;
25
+ });
26
+
27
+ return !invalid;
16
28
  }
@@ -42,12 +42,8 @@ export function useContainerCreation({ onCreate, onCancel, dbImages = [] }) {
42
42
  return;
43
43
  }
44
44
  if (step === 2) {
45
- if (!portInput.trim()) {
46
- setMessage("You must specify at least one port to expose (e.g. 8080:80)");
47
- setMessageColor("red");
48
- return;
49
- }
50
- if (!validatePorts(portInput)) {
45
+ // Ports are now optional - only validate if provided
46
+ if (portInput.trim() && !validatePorts(portInput)) {
51
47
  setMessage("Port format must be host:container and both must be numbers (e.g. 8080:80)");
52
48
  setMessageColor("red");
53
49
  return;
@@ -200,7 +200,11 @@ export function useControls(containers = []) {
200
200
  logsViewer.openLogs();
201
201
  getLogsStream(
202
202
  containers[selected].id,
203
- (data) => logsViewer.setLogs((prev) => [...prev, ...data.split("\n").filter(Boolean)]),
203
+ (data) => logsViewer.setLogs((prev) => {
204
+ const newLogs = [...prev, ...data.split("\n").filter(Boolean)];
205
+ // Limit to last 1000 lines to prevent memory leak
206
+ return newLogs.slice(-1000);
207
+ }),
204
208
  () => {},
205
209
  (err) => logsViewer.setLogs((prev) => [...prev, `Error: ${err.message}`])
206
210
  );
@@ -1,8 +1,10 @@
1
1
  let validatePorts;
2
+ let validateEnvVars;
2
3
 
3
4
  beforeAll(async () => {
4
5
  const mod = await import('../src/helpers/validationHelpers.js');
5
6
  validatePorts = mod.validatePorts;
7
+ validateEnvVars = mod.validateEnvVars;
6
8
  });
7
9
 
8
10
  describe('validatePorts', () => {
@@ -26,3 +28,33 @@ describe('validatePorts', () => {
26
28
  expect(validatePorts('')).toBe(false);
27
29
  });
28
30
  });
31
+
32
+ describe('validateEnvVars', () => {
33
+ test('empty input is valid', () => {
34
+ expect(validateEnvVars('')).toBe(true);
35
+ });
36
+
37
+ test('valid single env var', () => {
38
+ expect(validateEnvVars('NODE_ENV=production')).toBe(true);
39
+ });
40
+
41
+ test('valid multiple env vars', () => {
42
+ expect(validateEnvVars('NODE_ENV=production,PORT=3000')).toBe(true);
43
+ });
44
+
45
+ test('valid env var with underscores', () => {
46
+ expect(validateEnvVars('MY_VAR_NAME=value')).toBe(true);
47
+ });
48
+
49
+ test('invalid env var without equals sign', () => {
50
+ expect(validateEnvVars('NOEQUALS')).toBe(false);
51
+ });
52
+
53
+ test('invalid env var with invalid name', () => {
54
+ expect(validateEnvVars('123INVALID=value')).toBe(false);
55
+ });
56
+
57
+ test('invalid env var with special characters in name', () => {
58
+ expect(validateEnvVars('MY-VAR=value')).toBe(false);
59
+ });
60
+ });