Skip to content

Commit f7bd633

Browse files
committed
Merge branch 'next' of github.com:devforth/adminforth into next
2 parents 4b848f9 + 3f714c3 commit f7bd633

File tree

6 files changed

+266
-2
lines changed

6 files changed

+266
-2
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
# Many2Many
2+
3+
This plugin lets you manage many-to-many relationships.
4+
5+
## Installation
6+
7+
Install the plugin:
8+
9+
```bash
10+
npm i @adminforth/many2many
11+
```
12+
13+
## Setting up
14+
15+
Let's say we want to implement a relationship where every apartment can have many realtors and each realtor can have many apartments.
16+
We'll also need a junction resource to connect realtors and apartments.
17+
18+
First, create the `realtors` table and the junction table `realtorsAparts`:
19+
20+
21+
```ts title="./schema.prisma"
22+
//diff-add
23+
model realtors {
24+
//diff-add
25+
id String @id
26+
//diff-add
27+
name String
28+
//diff-add
29+
surname String
30+
//diff-add
31+
}
32+
//diff-add
33+
model realtorsAparts {
34+
//diff-add
35+
id String @id
36+
//diff-add
37+
realtorId String
38+
//diff-add
39+
apartmentId String
40+
//diff-add
41+
}
42+
```
43+
44+
Migrate the Prisma schema:
45+
46+
```bash
47+
npm run makemigration -- --name add-realtors-and-realtorsAparts; npm run migrate:local
48+
```
49+
50+
Now create a resource for the realtors:
51+
52+
```ts title="./resources/realtors.ts"
53+
import { AdminForthDataTypes, AdminForthResourceInput } from 'adminforth';
54+
55+
export default {
56+
dataSource: 'maindb',
57+
table: 'realtors',
58+
resourceId: 'realtors',
59+
label: 'Realtors',
60+
recordLabel: (r) => ` ${r.name}`,
61+
columns: [
62+
{
63+
name: 'id',
64+
type: AdminForthDataTypes.STRING,
65+
label: 'Identifier',
66+
showIn: {
67+
list: false,
68+
edit: false,
69+
create: false,
70+
},
71+
primaryKey: true,
72+
fillOnCreate: ({ initialRecord, adminUser }) => Math.random().toString(36).substring(7),
73+
},
74+
{
75+
name: 'name',
76+
required: true,
77+
showIn: { all: true },
78+
type: AdminForthDataTypes.STRING,
79+
maxLength: 255,
80+
minLength: 3,
81+
},
82+
{
83+
name: "surname",
84+
required: true,
85+
showIn: { all: true },
86+
type: AdminForthDataTypes.STRING,
87+
maxLength: 100,
88+
minLength: 3,
89+
}
90+
],
91+
options: {
92+
listPageSize: 12,
93+
allowedActions: {
94+
edit: true,
95+
delete: true,
96+
show: true,
97+
filter: true,
98+
},
99+
},
100+
} as AdminForthResourceInput;
101+
```
102+
103+
And one for the junction table `realtorsAparts`:
104+
105+
```ts title="./resources/realtorsAparts.ts"
106+
import { AdminForthDataTypes, AdminForthResourceInput } from 'adminforth';
107+
108+
export default {
109+
dataSource: 'maindb',
110+
table: 'realtorsAparts',
111+
resourceId: 'realtorsAparts',
112+
label: 'Realtors-aparts',
113+
columns: [
114+
{
115+
name: 'id',
116+
type: AdminForthDataTypes.STRING,
117+
label: 'Identifier',
118+
showIn: {
119+
list: false,
120+
edit: false,
121+
create: false,
122+
},
123+
primaryKey: true,
124+
fillOnCreate: ({ initialRecord, adminUser }) => Math.random().toString(36).substring(7),
125+
},
126+
{
127+
name: 'realtorId',
128+
foreignResource: {
129+
resourceId: 'realtors',
130+
searchableFields: ['name'],
131+
searchIsCaseSensitive: true
132+
}
133+
},
134+
{
135+
name: 'apartmentId',
136+
foreignResource: {
137+
resourceId: 'aparts',
138+
searchableFields: ['title'],
139+
searchIsCaseSensitive: true
140+
}
141+
},
142+
],
143+
options: {
144+
listPageSize: 12,
145+
allowedActions: {
146+
edit: true,
147+
delete: true,
148+
show: true,
149+
filter: true,
150+
},
151+
},
152+
} as AdminForthResourceInput;
153+
```
154+
155+
Now add the plugin resources to the main config file:
156+
157+
```ts title="./index.ts"
158+
159+
//diff-add
160+
import realtorsResource from './resources/realtors.js';
161+
//diff-add
162+
import realtorsApartsResource from './resources/realtorsAparts.js';
163+
164+
...
165+
166+
167+
dataSources: [
168+
{
169+
id: 'maindb',
170+
url: `${process.env.DATABASE_URL}`
171+
},
172+
],
173+
resources: [
174+
...
175+
//diff-add
176+
realtorsResource,
177+
//diff-add
178+
realtorsApartsResource
179+
]
180+
181+
...
182+
183+
menu: [
184+
185+
...
186+
//diff-add
187+
{
188+
//diff-add
189+
label: 'Realtors',
190+
//diff-add
191+
resourceId: 'realtors'
192+
//diff-add
193+
},
194+
//diff-add
195+
{
196+
//diff-add
197+
label: 'Realtors-aparts',
198+
//diff-add
199+
resourceId: 'realtorsAparts'
200+
//diff-add
201+
},
202+
203+
...
204+
205+
]
206+
207+
```
208+
209+
Finally, add the plugin to the `apartments` resource:
210+
211+
212+
```ts title="./resources/apartments.ts"
213+
//diff-add
214+
import Many2ManyPlugin from '@adminforth/many2many';
215+
216+
...
217+
218+
plugins: [
219+
...
220+
221+
//diff-add
222+
new Many2ManyPlugin({
223+
//diff-add
224+
linkedResourceId: 'realtors',
225+
//diff-add
226+
})
227+
228+
...
229+
]
230+
231+
...
232+
233+
```
234+
235+
236+
The plugin is set up. Create some records in the `realtors` table:
237+
![alt text](Many2Many-1.png)
238+
Now, when creating an apartment, you can select (link) one or more realtors.
239+
![alt text](Many2Many-2.png)
240+
After saving the record, rows in the junction table are created automatically:
241+
![alt text](Many2Many-3.png)
242+
243+
244+
## Disable automatic cleanup of the junction table
245+
By default, when you delete a realtor or an apartment, all related rows in the junction table are deleted automatically. To avoid this behavior, add:
246+
247+
```ts
248+
249+
...
250+
251+
new Many2ManyPlugin({
252+
linkedResourceId: 'realtors',
253+
//diff-add
254+
dontDeleteJunctionRecords: true, // prevents automatic deletion of related junction rows
255+
})
256+
257+
...
258+
259+
```
38.7 KB
Loading
71.5 KB
Loading
59 KB
Loading

