@@ -34,6 +34,10 @@ export default class ConfigValidator implements IConfigValidator {
3434
3535 customComponentsDir : string | undefined ;
3636
37+ private static readonly LOGIN_INJECTION_KEYS = [ 'underInputs' , 'underLoginButton' , 'panelHeader' ] ;
38+ private static readonly GLOBAL_INJECTION_KEYS = [ 'userMenu' , 'header' , 'sidebar' , 'sidebarTop' , 'everyPageBottom' ] ;
39+ private static readonly PAGE_INJECTION_KEYS = [ 'beforeBreadcrumbs' , 'beforeActionButtons' , 'afterBreadcrumbs' , 'bottom' , 'threeDotsDropdownItems' , 'customActionIcons' ] ;
40+
3741 constructor ( private adminforth : IAdminForth , private inputConfig : AdminForthInputConfig ) {
3842 this . adminforth = adminforth ;
3943 this . inputConfig = inputConfig ;
@@ -57,16 +61,8 @@ export default class ConfigValidator implements IConfigValidator {
5761 }
5862 injections . forEach ( ( target , i ) => {
5963 injections [ i ] = this . validateComponent ( target , errors ) ;
60- injections [ i ] . meta . afInitialOrder = injections . length - i ; // to keep initial order for sorting later
6164 } ) ;
62- // sort by (injection.meta?.afOrder || 0) * 1000 desc, fallback to initial order in array
63- return injections . sort (
64- ( a , b ) => (
65- ( b . meta ?. afOrder ?? 0 ) * 1000 || b . meta ?. afInitialOrder
66- ) - (
67- ( a . meta ?. afOrder ?? 0 ) * 1000 || a . meta ?. afInitialOrder
68- )
69- ) ;
65+ return injections ;
7066 }
7167
7268 checkCustomFileExists ( filePath : string ) : Array < string > {
@@ -122,21 +118,20 @@ export default class ConfigValidator implements IConfigValidator {
122118
123119 const loginPageInjections : AdminForthConfigCustomization [ 'loginPageInjections' ] = {
124120 underInputs : [ ] ,
121+ underLoginButton : [ ] ,
125122 panelHeader : [ ] ,
126123 } ;
127124
128125 if ( this . inputConfig . customization ?. loginPageInjections ) {
129- const ALLOWED_LOGIN_INJECTIONS = [ 'underInputs' , 'panelHeader' ]
130126 Object . keys ( this . inputConfig . customization . loginPageInjections ) . forEach ( ( injection ) => {
131- if ( ALLOWED_LOGIN_INJECTIONS . includes ( injection ) ) {
127+ if ( ConfigValidator . LOGIN_INJECTION_KEYS . includes ( injection ) ) {
132128 loginPageInjections [ injection ] = this . validateAndListifyInjectionNew ( this . inputConfig . customization . loginPageInjections , injection , errors ) ;
133129 } else {
134- const similar = suggestIfTypo ( ALLOWED_LOGIN_INJECTIONS , injection ) ;
135- errors . push ( `Login page injection key "${ injection } " is not allowed. Allowed keys are ${ ALLOWED_LOGIN_INJECTIONS . join ( ', ' ) } . ${ similar ? `Did you mean "${ similar } "?` : '' } ` ) ;
130+ const similar = suggestIfTypo ( ConfigValidator . LOGIN_INJECTION_KEYS , injection ) ;
131+ errors . push ( `Login page injection key "${ injection } " is not allowed. Allowed keys are ${ ConfigValidator . LOGIN_INJECTION_KEYS . join ( ', ' ) } . ${ similar ? `Did you mean "${ similar } "?` : '' } ` ) ;
136132 }
137133 } ) ;
138134 }
139-
140135 const globalInjections : AdminForthConfigCustomization [ 'globalInjections' ] = {
141136 userMenu : [ ] ,
142137 header : [ ] ,
@@ -146,13 +141,12 @@ export default class ConfigValidator implements IConfigValidator {
146141 } ;
147142
148143 if ( this . inputConfig . customization ?. globalInjections ) {
149- const ALLOWED_GLOBAL_INJECTIONS = [ 'userMenu' , 'header' , 'sidebar' , 'sidebarTop' , 'everyPageBottom' ] ;
150144 Object . keys ( this . inputConfig . customization . globalInjections ) . forEach ( ( injection ) => {
151- if ( ALLOWED_GLOBAL_INJECTIONS . includes ( injection ) ) {
145+ if ( ConfigValidator . GLOBAL_INJECTION_KEYS . includes ( injection ) ) {
152146 globalInjections [ injection ] = this . validateAndListifyInjectionNew ( this . inputConfig . customization . globalInjections , injection , errors ) ;
153147 } else {
154- const similar = suggestIfTypo ( ALLOWED_GLOBAL_INJECTIONS , injection ) ;
155- errors . push ( `Global injection key "${ injection } " is not allowed. Allowed keys are ${ ALLOWED_GLOBAL_INJECTIONS . join ( ', ' ) } . ${ similar ? `Did you mean "${ similar } "?` : '' } ` ) ;
148+ const similar = suggestIfTypo ( ConfigValidator . GLOBAL_INJECTION_KEYS , injection ) ;
149+ errors . push ( `Global injection key "${ injection } " is not allowed. Allowed keys are ${ ConfigValidator . GLOBAL_INJECTION_KEYS . join ( ', ' ) } . ${ similar ? `Did you mean "${ similar } "?` : '' } ` ) ;
156150 }
157151 } ) ;
158152 }
@@ -814,7 +808,6 @@ export default class ConfigValidator implements IConfigValidator {
814808 } ) ;
815809
816810 // if pageInjection is a string, make array with one element. Also check file exists
817- const possibleInjections = [ 'beforeBreadcrumbs' , 'beforeActionButtons' , 'afterBreadcrumbs' , 'bottom' , 'threeDotsDropdownItems' , 'customActionIcons' ] ;
818811 const possiblePages = [ 'list' , 'show' , 'create' , 'edit' ] ;
819812
820813 if ( options . pageInjections ) {
@@ -826,11 +819,11 @@ export default class ConfigValidator implements IConfigValidator {
826819 }
827820
828821 Object . entries ( value ) . map ( ( [ injection , target ] ) => {
829- if ( possibleInjections . includes ( injection ) ) {
830- this . validateAndListifyInjection ( options . pageInjections [ key ] , injection , errors ) ;
822+ if ( ConfigValidator . PAGE_INJECTION_KEYS . includes ( injection ) ) {
823+ options . pageInjections [ key ] [ injection ] = this . validateAndListifyInjectionNew ( options . pageInjections [ key ] , injection , errors ) ;
831824 } else {
832- const similar = suggestIfTypo ( possibleInjections , injection ) ;
833- errors . push ( `Resource "${ res . resourceId } " has invalid pageInjection key "${ injection } ", Supported keys are ${ possibleInjections . join ( ', ' ) } ${ similar ? `Did you mean "${ similar } "?` : '' } ` ) ;
825+ const similar = suggestIfTypo ( ConfigValidator . PAGE_INJECTION_KEYS , injection ) ;
826+ errors . push ( `Resource "${ res . resourceId } " has invalid pageInjection key "${ injection } ", Supported keys are ${ ConfigValidator . PAGE_INJECTION_KEYS . join ( ', ' ) } ${ similar ? `Did you mean "${ similar } "?` : '' } ` ) ;
834827 }
835828 } ) ;
836829
@@ -904,6 +897,65 @@ export default class ConfigValidator implements IConfigValidator {
904897
905898 }
906899
900+ validateAfterPluginsActivation ( ) {
901+ // Sort all page injections throughout the config by afOrder
902+ this . sortAllPageInjections ( ) ;
903+ }
904+
905+ private sortAllPageInjections ( ) : void {
906+ const config = this . adminforth . config ;
907+
908+ // Sort login page injections
909+ if ( config . customization ?. loginPageInjections ) {
910+ const loginInjections = config . customization . loginPageInjections ;
911+ ConfigValidator . LOGIN_INJECTION_KEYS . forEach ( key => {
912+ if ( loginInjections [ key ] ) {
913+ this . sortInjectionArray ( loginInjections [ key ] ) ;
914+ }
915+ } ) ;
916+ }
917+
918+ // Sort global injections
919+ if ( config . customization ?. globalInjections ) {
920+ const globalInjections = config . customization . globalInjections ;
921+ ConfigValidator . GLOBAL_INJECTION_KEYS . forEach ( key => {
922+ if ( globalInjections [ key ] ) {
923+ this . sortInjectionArray ( globalInjections [ key ] ) ;
924+ }
925+ } ) ;
926+ }
927+
928+ // Sort resource page injections
929+ if ( config . resources ) {
930+ config . resources . forEach ( resource => {
931+ if ( resource . options ?. pageInjections ) {
932+ const pageInjections = resource . options . pageInjections ;
933+
934+ // For each page type (list, show, create, edit)
935+ Object . keys ( pageInjections ) . forEach ( pageType => {
936+ const pageTypeInjections = pageInjections [ pageType ] ;
937+ if ( pageTypeInjections ) {
938+ // For each injection point within the page
939+ ConfigValidator . PAGE_INJECTION_KEYS . forEach ( injectionKey => {
940+ if ( pageTypeInjections [ injectionKey ] ) {
941+ this . sortInjectionArray ( pageTypeInjections [ injectionKey ] ) ;
942+ }
943+ } ) ;
944+ }
945+ } ) ;
946+ }
947+ } ) ;
948+ }
949+ }
950+
951+ private sortInjectionArray ( injections : any ) : void {
952+ if ( Array . isArray ( injections ) ) {
953+ injections . sort ( ( a : AdminForthComponentDeclarationFull , b : AdminForthComponentDeclarationFull ) =>
954+ ( b . meta ?. afOrder ?? 0 ) - ( a . meta ?. afOrder ?? 0 )
955+ ) ;
956+ }
957+ }
958+
907959 validateConfig ( ) {
908960 const errors = [ ] ;
909961 const warnings = [ ] ;
0 commit comments