(bright upbeat music) - Hey everybody, thanks for coming. This is the workshop for Redwood, and I hope that y'all
actually get something pretty cool out of this today. So the plan is we're gonna go
through and make a dashboard. And this dashboard is
gonna be for students, no particular reason why,
just cause that feels useful. But I wanted to give you a quick intro. My name is Milecia McGregor, I'm a developer advocate at Iterative.ai, which is completely unrelated to Redwood because we do machine learning stuff. But I'm also a huge tech nerd, so I've done front end development, back end, DevOps, database, admin stuff. And in a previous life, I
did robotics as a mechanical and aerospace engineer. So the reason that I ended
up working with Redwood is because last year when
everything was shut down, I ended up looking at just
different JavaScript frameworks because we all know about
reacting angular, but I was like, "What else is out here that seems useful." So I found Redwood, jumped straight in and now I'm basically
like a Redwood fan girl. (Milecia laughs) So that is why I'm here
to talk to you all today. But pretty much all of this
is just gonna be live coding. I don't have any type
of presentation ready, it's just us making this up. And feel free to stop me
with questions at any time. It's not like this is something, I don't know, we have a couple of hours, so we have time if y'all
have specific questions. So with that being said,
I'm gonna try the hardest thing of the year and share my screen. Maybe. Oh, there it is. Okay. So I hope that y'all
can see my screen okay. Sweet. Glad that y'all can see it. So we'll just jump straight in. I was debating earlier on whether to run the create
Redwood app command live, but it can take a little while and I didn't want y'all just
sit in here for like five, 10 minutes while all of
these packages install. But the command to set
up a new Redwood app is Yarn create Redwood app and then the name of
the app you wanna make. Wanna try to make this a little bigger. Yeah, hopefully that helps. But you run this command
and we've named our project student dashboard, and it'll go through and install all of these
dependencies and get Redwood, basically bootstrapped and
ready for us to work with. So they have some really good docs which I'll be referencing
throughout this workshop. And community's great. I'm gonna try to stop saying so many good things about Redwood, but I don't really have
very many bad things. So since I've cheated
and already installed and created this new
app, I'm gonna go ahead and go to my repo and open it. And this is what you'll see
after that create Redwood app command is finished running. You'll have all of these files and folders that you have never created. And one fancy thing I wanna
show you, if you run Yarn, RW dev, RW is short for Redwood, we'll be using the shorthand quite a bit. Let me change my Node version. Sometimes that happens. So make sure you're on
Node somewhere between 14.0 and 15.0, if you're on
the newest one like I was, it will cause problems and you
won't be able to run Redwood. So this is doing some
stuff, getting the front end and the back end running. And pulls up this in our browser. And ta-da, you're running
a Redwood app right now. That fast. And if you ever forget
which local host it's on, it's on eight, nine, 10 about
those cool and convenient, so that you don't have
to remember a whole lot. But when we run Yarn
RW dev, what that does, it starts up our Redwood app and Redwood is based on a mono repo. Wait. Oh, okay. Yep, use Node 14. Thanks for that comment, Joel. But yeah, so Redwood actually
works on a mono repo scheme. So we have our front end and
back end packages together, but they're in these separate folders. So let's just go through
what's happening in here. In the API folder, this is where all of our back end stuff happens. So this is where we'll be using Prisma to set up our database and seed some data, which we'll do in here. And then in the source folder, we'll have some stuff
for our GraphQL back end, so the GraphQL folder, we'll
hold the types for our queries and mutations and services will come to hold the resolvers
for our GraphQL back end. And that's pretty much
it for the back end. We have this package.json so that you know it's a different service. Then we have the web folder, this holds all of our
React front end code. So in the source folder,
you'll find some stuff that's already been bootstrapped for us. We have the app, we
have a couple of pages. So if for some reason
there's a really bad error, Redwood already has something
to handle it for us. And if the user navigates to
a page that doesn't exist yet, Redwood already has that covered. Then in layouts, this
is how Redwood handles basically the layout for different pages. So instead of worrying about the styles that need to be applied to a certain page, you just put the routes in the layout and it automatically
updates everything for you. And then components is pretty much where we put everything else. So if you have any styled components, we're gonna see how Redwood
handles data in a bit and that's gonna add
quite a few component too, but that's what the components folder is. And then here in the routes, you'll see this is just our routing. So few comments in here, 'cause Redwood's good
about commenting code. But now that you've
had a quick walkthrough of what all gets installed with Redwood, Let's go ahead and stop
running the app right now. And I'll clear out my terminal. And we're actually
gonna start with Prisma. So we're gonna set up our database and we'll be using Postgres. If you don't have Postgres
installed locally, if you just go to the, I think
it's postgresql.org site, we can take a look at that real quick. Yeah. So if you come to the Postgresql.org, you can download it for whichever operating system you're working with. But now that you know that
database we're working with, let's go ahead and go
in this API DB folder, and we're going start
by updating our schema. So the first thing we need to do is change our provider to Postgres QL, because we're working
with the Postgres database instead of MySQL. And I'll save that. You'll notice we're reading our database URL from the environment. So over here, if you open
up the environment file, you'll see that there's this commented out line for the database URL. So go ahead and uncomment with that. You want this to be your
connection string to Postgres. So I'm super original when
I come up with my username and password from my local instances. So these are my credentials, and no they're actually not that unique. They're pretty simple. So my username is Postgres
and my password is admin. So when you did set up
your Postgres instance, whatever username and
password you gave it, that's what these two values will be. And I'm not running on postgreshost.com, I'm running on local host. And the port should be fine unless you have something
running on it already, so make sure that when you do configure or you have configured
your Postgres instance, know which port you're pointing it to. And then for the database name, we'll just call this student dashboard. All right. So this is just our connection string to get to our Postgres instance. We shouldn't have to do
anything else with that file. Sorry, sometimes the Zoom controls are right above the little tabs here. But anyways, so we have
our database URL to find, we don't have to worry about this stuff 'cause it just makes it quiet for us. And of course, Redwood
has some bootstrap code. So gonna remove that to do. And we're actually gonna start building our student database model. So let's say we have
students which are our users. We'll call this model student. And this will be the name of
our table in Postgres as well. So I know sometimes people like to do pluralized names for
their database tables, but with Redwood things work out better if you just use the singular form, just because of how it handles
things for you automatically, you don't have to, you can tweak
things to however you want, but just know it's a little bit easier when you use the singular form in Redwood, but we'll keep going,
so we have an ID email. We'll keep that. We should probably know their name. You don't really want
students in your class and you don't even know their name. So we'll add the first and last name. And let's add a role
which will be a string. So we have our student models and we're gonna make a few more things. So something else that students probably care about are their grades. We wanna make sure that we have a way of storing their grades in the database. So we'll make a new model called grade and we'll give it an ID
just like the student. So I'll copy and paste that down here. And what should we call this? So this is their grade, I
guess let's just call it grade. It will be a string
and we will have grades that are associated with each student. So to do that, I'm gonna go
ahead and make this student ID. And it'll be an int that refers to this student ID in the model up here. And above it, I'm gonna
make a two digit connection. So a student relation, I mean, and what this does is just gonna connect our student to the grade. So we'll have add relation. And the field we'll be
using is the student ID, and this will reference the
ID in the student table. And I'm gonna go ahead and format that. And what this does is it adds this array of grades to our students, which is pretty much what we expect because a student will
have a specific grade and something else we should attach is probably the class name. Let me change that to course name, so that doesn't get confusing
when we move to the front end. And that'll just be a string,
I'll format a little bit. Actually let's just make this course. We haven't made the model for it yet, but that's okay, we'll come back too, so for now, let's just comment that up. And we're gonna make a
model for the courses. So students are probably
signed up for multiple courses and we need to know which ones they're in. So that means a student
will have a relationship with multiple classes. And so same thing, we'll add an ID here, and then we'll add a name, which was just gonna be
the name of the course. And let's see, every course will have. (Milecia mumbles) I'm trying to think about these relations. So if we have a course,
students can belong to multiple courses. So I think what we'll do
is add a course ID here, and this will be a foreign key. That's basically what
this relation is doing, it's adding a foreign key in our database. So we'll have a relation
to the field course ID and this will reference the
ID of this course table. So we know that students
will have a course ID. We know that each course
will have a grade, but I'm just trying to
make sure this makes sense. And while I'm doing that, does
anybody have any questions they'd like to drop in the chat? Like I said, I wanna make sure y'all feel like you can actually ask stuff because it's not just necessarily me talking to y'all if y'all
have questions, we're friends. But we have our course,
we have our student and we have the grade for those courses. So grade will be attached to the course, which is attached to the student. I think I'll just leave
it like this for now. No need to make it too complicated. But regardless, we have
these three models, which correspond to three
tables in our Prisma database. So now we're gonna go
ahead and seed some data. That way we won't get weird errors when we make the page for this stuff. And of course, Redwood has a
bunch of good comments in here. So if you're not familiar
with database seeding, you can check out some of the Prisma docs. And if you need just more of those details about how seed migrations
and all that works, you can check out Prisma's docs. But for now, I'm gonna come in
here and uncomment this code. And we're gonna do
something similar to this, but we're just gonna make
on entity for each table. So I'm gonna delete a bunch
of stuff, like a lot of stuff. So I'll get rid of pretty
much everything except the, oh wait. Don't bracket too hard y'all. (Milecia laughs) Okay. Now we're just gonna seed individual roles and gonna delete this too, because we won't be able to see more, but we're going to start with our student. So we'll create a new
student in a database. We'll need these fields. So we have our email, which
I'm just gonna make up. We'll say it is testbest.com. We have first and last name. So first name will be,
I don't know, Kaiya. Last name will be Best. And what else do we need? We need a role, so we'll
just say student teacher. Student teacher. And what else did we need here? Ah, of course ID. So when we make the course, I'll actually do that before
we create the student, it'll make a new ID. And since we're auto
incrementing an integer, it's just gonna be one. So that's how we know what
the course ID here is. And actually I'm gonna go ahead and swap these two things around, just so it looks like we're
actually writing stuff, and I'm gonna copy this await
here and paste it up above. And we're gonna create a course now, which will be a lot easier 'cause there's only two
things to put in there. So I'm gonna delete all of that. And in here, will just be
name and we'll say Redwood. Yeah. That's all we need in this one. Sweet. And then we'll make our
seed data for four grade. So we already have our student. I'm gonna copy this
and we'll make a grade, which would just have the
grade and the student ID. So we're gonna say that
everybody here today gets an A. And the student ID is just gonna be one, 'cause like I kind of explained earlier, since we are just auto incrementing
our integer for the ID, when we run this seed, it
will make a new student called Kaiya, and her ID will be one. So now we have everything in place that we need to run in migration. So let's see if I actually
typed everything right. And we'll run Yarn RW Prisma. Migrate. There. Might need a name for this. So we'll just call this
the initial migration. And if you notice over here, we have this new migration spile and it generates the SQL for us. So we have everything that we need, it even made our foreign keys, it made this unique index. Yeah, it just did everything for us. Nothing is no. So if I come over to my Postgres instance. And I refresh it, you'll see this new student dashboard database. And if I drop into the schemas and tables, you'll see the three tables we made. So let's see if my seed data is here. My seed data is not here. So I'm gonna take a little peek at another thing that I made, just to make sure that I
didn't do something weird, which happens quite a bit to me. Doesn't look like anything weird happened. Let me try to just run the seed manually. So if we do Yarn RW Prisma
DB, then we run seed. Okay, it says it's been seeded. Let's see, yip, there we go. I just needed to manually run that seed. And after we did the migration, we just seeded the database with this Yarn RW Prisma seed command. So if I go back in Postgres, you'll be able to see all
of the data that we made. So let's check out our student and boom, everything is in there
exactly like we expected it. This is off to a good start. Stuff is working right. I like that, but anyways, I'm gonna clear out the terminal now. Now we have our back end in place, at least the database part. And now I'm about to blow your mind with some of the stuff
Redwood can really do. So we are going to make a new page. This is gonna be our homepage. And yeah, it's just
what the root of our app will go to instead of the
placeholder right now. The way we'll make this page and the way we'll be doing a lot of stuff is with some of the Redwood COI commands. But before we jump into
that, I wanna check, anybody has any questions so far? Don't be afraid to post
something in the chat. I'll be checking it just throughout, so if you don't have anything
right now, that's fine too. But we'll run Yarn RWG,
which stands for generate. and we'll generate a new page. And we'll just call it home because it's gonna be our homepage, actually, let's be more creative, let's call it a dashboard, 'cause we're making a student dashboard, so a homepage should be that. So we're gonna make
this dashboard homepage in a way that we direct
the root of this page is just by adding it to the end. So we're saying we want dashboard to point to the root of our app. And we're gonna go ahead and run that. Generally, if you don't specify
the route that you want, Redwood we'll just create a route based on the name of the
page that you give it. So we've generated this new page, this is inside of our web directory. So the first thing I wanna
look at are the routes. If you look here, we
did not add this route, it was auto-generated
or automatically added when we ran this one command. And now when we run the app, it will go straight to
this dashboard page. So if we go into pages,
you'll see this new directory called dashboard page,
and it has the dashboard page component, we have a storybook story for the dashboard page in case we wanna do some kind of component driven development or we just wanna test this
component in isolation. And then we also have tests already. Redwood generated all of these files, pre-populated with stuff for us, just for this one command. And this is where Redwood started it to, guess, steal my little tech heart. It does so much for you,
but it doesn't do it in that black boxy kind of way
that a lot of frameworks do. You can go in and edit all of these files. If you wanna completely gut this, you can, Redwood doesn't hide anything from you, which is really nice. So we're in this dashboard page and I'm gonna run the
app with Yarn RW dev, just so you can see what
this looks like now. So it's loading up for us. And you see, this is not the
placeholder we had before. This is exactly what is in this file here. So is gonna serve as our dashboard homepage for everything. But before we get too far into this page, I wanna show you the cool thing. So I'm going to open up
a new terminal down here and we're still in the same directory, but we want to be able
to add new students. we wanna be able to add new courses and we wanna be able to
give students grades. So the way we're gonna
do this is by creating this entire CRUD functionality
for all of those actions. And yeah, this is where
Redwood gets incredible. So we're gonna run Yarn RWG for generate and we're gonna do a scaffold for courses, but we'll just say course. So I'm gonna run this. My local setup is a little weird, I'm sure we all have those quirks. But when I open a new terminal, it just resets my Node version. Should fix that one day but not right now. So I'm gonna go back up in the terminal and run this command. This is where Redwood flexes itself. So when you run the scaffold command, it makes everything for
you, it makes the front end, the back end CRUD, everything. So let's just dive into this, in pages, you'll see we have this new course folder and inside, of course, you'll see we have all of
these different folders. So we have a file to look
at an individual course. We have one to look at a bunch of courses. We can edit a course. We can make a new one. All of this is just here for you. And let's take a look at the routes, you'll notice we have all
of these new routes too. So we have a route to make
new courses, edit them, look at them individually,
look at a list of them, it's all generated for you. We even have a layout
for this course already. So if we come back up here to layout, you'll see this courses layout folder, and it's just this
layout in place for you. You didn't have to do
anything to get this, it already has styles applied, it's just nice that it
did every thing for you. But that's not all, so that's
just the front end piece, part of the front end piece. If we look in the component, you'll see there's a course folder that has a bunch of new stuff. So if we look at this
course file in particular, you'll see that we have
bunch of stuff in here that handles the course details, we can edit, we can delete, it even has the GraphQL
mutation in here for you. It's already there and it's
already being created basically. So we have that for one page, then we have this course cell. So cells are something
that are unique to Redwood and it's just the way that
Redwood handles data management. So you're able to pull in
your course information through the GraphQL query and
this cell handles it for you. So if it's still in a loading state, this message will get displayed. If there aren't any courses
returned from this query, then this gets displayed. And if there are courses returned, or if there's one course, I should say, since we're getting it by an ID, this success component will return that course component we just looked at, but with data inside of it. So that is where course
comes from in this component, it's coming from this cell. So that's just a little bit
about how Redwood handles data. And then we have a form,
I don't know about y'all, but sometimes I just hate making forms. You don't have to hate it anymore because Redwood does it for you, it even has a built in error handling. (exhales heavily) I don't know, that makes me super excited, so I'm gonna try to calm
down, but we have the form. If you do have multiple courses, then it'll show all of
them in this courses list, which is just a table that
has all of the courses returned from the database
map to different rows. And we get this data
from our courses cell. So here, this is where
the query comes from, where we fetch all of the
courses from the database. This is how we handle,
if it's still loading, if there aren't any courses, we'll link the user to
create a new course. And, yay, thanks for the feedback, Jake. I'm glad that it feels
familiar, or it's good so far, But anyways, so empty state, we have the ability to direct
users to make a new course. And if we actually get some data back from our GraphQL query, it will display that courses
component like you saw here. So that's a little bit about how Redwood handles data management,
how it handles forms, plus take a look at this edit cell. So this is another one that we have our query already here for us. We actually have a mutation here for us, since this is the edit cell, we would be updating an existing course, which that makes sense. And we have our loading as usual because this is probably
pulling up an individual course. And then the success, when we submit it, it's just posting this to the back end through that mutation we have up here. And this is just the form. So that's all happening here. And then in new course is super similar. So you already have your
create mutation here. You have this new course
component that uses the force. Everything's just
already in place for you, which makes getting a
really complex app up and working really fast. So yeah, again, Jacob, you're right, you don't have to make a whole lot of decisions to get rolling. Pretty much to get started with Redwood, as long as you know what your database schema is gonna be like, you already know what
your functionality is. You can just use Redwood commands to generate everything else, 'cause this was just the stuff
it made on the front end, we haven't even touched the back end. It has all these GraphQL
queries and mutations in place, but we didn't make any of these. We didn't do this. We haven't made any types. But if I close all this stuff
and go to the API folder, you'll see, we didn't
have to do any of that. This scaffold command. Look at that. We have this courses SDO with
all of our types defined. We have our mutations
defined, everything is here. So the way that this gets generated is based on that schema.prisma
file we made earlier. Redwood has a way of
just taking the schema and generating everything based off of it. So we don't even have to worry about syntax issues, it's already done. And the reason that this has
giving us an error right now is because we haven't
generated the student type yet. But don't worry, we will very soon. I just wanted y'all to
see, look at all the stuff, it's just here. We have types, we have queries, we have mutations and we're not done yet. If you look in services,
there's this courses folder that has all of the resolvers. It has a scenario for
us where we can define some data that we use in our tests. It actually made the GraphQL tests for us, which is pretty crazy. We didn't have to write any of this code and it's already a maintainable
project, which is wild. So we have our resolvers in this course.js inside of our services folder. And you'll see that if we were
doing like a production app, you can require authentication
right out of the gate. But since we're not worried
about authentication right now, we're gonna look at these
queries and mutations. So these make calls to the database using some Prisma stuff that Redwood has kind of put a thin layer on top of, just to make it, I guess a little easier. But pretty much, we have our call to get all of the courses, we find many. We have the thing to get one course by ID, the mutation to create a course, the mutation to update one,
the mutation to delete one. It's just here. We didn't write any of the code. And now we have this
fully functional front and back end CRUD. And I'm gonna show you
that it's fully functional because we go back to the browser and I'm gonna go to this courses URL. Oh no. Why did it crash on me? Oh, sometimes when you
make a bunch of changes, (Milecia sighs) this is where it gets a
little tricky with Redwood. So if you go ahead and define your model with these foreign keys
and you use Redwood to auto-generate a lot of things, you're probably gonna need to go ahead and auto-generate everything, you don't necessarily have to, but Redwood is gonna make references to those other types, like
I showed you here in API. If we look at this type, it already has a reference to student, but student doesn't exist. So that's where this error is coming from. And we'll go ahead and fix that by scaffolding the other views. So we'll run Yarn RW generate, which is just G for short and we'll run scaffold for
student, and it's gonna generate all of the exact same
files just for students. So you'll see this new SDL is in here and it has our students. So we're gonna go ahead and finish up. 'Cause you see we have this grade, that's definitely gonna be a problem. So we'll run Yarn RWG,
we'll scaffold our grade. So now that we have everything in place, we should be able to run this, but I might need to restart the server, so let's see what happens. Let me refresh this page. Oh, we didn't need to restart the server, it just works, because
generally Redwood just works, it's the thing that I enjoy
the most about this framework. I've done quite a few live demos with it and it very rarely breaks,
and if it does break, it's probably because
of something that I did or I forgot to do, just
like you saw a second ago with getting this course's view to show. But what we have here is
this table with the data, we seeded in the database,
if I click quick show, boom, is just this course one detail. If I edit it, it brings up the form where we can change this to, I don't know, Redwood Prisma Day. Yeah. If I stop using caps
lock, that might be nice, but we'll save that, and I just
wanna show you it's working, so we'll come over here to the database and this is what it looked like before. And now this is what it looks like now. Yeah. So thanks Dean, I'm glad
that this is making sense. I hope y'all are as excited as I am. I'm really trying to keep it not, I'm not trying to fan girl too hard here. (Milecia laughs) But anyways, we haven't written any code outside of making that model. That's it. We didn't make this, we
didn't style this table. Look at this, look at
this new course thing. It's just here. Let's make a new course. Let's call it Redwood GraphQL, I don't know, just making up a name. But if we save it, boom, it's
right there in the table, if we come back to Postgres, it's right there in the database and we didn't write a
line of code for this. If I want it to go ahead
and delete this one, it even asks for confirmation, it doesn't just randomly
delete stuff for you. So if you confirm, it's gone,
if I come back over here, it's also gone, all of
that and we didn't write more than a few lines of code. It's beautiful. So we have all of our GraphQL definitions. We have all of our resolvers, we have a fully functioning app. Like pretty much anything we do from here is just adding Polish, cleaning things up and making sure that it is ready to ship. Yes. So we're basically
getting ready to ship it and what we're gonna do,
I just wanna show you, that all of these pages
exist in our functional and it also makes me feel better to know that stuff is working. So if we go to the parades route, look at that, it's already there. And then if we go to students, I bet you, it's already there. Look at that, it's just so nice. But now I wanna show you a little bit about the details of Redwood. So we have the CRUD, we have the back end, we have everything we need laid out here. So on the front end, we
need to clean things up. It would be nice. We don't have a layout
for the overall dashboard, so that's something we
should probably get together, and you guessed it,
there's a command for that, so we're gonna run Yarn RWG,
and this will be a layout, and we'll call this dashboard because when we created
the page for the dashboard, it didn't auto generate a layout. It just made the page, the test, the story book, and it added the route. It did so much for us that
we can add our own layout. So when we run Yarn RW generate layout, this just generates another thing, it's not ready for production yet because they're still getting
the 1.0 version ready. So I wanna say that should
be done in a few months, but do not hold me to that at all. That's a core team decision
and I'm just a humble fan, but I think that it should be
ready in like a couple months. But with that being said,
let's look at this layout, so it has the storybook, it has tests, all of that's already in there. But what we really need is to decide how we want to style this,
and the way we'll do that is, I'm gonna add the style
component library to the project. But there's something
you have to keep in mind when you add packages
to a Redwood project, you wanna make sure that you add the package in the right directory. Because like I mentioned a little earlier, this is like a mono repo,
so we have our front end and back end services together and doing just an overall
Yarn add at the root level, will not work because there's
nothing at the root level. So for us, they'll clear
out this terminal again, we're gonna CD into the web directory and this is where we'll add
the style component package. So we'll run Yarn, add styled components, and we'll just be using this to make our layout actually look like a dashboard. So I'm gonna go ahead and
import style component up here. So we'll import styled
from styled components and we'll use this to make some new stuff, I might be a little bit of a weirdo here, but I like to have my
component at the top of a file, I know most people do it the opposite way, but it makes sense to have the style components at the bottom to me. So feel free to put
yours on top if you like. But the first thing we'll
do is just make a container. So we'll make this container and it will be equal to styled.dev, we'll use the little back ticks because we need a, what is that? A string template? And then we will say that this is a flex, so we'll give it a display of flex. I think that's it for now. Maybe we'll make sure it
takes up the whole width. So that'll take up a
hundred percent of the page and I'm gonna to wrap the children. That's so weird. I'm gonna wrap the
children in a container. So we'll put that there and go ahead, I wonder if my formatting will do that. Nope. So I'll do this like this. There we go. So now we have a container
for our children, but there's one thing
that we might wanna add. Having some navigation
to those different pages would probably be useful instead of just having to
manually go into that URL, like we have been. So to do that, I'm gonna
make another styled component and I'll call that nav. And it will be a styled nav, because we still wanna keep
those HTML semantics straight. That way people who are using
devices like screen readers can still get around the page easily. So that's why we're using the nav here. But we'll say this has a width of 20% and what else? Let's give it a right border,
did I type that right. I don't know. We'll find out if that is the right way to type that CSS property. Sometimes I forget the names of them. But anyways, we'll have
this as a solid one pixel. And I don't know, let's see
what random color this makes. Yeah, no clue what color that's gonna be, but it'll be something, so I'll say that. And then inside of our container, just gonna drop down
and add this nav here. So now we get to talk a little
bit about Redwood routing and I'm gonna steal an example
from our dashboard page. So Redwood handles routes pretty
similar to everything else, it's just the way that we add a link is a little bit different. But I'm gonna take this import line from the dashboard page and just copy it. And I'm going paste it over here. And I'm also gonna copy a
link, well, this link here, and we will put this inside of the nav. So now I have a link to the dashboard, which just takes us home. If you look over here at the routes, you'll see that all of
these have a certain name and that name is how we
reference the route that we want. So back here in the layout, you'll see this routes.dashboard, well, that is referencing
this dashboard name. So that's where those things come from. I'm gonna do this and
we'll copy and paste this, think three time's enough. So we'll go to our courses page. We'll go to the student's page
and we'll go to the grades. And just because I feel
like that's is gonna look really funky, I'm gonna add another style. So inside of this nav, I'm gonna
add a child selector thing. So on this we'll say
that we'll add a padding to the bottom of 18 pixels. And this CSS might not even be right. We'll find out here. So let's go back to the
browser and go home. Oh, something we might need to do is actually use this layout. So if I come back to the routes, you'll notice that we
have these set components that wrap certain routes
in certain layouts. So when we were running
the scaffold command, it was generating these routes wrapped in the specific
layout for that page. But now we wanna apply this dashboard layout to all of the pages. And we'll do that real simple, we'll use another set component. So at the very top, we'll have set wrap equals dashboard layout. And it probably, yip, it
auto imported that for me, I don't know if it'll
do that for everybody or if that's just part
of my settings locally, but it's there. So we'll close that tag, and I'm gonna the that closing tag and move it right down
below the dashboard page. So I'm deleting the not found page out. I don't know why I'm leaving it out, it felt like a good idea. But let's go ahead and
wrap that in there too. That way, if they are somewhere weird, they can click on a link
to get out of there. So I'll save this and then come back and see why there's an error. It shouldn't matter, but
I'm gonna import that. Let's see, gonna refresh the page. Yeah. It's here. It's pretty ugly, but that's okay. It is okay 'cause I just wanted you to see that we can do this. So if we spend a little bit
of time just styling this, what I really wanted to do
now that I think about it, was make this display flex and then we'll do a flex
direction is column. Let me see if I did it. Yip, that is what I was going for. Maybe if I add that back and do all of those with padding
bottom of 18 pixels again. Okay, that's starting
to look like something. So I'm gonna try not to
spend too much time on style and all of this, but
the next thing we'll do is just add a container for our children. Think that's so funny to say. But we'll make a new container that we'll call component holder? Names are hard, y'all. So this will just be a dev with
those same template strings. And we'll give this a
width of, let's say 75%. And we'll give it a padding, might not even need that with,
but we'll see in a second. So I'm giving it a padding
all around, of 24 pixels, and now I'm gonna wrap the children in this component holder. Move that tag down here. And save it. Hey, it looks okay, we'll
take that way width. The last thing I'm gonna
do as far as styles on this is probably just add a height of a hundred view heights, that way this takes up the whole page. So maybe I need to do that
at the container level. Yeah, that looks like a dashboard, that looks like a real dashboard y'all. I'm okay with this. So now that we have that in place, let's actually click through. Now it looks like something people might actually log into and do stuff with because you can navigate around. Let's say I go to the wrong page, it still gives me that page not found. Did I wrap that page not found in here? I did. Well, now I found this or
something, we can edit that. It's just the way that
Redwood put it in initially. But let's add a new course just to show you something real quick. We'll call this GraphQL again. I'm gonna add a new student, but how about best@rest.com. And we'll have Beth Bowman. And she's just a student,
but she's in that new course. So we got that. And then we will give Beth, which her ideas two, we'll give her a B. So we get that in place. Now I wanna show you what
happens if you need to make updates to your data base,
so this is pretty common, sometimes you'll be working on a project and a client will come back, or a product will come
back with a new requirement and you need to completely
update your back end. It happens. So in this case, let's say
that on student's table, do we want on student? No. Let's say we will have a course ID also associated with the grade. So if we come back in here and close all of our
awesome fricking stuff. We'll go to the API folder, open up our schema. And what we'll do is add another foreign key to the grade table. So we wanna associate a course with these and that's what we'll be doing. So come back over here, we
will add another foreign key. We'll call this one course
ID, and it's in int. And that relation will be two course, which will have a type of course, and we'll have a relation of fields, we know we're gonna
reference this course ID. And the course ID is going to reference the ID in the course table. So I'll format that. There's some shortcut key I have, but whenever you make a
foreign key relationship, you'll notice that it tags the table onto, it makes a reference to
the foreign key table on the primary table, if that makes sense. So you've got to have that there so that the two tables are connected. So I'll save this and come over here. Clear my browse, clear my
terminal like I normally do. And then we'll run Yarn,
RW Prisma my great dev, so we're adding a new migration. Oh, there is something
that I think we wanna do. So since we're adding a new value after an initial migration and we
have data in the data base, we probably wanna make
this course ID optional. Well, there we go. So the reason that we're doing
this is because right now, the way that our database is set up, we don't have a course
ID for those students that are already there. And we can go in and update that in a number of different ways, which we will, but just to
get this migration going, we're going to make this
course ID an optional field. So, oh, I'm also in the wrong directory. So I'm still in web here,
but I shouldn't be in web when I'm running Redwood commands, you should be in the root
of your project directory when you're running Redwood commands. So we'll do Yarn RW
Prisma, migrate dev again. Okay, that's better. And we'll say we added
course ID the to grade. Okay. So now that field is on our table, we need to go ahead and update couple things in our GraphQL. So we'll update this to have,
the grade type to have course, which would just be course. And we're not gonna include
the exclamation point because these are optional, so
we'll have a course ID of it. Let's see, probably need the course ID for creating a new grade. And we'll also need it
when we update the grade. So we have our types updated, that should not change
anything with our resolvers. Nope, nothing to change there. And yeah, if we come back over here to the browser and refresh. Wait, there's front end
stuff we need to do too. So this is why you wanna try to have as much of your model defined upfront. You probably wanna do that in general, but with Redwood in particular, since it can handle so much
out of the box for you, if you have your model
clearly defined upfront, when you run these commands like scaffold, or you make a new layout,
or maybe you just run to generate an SDL in general, it will have everything
that it needs to do that. But this is also the beauty of Redwood. You don't need the Redwood commands to make updates to your files. You can just go in there and edit them like you would normally do. So what we're gonna do, if I
can just get that to close. Sometimes the little Zoom commands are just in the wrong place. So let me try, there is
no better place for it. Anyways, I'm gonna go ahead
and close out of the API folder and we'll go back to web. So over here in our
grade, let's take a look, so we know when we are fetching data, now we wanna bring back the course ID. So I'll save that. And when we are updating data, we'll probably also want the course ID. Let's see, what else do we need here? That should be good for editing. Then if we look at the grade
component, that's fine. Great, so let's bring in the course ID. And then, let's see, for the form, we definitely need to
add that to that form. So the good thing is that we
can just do some copy pasta, so we'll just take the student ID field, copy it and paste it below. And just update some names. So this will be course ID, type that in, this will be course ID, what else will be? Everything is course ID
now, so we'll have that. And what else? I think that is all of the
course ID updates we need here. Yes. So let's take a look at grades. We don't need to update anything there. We'll get that cell,
probably need to bring in this course ID here. That's it there. The new grade. Yeah. Yeah. I guess we don't need to
return to the course ID when we make a new grade. That's fine. So now with all of that
in place, if I refresh. Modified that, everything is updated now, why are you not showing me this course ID? Let's see if it's in the form. It is in the form, a student
ID isn't in the form. Oops, I deleted that. That's my bad. So now we're gonna remake
the student ID one. So we'll just update these again to be what they were initially. No big deal. So that'll be student. Oh, we need to, where's that table? That is why it's not showing. Table, right here. I need to add that student
ID here, that would help. So we'll add that. Not student ID, course ID. So we'll add the course ID
here and save everything. And now we have everything. So I'm gonna say somebody got a B plus, we'll give it to Beth, why not? And the first course, so we'll save that. And there you go. So like I mentioned earlier, we need to update these
two to have a course ID and then we can actually update that migration one more time or I should say we can
make a new migration. So that course ID is always required because you probably
shouldn't have a random grade just floating around with students that's not attached to anything. So I'm gonna go ahead and edit this and add that course ID
to the first student. And then I'm gonna add a course ID for the second student. I'm gonna put two here. Everybody's in the first class. Oh, wait, did I put? Oh, that's right, we deleted
that, so this will be three. So those auto-generating
IDs, if you delete anything, then that ID is no longer valid. But anyways, we have a new course ID and all of that good stuff. So let's come back here
and update our schema. So I'm gonna remove this
optional flag from everywhere. So on the back end for our
grade, let's make this required. So we'll just be adding
some exclamation points because we're really excited
about these course IDs. So we've got that in place. Now I'll switch terminals,
clear that one out and we'll run another migration. So Yarn RW Prisma, migrate dev. Made course ID required. On. Great. So now we're able to make
this a required field for all of the future inputs. The only reason we didn't do that before was because we had existing data that did not have a course
ID attached to it yet. But since all of the data in the database has a course ID now, we are good to go. So this is actually it. This is what I have for you for making this Redwood
dashboard with Prisma. And I hope that it was really informative, I hope you got as excited as I did because we did a lot of stuff
without writing a lot of code. And I'm gonna push this repo
up to get hub here shortly, and I'll drop a link to it
in the Prisma Day channel in Slack, so if you wanna
take a look at this code in more detail, it'll be there
for you here in a little bit. But before I disappear, I wanna know, do y'all have any questions whatsoever? This felt like a lot,
but at the same time, we really just ran a few commands. As long as you're comfortable
with React, GraphQL, Prisma, or just some general
database setup stuff. You're pretty much good
to go with Redwood. So does anybody have any questions for me they like to put in the chat? Or you can reach out to me
on Twitter @FlippedCoding, I can drop a link to that here. Oh no, that's not it. So yeah, if you have
any questions about this or anything else Redwood,
the GraphQL, Prisma related, feel free to reach out to me on Twitter or in the Prisma Day channel on Slack or wherever else you can
find me on the internet. So I'm gonna open it up or throw the offer out there one more time for questions. Ooh, is it possible to map
a Prisma response to a class that includes methods
instead of a plain object? Yeah, I don't see why not. Are you talking about
here in our resolvers? Let me get one open real quick. So do you mean we have a
method in this delete function instead of just doing a
plain old object thing here. Like we do some data handling before we get to the delete part. Is that what you mean, Eduardo? Ooh, yeah. So there's no problem there. You can definitely just have a response in there instead of just a regular object. As long as you execute
the Prisma requests, like with a delete or update or whatever, you can put anything inside of here, as long as it maps to your database, you can put anything inside of the data, you can put anything
inside of this function, if you have some processing to do before. Did that answer your question, Eduardo? Yeah, I think so. But, what? The objects that are returned
to the client.find method. Oh, you're fine, no
worries about the English, I barely understand
English myself, so worries. Do you mean over in the web? Let me see, do you mean like in here? Where we return the stuff in the query. And then Jacob to answer your question, you can host it on Netlify, Vercel, those are the two that are
just off the top of my head. But yeah, there's a couple of other places that Redwood has really
good host support for, but it's somewhere in the docs, but I know Netlify and Vercel are already up there on the list. No, I don't think you need Node to host, you can just throw it up on one of those quick things like
Netlify, probably Heroku. I'm not sure. Oh, you mean the client object of Prisma. Eduardo, you mean actually
inside of the Prisma command? I think I got you. So you can still map this stuff. Where is one of the good ones? Let's look at grades maybe. Yeah. So basically what you could
do, is inside of here, if you had like, I don't know, you know specifics of
what is in the database, so you could have something
like, I don't know, what did we have in grade? Course ID would be
equal to input.courseid. Or maybe you have it as
course number or something. So if you wanted it to
destruct that object like that, that's fine, there's nothing
stopping you from doing that. As long as when it gets to the database, it matches the model that you made, whatever you do inside of
that object is up to you. Does that answer your question, Eduardo? Yay, I'm glad we got that worked out. So did anybody else have questions? I have no problem answering
whatever you feel like asking. I'm also getting really good at sitting with awkward silences because of how much a virtual stuff has happened in the past year. So I'll give it a few minutes, but if nobody has any questions,
you can feel free to leave and go back to some of the
other Prisma Day workshops. I'll be around for a couple more minutes. Oh yeah, this is recorded too. So if at some point you do wanna come back and look at this talk later, I'm not sure when the people at Prisma are posting these videos, but
it will be live at some point. I do hope this at least got everybody as worked up about Redwood
accounting when I first saw it, 'cause it completely blew my mind. I saw one command can make
my front end and back end. And it does all the crack stuff. It's like, holy crap,
this does everything. I don't even need to write code anymore. But when you start adding some of the, after you get past the initial setup and you need to start adding features, and you need to start
making updates to things. It gets back to the regular code, it's just Redwood give you
such a big jump out of the box that you can get to feature implementation and start iterating on things like that a lot faster than you would if you had to build out the form, build out the GraphQL
services and build everything. So it's just a great way
to get you jump-started. But if nobody else has
any questions for me, then I think I'll go ahead and check out. Thanks for coming to
my workshop everybody. And I guess I'll see
all around the internet. (bright upbeat music)