11import IngressDetailEditHelper from '@shell/utils/ingress' ;
22import { SECRET_TYPES as TYPES } from '@shell/config/secret' ;
3+ import { get , set } from '@shell/utils/object' ;
34
4- /**
5- * Mirrors the port parsing logic used in RulePath.vue and DefaultBackend.vue
6- * to decide whether to write port.number or port.name
7- */
85function parseServicePort ( rawPort : string | number ) : string | number {
96 const parsed = Number . parseInt ( String ( rawPort ) ) ;
107
118 return Number . isNaN ( parsed ) ? rawPort : parsed ;
129}
1310
14- /**
15- * Mirrors the portRequired validation rule from index.vue.
16- * Handles both scalar values (from component-level validation)
17- * and port objects (from form-validation mixin).
18- */
1911function portRequired ( port : any ) : string | undefined {
2012 if ( typeof port === 'string' || typeof port === 'number' ) {
2113 if ( ! port ) {
@@ -28,10 +20,6 @@ function portRequired(port: any): string | undefined {
2820 return undefined ;
2921}
3022
31- /**
32- * Mirrors the portRange validation rule from index.vue.
33- * Checks that a numeric port is within 1-65535 (handles both scalar and object inputs).
34- */
3523function portRange ( port : any ) : string | undefined {
3624 let num ;
3725
@@ -50,6 +38,45 @@ function portRange(port: any): string | undefined {
5038 return undefined ;
5139}
5240
41+ /**
42+ * Mirrors willSave() from index.vue.
43+ * Clears the default backend when the service name or port is missing.
44+ */
45+ function willSave ( spec : any , paths : { defaultBackendPath : string ; serviceNamePath : string ; servicePortPath : string ; servicePortNamePath : string } ) : void {
46+ const backend = get ( spec , paths . defaultBackendPath ) ;
47+ const serviceName = get ( backend , paths . serviceNamePath ) ;
48+ const servicePort = get ( backend , paths . servicePortPath ) ||
49+ get ( backend , paths . servicePortNamePath ) ;
50+
51+ if ( backend && ( ! serviceName || ! servicePort ) ) {
52+ set ( spec , paths . defaultBackendPath , null ) ;
53+ }
54+ }
55+
56+ /**
57+ * Mirrors defaultBackendNameRequired from index.vue.
58+ * Only enforces required when a service is actually selected.
59+ */
60+ function defaultBackendNameRequired ( name : any , hasService : boolean ) : string | undefined {
61+ if ( hasService && ! name ) {
62+ return 'Target Service is required' ;
63+ }
64+
65+ return undefined ;
66+ }
67+
68+ /**
69+ * Mirrors defaultBackendPortRequired from index.vue.
70+ * Delegates to portRequired only when a service is selected.
71+ */
72+ function defaultBackendPortRequired ( port : any , hasService : boolean ) : string | undefined {
73+ if ( ! hasService ) {
74+ return undefined ;
75+ }
76+
77+ return portRequired ( port ) ;
78+ }
79+
5380const makeHelper = ( ) => new IngressDetailEditHelper ( {
5481 $store : { } as any ,
5582 namespace : 'default' ,
@@ -436,4 +463,91 @@ describe('ingress', () => {
436463 } ) ;
437464 } ) ;
438465 } ) ;
466+
467+ describe ( 'willSave' , ( ) => {
468+ const nestedPaths = {
469+ defaultBackendPath : 'defaultBackend' ,
470+ serviceNamePath : 'service.name' ,
471+ servicePortPath : 'service.port.number' ,
472+ servicePortNamePath : 'service.port.name' ,
473+ } ;
474+
475+ it ( 'preserves backend when port.number is set' , ( ) => {
476+ const spec = { defaultBackend : { service : { name : 'my-svc' , port : { number : 80 } } } } ;
477+
478+ willSave ( spec , nestedPaths ) ;
479+ expect ( spec . defaultBackend ) . toStrictEqual ( { service : { name : 'my-svc' , port : { number : 80 } } } ) ;
480+ } ) ;
481+
482+ it ( 'preserves backend when port.name is set' , ( ) => {
483+ const spec = { defaultBackend : { service : { name : 'my-svc' , port : { name : 'http' } } } } ;
484+
485+ willSave ( spec , nestedPaths ) ;
486+ expect ( spec . defaultBackend ) . toStrictEqual ( { service : { name : 'my-svc' , port : { name : 'http' } } } ) ;
487+ } ) ;
488+
489+ it ( 'clears backend when service name is empty' , ( ) => {
490+ const spec = { defaultBackend : { service : { name : '' , port : { number : 80 } } } } ;
491+
492+ willSave ( spec , nestedPaths ) ;
493+ expect ( spec . defaultBackend ) . toBeNull ( ) ;
494+ } ) ;
495+
496+ it ( 'clears backend when both port paths are empty' , ( ) => {
497+ const spec = { defaultBackend : { service : { name : 'my-svc' , port : { } } } } ;
498+
499+ willSave ( spec , nestedPaths ) ;
500+ expect ( spec . defaultBackend ) . toBeNull ( ) ;
501+ } ) ;
502+
503+ it ( 'clears backend when port is undefined' , ( ) => {
504+ const spec = { defaultBackend : { service : { name : 'my-svc' } } } ;
505+
506+ willSave ( spec , nestedPaths ) ;
507+ expect ( spec . defaultBackend ) . toBeNull ( ) ;
508+ } ) ;
509+
510+ it ( 'does nothing when there is no backend' , ( ) => {
511+ const spec = { rules : [ { } ] } as any ;
512+
513+ willSave ( spec , nestedPaths ) ;
514+ expect ( spec ) . toStrictEqual ( { rules : [ { } ] } ) ;
515+ } ) ;
516+ } ) ;
517+
518+ describe ( 'defaultBackendNameRequired' , ( ) => {
519+ it ( 'returns error when service is selected but name is empty' , ( ) => {
520+ expect ( defaultBackendNameRequired ( '' , true ) ) . toBeDefined ( ) ;
521+ } ) ;
522+
523+ it ( 'passes when service is selected and name is set' , ( ) => {
524+ expect ( defaultBackendNameRequired ( 'my-svc' , true ) ) . toBeUndefined ( ) ;
525+ } ) ;
526+
527+ it ( 'passes when no service is selected and name is empty' , ( ) => {
528+ expect ( defaultBackendNameRequired ( '' , false ) ) . toBeUndefined ( ) ;
529+ } ) ;
530+
531+ it ( 'passes when no service is selected and name is undefined' , ( ) => {
532+ expect ( defaultBackendNameRequired ( undefined , false ) ) . toBeUndefined ( ) ;
533+ } ) ;
534+ } ) ;
535+
536+ describe ( 'defaultBackendPortRequired' , ( ) => {
537+ it ( 'delegates to portRequired when service is selected' , ( ) => {
538+ expect ( defaultBackendPortRequired ( '' , true ) ) . toBeDefined ( ) ;
539+ expect ( defaultBackendPortRequired ( 80 , true ) ) . toBeUndefined ( ) ;
540+ expect ( defaultBackendPortRequired ( 'http' , true ) ) . toBeUndefined ( ) ;
541+ expect ( defaultBackendPortRequired ( { number : 80 } , true ) ) . toBeUndefined ( ) ;
542+ expect ( defaultBackendPortRequired ( { name : 'http' } , true ) ) . toBeUndefined ( ) ;
543+ expect ( defaultBackendPortRequired ( { } , true ) ) . toBeDefined ( ) ;
544+ } ) ;
545+
546+ it ( 'skips validation when no service is selected' , ( ) => {
547+ expect ( defaultBackendPortRequired ( '' , false ) ) . toBeUndefined ( ) ;
548+ expect ( defaultBackendPortRequired ( undefined , false ) ) . toBeUndefined ( ) ;
549+ expect ( defaultBackendPortRequired ( null , false ) ) . toBeUndefined ( ) ;
550+ expect ( defaultBackendPortRequired ( { } , false ) ) . toBeUndefined ( ) ;
551+ } ) ;
552+ } ) ;
439553} ) ;
0 commit comments