Skip to content

Commit 0c98741

Browse files
committed
Add link list
1 parent ca36d05 commit 0c98741

7 files changed

Lines changed: 228 additions & 1 deletion

File tree

admin/pages/general.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { EditPage, TextField } from '@contember/admin'
2-
import { LinkField } from '../../src'
2+
import { LinkField, LinkListField } from '../../src'
33
import { CollapsibleBox } from '../../src/collapsibleBox/admin'
44
import { ImageField, ImageListField } from '../../src/image/admin'
55
import { YoutubeVideoField, YoutubeVideoListField } from '../../src/youtube/admin'
@@ -15,6 +15,7 @@ export default () => (
1515
<TextField field="text" label="Text" />
1616
<LinkField field="homePage" label="Link to home" allowDisconnect titleField={false} />
1717
<LinkField field="privacyPolicyPage" label="Link to another" allowTargetBlank allowDisconnect />
18+
<LinkListField field="linkList" label="Link list" allowTargetBlank />
1819

1920
<CollapsibleBox heading="Images">
2021
<ImageField field="singleImage" label="Single image" />
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
{
2+
"formatVersion": 3,
3+
"modifications": [
4+
{
5+
"modification": "createEntity",
6+
"entity": {
7+
"name": "LinkList",
8+
"primary": "id",
9+
"primaryColumn": "id",
10+
"tableName": "link_list",
11+
"fields": {
12+
"id": {
13+
"name": "id",
14+
"columnName": "id",
15+
"columnType": "uuid",
16+
"nullable": false,
17+
"type": "Uuid"
18+
}
19+
},
20+
"unique": {},
21+
"indexes": {},
22+
"eventLog": {
23+
"enabled": true
24+
}
25+
}
26+
},
27+
{
28+
"modification": "createEntity",
29+
"entity": {
30+
"name": "LinkListItem",
31+
"primary": "id",
32+
"primaryColumn": "id",
33+
"tableName": "link_list_item",
34+
"fields": {
35+
"id": {
36+
"name": "id",
37+
"columnName": "id",
38+
"columnType": "uuid",
39+
"nullable": false,
40+
"type": "Uuid"
41+
}
42+
},
43+
"unique": {},
44+
"indexes": {},
45+
"eventLog": {
46+
"enabled": true
47+
}
48+
}
49+
},
50+
{
51+
"modification": "createColumn",
52+
"entityName": "LinkListItem",
53+
"field": {
54+
"name": "order",
55+
"columnName": "order",
56+
"columnType": "integer",
57+
"nullable": false,
58+
"type": "Integer",
59+
"default": 0
60+
},
61+
"fillValue": 0
62+
},
63+
{
64+
"modification": "createRelation",
65+
"entityName": "General",
66+
"owningSide": {
67+
"type": "OneHasOne",
68+
"name": "linkList",
69+
"target": "LinkList",
70+
"joiningColumn": {
71+
"columnName": "link_list_id",
72+
"onDelete": "set null"
73+
},
74+
"nullable": true
75+
}
76+
},
77+
{
78+
"modification": "createRelation",
79+
"entityName": "LinkListItem",
80+
"owningSide": {
81+
"type": "ManyHasOne",
82+
"name": "list",
83+
"target": "LinkList",
84+
"joiningColumn": {
85+
"columnName": "list_id",
86+
"onDelete": "cascade"
87+
},
88+
"nullable": false,
89+
"inversedBy": "items"
90+
},
91+
"inverseSide": {
92+
"type": "OneHasMany",
93+
"name": "items",
94+
"target": "LinkListItem",
95+
"ownedBy": "list",
96+
"orderBy": [
97+
{
98+
"path": [
99+
"order"
100+
],
101+
"direction": "asc"
102+
}
103+
]
104+
}
105+
},
106+
{
107+
"modification": "createRelation",
108+
"entityName": "LinkListItem",
109+
"owningSide": {
110+
"type": "OneHasOne",
111+
"name": "link",
112+
"target": "Link",
113+
"joiningColumn": {
114+
"columnName": "link_id",
115+
"onDelete": "set null"
116+
},
117+
"nullable": true
118+
}
119+
},
120+
{
121+
"modification": "patchAclSchema",
122+
"patch": [
123+
{
124+
"op": "add",
125+
"path": "/roles/admin/entities/LinkList",
126+
"value": {
127+
"predicates": {},
128+
"operations": {
129+
"read": {
130+
"id": true,
131+
"items": true
132+
},
133+
"create": {
134+
"id": true,
135+
"items": true
136+
},
137+
"update": {
138+
"id": true,
139+
"items": true
140+
},
141+
"delete": true,
142+
"customPrimary": true
143+
}
144+
}
145+
},
146+
{
147+
"op": "add",
148+
"path": "/roles/admin/entities/LinkListItem",
149+
"value": {
150+
"predicates": {},
151+
"operations": {
152+
"read": {
153+
"id": true,
154+
"list": true,
155+
"order": true,
156+
"link": true
157+
},
158+
"create": {
159+
"id": true,
160+
"list": true,
161+
"order": true,
162+
"link": true
163+
},
164+
"update": {
165+
"id": true,
166+
"list": true,
167+
"order": true,
168+
"link": true
169+
},
170+
"delete": true,
171+
"customPrimary": true
172+
}
173+
}
174+
},
175+
{
176+
"op": "add",
177+
"path": "/roles/admin/entities/General/operations/read/linkList",
178+
"value": true
179+
},
180+
{
181+
"op": "add",
182+
"path": "/roles/admin/entities/General/operations/create/linkList",
183+
"value": true
184+
},
185+
{
186+
"op": "add",
187+
"path": "/roles/admin/entities/General/operations/update/linkList",
188+
"value": true
189+
}
190+
]
191+
}
192+
]
193+
}

api/model/General.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { SchemaDefinition as d } from '@contember/schema-definition'
22
import { Image, ImageList } from './Image'
33
import { Link } from './Link'
4+
import { LinkList } from './LinkList'
45
import { One } from './One'
56
import { YoutubeVideo, YoutubeVideoList } from './Youtube'
67

@@ -14,6 +15,7 @@ export class General {
1415

1516
homePage = d.oneHasOne(Link).setNullOnDelete()
1617
privacyPolicyPage = d.oneHasOne(Link).setNullOnDelete()
18+
linkList = d.oneHasOne(LinkList).setNullOnDelete()
1719

1820
singleYoutubeVideo = d.oneHasOne(YoutubeVideo).setNullOnDelete()
1921
youtubeVideoList = d.oneHasOne(YoutubeVideoList).setNullOnDelete()

api/model/LinkList.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { SchemaDefinition as d } from '@contember/schema-definition'
2+
import { Link } from './Link'
3+
4+
export class LinkList {
5+
items = d.oneHasMany(LinkListItem, 'list').orderBy('order')
6+
}
7+
8+
export class LinkListItem {
9+
list = d.manyHasOne(LinkList, 'items').cascadeOnDelete().notNull()
10+
11+
order = d.intColumn().notNull().default(0)
12+
link = d.oneHasOne(Link).setNullOnDelete()
13+
}

api/model/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ export * from './General'
22
export * from './GenericPage'
33
export * from './Image'
44
export * from './Link'
5+
export * from './LinkList'
56
export * from './Linkable'
67
export * from './One'
78
export * from './Seo'

src/link/admin/LinkListField.tsx

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { Component, HasOne, Repeater } from '@contember/admin'
2+
import { LinkField } from './LinkField'
3+
4+
export interface LinkListFieldProps {
5+
field: string
6+
label?: string
7+
allowTargetBlank?: boolean
8+
}
9+
10+
export const LinkListField = Component<LinkListFieldProps>(({ field, label = 'Links', allowTargetBlank }) => (
11+
<HasOne field={field}>
12+
<Repeater field="items" sortableBy="order" label={label} addButtonText="Add link">
13+
<LinkField field="link" label="Link" allowDisconnect={false} allowTargetBlank={allowTargetBlank} />
14+
</Repeater>
15+
</HasOne>
16+
))

src/link/admin/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
export * from './LinkField'
2+
export * from './LinkListField'

0 commit comments

Comments
 (0)