One of the best ways to learn software development is to create a slimmed-down version of software you use every day to get a better understanding of how it might work. This process helps you understand the problem space constraints and techniques required to build a real-world use-case.
We just published a course on the freeCodeCamp.org YouTube channel that will teach you how to build your own SaaS app. In this case, a PagerDuty clone.
Ania Kubów developed this course. She creates popular software tutorials on both the freeCodeCamp channel and her own channel.
In this tutorial, Ania will teach you how to build a dashboard to let you know if your app is down. And if your app goes down you will be notified via email and SMS. This is a clone of the popular software as a service app called PagerDuty.
By the end of this tutorial, you will be able to:
- Create data structures in Postgres to feed into your application.
- Create a UI and feed data into the UI.
- Add functionality to the UI to interact and modify the data.
- And finally hook up Twilio and SMTP to send email notifications and SMS notifications
Here are all the sections in this course:
- Working with pre-made UI Components
- Setting up our Postgres database
- Creating Tables in Postgres
- Feeding in Data to our Dashboard
- Adding new Incidents
- Deleting Incidents
- The Team members page
- Hooking up the Twilio and SMPT API
Watch the full course below or on the freeCodeCamp.org YouTube channel (1-hour watch).
Hey everyone here on the freeCodeCamp channel.In this tutorial, I'm going to be building a tool that every app on startup should have.
I'm going to build a dashboard to let you know if your app is down. And if it does notify you via email and SMS.
So in other words, it clone of the popular software as a service app pager duty.
My name is Ania Kubow. And I'm a course creator here on Free Code Camp, as well as on my own channel.
And I'm going to be your guide to this wonderful tutorial on building this platform here today.
One of the best ways to learn software development is to create a slimmed down version of software you use every day to get a better understanding of how it might work.
This process helps you understand the problem space constraints and techniques required to build a real world use case pager duty is awesome as it helps alert teams to high priority incidents like web outages or security issues using pre configured configuration strategies, and multi channel notifications.
Postgres is store our data, results of other user interface and back end workflows.
And finally Twilio to power SMS notification as well as SMTP.
By the end of this tutorial, you will be able to create data structures and Postgres to feed into your application.
This will include creating an incidence table as well as team members table, we will then feed this data into our UI so we can see it and interact with it.
So as you will see here under the incidents tab, and the team members tab, that we are bringing back all that data.
The Team Members tab will also help us see who is working on what, as well as their shift times so that we can tell who is on call.
And when we will also then be able to see all the incidents that are currently acknowledged and being worked on, as well as filter them down to just the ones assigned to a specific user.
We will add functionality to bring up data if we click on specific rows, and much more, we will also add the ability to add team members from the interface as well as add in new incidents via the interface as well as delete a team member or delete an interface.
So bunch of stuff going on here.
And finally, we will hook up Twilio and SMTP. So that we can send email notifications and SMS notifications to our team members in case the website theoretically goes down.
This video is created thanks to a grant from resource, the local solution for building internal tools and platforms.
So what are we waiting for? Let's do it. Okay, so let's do it.
First off, I'm just going to create a new app.
So I'm just going to go ahead and click on here.
And I'm going to call this pager duty club.
Okay, and click create the app.
So there we go, we've just created our app, essentially, this is essentially our work zone.
And I'm going to start off by just dragging in some UI in order to make it look like a pager duty clone.
So the first thing I'm going to do is actually just drag in some tabs containers, as we're gonna have two tabs here, one to view the incidents, and one to view all our team members.
So let's make that reflect here.
We can also rename this actual UI component.
So I can call it main tabs if I wish.
And I'm here, I'm just going to change this to say incidents.
And this one to say team members.
So we are literally just creating our tabs container, just like so.
We can of course, also change the colors of this.
So if you just highlight the whole UI component, and then go down here, I can choose the header background color, I can choose the footer background color, or I could just choose the background, I'm going to go ahead with Canvas to make it much the background that we have.
Okay, and if we wanted a little darker, we can also choose our own custom color.
So for example, I could do hex E, E, E, or just three E's for short.
And that will also be applied.
To get rid of the third view that we are not going to be using simply just go ahead and click on here and delete it from view.
So there we have it, one view and a second view.
We can also personalize the actual selected colors.
So I'm gonna go with green for now as I think it looks better.
incidents, what do we want to show? Well, we should probably have some kind of header, right.
So let's go ahead and select a text option, we're going to have a simple text, or we're going to have a text area, or rich text editor, or even editable text, I'm just going to go ahead and select the text option.
And we can even choose if we would like to use HTML elements to kind of decide how big each of the text elements are going to be.
So I can have incidents on all teams as a title, just like so.
And it's styled like an h1 element title.
If you wanted to give a custom styling to this h1 element, that is also possible, okay, all you would have to do is go to scripts and styles and add in some custom CSS for this whole document.
We are not going to be doing that now.
But I just thought it was worth giving you a sneak peek at that.
Next up, what do I want? Well, we can have dividers to kind of separate out everything in here.
So I'm going to in fact, use a divider to separate the title from the table that we are going to input.
Now let's put in a table.
So our table at the moment is not going to mean much.
Okay, it's just going to have some dummy data in there.
So there is some dummy data that's being fed in, we're going to delete all of this as we're going to use some actual data from a Postgres database that we are going to make.
So just leave that blank for now.
In the meantime, I'm also just going to drag in some text to go below here.
And I'm going to use the H five element this time, so a smaller header
to say, your open incidents
and then just drag in some more texts, so that we can actually see those incidents.
For now I'm going to put zero triggered and make this red.
So the text is going to be danger.
And then just copy and paste that.
And this time, this is going to be to show our acknowledged incidents.
And I'm going to change this color to be info.
So there's a lot you can do with styling with this text, I'm going to leave it like that for now.
And we're going to choose this number dynamically based off our you guessed it, our database.
So in fact, I'm just going to copy this and paste it because we're going to drag this over to the right and see all our open incidents as well.
So we've got your open incidents, let's also have all open incidents.
And again, we're going to feed that number in dynamically on component text seven, and component text five.
Now I'm going to add a button, this button was clicked, it's going to help us add a new incident to our database.
So we can actually do that from our UI, which is kind of cool.
And this button, we can style it up.
So I can have an incident if I wish.
And let's make this blue, green just to match the rest of this board.
And I can even choose to make it a little bit bigger.
Next, I'm just going to use a container to contain a bunch of stuff that I want to add next.
So I'm just going to put that in here like so for now.
And this time, in fact, I'm going to get rid of the header.
So we can do that, we can select the whole UI component, and then I can choose to hide the header.
So at the moment, we're just showing the body if you wanted to show footer, then you can do that.
That is totally up to you.
So we have one container, I'm actually going to have to so I'm just going to drag in another one right below here.
Okay, so that we go.
This one again, I don't want to have a header showing, so I'm just going to hide it now and the first one, we're going to just display who is on call.
So I'm going to just have the title here of encore.
Okay, and I'm just going to make it green.
So I'm going to change the color to be green of the text.
We can also make it bold if we wish.
Okay, so I'm just going to use a opening and a closing tag for that to make that bold.
That name next thing I'm going to drag in is a place to actually display whoever is currently on call.
So for now I'm just going to put x x x as we don't really know who's on call yet.
because, once again, we're going to get that from our database.
So I'm just going to also make sure that it's an h3 element, just like that, just to make sure it's a bit bolder.
And we can even use an avatar.
So I can just drag in a premade component.
That's right, that will show us our avatar.
At the moment.
Again, this is just based off my information, my user detail, I'm the current user of this app.
But we will over write this.
So in fact, just so I don't forget to do this, I'm just going to put x x x for all of these so that we don't forget to add that in dynamically.
Now, we can put a divider or we can add a footer is totally up to you.
Let's choose to add a footer.
And in the footer, here, I'm going to add some more information, I'm going to drag in a text component, just like so.
And here, I'm going to put in a bolt you are on call for.
And once again, this is going to be fed dynamically, I'm going to essentially create a list of tags.
So we can find these tags in here too.
And I'm just going to put them in below.
Just like sir.
Okay, so that's going to display what we as the person on call on call for.
In here, again, I'm just going to drag in some more tax, this is going to say and called on call.
Let's go ahead and make this color green.
And here, we're just going to list out all the incidents that we are currently on call for.
Okay, so I'm going to exercise for now as that will be fed dynamically.
And we're also going to show the shift of the current person that is on call.
So it's really obvious.
I'm going to put once again and fold your shift,
and then close this tag.
And then actually display the two shift times as well as some contact information.
So this is going to be from, we're going to put our starting time of the shift, and this is going to be two and we're going to put the end time of the shift of the current person on call.
And here, I'm just going to put some information like contact.
And then I'm going to put info at
Free Code camp.org as well pretending business free code camps pager duty app to make any changes to your shift.
So that's really it.
Okay, so that's for showing all the incidents.
Of course, we haven't hooked this up to any data quite yet.
Let's work on the team members tab next.
So just like with the team members tab, in fact, what I'm going to do is so super simple, I'm just going to copy this, I'm going to copy the divider, we're going to copy the button.
And I'm also going to copy this container
and click Command C.
And inside here, I'm just going to paste it in.
Okay, so it looks kind of similar.
We're going to change this title to say, team members, okay.
And on the Add incident button, well, I'm going to put add, new team member, of course, as this is dealing with team members.
And in here, well, let's just delete that we don't really want that, I'm just going to show the selected team member from the table that we're going to have, we're not going to have an avatar.
So let's delete that we're not going to have your own code for instead, we're going to have a signed operations.
So we can see the assigned operations that are there for the user.
Okay, so there we go, we have the same operations that will be viewed as a tag list.
And I'm also going to put in the shift dates for the user we are selecting.
OK, so once again, in bold, I'm just going to put shift dates
and close that off.
Okay, and once again, let's just put from
and then I'm also going to put the evil of the person that we want to contact.
Okay, so our emails gonna go.
Now one small is also dragging a table, as this is going to show all our team members from what you guessed, our Postgres database.
So let's go ahead and delete all that data.
That is some fake data that has been passed through
And finally, outside of the incidents and outside of the members, so outside of this whole tab container, I'm going to have another container.
Okay, so I'm going to put in a container.
In fact, let's make a form, as essentially, we are going to be sending something from here, we're gonna be sending an email.
So there we go, there is an email form for us.
And I'm just going to put email
composer, as that is what I want to build, let's make the title of this the header, I'm going to change the color of the header.
So if we find the header background, I'm just going to go with highlight as the color of choice.
And let's change the Submit button to I'm going to make a warning.
Okay, and in here I'm going to put to send to, and then whoever we are highlighting from the team members is going to be the person to receive this email.
So that is going to be quite cool.
And another thing we can do is use the rich text editor.
So now we get a whole rich text editor component, this is pretty cool.
Okay, imagine trying to code that out yourself.
And in here, we're going to put Hi, and we're just going to put the selected user from our table.
So that's it.
That's what we have built so far.
Now let's get to linking all of this up.
So for this tutorial, I'm going to use a render.com lynda.com is essentially a way for us to host our database in a non paid way.
Okay, so please go ahead and just go to the dashboard, sign up, go to the dashboard.
And we are going to sign in, I'm going to just choose to sign in with Google.
Okay, so please choose your own way of signing in, it's up to you.
And once he actually need to click on New, and it's a Postgres database that we are going to be create that is hosted on render, I'm going to call this pager duty as that's what I'm creating this database for, I'm happy for the database to be randomly generated, as well as the user name.
And we're just going to select the free tier and click create database.
Okay, so it really was that easy that is creating.
In the meantime, I'm gonna go here and go to resources.
So let's go ahead and create a new resource is going to be a Postgres SQL database, I'm just going to call it pager duty, as that will be easy for us to find the host.
Well, that is this.
So I'm just going to copy this host name, like so.
But then I'm also going to
have to append
So just make sure to append that keep the port as 5432.
As you see here, the database name is pager duty.
So let's put that in here.
And as authentication, we're going to use the database username, which is this, and the database password.
So here's the password, please go ahead and use your own because this one will not work after this tutorial is.
So there we go.
I'm going to click connect using SSL.
And let's just test this works.
And connection is a success.
This is because we left the address, IP address as everywhere, okay.
But if you wanted to, you know, keep it kind of private, you might consider adding these IP addresses.
Let's create a resource.
Let's go back to the resources.
And now I'm just going to shut that down and refresh this.
So it loads the latest resources.
And I'm going to choose pager duty as my resource name, that's just the one I made.
Okay, so I'm actually going to use this UI in order to add the actual tables that I'm going to use for this project.
Okay, so I'm going to just go ahead and create my first table.
So I'm going to use the Create Table command.
And I'm going to create a table of incidents.
Okay, so get up your parenthesis and let's define what's going to go on our table.
Well, I'm going to put an ID, which is going to take an integer value, I'm going to put an urgency level which is just going to take our chart 30.
So 30 characters, essentially, I'm going to have triggered Is this a triggered event? Well, it's yes or no.
So I'm gonna have a Boolean for this.
Next, I'm also gonna have acknowledged, this will also be a Boolean,
as well as resolved, which is also going to be a Boolean.
Next we're going to have a description of the actual incident itself.
So that's going to take
And I'm going to actually limit that to 30.
Okay, we don't want them to be too long, and then assigned to, and this is going to take an integer.
In fact, it's going to take the ID of a an employee.
And I'm also going to have a created
date, which is gonna take a date.
So that's what my table looks like, don't forget to finish it off with some semi colons.
Let's check if this works, I'm going to click Save and Run.
And great, that seems to have worked, we haven't got any errors.
And we're gonna call this playground for now, as I'm essentially using this as a little mini playground to add our tables.
Okay, so that was one thing that we have done, you can keep this in here, if you wish.
In fact, I'm just going to comment that out.
Because I'm going to create a new table to create
table team, this is going to take our team.
So what's our team going to be made up of? Well, each team member is going to have an ID, which I'm going to say has to be an integer, they're going to have a first name, which I'm going to take as virtuoso characters, let's just do 30.
Again, a last name, which I'm going to be super strict about this too.
Of course, you don't have to have 30, I'm just choosing to for now.
And an email, var char binders put 225 wide dots, okay, you can have higher character numbers, if you wish.
Next, I'm going to have a phone number of your team mate, which is going to be an integer value, and Avatar, which is actually going to be a URL to an image on the internet.
And then we're going to have on call to check if they're on court or not.
And this is going to be a boolean value, as well as a shift,
And that's going to be a date,
a shift and value, which is also going to be a date, and incidents that they are working on, which is going to be text, but it's also going to be an array of texts.
So that's how I would write that.
And just finish off some semicolons.
And hit save and run.
So there we go, we have just added our table for team members.
So I'm just going to comment that out.
I'm going to go ahead and just add two incidents just to start off with just so we have stuff to play around with.
So I'm going to insert into the table called incidents.
And we're going to insert an ID and urgency value a triggered value, an AK, knowledge value, resolved value or description assigned to
making sure to spell it exactly the same as we did up here.
And that should be it.
So those are the values we want to insert into let's actually get the values.
So the value for the ID, I'm going to put incident ID number one, we're going to put urgency as the string of high as well as the triggered is going to be true.
Technology is going to be true and resolved is going to be false.
So we've put in Boolean values for those.
And now I'm just going to put in a description of this incident, it's going to be DevOps escalation.
So just like that, it's going to be assigned to the employee with ID 201.
And then we're just going to put in a date that this was created at, I'm going to put a date in the past, okay, because, you know, we don't want to put everything as today's date.
So there we go.
Okay, and don't forget to finish the off with a semi colon.
Okay, so there is our semicolon, and just hit save and run.
And that has run successfully.
So that is one incidence, let's just add a another one.
This one is going to have the value of two.
Let's put the
urgency as low.
Let's add true, maybe false false, this time for triggered, acknowledged and resolved.
This one can be called Security ops.
S escalation making sure to spell security correctly.
It's going to be assigned to use a 201 as well.
And let's put this as maybe one day
I'm click Save and Run.
And I'm just going to comment that out.
I am now just going to insert into team so I'm only going to insert one person into here i
Pick, that will be fine, we need to get the ID, we also get the first name of the person we are inserting, and the last name making sure this will exactly the same as we have in this table.
Next up is email.
Next up is the phone number.
Next up is the Avatar.
And I'm going to have on call.
It's up shift
shift and, and the incidence attached to them.
Once again, just making sure that everything is spelled correctly, because next we're going to put in the values.
And the value of this, well, this is going to be team number 201, the name is going to be Ania.
And their last name is going to be Kubo.
Now my email address, I'm just going to put as the string of Ania at Free Code camp.org.
The phone number, I'm just going to put a fake phone number for now.
And as my avatar Well, I'm just going to use my avatar from Free Code Camp.
So please make sure to take an image that you know is unlikely to be taken offline, or alternatively store them yourself on imager.com.
Or you can put them on an external database such as AWS, for example.
So I'm just going to copy this image address.
And I'm just going to paste it in like so.
Now after the avatar, I'm just going to specify if this person is on call, I'm going to put true.
And then I'm going to also
put a made up start shift time, a made up and shift time as a string,
and then an array.
So we can literally just put the word array like so.
And then I'm going to put in dev ops, s collation.
And security ops, a skull escalation as the incidents assigned to this user.
Okay, don't forget to end it with some semicolons, hit save and run it say integer out of range, that's fine, I'll just change the format of the folder.
And now I'm going to add in that Twilio phone number making sure to add 001 at the front and hit Run and safe.
Now it does say that integer out of range, which is kind of strange, I don't think this should be out of range.
But that is fine, we might have to make this a string instead.
So let's go ahead and make that a string, I'm actually going to just comment this out, we're going to drop the table DROP TABLE team.
So essentially, we're going to delete it, because we have to change the data type of the phone number.
So make sure to drop that.
And now I can create a table again.
So this is good for anyone who perhaps made an error in the first place.
And I'm just going to change this to var char as well.
So that will not take a string.
So save that and run it to create this table again, with the number of being an email.
And now we can insert into Tim, after you have commented this out.
So save and run.
We have now added our first team member, so I'm just going to comment this out for now.
Okay, so that was our playground.
And now I'm going to get some data that we can feed in into our first table of all the incidents.
So let's create a new resource.
And let's make sure that the result is pager duty.
I'm just going to do select all from the table incidents.
And click Save and Run.
Let's see what that looks like.
And indeed, we get two incidents back.
I'm going to rename this get incidents as that is essentially what this query does.
And now in here, instead of adding data manually, I can get incidents and get the data of those incidents so that it feeds in there and it's automatically mapped out to these lovely table rows.
What is cool is if you want to see the whole data object that comes back, you can all you have to do is go to state and get the incidents and there's the data and you will see all that information as
The arrays that we can use.
Okay, so that's just in this tab on the left here, I'm just going to minimize that left panel now.
So that's what I have done.
Let's carry on working on this.
So another cool thing we can do is actually adjust which kind of columns do you want to see or edit or anything like that.
So for example, I can choose to hide the description if I want.
So I'm just going to select the whole table.
And I'm going to choose to hide the description by pressing on this little irate here, I'm also going to hide the assigned to, I'm going to keep the created date.
And I can even if I want, add a new column, add a custom column.
And this column is going to help me delete incidents if I want.
So at the moment, I'm not really going to put anything in here apart from just decide that it's going to be a button.
Okay, that is my button.
And the value of this is just going to say, delete.
So there we go, we can of course, make the columns smaller if we wish, and just in general, play around with this a little bit better.
So I'm happy with this table.
Let's now change the value of this hard coded zero.
And I can do so easily, I can literally get the incidence data.
And I can look inside to see how many of the objects triggered are true, right.
So for this, I'm going to use the filter method.
And I'm going to look through each item, okay, by essentially filtering through each one, and used AI as the representation of each item that we are filtering.
And if i equals true, I'm going to get the length of that array.
So as you will see here, two incidents are triggered.
And if we look here, indeed, two incidents are triggered.
So if we do the same for acknowledge, we should get one acknowledged incident.
So let's try again, we'll use the two curly braces as that is how we do things in retool in order to get values from the queries.
So the query we wrote is called Get incidents, right.
So I'm essentially getting the name of whatever we called this query and getting the data from it.
And I am going to this time filter by the acknowledged, so I'm going to get acknowledged and use the filter method on it to essentially filter and if I or each item in that array equals true, I'm going to get the whole arrays length.
And indeed, we get a one.
So once again, curly braces, in order to access data from the queries, the query I wanted to access is the get incidents query, you can see all the information that comes back here.
And again, if you really want to see the whole object, we can look in here.
So I've got incidents I've got into the data object, then I've gone into the acknowledged array, and I filtered out anything that is equal to true and got the length of that array.
Got it? Cool.
Okay, so to do your open incidents, we're going to have to do something else, because we're going to actually have to get the user.
Okay, so perhaps let's do that next.
Now, who was the user? Well, I think the user should be whoever's on call, right.
So let's go ahead and create a new resource query, I'm going to call this get user.
And I'm going to select all from team this time.
So the table of team were on call equals true, I'm going to save and run this.
So there we go, it comes back with one user and at all points, we really should only have one person on call, right.
So that is a kind of rule that should be done in the backend, this isn't a front end thing.
So we can just assume that this will come back with one user at all times.
So that is going to be a user.
And I'm going to filter incidents by the user.
So let's try another resource.
I'm going to write filter incidents.
And I'm going to select all, from incidents.
to equals and then I'm just gonna get the user data.
So this is our get user query.
We're going to get the ID but only going to get the first ID from the array because we are assuming there is only one so that should be fine.
And don't forget your semicolons at the end, so
I'm just going to save and run that.
And making sure to spell incidents there correctly.
Just run that again.
Okay, so two items come back.
This is because indeed, two items are assigned to me and your Kuba because my user ID is 201.
Once we get to adding more incidents in here, you will see how that changes.
So now that means I can use my filter incidents query to dynamically update these.
So once again, use our curly braces, filter incidence is the query I want to use, I want to get the data from it.
And I want to get the triggered.
And I want to filter it based on if I have the item in here in this array equals true, and I want to get its length.
Okay, so to will be triggered, that is correct, because I'm just going on my open incidents.
And other moment, I'm the only user in here.
So once again, you guessed it, we're gonna get the curly braces, we're gonna get the filtered incidents.
So let's get the filter incidents data.
And this time, we're going to get the acknowledged array and filter it by looping over i and if i equals true, we're going to get to the length of this array at the end.
So this is all looking good.
We can now actually also fill out this because we aren't technically getting the user.
So we can use this query, let's run it again and see what it looks like to find out who's on call, right? So I can use my curly braces, to go into the get user query and get the data and get the first name that comes back to us.
Okay, so I'm going to get the first name.
And I could also put the second name, I've literally just put a space there, this will work, I'm going to get user data.
Last Name, great.
And same for the avatar, well, I'm going to get user data,
Avatar at this time, and just go into the first item of that array.
Same for the email.
So on the label here, I'm just going to get into get user data to the email
and get the first item from the array.
In fact, maybe we should have that on the actual caption of the label.
And here, we will just have the first name again.
So I'm just going to take all of this
and whack it onto the label here.
We can also essentially map out what the tags are.
And here we're going to get the incidents, right, so let's get rid of that curly braces, get user data incidents.
And we're gonna have to go into the first item, that array.
And there we go.
So these incidents have now been mapped out onto here.
Let's also do the same for here.
So I'm just going to show all the incidents, I'm going to get the user data incidents.
And actually, if I treat this as an element, we can actually just put the array in here like so.
Okay, so that's something I have done.
Now, from here, I'm just gonna get into the user again data and get the
And once again, on here, I'm going to get user data, this time shift, and great.
So we've populated all of that base of the get user query.
How cool is that? Next up was work on adding an incident.
So for this, I'm actually going to create a modal that's going to pop up.
So in fact, let's go ahead and just put that up here.
And I'm just going to delete this button.
So delete it, and I'm going to change the text of this to be add incident.
Let's also change it to be green.
So I'm just going to minimize that for now.
As well as the state.
The accent background is going to be green.
We're just going to make it a little bit bigger.
Okay, so that is our modal.
And here I'm just going to put in some tags.
So I'm going to drag in some texts, and this is going to say add incident.
I'm going to make this an h2 element, add
Just like so
let's also put a divider, I'm going to put that in right down here.
And then I'm going to create a number input.
So one specifically to put in numbers.
So just like that with a label in incident ID.
Next, I'm going to create a drop down.
So I'm going to have this select drop down, just like so.
And I'm going to put the value of the label as urgency.
And I'm going to hard code my options, option one is going to be high, option two is going to be medium.
And option three is of course going to be low.
So those are my options.
And if you leave the label as empty, it will just take the value as the default.
And I'm happy with that.
Next, I'm just going to create some
So this is because I'm going to be dealing with Boolean values, so I'm fine with this, I'm going to have one for triggered.
Let's also have one for acknowledged.
And finally, let's have one for resolved.
Okay, so those are my three options right? There.
You can of course, start them up as much as you want.
Next, we're going to have a description input.
So for this, I think we should just have some text.
So I'm going to put in a text input.
This is why I kept the description short, Max 30 characters, because you know, that's not a lot to work with.
And we can also cap this as well.
So we can cap the value.
You can have a max length of 30, just like so.
And let's go ahead and put description
And finally, let's have one more select drop down.
And here, we're going to select who this is assigned to.
So I'm going to put assigned to.
And instead of having options, I'm going to map out the options, this time, the data source for this, well, we're going to have to get all the team members, right, so let's go ahead and write a new query, I'm going to call this get team and we're gonna get all the team members.
And the query for this is select all from Team and run it.
So that's going to be the data source, get team.
And that's going to auto populate for you.
And great, this is fantastic is exactly what I want.
Okay, so now we can actually choose which team member to select in such a nice way.
Okay, and whichever one we select, it's actually going to pick out the ID of that item.
So if I select me, the value of this, when it's selected will be 201.
So readable, and then practical.
And finally, I'm just going to put in a button,
that's going to submit this modal.
So I'm just going to put Summit, and we can actually make the height of this Moodle dynamic based on what's inside.
So I can do hug content, and then that will happen.
Now let's write a query for adding an incident.
So add incident, just like so making sure the resource is pager duty.
And once again, we're essentially going to use this piece of code.
So I'm just going to copy all of that, because that is the code that we will need in order to add a new incident, of course when it's uncommented out.
So that's what we are going to insert into the table incidents.
However, this time the values will not be hard coded.
They will in fact be taken from here.
So I'm going to use my curly braces to access this component which is called number input one number input one and get its value.
If you hover over that you will see that zero well if I change this that will change and you will see the value is now two
Okay, so as literally getting the value of that input, this second one is the urgency, right.
And this component is called select one.
So I'm going to gret select one and get its value once more.
So if I choose high, that will now be high.
So hopefully that's kind of making sense.
Next, we're going to go on these switches.
So that is going to be switch one, two, and three.
So once again, I'm just gonna use my curly braces to get switch ones value, switch, two's value, as long as these are of course in the correct order.
And then switch threes value switch, three, value.
And finally, I'm just going to minimize this, we need to get the description which is text input one, and the Select to value.
So description is going to go here.
And that is text input value one, I believe, yes, text input one and select two.
So select to value, and we're just going to get today's date.
So that's what I've done, I'm essentially getting the values of all these inputs, let's have a go at filling this out.
So let's go Incident Number three, urgency, high triggered, acknowledge, not resolved description, well, I can go ahead and put anything I want, let's put
And assigned to what I'm the only one here right now.
And now this button, well, we need to trigger the Add incident query we just wrote.
So I'm going to add an event listener control query that's been generated for me at incidents because I'm currently on that query.
And we're going to trigger that.
Okay, that looks great to me.
So now, before I submit this, I'm going to run this query with all these values filled out, you will see the values that we are essentially going to put, they've all been now filled out.
And if this works, well on success actually want to do a few things, right, I want to get all the incidents again.
So the freshest incidents, and I also want the modal to close.
So I'm going to control a component to this time.
And that component is the modal.
So let's go ahead and find it.
And I want it to close, we can also add some other fun things like confetti if we want.
So confetti, let's go ahead and do that.
So I haven't run this because I want to trigger it by pressing this button.
So I'm going to click on here,
we have got an error, let's debug.
It would seem I just put a extra
string, I didn't delete those strings properly.
So now let's save.
Let's try it again.
And hit submit.
And great that has worked.
And tada, we have gotten the fresh incidents again.
And that has updated our table.
So this is looking great.
And you will see that this has been updated to
oh, this has not been updated.
That's because we of course also need to run the filter incidents method as well.
So on success of adding an incident, let's add the gets filtered incidents also.
Okay, so there we go.
Now I've just run that again.
So we would have added the same stuff again, because as you will see, that information is still there.
So now let's work on deleting that third one, okay, because we don't want it but at least we know this is working.
And this is working and everything is updating.
So now let's work on it deleting an incident.
So this one I'm going to call delete incident.
The resource is going to be pager duty, and all I'm going to do is delete from incidents where ID equals and then this is table one selected row.
Data it so this for the either it is going to cause a problem.
This is because you know, if we essentially delete, this one is going to look at the ID and it's going to delete both of these.
So just keep in mind that whenever you add an incident that Id needs to be unique.
So save that and onsuccess of this well once again, I'm going to essentially get all the incidents
The filter incidents query once more.
So let's save that.
And now let's hook up this button to that.
So let's find that custom button that we made an on click, we're going to run a query, and that query is delete incident.
Okay, so that's what we want to happen.
Now let's try it out.
I'm going to click Delete incident.
And that should delete and it's deleted all of these incidents, and it's gotten all the incidents again, so we can view them in the table.
And it's updated these based on the filter incident query and the get incident query.
So I'm really happy with this.
Let's carry on.
Okay, now it's time to move on to the team members page.
So in here, let's go ahead and use the get team query in order to populate this table.
So once again, I will use my curly braces, get the get team query and the data from it.
And that should automatically update my table right here.
Again, we can choose which columns to hide, so I'm going to hide the avatar column, this time, I'm going to hide the phone number, I'm also going to hide the start shift and the end shift as well as the incidence, okay, and I'm going to add a custom column once again, to be able to delete that user.
So this is going to be a button.
So let's go ahead and do that.
So there we go, there is a button that says, delete after we update the value.
Before we go deleting anything, let's populate this container with this selected user, as well as add functionality to add a new team member.
So to do this, I'm actually going to rename this component, as I mentioned, this is something you can do.
So I'm just going to call it team table.
And that just makes it more reasonable for when I use this table.
So the team table, so I can literally use my curly braces, to access the team table component
and get the selected row data.
And I could just grab the first name, if I wish of that selected row.
And of course, I could do so for the last name too.
So once again, that's going to Bacardi braces.
And I'm just going to use 10 tables selected row data.
Last Name, this time.
Great, we can also use the avatar that I have hidden from the table, but it still does exist.
So if I want to just go ahead and grab an image,
just like so.
And now I can go into the team table on small selection of data and get the avatar as that exists.
On here, even though it's a deleted column.
Once again, if you want to have a look at the objects for this, just have a look in here look at get team data.
And we're getting the selected row data, right avatar.
And that is the URL that I am getting.
And now let's populate these other components.
So here once again, I would delete all that would use the team table selected row data to get the array of incidents that will be mapped out onto these tags.
And you know what to do this should be easy.
Now once again, let's go into the team table selected row data and get the shift start time.
And then also get this shift and time.
So team table, select data,
shift and is what I want.
And here I'm just going to display the email address.
So once again, Team table selected or data dot email.
And that was it very painless.
Now let's get to adding a new team member.
So for this, I'm actually going to use the modal components.
I'm just going to put that in here for now and it's delete this button.
So I'm just going to delete that and move this over.
So move over the modal button
just to here.
It's going to make it a little bit bigger.
And of course we can style it up.
I'm just going to make everything green.
And then it's changed the font of this to be add new team member.
So now let's work on the modal
So for this, I'm just going to drag in some text, let's make this an h3 element.
And it's gonna say add a new team member.
Just like that.
And I'm just going to drag it out, I'm also going to have another divisor just like we did previously.
So I can put that divide it in right here.
And then let's add some inputs.
So I'm going to put a number input.
And this is going to say, Team Member ID.
So let's change the text of the label to say, Team Member ID.
Let's also just have a text input, this is going to be for the first name.
And we're gonna also have one for the last name, too.
So let's change this to say, first name.
And I'm literally going to copy and paste.
So the second one shows up.
So I can change this to last name, we're also going to have email.
So there is a special email input we can use.
So there we go, I'm just going to drag that in like so and put it here.
Maybe let's put some two dots there, just so we can make it look the same.
And then we're going to have a phone number.
Well, this is actually a text input as we know, because we changed that to be a text input.
So I'm just going to put phone number like
And it's also an avatar image.
Well, this is just going to be a URL to something on the internet, as we mentioned, for now, of course, you don't have to have it like that, you can link this up to an AWS database if you wish in order to store images.
Next, we need to have a checkbox to allow us to check if someone's on call or not.
Okay, so let's go ahead and put on call here, and then someone can choose to select that or not select that, that'll be up to them.
We also have a date picker.
So I'm going to go ahead and just put in
this date picker right here.
And by default, that will show you today's date, which you can then change.
And I'm going to go ahead and change this label to start dates.
And let's make an end date, one, two, so end date end date of each shift.
And finally, we're also going to have a select by a multiple select, okay, because we can pick multiple
operations assigned to one user.
So I'm just going to change this to operations.
And let's Harker the options, the first one is going to be email ops, escalation,
just like that.
The second one is going to be security ops, escalation.
And the third one is going to be DevOps escalation.
So I'm just going to put dev ops, escalation just like that.
Okay, so now people can select multiple ones, which is quite cool.
And then finally, let's have a submit button.
So I'm just gonna get rid of that and find a button so that people can submit these answers.
So there we go.
And it's changes to say, submit.
So wonderful, I think that is looking good.
Now let's get to writing a query for this.
So this is going to be add team member.
So let's change this say add team member, just make sure that's the correct resource.
And then we are also going to insert into so this is where our playground comes in handy, we're going to insert into team, it's going to grab all of that
team member, just paste it in uncomment that out and just change the values.
So the value of this will be whatever the number input two is.
So let's grab the number input to value.
This will be text input two values, so just get rid of that input, text input two value, and then we have text input three value.
So text input three value
will also have email one, so get rid of that string, input email, one value.
We also then have the phone number, which is text input four.
So let's go ahead and put text input for value.
Then we have the avatar, right, which will be text input five value.
So let's get rid of that text input five value.
And then we have a checkbox.
So the checkbox is checkbox one and then we update one do
To add multi select one, so that's really easy to remember, check box value one, this will be date one.
So date, one value, this will be date to value.
And this will be the multi select options or multi, select one value.
So now let's save this, I'm actually going to also add some things to do on success because on success, we want to, essentially we get the team, right, so that will happen onsuccess.
And then let's also have some confetti, because why not, let's also close the modal.
So we're going to this time control a component and find the second modal that we made.
So just scroll down for modal two, and then we want to close it.
So that's what we want to do on success.
So now I'm going to save that and hook up the Submit button to run that query.
So let's just add an event handler, control query add team member.
So wonderful, let's try it out.
I'm going to put employee to to I'm going to put Beau Carnes and as an email, I'm just gonna go well, at Free Code camp.org.
And as a phone number, I'm just going to make this one up.
Okay, just like that.
And as an avatar image, I'm just going to get one off the internet Akbar.
Okay, so I'm going to copy the image address.
And just paste that in, he's not going to be on call.
And let's put his start date as the 11th.
And the end date as the 14th.
And the operations he's going to be assigned to?
Well, let's have a look.
I think there's just an email ops, and security DevOps as well.
So now let's hit submit.
And great bow has been added.
This is looking wonderful.
And finally, let's add a way to actually delete a team member.
So I'm going to actually do is write a new query.
So let's add a new query resource query, this is going to be delete team number.
Make sure the resource is correct.
And we're going to delete from
where the ID equals the team table selected row data ID, right, because we're here, if we're selecting this one, and we want to delete it, we just want to make sure that it's the correct ID.
And that's how we're going to delete that team member.
So on success, we're, of course going to have to rerun the query to get all team members.
So get team and save.
And now we just need to hook up this button.
So let's find that button.
And on click, we want to run a query.
And that query is to delete a team member.
Okay, so there we go.
And Shall we try it out?
Let's do it.
I'm going to delete this team member.
And wonderful, so that we have it.
And I'm just going to Riad him.
Luckily, all of this is still here, as I have not cleared that.
I've done that on purpose, just so it's easy for us for this tutorial, I'm just going to hit submit.
So there's both again.
Now for the email composer, well, it'll be quite nice to have whoever I'm highlighting, have their first name show up.
So that's what I'm going to do.
I'm going to you once again, use the team table, select your data to get the first name of that person.
Okay, so there we go.
It says Hi, Bo.
So this is the default value of our whole rich text editor and put a comma there too.
And here as well, we can show who was sending this to.
So I can use team table selected or data came out this time.
At the moment, it's showing Bo, the device selects myself, of course, this updates, but this updates to and then I can write an email and send it but of course for that we need to hook this up.
Well, I'm also going to do though, is whenever we send an email, I'm going to also send a text notification.
So that's two resources we need to add.
Let's go ahead and do it.
So I'm going to go to Resources.
And let's just hook up our Twilio that
We signed up to before.
So please go ahead and find Twilio on here.
That is Twilio.
And I'm going to do
Let's get the s ID account.
So here is my account s ID.
Let's get the auth token.
So here is my auth token, I will be deleting this.
So please don't think that it will still work.
If you use it.
I'm just going to select this as it's not allowing me to update the IP addresses.
And let's test the connection.
So that connection is successful.
And let's create a resource.
So that is now done, I'm going to save these changes.
And let's go back to resources.
And this time, I'm going to create another resource.
This time it's going to be for emailing, I'm just going to scroll down to a previous one that I've made and reconfigure it.
So here are the settings that you need.
However, you do need to have a Google workspace, which is a paid workspace for this to work now.
So my Google workspace credentials are Ania at code with ania.com.
And then I'm just going to put in my password for that email.
Okay, so that's what you need to do, let's test the connection.
And then we're just going to have to allow less secure apps.
So just go to your admin console.
And I'm just going to search for a way to control access to less secure apps.
Okay, so that's here, we go to settings.
And then we go to access and data control and less secure apps.
And I'm going to allow users to manage the less secure apps.
So that's for all users in my company.
And that connection is a success.
So there we go, we have done it.
Now let's go back to our app is going to get rid of that.
So now let's hook this up, I'm just going to create a new query.
So let's create a new query resource query, this is going to be to send email.
And this time the resource Well, it's going to be Gmail.
And the from email
is just going to be from Ania at
And the to email is essentially going to be whatever we are selecting right, so the selected row.
So let's go into the team table, select a row data email,
where you can have a BBC or a CC, I'm not going to.
And this is just going to say email from pager duty clone.
And the body.
Well, it's just going to be the body of our rich text editor.
So we're going to go into rich text editor one and get the value.
Let's also just have some confetti, and save that.
And now let's hook it up to the Form button.
So event handler on click, we're going to control the query sent email, because that is the query that we are on now.
So it's picked that up.
Another thing I want to do is actually just sent a text message that we got an email.
So there's gonna be another resource query send text.
And this time, this is going to be the resource Twilio that we just made.
So and use Twilio.
Okay, so that's been pre configured for me.
And this is the operation we need to do.
It's a post request, this is the endpoint and it's populated my account Sid, that is good, too.
Well, who we're going to be sending this to.
I'm going to put in my own phone number in a bit to test this out.
But of course, usually you would go into the team table selected row data and get the phone number right.
So just like that, so let's go ahead and select someone.
So I am selected so that should be bringing up my phone number.
The body I'm just going to put you have an email notification from pager duty clan, and from well from is going to be my Twilio phone number which is actually in fact this you can get it from Twilio as well.
If you don't have a from here, please go ahead and add a parameter by clicking here.
So that's what we want to do and let's just add some confetti for when this saves
And I'm just going to attach that to this bottom two.
So send a text trigger.
Okay, so both those things will happen.
because of course, this number doesn't really exist, I am going to put in my phone number.
So please look away.
And let's say this untested out.
That has worked, I should have received a text.
So let's check it out.
Well, first off, I'm just going to run this and see if that has worked.
And let's see bug.
Okay, just to make sure that you have your email the same one as you are using in the app.
And that should work.
Let's check the Gmail account.
So I'm just going to sign in and check out if I got an email.
And I did.
Okay, here's my email.
Of course, it does come as HTML.
So we're probably gonna have to format that a little bit better.
But at least it's sending something.
So there we have it.
We have completed our pager duty app.
Here is in all its glory.
The Twilio API works.
The SMTP API works.
We are using a Postgres database, we can add incidents, team members, delete team members, delete incidents.
This is looking glorious.
I hope this tutorial was useful.
And I hope you had fun while learning and I'll see you soon