Canvas: Add VM/PROXY dev modes support

- Update ServiceSchema to discriminate between VM and PROXY dev modes
- Add DevDisabled, DevVM, DevProxy TypeScript types
- Update ServiceData type in graph.ts for new dev structure
- Update generateDodoConfig to handle both VM and PROXY modes
- Update configToGraph to properly convert dev configurations
- Maintain backward compatibility with existing dev configurations
- Update UI and introduce two new DevVM and DevProxy components
- Fetch user machine list from headscale API

Change-Id: I8f9df4ab9bd34c049fffadb748115335e8260a54
diff --git a/apps/canvas/front/package-lock.json b/apps/canvas/front/package-lock.json
index 247a513..2f44d68 100644
--- a/apps/canvas/front/package-lock.json
+++ b/apps/canvas/front/package-lock.json
@@ -18,6 +18,7 @@
 				"@radix-ui/react-icons": "^1.3.1",
 				"@radix-ui/react-label": "^2.1.7",
 				"@radix-ui/react-popover": "^1.1.2",
+				"@radix-ui/react-radio-group": "^1.3.7",
 				"@radix-ui/react-scroll-area": "^1.2.0",
 				"@radix-ui/react-select": "^2.1.2",
 				"@radix-ui/react-separator": "^1.1.0",
@@ -2762,6 +2763,311 @@
 				}
 			}
 		},
+		"node_modules/@radix-ui/react-radio-group": {
+			"version": "1.3.7",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.7.tgz",
+			"integrity": "sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/primitive": "1.1.2",
+				"@radix-ui/react-compose-refs": "1.1.2",
+				"@radix-ui/react-context": "1.1.2",
+				"@radix-ui/react-direction": "1.1.1",
+				"@radix-ui/react-presence": "1.1.4",
+				"@radix-ui/react-primitive": "2.1.3",
+				"@radix-ui/react-roving-focus": "1.1.10",
+				"@radix-ui/react-use-controllable-state": "1.2.2",
+				"@radix-ui/react-use-previous": "1.1.1",
+				"@radix-ui/react-use-size": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/primitive": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.2.tgz",
+			"integrity": "sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==",
+			"license": "MIT"
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-collection": {
+			"version": "1.1.7",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz",
+			"integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-compose-refs": "1.1.2",
+				"@radix-ui/react-context": "1.1.2",
+				"@radix-ui/react-primitive": "2.1.3",
+				"@radix-ui/react-slot": "1.2.3"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-compose-refs": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz",
+			"integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-context": {
+			"version": "1.1.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz",
+			"integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-direction": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz",
+			"integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-id": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz",
+			"integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-use-layout-effect": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-presence": {
+			"version": "1.1.4",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.4.tgz",
+			"integrity": "sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-compose-refs": "1.1.2",
+				"@radix-ui/react-use-layout-effect": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-primitive": {
+			"version": "2.1.3",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz",
+			"integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-slot": "1.2.3"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-roving-focus": {
+			"version": "1.1.10",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.10.tgz",
+			"integrity": "sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/primitive": "1.1.2",
+				"@radix-ui/react-collection": "1.1.7",
+				"@radix-ui/react-compose-refs": "1.1.2",
+				"@radix-ui/react-context": "1.1.2",
+				"@radix-ui/react-direction": "1.1.1",
+				"@radix-ui/react-id": "1.1.1",
+				"@radix-ui/react-primitive": "2.1.3",
+				"@radix-ui/react-use-callback-ref": "1.1.1",
+				"@radix-ui/react-use-controllable-state": "1.2.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"@types/react-dom": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
+				"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				},
+				"@types/react-dom": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-slot": {
+			"version": "1.2.3",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
+			"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-compose-refs": "1.1.2"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-callback-ref": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz",
+			"integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-controllable-state": {
+			"version": "1.2.2",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz",
+			"integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-use-effect-event": "0.0.2",
+				"@radix-ui/react-use-layout-effect": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-layout-effect": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz",
+			"integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-previous": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz",
+			"integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==",
+			"license": "MIT",
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
+		"node_modules/@radix-ui/react-radio-group/node_modules/@radix-ui/react-use-size": {
+			"version": "1.1.1",
+			"resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz",
+			"integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==",
+			"license": "MIT",
+			"dependencies": {
+				"@radix-ui/react-use-layout-effect": "1.1.1"
+			},
+			"peerDependencies": {
+				"@types/react": "*",
+				"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
+			},
+			"peerDependenciesMeta": {
+				"@types/react": {
+					"optional": true
+				}
+			}
+		},
 		"node_modules/@radix-ui/react-roving-focus": {
 			"version": "1.1.0",
 			"resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.0.tgz",