🕰️ Chapters
- Creating Our Dashboard Page File
- Creating Our Admin Layout
- Setting Up Our Admin Dashboard Route
- Using Our Admin Layout
- Adding Link To Admin Section for Admin Users
- Conditional Logout Redirect Away from Admin Section
- Testing Our Conditional Logout Redirect
Creating An Admin Layout
In this lesson, we'll learn how to create an admin layout we can use throughout our admin section pages. This layout will include a secondary navigation specific to administrative actions.
- Author
- Tom Gobich
- Published
- Jun 06
- Duration
- 7m 14s
![Tom Gobich](/img/1/profile/avatar_1703713552864.jpg)
Developer, dog lover, and burrito eater. Currently teaching AdonisJS, a fully featured NodeJS framework, and running Adocasts where I post new lessons weekly. Professionally, I work with JavaScript, .Net C#, and SQL Server.
Adocasts
Burlington, KY
Transcript
Creating An Admin Layout
-
(upbeat music)
-
So earlier in the series, we set up this admin page.
-
It's currently not doing much,
-
it's just returning back a plain text response
-
that we are actually here,
-
and it's protecting this
-
so that only admins can access this page.
-
What we need to do now is add a page for this actual route,
-
and we'll also make a layout specific
-
to all of our administration pages as well.
-
So let's hide this away.
-
We can start by creating our page.
-
So we'll go ahead and right click that, new file.
-
We're gonna create a specific admin directory.
-
So we'll do admin/
-
and we'll call the homepage
-
of our administration section, our dashboard.
-
So let's go ahead and create that there.
-
Now, before we start adding stuff to this page,
-
let's go ahead and create a layout.
-
So we can use what we already have for our app layout.
-
Here's a good starting point.
-
So let's go ahead and dive into there,
-
give everything there a copy.
-
And then we can right click our layout folder,
-
click new file,
-
and we'll add a file called admin.edge
-
and paste everything that we had
-
inside of our index.edge,
-
inside of our admin.edge.
-
Having a completely separate HTML document
-
gives us the full flexibility
-
to be able to add in additional CSS,
-
meta tags, layouts, and the like,
-
as we see fit.
-
So you can do whatever you want
-
to this admin layout,
-
and it will only impact pages
-
that we've applied the admin layout to.
-
For us, I think all that we wanna do
-
is add a specific navigation
-
that'll serve as kind of a secondary navigation
-
specific to our administrative routes.
-
So I'm just gonna do flex align items center
-
and maybe a gap of four.
-
And since all of our main navigation items
-
are text, text, or small,
-
we'll go ahead and keep that here too.
-
We'll do a py of maybe three,
-
and then let's do border wide
-
and a border to the top and bottom.
-
And we'll do border slate,
-
maybe 300 for the color.
-
Then let's go and add in an anchor href.
-
We haven't defined a route specifically for this yet.
-
So I'm gonna leave these empty
-
as we'll do this next.
-
And we'll just have this href be
-
for our dashboard,
-
and we'll add items as we add pages.
-
Okay, let's go and jump into our routes.
-
And okay, it does look like we actually
-
already have a route name for the entire group,
-
as well as our individual index page.
-
I think maybe we just change this name here
-
to our dashboard.
-
We'll keep the path as slash,
-
but we do wanna get rid
-
of the individual route handler.
-
And inside of our app controllers directory,
-
we'll create a separate directory
-
just like we did for auth for our admin controllers.
-
So we can jump into our terminal,
-
stop our server, clear that out,
-
node ace make controller.
-
We'll prefix the actual controller
-
that we wanna create with admin slash,
-
which will create our admin directory
-
and then the controller inside of there.
-
And we'll call this our dashboard controller.
-
Let's go and do hyphen s
-
just to keep that name singular.
-
And we can add a handle method inside of it.
-
Go and create that.
-
And there we go.
-
While we're here, let's go and boot
-
our application back up.
-
So npm run dev, and we can hide that back away.
-
All right, now for our controller,
-
for our dashboard route,
-
we can use our dashboard controller.
-
Hit tab to auto import that
-
and use the handle method.
-
Give that a save the format.
-
And one option that you always have
-
with these controllers is you can rename the import.
-
So for example, if we wanted this
-
to specifically be our admin dashboard controller,
-
we could change that.
-
So we could scroll on up
-
to where we have that import.
-
And that looks like it's right here.
-
So these files are just exported default.
-
So we can name them whatever.
-
So we can prefix this with admin dashboard controller.
-
So that if we were to have a dashboard controller
-
anywhere else inside of our application,
-
we wouldn't have a naming collision.
-
And this also specifically specifies
-
that this controller is for our admin section.
-
So let's go jump inside of that controller.
-
So we'll go in the admin dashboard controller.
-
Right now we just need our view
-
and we'll just return view,
-
render our pages, admin dashboard page.
-
Then we can jump back into our admin layout
-
and finish our thought with our route definition.
-
So we can do route and point this to admin dot
-
and we renamed it index to dashboard.
-
And now we need to actually apply this layout
-
into our dashboard page.
-
And since we placed this
-
inside of our components layout directory,
-
we can do @layout.
-
And you can see the auto-completes coming up
-
to reference our access to this as admin there.
-
And then we can go ahead and end that.
-
And let's just add an H1 of dashboard in.
-
Give that a save.
-
And let's go see what that looks like
-
currently in our browser.
-
So we can come back into here,
-
give it a refresh since that was just a plain text response.
-
And cool.
-
So we can still see this top level navigation
-
for our main application routes,
-
but now we have access to the secondary navigation
-
for our admin based routes.
-
Next, what we want to do
-
is be able to give our admins access
-
to the admin section whenever they're logged in,
-
probably somewhere right over here.
-
So we can hide our browser back away
-
and this will take place within our partials navigation.
-
Let's add this right before our logout button.
-
So we'll want to do an @if auth.user.roleid equals,
-
and then we can make use of our roles enum
-
to check and see whether or not our user
-
is just a plain user or an administrator.
-
In order to actually access this roles enum though,
-
we need to make it accessible within EdgeJS.
-
So let's scroll on down to our start directory here
-
and we'll want to double check inside of our globals.ts
-
where we're registering our EdgeJS globals
-
to see whether or not we're currently adding our roles
-
as a global, which we are not.
-
So let's go ahead and do that.
-
So we can do edge global,
-
and we'll give this enum the exact same name
-
that we would access it with outside of EdgeJS,
-
which is our roles.
-
And then we can just import the roles
-
and provide that in as the value.
-
This enables us now inside of our navigation
-
to do roles.admin to check and see
-
whether or not our authenticated user's role is admin.
-
If it is, then we can display the admin section link,
-
otherwise we'll leave it out.
-
So do a href route admin.dashboard
-
and class text extra small
-
and point them to the admin section.
-
Cool, so now if we jump back into our browser,
-
we should have this nice link right here
-
to our admin section, give that a click,
-
and we jump into our dashboard.
-
If we were to log out,
-
it will attempt to redirect us back to our admin section
-
after we've logged out,
-
and it will state that we're no longer authorized
-
to perform this action
-
since we are no longer authenticated
-
and don't have access to the admin section.
-
What would be ideal is if we did a check for that
-
on log out to make sure that we weren't trying
-
to redirect the user back to a protected route.
-
So within our log out controller,
-
what response redirect back is doing
-
is just checking the refer,
-
and it will return the user back to the refer
-
from the headers.
-
So we can do if,
-
and we'll wanna access our request object,
-
so request, and do request.header
-
and reach for our refer.
-
And AdonisJS does support both the spelling
-
as it's defined in the spec
-
and the spelling as it's defined with the word.
-
So you can do either one there,
-
and you can also specify a default value
-
if one's not provided.
-
So we'll just ensure that we get back some form of a string
-
by providing a string as a default value.
-
So we can do dot,
-
and we can just check for the inclusion
-
of slash admin to some extent.
-
And if that's found,
-
then instead of returning the user back,
-
we can just return response redirect to a specific route.
-
And that might be our homepage
-
or it might be the login page.
-
So we can do auth, login,
-
show to redirect them back to the login page.
-
You could also avert this altogether
-
by just always returning back to the login page as well.
-
But let's go give that a test real quick.
-
So let's give that a save,
-
jump back into our browser,
-
go to our login,
-
let's log in with our test admin user.
-
So that's [email protected],
-
some password, there we go.
-
Let's go into our admin section
-
and now let's try to log out.
-
And there we go.
-
So now we're no longer redirected back
-
to an unauthorized access error,
-
but instead to our login page.
-
Furthermore, if we now log in with test,
-
plus I think Tom is another one that we created,
-
dot test.com, type in the password, there we go.
-
We no longer have an admin link up here
-
because this user is not an administrator.
-
And we can also check to make sure
-
that we cannot access the admin section,
-
which we can not.
-
Awesome.
-
So everything there seems okie dokie.
-
Let's go ahead and log out,
-
Log in again with [email protected], and now we're ready to move on.
-
Introduction
-
Fundamentals
-
2.0Routes and How To Create Them5m 24s
-
2.1Rendering a View for a Route6m 30s
-
2.2Linking Between Routes7m 52s
-
2.3Loading A Movie Using Route Parameters9m 18s
-
2.4Validating Route Parameters6m 7s
-
2.5Vite and Our Assets6m 39s
-
2.6Setting Up Tailwind CSS7m 5s
-
2.7Reading and Supporting Markdown Content4m 32s
-
2.8Listing Movies from their Markdown Files8m 51s
-
2.9Extracting Reusable Code with Services7m 4s
-
2.10Cleaning Up Routes with Controllers4m 52s
-
2.11Defining A Structure for our Movie using Models9m 38s
-
2.12Singleton Services and the Idea of Caching6m 11s
-
2.13Environment Variables and their Validation4m 16s
-
2.14Improved Caching with Redis10m 44s
-
2.15Deleting Items and Flushing our Redis Cache6m 46s
-
2.16Quick Start Apps with Custom Starter Kits6m 28s
-
2.17Easy Imports with NodeJS Subpath Imports8m 40s
-
-
Building Views with EdgeJS
-
3.0EdgeJS Templating Basics8m 49s
-
3.1HTML Attribute and Class Utilities6m 9s
-
3.2Making A Reusable Movie Card Component10m 24s
-
3.3Component Tags, State, and Props4m 53s
-
3.4Use Slots To Make A Button Component6m 56s
-
3.5Extracting A Layout Component5m 13s
-
3.6State vs Share Data Flow2m 59s
-
3.7Share vs Global Data Flow6m 8s
-
3.8Form Basics and CSRF Protection6m 13s
-
3.9HTTP Method Spoofing HTML Forms3m 3s
-
3.10Easy SVG Icons with Edge Iconify7m 57s
-
-
Database and Lucid ORM Basics
-
4.0Configuring Lucid and our Database Connection4m 3s
-
4.1Understanding our Database Schema9m 35s
-
4.2Introducing and Defining Database Migrations18m 35s
-
4.3The Flow of Migrations8m 28s
-
4.4Introducing Lucid Models5m 43s
-
4.5Defining Our Models6m 49s
-
4.6The Basics of CRUD11m 56s
-
4.7Defining Required Data with Seeders11m 11s
-
4.8Stubbing Fake Data with Model Factories13m 48s
-
4.9Querying Our Movies with the Query Builder15m 30s
-
4.10Unmapped and Computed Model Properties3m 24s
-
4.11Altering Tables with Migrations7m 6s
-
4.12Adding A Profile Model, Migration, Factory, and Controller2m 57s
-
4.13SQL Parameters and Injection Protection9m 19s
-
4.14Reusable Query Statements with Model Query Scopes8m 11s
-
4.15Tapping into Model Factory States9m 15s
-
4.16Querying Recently Released and Coming Soon Movies4m 59s
-
4.17Generating A Unique Movie Slug With Model Hooks7m 59s
-
-
Lucid ORM Relationships
-
5.0Defining One to One Relationships Within Lucid Models5m 49s
-
5.1Model Factory Relationships2m 54s
-
5.2Querying Relationships and Eager Vs Lazy Loading5m 17s
-
5.3Cascading and Deleting Model Relationships5m 16s
-
5.4Defining One to Many Relationships with Lucid Models6m 56s
-
5.5Seeding Movies with One to Many Model Factory Relationships5m 24s
-
5.6Listing A Director's Movies with Relationship Existence Queries8m 41s
-
5.7Listing and Counting a Writer's Movies8m 41s
-
5.8Using Eager and Lazy Loading to Load A Movie's Writer and Director5m 18s
-
5.9Defining Many-To-Many Relationships and Pivot Columns9m 48s
-
5.10Many-To-Many Model Factory Relationships4m 50s
-
5.11A Deep Dive Into Relationship CRUD with Models18m 5s
-
5.12How To Create Factory Relationships from a Pool of Data13m 55s
-
5.13How To Query, Sort, and Filter by Pivot Table Data9m 47s
-
-
Working With Forms
-
6.0Accepting Form Data12m 15s
-
6.1Validating Form Data with VineJS9m 29s
-
6.2Displaying Validation Errors and Validating from our Request7m 16s
-
6.3Reusing Old Form Values After A Validation Error2m 3s
-
6.4Creating An EdgeJS Form Input Component5m 28s
-
6.5Creating A Login Form and Validator5m 1s
-
6.6How To Create A Custom VineJS Validation Rule9m 7s
-
-
Authentication & Middleware
-
7.0The Flow of Middleware7m 49s
-
7.1Authenticating A Newly Registered User4m 14s
-
7.2Checking For and Populating an Authenticated User2m 10s
-
7.3Logging Out An Authenticated User2m 24s
-
7.4Logging In An Existing User6m 54s
-
7.5Remembering A User's Authenticated Session6m 55s
-
7.6Protecting Routes with Auth, Guest, and Admin Middleware5m 36s
-
-
Filtering and Paginating Queries
-
8.0Creating A Movie List Page3m 43s
-
8.1Filtering A Query By Pattern Likeness7m 9s
-
8.2Filtering Our List by Movie Status5m 47s
-
8.3How To Apply A Dynamic Sort Filter To Your Query7m 12s
-
8.4Joining SQL Tables To Order By A Related Column4m 49s
-
8.5Validating Query String Filter Values7m 24s
-
8.6How To Paginate Filtered Query Results9m 15s
-
8.7Pagination First, Last, Next, and Previous Buttons4m 3s
-
-
User Watchlist
-
9.0An Alternative Approach to Many-To-Many Relationships4m 56s
-
9.1Toggling A Movie in an Authenticated User's Watchlist9m 56s
-
9.2Listing and Filtering User Watchlist Items7m 31s
-
9.3Allowing Users To Toggle A Movie As Watched4m 44s
-
9.4Filtering By User's Watched Status6m 7s
-
9.5Defining A Composite Unique Constraint4m 47s
-
9.6Persist Filters Easily with Lucid's Query String Method3m 58s
-
-
User Profiles
-
10.0How to Create and Fix Missing User Profiles in Your Application7m 37s
-
10.1Using Dependency Injection to Update A User's Profile9m 46s
-
10.2Saving All Or Nothing with Database Transactions5m 15s
-
10.3Uploading and Displaying User Avatars15m 29s
-
10.4Displaying A User's Profile6m 1s
-
10.5Filtering, Preloading, and Sorting By Relationship7m 6s
-
-
Admin Panel
-
11.0Creating An Admin Layout7m 14s
-
11.1Counting Stats for our Admin Dashboard5m 43s
-
11.2Paginated Admin Movie Table13m 2s
-
11.3Allowing Admins to Create Movies16m 39s
-
11.4Allowing Admins to Update Movies and Clear Values13m 27s
-
11.5How To Use One Form to Create or Edit Movies5m 32s
-
Uploading Movie Cover Images in our Create or Edit Form10m 29s
-
Using A Wildcard Route Param to Download Storage Images7m 57s
-
Posting Objects, Arrays, and an Array of Objects in HTML Forms26m 26s
-
Managed Transactions and Syncing Movie Cast Members15m 55s
-
Allowing Admins to Delete Movies and their Relationships7m 42s
-
Thank You for Watching!0m 31s
-
Join The Discussion! (0 Comments)
Please sign in or sign up for free to join in on the dicussion.
Be the first to Comment!