Skip to content

Commit bbace84

Browse files
committed
Merge branch 'next' of github.com:devforth/adminforth into next
2 parents 590f699 + f086b33 commit bbace84

File tree

5 files changed

+88
-24
lines changed

5 files changed

+88
-24
lines changed

adminforth/commands/createCustomComponent/configLoader.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ dotenv.config({ path: '.env', override: true });
1010
export async function getAdminInstance() {
1111
const configFileName = 'index.ts';
1212
const configPath = path.resolve(process.cwd(), configFileName);
13-
console.log('Loading config from', configPath);
1413
try {
1514
await fs.access(configPath);
1615
} catch (error) {

adminforth/index.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,10 @@ class AdminForth implements IAdminForth {
157157
this.activatePlugins();
158158
process.env.HEAVY_DEBUG && console.log('🔧 Plugins activated');
159159

160+
process.env.HEAVY_DEBUG && console.log('🔧 Validating after plugin activation...');
161+
this.configValidator.validateAfterPluginsActivation();
162+
process.env.HEAVY_DEBUG && console.log('🔧 Config validated');
163+
160164
process.env.HEAVY_DEBUG && console.log('🔧 Creating ExpressServer...');
161165
this.express = new ExpressServer(this);
162166
process.env.HEAVY_DEBUG && console.log('🔧 ExpressServer created');

adminforth/modules/configValidator.ts

Lines changed: 75 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -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 = [];

adminforth/spa/src/views/LoginView.vue

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,12 @@
105105
<Button @click="login" :loader="inProgress" :disabled="inProgress || disableLoginButton" class="w-full">
106106
{{ $t('Login to your account') }}
107107
</Button>
108+
<component
109+
v-for="c in coreStore?.config?.loginPageInjections?.underLoginButton || []"
110+
:is="getCustomComponent(c)"
111+
:meta="c.meta"
112+
@update:disableLoginButton="setDisableLoginButton($event)"
113+
/>
108114
</form>
109115
</div>
110116
</div>

adminforth/types/Back.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export interface ICodeInjector {
2828

2929
export interface IConfigValidator {
3030
validateConfig(): void;
31+
validateAfterPluginsActivation(): void;
3132
postProcessAfterDiscover(resource: AdminForthResource): void;
3233
}
3334

@@ -794,6 +795,7 @@ interface AdminForthInputConfigCustomization {
794795
*/
795796
loginPageInjections?: {
796797
underInputs?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
798+
underLoginButton?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
797799
panelHeader?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
798800
}
799801

@@ -1131,6 +1133,7 @@ export interface AdminForthConfigCustomization extends Omit<AdminForthInputConfi
11311133

11321134
loginPageInjections: {
11331135
underInputs: Array<AdminForthComponentDeclarationFull>,
1136+
underLoginButton?: AdminForthComponentDeclaration | Array<AdminForthComponentDeclaration>,
11341137
panelHeader: Array<AdminForthComponentDeclarationFull>,
11351138
},
11361139

0 commit comments

Comments
 (0)