-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathschema.ts
265 lines (258 loc) · 8.91 KB
/
schema.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
Welcome to the schema! The schema is the heart of Keystone.
Here we define our 'lists', which will then be used both for the GraphQL
API definition, our database tables, and our Admin UI layout.
Some quick definitions to help out:
A list: A definition of a collection of fields with a name. For the starter
we have `User`, `Post`, and `Tag` lists.
A field: The individual bits of data on your list, each with its own type.
you can see some of the lists in what we use below.
*/
// Like the `config` function we use in keystone.ts, we use functions
// for putting in our config so we get useful errors. With typescript,
// we get these even before code runs.
import { list } from "@keystone-6/core";
// We're using some common fields in the starter. Check out https://keystonejs.com/docs/apis/fields#fields-api
// for the full list of fields.
import {
text,
relationship,
password,
timestamp,
select,
checkbox,
image,
integer,
} from "@keystone-6/core/fields";
// The document field is a more complicated field, so it's in its own package
// Keystone aims to have all the base field types, but you can make your own
// custom ones.
import { document } from "@keystone-6/fields-document";
// We are using Typescript, and we want our types experience to be as strict as it can be.
// By providing the Keystone generated `Lists` type to our lists object, we refine
// our types to a stricter subset that is type-aware of other lists in our schema
// that Typescript cannot easily infer.
import { Lists } from ".keystone/types";
// We have a users list, a blogs list, and tags for blog posts, so they can be filtered.
// Each property on the exported object will become the name of a list (a.k.a. the `listKey`),
// with the value being the definition of the list, including the fields.
export const lists: Lists = {
// Here we define the user list.
User: list({
// Here are the fields that `User` will have. We want an email and password so they can log in
// a name so we can refer to them, and a way to connect users to posts.
fields: {
name: text({ validation: { isRequired: true } }),
email: text({
validation: { isRequired: true },
isIndexed: "unique",
isFilterable: true,
}),
admin: checkbox(),
// The password field takes care of hiding details and hashing values
password: password({ validation: { isRequired: true } }),
// Relationships allow us to reference other lists. In this case,
// we want a user to have many posts, and we are saying that the user
// should be referencable by the 'author' field of posts.
// Make sure you read the docs to understand how they work: https://keystonejs.com/docs/guides/relationships#understanding-relationships
projects: relationship({ ref: "Project.author", many: true }),
},
// Here we can configure the Admin UI. We want to show a user's name and posts in the Admin UI
ui: {
listView: {
initialColumns: ["name", "projects"],
},
},
access: {
operation: {
query: ({ session, context, listKey, operation }) => true,
create: ({ session, context, listKey, operation }) =>
session.data.admin,
update: ({ session, context, listKey, operation }) =>
session.data.admin,
delete: ({ session, context, listKey, operation }) =>
session.data.admin,
},
filter: {
query: ({ session }) =>
session.data.admin ? {} : { id: { equals: session.itemId } },
},
},
}),
Project: list({
fields: {
teamName: text({}),
teamSize: integer({
defaultValue: 1,
ui: {
description: "How many people are there in the team?",
},
}),
teamMembers: text({
defaultValue: "",
ui: {
description:
"Please list the team members. This will be displayed on the website. Feel free to include URL. Example: Name1 (github.com/username1)",
displayMode: "textarea",
},
}),
title: text({
label: "Project Title",
}),
description: document({
formatting: true,
links: true,
label: "Project Description",
ui: {
description: "The description will be displayed on the archive.",
},
}),
image: image({
storage: "images",
label: "Thumbnail Image",
ui: {
description:
"The image will be displayed on the archive. Recommeded size 1280x720.",
},
}),
safe: checkbox({
defaultValue: true,
label: "This Project is Safe for Public Broadcast",
ui: {
description:
"Uncheck this box if publicly broadcasting/publishing this project might cause you or the organizers to get in trouble.",
},
}),
author: relationship({
ref: "User.projects",
}),
urls: text({
label: "URLs",
ui: {
displayMode: "textarea",
description: "GitHub, Demo URL, etc.",
},
}),
video: text({
label: "YouTube Video (if submitting remotely)",
ui: {
description:
"If you cannot present your project in person, you can submit it remotely. Please enter the YouTube video URL here.",
},
}),
},
access: {
operation: {
query: ({ session, context, listKey, operation }) => true,
create: ({ session, context, listKey, operation }) =>
session.data.admin,
update: ({ session, context, listKey, operation }) => true,
delete: ({ session, context, listKey, operation }) =>
session.data.admin,
},
filter: {
query: ({ session }) =>
session.data.admin
? {}
: { author: { id: { equals: session.itemId } } },
update: ({ session }) =>
session.data.admin
? {}
: { author: { id: { equals: session.itemId } } },
},
},
ui: {
hideCreate: async ({ session }) => {
return !session.data.admin;
},
},
hooks: {
resolveInput: ({ resolvedData, context }) => {
if (!context.session?.data.admin) {
return {
...resolvedData,
author: {
connect: {
id: context.session.itemId,
},
},
};
}
return resolvedData;
},
},
}),
// // Our second list is the Posts list. We've got a few more fields here
// // so we have all the info we need for displaying posts.
// Post: list({
// fields: {
// title: text(),
// // Having the status here will make it easy for us to choose whether to display
// // posts on a live site.
// status: select({
// options: [
// { label: "Published", value: "published" },
// { label: "Draft", value: "draft" },
// ],
// // We want to make sure new posts start off as a draft when they are created
// defaultValue: "draft",
// // fields also have the ability to configure their appearance in the Admin UI
// ui: {
// displayMode: "segmented-control",
// },
// }),
// // The document field can be used for making highly editable content. Check out our
// // guide on the document field https://keystonejs.com/docs/guides/document-fields#how-to-use-document-fields
// // for more information
// content: document({
// formatting: true,
// layouts: [
// [1, 1],
// [1, 1, 1],
// [2, 1],
// [1, 2],
// [1, 2, 1],
// ],
// links: true,
// dividers: true,
// }),
// publishDate: timestamp(),
// // Here is the link from post => author.
// // We've configured its UI display quite a lot to make the experience of editing posts better.
// author: relationship({
// ref: "User.posts",
// ui: {
// displayMode: "cards",
// cardFields: ["name", "email"],
// inlineEdit: { fields: ["name", "email"] },
// linkToItem: true,
// inlineConnect: true,
// inlineCreate: { fields: ["name", "email"] },
// },
// }),
// // We also link posts to tags. This is a many <=> many linking.
// tags: relationship({
// ref: "Tag.posts",
// ui: {
// displayMode: "cards",
// cardFields: ["name"],
// inlineEdit: { fields: ["name"] },
// linkToItem: true,
// inlineConnect: true,
// inlineCreate: { fields: ["name"] },
// },
// many: true,
// }),
// },
// }),
// // Our final list is the tag list. This field is just a name and a relationship to posts
// Tag: list({
// ui: {
// isHidden: true,
// },
// fields: {
// name: text(),
// posts: relationship({ ref: "Post.tags", many: true }),
// },
// }),
};