@@ -10,37 +10,49 @@ type PortEntry = {
1010 custom_ip ?: string ; // User-entered IP for custom mode
1111} ;
1212
13+ // ... keep your types as-is ...
14+
1315type ComponentInstance = {
1416 ports : PortEntry [ ] ;
17+ normalizePort : ( p : PortEntry ) => void ;
1518} ;
1619
1720const PortMappingEditorComponent = {
1821 name : 'PortMappingEditor' ,
1922 props : {
23+ ports : { type : Array , required : true } ,
24+ } ,
25+
26+ // ✅ NEW: normalize on initial load
27+ created ( this : ComponentInstance ) {
28+ this . ports . forEach ( ( p ) => this . normalizePort ( p ) ) ;
29+ } ,
30+
31+ // ✅ NEW: normalize again if parent replaces ports array (e.g. after refresh)
32+ watch : {
2033 ports : {
21- type : Array ,
22- required : true ,
34+ deep : true ,
35+ handler ( this : ComponentInstance , newPorts : PortEntry [ ] ) {
36+ newPorts . forEach ( ( p ) => this . normalizePort ( p ) ) ;
37+ } ,
2338 } ,
2439 } ,
40+
2541 template : /* html */ `
2642 <div class="port-mapping-editor">
2743 <label>Port Mappings</label>
2844 <div v-for="(port, index) in ports" :key="index" class="port-row">
29-
30- <!-- protocol -->
3145 <select v-model="port.protocol">
3246 <option value="tcp">TCP</option>
3347 <option value="udp">UDP</option>
3448 </select>
3549
36- <!-- address mode selector -->
3750 <select v-model="port.host_address_mode" @change="onModeChange(port)">
3851 <option value="local">Local</option>
3952 <option value="public">Public</option>
4053 <option value="custom">Custom</option>
4154 </select>
4255
43- <!-- custom IP input -->
4456 <input
4557 v-if="port.host_address_mode === 'custom'"
4658 type="text"
@@ -49,24 +61,32 @@ const PortMappingEditorComponent = {
4961 @input="onCustomIPChange(port)"
5062 />
5163
52- <!-- ports -->
5364 <input type="number" v-model.number="port.host_port" placeholder="Host Port" required>
5465 <input type="number" v-model.number="port.vm_port" placeholder="VM Port" required>
55-
56- <!-- remove -->
57- <button type="button" class="action-btn danger" @click="removePort(index)">
58- Remove
59- </button>
66+ <button type="button" class="action-btn danger" @click="removePort(index)">Remove</button>
6067 </div>
61-
62- <!-- add -->
63- <button type="button" class="action-btn" @click="addPort">
64- Add Port
65- </button>
68+ <button type="button" class="action-btn" @click="addPort">Add Port</button>
6669 </div>
6770 ` ,
6871
6972 methods : {
73+ // ✅ NEW: derives mode + custom_ip from host_address when editing existing VMs
74+ normalizePort ( this : ComponentInstance , port : PortEntry ) {
75+ // If mode already set, keep it (don’t fight the user while editing)
76+ if ( port . host_address_mode ) return ;
77+
78+ if ( port . host_address === '127.0.0.1' ) {
79+ port . host_address_mode = 'local' ;
80+ port . custom_ip = '' ;
81+ } else if ( port . host_address === '0.0.0.0' ) {
82+ port . host_address_mode = 'public' ;
83+ port . custom_ip = '' ;
84+ } else {
85+ port . host_address_mode = 'custom' ;
86+ port . custom_ip = port . host_address ; // show dedicated IP in input
87+ }
88+ } ,
89+
7090 addPort ( this : ComponentInstance ) {
7191 this . ports . push ( {
7292 protocol : 'tcp' ,
@@ -82,20 +102,25 @@ const PortMappingEditorComponent = {
82102 this . ports . splice ( index , 1 ) ;
83103 } ,
84104
85- // Called when switching between Local / Public / Custom
86105 onModeChange ( port : PortEntry ) {
87106 if ( port . host_address_mode === 'local' ) {
88107 port . host_address = '127.0.0.1' ;
89- }
90- else if ( port . host_address_mode === 'public' ) {
108+ port . custom_ip = '' ;
109+ } else if ( port . host_address_mode === 'public' ) {
91110 port . host_address = '0.0.0.0' ;
92- }
93- else if ( port . host_address_mode === 'custom' ) {
111+ port . custom_ip = '' ;
112+ } else if ( port . host_address_mode === 'custom' ) {
113+ // if coming from existing custom, keep it; otherwise start empty
114+ if ( ! port . custom_ip || port . custom_ip === '' ) {
115+ // if host_address already contains a non-standard IP, reuse it
116+ if ( port . host_address !== '127.0.0.1' && port . host_address !== '0.0.0.0' ) {
117+ port . custom_ip = port . host_address ;
118+ }
119+ }
94120 port . host_address = port . custom_ip || '' ;
95121 }
96122 } ,
97123
98- // Called when user types a custom IP
99124 onCustomIPChange ( port : PortEntry ) {
100125 if ( port . host_address_mode === 'custom' ) {
101126 port . host_address = port . custom_ip || '' ;
0 commit comments