Skip to content

Commit 06e7908

Browse files
committed
feat: implement filtersTools for managing query filters in hooks
1 parent 55a870b commit 06e7908

File tree

4 files changed

+83
-11
lines changed

4 files changed

+83
-11
lines changed

adminforth/documentation/docs/tutorial/03-Customization/04-hooks.md

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -135,16 +135,10 @@ For example we can prevent the user to see Apartments created by other users. Su
135135
if (adminUser.dbUser.role === "superadmin") {
136136
return { ok: true };
137137
}
138-
if (!query.filters || query.filters.length === 0) {
139-
query.filters = [];
140-
}
141-
// skip existing realtor_id filter if it comes from UI Filters (right panel)
142-
query.filters = query.filters.filter((filter: any) => filter.field !== "realtor_id");
143-
query.filters.push({
144-
field: "realtor_id",
145-
value: adminUser.dbUser.id,
146-
operator: "eq",
147-
});
138+
139+
// this function will skip existing realtor_id filter if it supplied already from UI or previous hook, and will add new one for realtor_id
140+
query.filterTools.replaceOrAddTopFilter(Filters.EQ('realtor_id', adminUser.dbUser.id).
141+
148142
return { ok: true };
149143
},
150144
},
@@ -199,7 +193,7 @@ Let's limit it:
199193
dropdownList: {
200194
beforeDatasourceRequest: async ({ adminUser, query }: { adminUser: AdminUser, query: any }) => {
201195
if (adminUser.dbUser.role !== "superadmin") {
202-
query.filters = [{field: "id", value: adminUser.dbUser.id, operator: "eq"}];
196+
query.filtersTools.replaceOrAddTopFilter(Filters.EQ("id", adminUser.dbUser.id));
203197
};
204198
return {
205199
"ok": true,

adminforth/modules/filtersTools.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
export const filtersTools = {
2+
get(query: any) {
3+
return {
4+
checkTopFilterExists(field: string) {
5+
return Array.isArray(query.filters)
6+
? query.filters.some((f: any) => f.field === field)
7+
: false;
8+
},
9+
10+
removeTopFilter(field: string) {
11+
if (!Array.isArray(query.filters)) {
12+
throw new Error('query.filters is not an array');
13+
}
14+
15+
if (!this.checkTopFilterExists(field)) {
16+
throw new Error(`Top-level filter for field "${field}" not found`);
17+
}
18+
19+
query.filters = query.filters.filter((f: any) => f.field !== field);
20+
},
21+
22+
removeTopFilterIfExists(field: string) {
23+
try {
24+
this.removeTopFilter(field);
25+
} catch (e) {
26+
console.log(e);
27+
}
28+
},
29+
30+
replaceOrAddTopFilter(filter: { field: string; value: any; operator: string }) {
31+
if (!Array.isArray(query.filters)) query.filters = [];
32+
this.removeTopFilterIfExists(filter.field);
33+
query.filters.push(filter);
34+
}
35+
};
36+
}
37+
};

adminforth/modules/restApi.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { ActionCheckSource, AdminForthConfigMenuItem, AdminForthDataTypes, Admin
2121
AnnouncementBadgeResponse,
2222
GetBaseConfigResponse,
2323
ShowInResolved} from "../types/Common.js";
24+
import { filtersTools } from "../modules/filtersTools.js";
2425

2526
export async function interpretResource(
2627
adminUser: AdminUser,
@@ -614,10 +615,13 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
614615
}[source];
615616

616617
for (const hook of listify(resource.hooks?.[hookSource]?.beforeDatasourceRequest)) {
618+
const filterTools = filtersTools.get(body);
619+
body.filtersTools = filterTools;
617620
const resp = await hook({
618621
resource,
619622
query: body,
620623
adminUser,
624+
filtersTools: filterTools,
621625
extra: {
622626
body, query, headers, cookies, requestUrl
623627
},
@@ -856,9 +860,12 @@ export default class AdminForthRestAPI implements IAdminForthRestAPI {
856860
targetResources.map(async (targetResource) => {
857861
return new Promise(async (resolve) => {
858862
for (const hook of listify(columnConfig.foreignResource.hooks?.dropdownList?.beforeDatasourceRequest as BeforeDataSourceRequestFunction[])) {
863+
const filterTools = filtersTools.get(body);
864+
body.filtersTools = filterTools;
859865
const resp = await hook({
860866
query: body,
861867
adminUser,
868+
filtersTools: filterTools,
862869
resource: targetResource,
863870
extra: {
864871
body, query, headers, cookies, requestUrl

dev-demo/resources/apartments.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import {
22
ActionCheckSource,
33
AdminForthDataTypes,
4+
AdminForthResource,
45
AdminForthResourcePages,
56
AdminUser,
67
Filters,
@@ -80,6 +81,20 @@ export default {
8081
});
8182
return { ok: true, error: "" };
8283
},
84+
beforeDatasourceRequest: async ({
85+
query, adminUser, resource,
86+
}: {
87+
query: any; adminUser: AdminUser; resource: AdminForthResource;
88+
}) => {
89+
if (adminUser.dbUser.role === "superadmin") {
90+
return { ok: true };
91+
}
92+
93+
// this function will skip existing realtor_id filter if it supplied already from UI or previous hook, and will add new one for realtor_id
94+
query.filtersTools.replaceOrAddTopFilter(Filters.EQ('realtor_id', adminUser.dbUser.id));
95+
96+
return { ok: true };
97+
},
8398
},
8499
},
85100
columns: [
@@ -275,6 +290,25 @@ export default {
275290
name: "listed",
276291
required: true, // will be required on create/edit
277292
},
293+
{
294+
name: 'realtor_id',
295+
showIn: {filter: true, show: true, edit: true, list: true, create: true},
296+
foreignResource: {
297+
resourceId: 'users',
298+
hooks: {
299+
dropdownList: {
300+
beforeDatasourceRequest: async ({ adminUser, query }: { adminUser: AdminUser, query: any }) => {
301+
if (adminUser.dbUser.role !== "superadmin") {
302+
query.filtersTools.replaceOrAddTopFilter(Filters.EQ("id", adminUser.dbUser.id));
303+
};
304+
return {
305+
"ok": true,
306+
};
307+
}
308+
},
309+
}
310+
}
311+
},
278312
{
279313
name: "user_id",
280314
showIn: {filter: true, show: true, edit: true, list: true, create: true},

0 commit comments

Comments
 (0)