@smartive/graphql-magic 15.1.1 → 15.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,6 +1,6 @@
1
- ## [15.1.1](https://github.com/smartive/graphql-magic/compare/v15.1.0...v15.1.1) (2024-04-03)
1
+ ## [15.2.1](https://github.com/smartive/graphql-magic/compare/v15.2.0...v15.2.1) (2024-04-03)
2
2
 
3
3
 
4
4
  ### Bug Fixes
5
5
 
6
- * Docusaurus config ([415736b](https://github.com/smartive/graphql-magic/commit/415736b866c8526b24770a8e374cf0b3667380f6))
6
+ * Finish intro ([4ecc445](https://github.com/smartive/graphql-magic/commit/4ecc44575901cbe731dca7b70f109da6eaa847ba))
@@ -10,59 +10,85 @@ Let's create a blog with `graphql-magic`!
10
10
 
11
11
  ### Code base
12
12
 
13
- First create a next.js website:
13
+ First create a `next.js` website:
14
14
 
15
15
  ```
16
16
  npx create-next-app@latest magic-blog --ts --app --tailwind --eslint --src
17
17
  cd magic-blog
18
18
  ```
19
19
 
20
- For some styling install `preline` and dependencies:
20
+ Replace `src/app/globals.css`:
21
21
 
22
22
  ```
23
- npm i preline @tailwindcss/forms
24
- ```
23
+ @tailwind base;
24
+ @tailwind components;
25
+ @tailwind utilities;
25
26
 
26
- Add `@tailwindcss/forms` to `tailwind.config.ts`:
27
+ main {
28
+ @apply w-96 mx-auto
29
+ }
27
30
 
28
- ```
29
- plugins: [
30
- require('@tailwindcss/forms'),
31
- ],
32
- ```
31
+ nav {
32
+ @apply flex items-center
33
+ }
33
34
 
34
- Replace `app/globals.css`:
35
+ h1, h2, h3, h4 {
36
+ @apply font-bold
37
+ }
35
38
 
36
- ```
37
- TODO
38
- ```
39
+ h1 {
40
+ @apply text-4xl mb-4 flex-grow
41
+ }
39
42
 
40
- Replace `app/layout.tsx`:
43
+ h2 {
44
+ @apply text-3xl mb-3
45
+ }
41
46
 
42
- ```
43
- export default function RootLayout({
44
- children,
45
- }: Readonly<{
46
- children: React.ReactNode;
47
- }>) {
48
- return (
49
- <html>
50
- <body>{children}</body>
51
- </html>
52
- );
47
+ h3 {
48
+ @apply text-2xl mb-2
49
+ }
50
+
51
+ h4 {
52
+ @apply text-xl mb-1
53
+ }
54
+
55
+ a {
56
+ @apply text-blue-500
57
+ }
58
+
59
+ article, form {
60
+ @apply mb-4 p-3 rounded-lg shadow-md border border-gray-100
61
+ }
62
+
63
+ input, textarea {
64
+ @apply border border-gray-300 w-full rounded-md p-1
65
+ }
66
+
67
+ label span {
68
+ @apply font-bold
53
69
  }
54
70
  ```
55
71
 
56
- Replace `app/page.tsx`:
72
+ Replace `src/app/page.tsx`:
57
73
 
58
74
  ```
59
- export default function Page() {
60
- return <div>
75
+ export default async function Home() {
76
+ return <main>
77
+ <nav>
61
78
  <h1>Magic Blog</h1>
62
- </div>
79
+ </nav>
80
+ </main>
63
81
  }
64
82
  ```
65
83
 
84
+ Start the website:
85
+
86
+ ```
87
+ npm run dev
88
+ ```
89
+
90
+ ### Install graphql-magic
91
+
66
92
  Add this setting to `next.config.mjs`:
67
93
 
68
94
  ```
@@ -79,28 +105,16 @@ Install `@smartive/graphql-magic`:
79
105
  npm install @smartive/graphql-magic
80
106
  ```
81
107
 
82
- Temporary:
83
-
84
- ```
85
- npm i @graphql-codegen/typescript-compatibility
86
- ```
87
-
88
108
  Run the gqm cli:
89
109
 
90
110
  ```
91
111
  npx gqm generate
92
112
  ```
93
113
 
94
- Start the website:
95
-
96
- ```
97
- npm run dev
98
- ```
99
-
100
114
  ### Database setup
101
115
 
102
- Adapt the database `.env` variables to connect to a postgresql instance, or create a new one.
103
- For example, to create a local instance with docker and docker-compose, create the following `docker-compose.yml`:
116
+ Let's boot a local database instance.
117
+ Create the following `docker-compose.yml`:
104
118
 
105
119
  ```
106
120
  version: '3.4'
@@ -126,7 +140,7 @@ Generate the first migration:
126
140
  npx gqm generate-migration
127
141
  ```
128
142
 
129
- Enter "setup" as migration name. Or you could first create a `feat/setup` git branch, then it would use that name automatically.
143
+ Enter a migration name, e.g. "setup".
130
144
 
131
145
 
132
146
  Run the migration
@@ -148,10 +162,12 @@ import { getSession } from '@auth0/nextjs-auth0';
148
162
  export default async function Page() {
149
163
  const session = await getSession();
150
164
 
151
- return <div>
165
+ return <main>
166
+ <nav>
152
167
  <h1>Welcome to my Blog</h1>
153
168
  {session ? <a href="/api/auth/logout">Logout</a> : <a href="/api/auth/login">Login</a>}
154
- </div>
169
+ </nav>
170
+ </main>
155
171
  }
156
172
  ```
157
173
 
@@ -241,23 +257,27 @@ npx gqm generate
241
257
  Now, let's modify `src/app/page.tsx` so that it fetches the user from the database:
242
258
 
243
259
  ```
244
- import { GetMeQuery } from "../generated/client";
245
- import { GET_ME } from "../graphql/client/queries/get-me";
246
- import { executeGraphql } from "../graphql/execute";
260
+ import { GetMeQuery } from "@/generated/client";
261
+ import { GET_ME } from "@/graphql/client/queries/get-me";
262
+ import { executeGraphql } from "@/graphql/execute";
247
263
 
248
- export default async function Page() {
249
- const { data: { me }} = await executeGraphql<GetMeQuery>({ query: GET_ME });
264
+ export default async function Home() {
265
+ const { data: { me } } = await executeGraphql<GetMeQuery>({ query: GET_ME });
250
266
 
251
- return <div>
252
- <h1>Welcome to my Blog</h1>
253
- {me ? <div>Hello {me.username}! <a href="/api/auth/logout">Logout</a></div> : <a href="/api/auth/login">Login</a>}
254
- </div>
267
+ return (
268
+ <main>
269
+ <nav>
270
+ <h1>Blog</h1>
271
+ {me ? <span>Hello, {me.username}! <a href="/api/auth/logout"> Logout</a></span> : <a href="/api/auth/login">Login</a>}
272
+ </nav>
273
+ </main>
274
+ );
255
275
  }
256
276
  ```
257
277
 
258
278
  ### Content!
259
279
 
260
- Let's create a blog by adding new models in `src/config/models.ts`:
280
+ Let's make a blog out of this app by adding new models in `src/config/models.ts`:
261
281
 
262
282
  ```
263
283
  {
@@ -313,10 +333,9 @@ Generate and run the new migrations and generate the new models:
313
333
  ```
314
334
  npx gqm generate-migration
315
335
  npx env-cmd knex migrate:up
316
- npx gqm generate
317
336
  ```
318
337
 
319
- new get-posts
338
+ Create a new query `src/graphql/client/queries/get-posts.ts`:
320
339
 
321
340
  ```
322
341
  import { gql } from '@smartive/graphql-magic';
@@ -342,12 +361,59 @@ export const GET_POSTS = gql`
342
361
  `;
343
362
  ```
344
363
 
364
+ Generate the new types:
365
+
345
366
  ```
346
- {me && <CreatePost/> }
347
- <Posts/>
367
+ npx gqm generate
348
368
  ```
349
369
 
370
+ Now add all the logic to create and display posts and comments to `src/app/page.tsx`
371
+
372
+
350
373
  ```
374
+ import { CreateCommentMutationMutation, CreateCommentMutationMutationVariables, CreatePostMutationMutation, CreatePostMutationMutationVariables, GetMeQuery, GetPostsQuery } from "@/generated/client";
375
+ import { CREATE_COMMENT, CREATE_POST } from "@/generated/client/mutations";
376
+ import { GET_ME } from "@/graphql/client/queries/get-me";
377
+ import { GET_POSTS } from "@/graphql/client/queries/get-posts";
378
+ import { executeGraphql } from "@/graphql/execute";
379
+ import { revalidatePath } from "next/cache";
380
+
381
+ export default async function Home() {
382
+ const { data: { me } } = await executeGraphql<GetMeQuery>({ query: GET_ME });
383
+
384
+ return (
385
+ <main>
386
+ <nav>
387
+ <h1>Blog</h1>
388
+ {me ? <span>Hello, {me.username}! <a href="/api/auth/logout"> Logout</a></span> : <a href="/api/auth/login">Login</a>}
389
+ </nav>
390
+ {me && <CreatePost />}
391
+ <Posts me={me} />
392
+ </main>
393
+ );
394
+ }
395
+
396
+ async function Posts({ me }: { me: GetMeQuery['me'] }) {
397
+ const { data: { posts } } = await executeGraphql<GetPostsQuery>({ query: GET_POSTS })
398
+
399
+ return <div>
400
+ {posts.map(post => <div key={post.id}>
401
+ <article>
402
+ <h2>{post.title}</h2>
403
+ <div>by {post.createdBy.username}</div>
404
+ <p>{post.content}</p>
405
+ <h4>Comments</h4>
406
+ {post.comments.map(comment => (<div key={comment.id}>
407
+ <div>{comment.createdBy.username}</div>
408
+ <p>{comment.content}</p> by {comment.createdBy.username}
409
+ </div>)
410
+ )}
411
+ {me && <CreateComment postId={post.id} />}
412
+ </article>
413
+ </div>)}
414
+ </div>
415
+ }
416
+
351
417
  async function CreatePost() {
352
418
  async function createPost(formData: FormData) {
353
419
  'use server'
@@ -365,44 +431,20 @@ async function CreatePost() {
365
431
 
366
432
  return <form action={createPost}>
367
433
  <h2>New Post</h2>
368
- <div>
434
+ <label>
369
435
  <span>Title</span>
370
436
  <input name="title" />
371
- </div>
372
- <div>
437
+ </label>
438
+ <label>
373
439
  <span>Content</span>
374
440
  <textarea rows={5} name="content" />
375
- </div>
441
+ </label>
376
442
  <div>
377
443
  <button type="submit">Create</button>
378
444
  </div>
379
445
  </form>
380
446
  }
381
- ```
382
447
 
383
- ```
384
- async function Posts() {
385
- const { data: { posts } } = await executeGraphql<GetPostsQuery>({ query: GET_POSTS })
386
-
387
- return <div>
388
- {posts.map(post => <div key={post.id}>
389
- <article>
390
- <h3>{post.title}</h3>
391
- <div>{post.createdBy.username}</div>
392
- <div>{post.content}</div>
393
- {post.comments.map(comment => (<div key={comment.id}>
394
- <div>{comment.createdBy.username}</div>
395
- <p>{comment.content}</p> by {comment.createdBy.username}
396
- </div>)
397
- )}
398
- <CreateComment postId={post.id} />
399
- </article>
400
- </div>)}
401
- </div>
402
- }
403
- ```
404
-
405
- ```
406
448
  function CreateComment({ postId }: { postId: string }) {
407
449
  async function createComment(formData: FormData) {
408
450
  'use server'
@@ -429,3 +471,5 @@ function CreateComment({ postId }: { postId: string }) {
429
471
  </form>
430
472
  }
431
473
  ```
474
+
475
+ Now you should have a working minimal blog example!
@@ -1,5 +1,5 @@
1
- import clsx from 'clsx';
2
1
  import Heading from '@theme/Heading';
2
+ import clsx from 'clsx';
3
3
  import styles from './styles.module.css';
4
4
 
5
5
  type FeatureItem = {
@@ -10,38 +10,35 @@ type FeatureItem = {
10
10
 
11
11
  const FeatureList: FeatureItem[] = [
12
12
  {
13
- title: 'Easy to Use',
13
+ title: 'Model-first',
14
14
  Svg: require('@site/static/img/undraw_docusaurus_mountain.svg').default,
15
15
  description: (
16
16
  <>
17
- Docusaurus was designed from the ground up to be easily installed and
18
- used to get your website up and running quickly.
17
+ Define your model, generate everything else.
19
18
  </>
20
19
  ),
21
20
  },
22
21
  {
23
- title: 'Focus on What Matters',
22
+ title: 'CLI',
24
23
  Svg: require('@site/static/img/undraw_docusaurus_tree.svg').default,
25
24
  description: (
26
25
  <>
27
- Docusaurus lets you focus on your docs, and we&apos;ll do the chores. Go
28
- ahead and move your docs into the <code>docs</code> directory.
26
+ Generate things with our cli.
29
27
  </>
30
28
  ),
31
29
  },
32
30
  {
33
- title: 'Powered by React',
31
+ title: 'Brought to you by smartive',
34
32
  Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
35
33
  description: (
36
34
  <>
37
- Extend or customize your website layout by reusing React. Docusaurus can
38
- be extended while reusing the same header and footer.
35
+ We developed this as an internal tool.
39
36
  </>
40
37
  ),
41
38
  },
42
39
  ];
43
40
 
44
- function Feature({title, Svg, description}: FeatureItem) {
41
+ function Feature({ title, Svg, description }: FeatureItem) {
45
42
  return (
46
43
  <div className={clsx('col col--4')}>
47
44
  <div className="text--center">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@smartive/graphql-magic",
3
- "version": "15.1.1",
3
+ "version": "15.2.1",
4
4
  "description": "",
5
5
  "source": "src/index.ts",
6
6
  "type": "module",