33"require fs" ;
44"require uci" ;
55"require form" ;
6+ "require ui" ;
67"require tools.widgets as widgets" ;
78
89// fix css paading (kusa
@@ -19,9 +20,40 @@ return view.extend({
1920 const area = ( results [ 0 ] . stdout || "" ) . trim ( ) ;
2021 const mape_status = ( results [ 1 ] . stdout || "" ) . split ( "\n" ) ;
2122
22- const areaValue = area || "UNKNOWN" ;
23+ let areaValue = area || "UNKNOWN" ;
2324 const mapeIsUnknown = mape_status . length <= 1 || mape_status [ 0 ] === "UNKNOWN" ;
2425
26+ // Special handling for NURO
27+ if ( mape_status [ 0 ] === "NURO" ) {
28+ areaValue = "UNKNOWN(NURO)" ;
29+ }
30+
31+ // Check for pending status if everything is UNKNOWN
32+ if ( areaValue === "UNKNOWN" && mapeIsUnknown ) {
33+ return L . resolveDefault ( fs . exec ( "/usr/sbin/fleth" , [ "get_pending_status" ] ) , { stdout : "" } )
34+ . then ( function ( pendingResult ) {
35+ const pendingStatus = ( pendingResult . stdout || "" ) . trim ( ) ;
36+
37+ if ( pendingStatus . endsWith ( "_pending" ) ) {
38+ const detectedArea = pendingStatus . split ( '_' ) [ 0 ] ;
39+ return {
40+ area : detectedArea ,
41+ dslite_provider : "UNKNOWN" ,
42+ mape_status : mape_status ,
43+ isPending : true ,
44+ } ;
45+ }
46+
47+ // No pending status, return all UNKNOWN
48+ return {
49+ area : areaValue ,
50+ dslite_provider : "UNKNOWN" ,
51+ mape_status : mape_status ,
52+ isPending : false ,
53+ } ;
54+ } ) ;
55+ }
56+
2557 // Only get DS-Lite if area is not UNKNOWN and MAP-E is UNKNOWN
2658 if ( areaValue !== "UNKNOWN" && mapeIsUnknown ) {
2759 return L . resolveDefault ( fs . exec ( "/usr/sbin/fleth" , [ "get_dslite_provider" ] ) , { stdout : "" } )
@@ -31,20 +63,30 @@ return view.extend({
3163 area : areaValue ,
3264 dslite_provider : dslite_provider || "UNKNOWN" ,
3365 mape_status : mape_status ,
66+ isPending : false ,
3467 } ;
3568 } ) ;
3669 } else {
3770 return {
3871 area : areaValue ,
3972 dslite_provider : "UNKNOWN" ,
4073 mape_status : mape_status ,
74+ isPending : false ,
4175 } ;
4276 }
4377 } ) ;
4478 } ,
4579
4680 render : async function ( data ) {
4781 let m , s , o ;
82+
83+ // Show pending construction popup if detected
84+ if ( data . isPending ) {
85+ ui . addNotification ( _ ( 'Service Status' ) , E ( 'div' , [
86+ E ( 'p' , _ ( 'Optical line construction completed, provider configuration in progress. Please wait patiently.' ) ) ,
87+ E ( 'p' , { style : 'color: #666; font-size: 0.9em;' } , _ ( 'Service typically becomes available in the evening after construction is completed.' ) )
88+ ] ) , 'info' ) ;
89+ }
4890
4991 m = new form . Map (
5092 "fleth" ,
@@ -73,44 +115,38 @@ return view.extend({
73115 return data . dslite_provider ;
74116 } ;
75117
76- // Create all MAP-E fields
77- const mapeFields = [
78- [ "mape_provider" , "MAP-E Provider" ] ,
79- [ "mape_ipaddr" , "IP Address" ] ,
80- [ "mape_peeraddr" , "Peer Address" ] ,
81- [ "mape_ip4prefix" , "IPv4 prefix" ] ,
82- [ "mape_ip4prefixlen" , "IPv4 Prefix Length" ] ,
83- [ "mape_ip6prefix" , "IPv6 Prefix" ] ,
84- [ "mape_ip6prefixlen" , "IPv6 Prefix Length" ] ,
85- [ "mape_ealen" , "EA Length" ] ,
86- [ "mape_psidlen" , "PSID Length" ] ,
87- [ "mape_offset" , "Offset" ] ,
88- [ "mape_map_ports" , "Available ports" ] ,
89- ] ;
118+ // Check if MAP-E data is available
119+ const hasMapeData = data . mape_status [ 0 ] !== "UNKNOWN" && data . mape_status . length > 1 ;
90120
91- // Check if we should hide MAP-E details initially
92- const shouldHideMapeDetails = data . mape_status [ 0 ] === "UNKNOWN" ||
93- data . mape_status . length <= 1 ;
121+ // Always show MAP-E Provider
122+ o = s . taboption ( "info" , form . DummyValue , "mape_provider" , _ ( "MAP-E Provider" ) ) ;
123+ o . cfgvalue = function ( ) {
124+ return data . mape_status [ 0 ] || _ ( "UNKNOWN" ) ;
125+ } ;
94126
95- // Create all MAP-E fields
96- mapeFields . forEach ( ( field , i ) => {
97- const [ fieldName , fieldLabel ] = field ;
98- o = s . taboption ( "info" , form . DummyValue , fieldName , _ ( fieldLabel ) ) ;
99- o . cfgvalue = function ( ) {
100- if ( i === 0 ) { // MAP-E Provider field
101- return data . mape_status [ 0 ] || _ ( "UNKNOWN" ) ;
102- }
103- return data . mape_status [ i ] || "" ;
104- } ;
105- // Add a class to identify MAP-E detail fields for hiding
106- if ( i > 0 && shouldHideMapeDetails ) {
107- o . rmempty = false ;
108- o . editable = false ;
109- // We'll hide these with CSS after render
110- o . modalonly = false ;
111- o . optional = true ;
112- }
113- } ) ;
127+ // Only show detailed MAP-E fields if we have valid data
128+ if ( hasMapeData ) {
129+ const mapeDetailFields = [
130+ [ "mape_ipaddr" , "IP Address" ] ,
131+ [ "mape_peeraddr" , "Peer Address" ] ,
132+ [ "mape_ip4prefix" , "IPv4 prefix" ] ,
133+ [ "mape_ip4prefixlen" , "IPv4 Prefix Length" ] ,
134+ [ "mape_ip6prefix" , "IPv6 Prefix" ] ,
135+ [ "mape_ip6prefixlen" , "IPv6 Prefix Length" ] ,
136+ [ "mape_ealen" , "EA Length" ] ,
137+ [ "mape_psidlen" , "PSID Length" ] ,
138+ [ "mape_offset" , "Offset" ] ,
139+ [ "mape_map_ports" , "Available ports" ] ,
140+ ] ;
141+
142+ mapeDetailFields . forEach ( ( field , i ) => {
143+ const [ fieldName , fieldLabel ] = field ;
144+ o = s . taboption ( "info" , form . DummyValue , fieldName , _ ( fieldLabel ) ) ;
145+ o . cfgvalue = function ( ) {
146+ return data . mape_status [ i + 1 ] || "" ;
147+ } ;
148+ } ) ;
149+ }
114150
115151 // o = s.taboption('general', form.Button, '_hook_luci-firewall-port-forward');
116152 // o.title = ' ';
@@ -197,24 +233,106 @@ return view.extend({
197233 o . nocreate = true ;
198234 o . default = "wan" ;
199235
200- // Hide MAP-E detail fields initially if no valid data
201- setTimeout ( ( ) => {
202- if ( data . mape_status [ 0 ] === "UNKNOWN" ||
203- data . mape_status . length <= 1 ) {
204- const mapeDetailFields = [
205- "mape_ipaddr" , "mape_peeraddr" , "mape_ip4prefix" , "mape_ip4prefixlen" ,
206- "mape_ip6prefix" , "mape_ip6prefixlen" , "mape_ealen" , "mape_psidlen" ,
207- "mape_offset" , "mape_map_ports"
208- ] ;
209- mapeDetailFields . forEach ( field => {
210- const fieldContainer = document . querySelector ( `[data-name="${ field } "]` ) ;
211- if ( fieldContainer ) {
212- fieldContainer . style . display = 'none' ;
213- }
214- } ) ;
215- }
216- } , 100 ) ;
236+ // Actions section in General Settings
237+ o = s . taboption ( "general" , form . DummyValue , "_actions_description" ) ;
238+ o . title = _ ( "Actions" ) ;
239+ o . description = _ ( "Actions will automatically save current configuration before execution." ) ;
240+ o . cfgvalue = function ( ) {
241+ return "" ;
242+ } ;
243+
244+ o = s . taboption ( "general" , form . Button , "_setup_ipv6_slaac" ) ;
245+ o . title = " " ;
246+ o . inputtitle = _ ( "Setup IPv6 SLAAC for NEXT(1Gbps) and without Hikari Denwa" ) ;
247+ o . inputstyle = "apply" ;
248+ o . onclick = L . bind ( function ( m ) {
249+ return this . setupIPv6SLAAC ( m ) ;
250+ } , this , m ) ;
251+
252+ o = s . taboption ( "general" , form . Button , "_setup_ipv6_pd" ) ;
253+ o . title = " " ;
254+ o . inputtitle = _ ( "Setup IPv6 PD for Cross(10Gbps) or with Hikari Denwa" ) ;
255+ o . inputstyle = "apply" ;
256+ o . onclick = L . bind ( function ( m ) {
257+ return this . setupIPv6PD ( m ) ;
258+ } , this , m ) ;
217259
218260 return m . render ( ) ;
219261 } ,
262+
263+ setupIPv6SLAAC : function ( mapObj ) {
264+ return new Promise ( function ( resolve , reject ) {
265+ // First save current configuration
266+ mapObj . save ( )
267+ . then ( function ( ) {
268+ // Show loading message
269+ ui . showModal ( _ ( 'Setting up IPv6 SLAAC' ) , [
270+ E ( 'p' , { 'class' : 'spinning' } , _ ( 'Applying IPv6 SLAAC configuration for NEXT(1Gbps) without Hikari Denwa...' ) )
271+ ] ) ;
272+
273+ // Execute the IPv6 SLAAC setup
274+ return fs . exec ( '/usr/sbin/fleth' , [ 'setup_ipv6_slaac' ] ) ;
275+ } )
276+ . then ( function ( result ) {
277+ ui . hideModal ( ) ;
278+
279+ if ( result . code === 0 && result . stdout . trim ( ) === 'SUCCESS' ) {
280+ ui . addNotification ( null , E ( 'p' , _ ( 'IPv6 SLAAC configuration applied successfully!' ) ) , 'info' ) ;
281+ } else {
282+ ui . addNotification ( null , E ( 'div' , [
283+ E ( 'p' , _ ( 'Failed to apply IPv6 SLAAC configuration:' ) ) ,
284+ E ( 'pre' , result . stdout || result . stderr || 'Unknown error' )
285+ ] ) , 'error' ) ;
286+ }
287+
288+ resolve ( ) ;
289+ } )
290+ . catch ( function ( error ) {
291+ ui . hideModal ( ) ;
292+ ui . addNotification ( null , E ( 'div' , [
293+ E ( 'p' , _ ( 'Error executing IPv6 SLAAC setup:' ) ) ,
294+ E ( 'pre' , error . message || error )
295+ ] ) , 'error' ) ;
296+ reject ( error ) ;
297+ } ) ;
298+ } ) ;
299+ } ,
300+
301+ setupIPv6PD : function ( mapObj ) {
302+ return new Promise ( function ( resolve , reject ) {
303+ // First save current configuration
304+ mapObj . save ( )
305+ . then ( function ( ) {
306+ // Show loading message
307+ ui . showModal ( _ ( 'Setting up IPv6 PD' ) , [
308+ E ( 'p' , { 'class' : 'spinning' } , _ ( 'Applying IPv6 PD configuration for Cross(10Gbps) or with Hikari Denwa...' ) )
309+ ] ) ;
310+
311+ // Execute the IPv6 PD setup
312+ return fs . exec ( '/usr/sbin/fleth' , [ 'setup_ipv6_pd' ] ) ;
313+ } )
314+ . then ( function ( result ) {
315+ ui . hideModal ( ) ;
316+
317+ if ( result . code === 0 && result . stdout . trim ( ) === 'SUCCESS' ) {
318+ ui . addNotification ( null , E ( 'p' , _ ( 'IPv6 PD configuration applied successfully!' ) ) , 'info' ) ;
319+ } else {
320+ ui . addNotification ( null , E ( 'div' , [
321+ E ( 'p' , _ ( 'Failed to apply IPv6 PD configuration:' ) ) ,
322+ E ( 'pre' , result . stdout || result . stderr || 'Unknown error' )
323+ ] ) , 'error' ) ;
324+ }
325+
326+ resolve ( ) ;
327+ } )
328+ . catch ( function ( error ) {
329+ ui . hideModal ( ) ;
330+ ui . addNotification ( null , E ( 'div' , [
331+ E ( 'p' , _ ( 'Error executing IPv6 PD setup:' ) ) ,
332+ E ( 'pre' , error . message || error )
333+ ] ) , 'error' ) ;
334+ reject ( error ) ;
335+ } ) ;
336+ } ) ;
337+ } ,
220338} ) ;
0 commit comments