adminforth/spa/src/App.vue

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
</div>
5353

5454
<ul class="py-1" role="none">
55-
<li v-for="c in coreStore?.config?.globalInjections?.userMenu || []" class="bg-lightUserMenuItemBackground hover:bg-lightUserMenuItemBackgroundHover text-lightUserMenuItemText hover:text-lightUserMenuItemText dark:bg-darkUserMenuItemBackground dark:hover:bg-darkUserMenuItemBackgroundHover dark:text-darkUserMenuItemText dark:hover:darkUserMenuItemTextHover" >
55+
<li v-for="c in userMenuComponents" class="bg-lightUserMenuItemBackground hover:bg-lightUserMenuItemBackgroundHover text-lightUserMenuItemText hover:text-lightUserMenuItemText dark:bg-darkUserMenuItemBackground dark:hover:bg-darkUserMenuItemBackgroundHover dark:text-darkUserMenuItemText dark:hover:darkUserMenuItemTextHover" >
5656
<component
5757
:is="getCustomComponent(c)"
5858
:meta="c.meta"
@@ -200,6 +200,10 @@ const expandedWidth = computed(() => coreStore.config?.iconOnlySidebar?.expanded
200200
201201
const theme = ref('light');
202202
203+
const userMenuComponents = computed(() => {
204+
return coreStore?.config?.globalInjections?.userMenu || [];
205+
})
206+
203207
function hideSidebar(): void {
204208
sideBarOpen.value = false;
205209
}

plugins/install-plugins.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,8 @@ PLUGINS="adminforth-audit-log adminforth-email-password-reset adminforth-foreign
33
adminforth-i18n adminforth-import-export adminforth-text-complete adminforth-open-signup \
44
adminforth-rich-editor adminforth-two-factors-auth adminforth-upload adminforth-oauth \
55
adminforth-list-in-place-edit adminforth-inline-create adminforth-markdown adminforth-email-invite adminforth-bulk-ai-flow \
6-
adminforth-universal-search adminforth-login-captcha adminforth-user-soft-delete adminforth-clone-row adminforth-quick-filters"
6+
adminforth-universal-search adminforth-login-captcha adminforth-user-soft-delete adminforth-clone-row adminforth-quick-filters \
7+
adminforth-many2many"
78

89
# Function to install a plugin
910
install_plugin() {

0 commit comments

Comments
 (0)