در حال بارگذاری ...

Creating Progress Metric0:00

Can you actually believe that we're this far into a series about administration panels, and we haven't once mentioned the word chart or graph? That's like the bread and butter of admin panels, isn't it? Well, let's fix that in this episode. Nova provides a very versatile tool set under the umbrella of metrics for anything like graphs and charts and progress bars. Now, in this episode, we'll cover a few different types of metrics, but we certainly won't get to covering all of them. So, do read through the documentation on metrics so that you have an idea of what's available for you. The first thing I want to focus on is the progress metric, which is amazing for tracking goals for your administrators. Now, we're a library, right? Let's say we have a goal of every month adding 10 new books to our library. Using the progress metric, we could see how close we are to achieving that goal each month, so that we know whether we need to get more books in or whether we can leave it until next month. We'll start in the terminal by creating our metric using php artisan nova:progress, and I'll call this one NewBooks.

so that we know whether we need to get more books in or whether we can leave it until next month. We'll start in the terminal by creating our metric using php artisan, nova-progress, and I'll call this one NewBooks. And here you can see our NewBooks class. If I scroll down, we have a calculate method. Most metrics in Nova have a calculate method, and it's where you'll tell Nova how to actually display this particular metric. The default here is pretty close to what we want. We want to count the number of results in the database, not for the model class, but for the Book class, and then we can alter the query. Well, we only want books created in the last month, so we'll say where the created_at column is greater or equal to now, and we can use the startOfMonth method that Carbon provides. The target by default is 100, which works great if you're planning on showing a percentage, but in our case, we're just wanting to show 10 books, so I'll change this to be 10.

Adding and Testing Metric2:01

The target by default is 100, which works great if you're planning on showing a percentage, but in our case, we're just wanting to show 10 books, so I'll change this to be 10. And that actually finishes the calculation for our NewBooks metric. Pretty simple, right? Now, we need to add our newly created metric somewhere, and I think the index of books would be perfect for showing this particular progress. So, inside our book resource, I'm going to jump down to the cards method, and we simply add our metrics to this array, in our case, a new instance of the NewBooks metric we've just created. Now, if we refresh our books index, you can see we have this brand new card here at the top, and it's currently at 0%, which makes complete sense. I've not added any books this month. Let's change that. We'll jump into the terminal. I'm going to php artisan tinker, and I'll use BookFactory in order to create a new book in our database.

Let's change that. We'll jump into the terminal. I'm going to php artisan tinker, and I'll use BookFactory in order to create a new book in our database. Now, when we refresh, we've actually reached 10% of our goal. We have created one new book this month. If I go to the terminal again, we'll create another book, and I'll refresh. We've hit 20%. I can do the same again, and we should hit 30%. You can see how we would use this in reality to make sure we're getting close to our target each month, and then at the start of each month, because of the query we've defined in Calculate, it would reset to 0%, and we can begin our goal again. So, a very simple metric, but perfect for tracking those goals you want to achieve, or even avoid, inside your administration panel.

Building Trend Metric3:37

So, a very simple metric, but perfect for tracking those goals you want to achieve, or even avoid, inside your administration panel. Another metric I think would be very useful in our case is how many books have been returned late over a given period of time, and any time you're dealing with a given period of time, you should reach for the Trend metric. This time I'm going to say php artisan nova:trend, and I'll call this one LateBooks, and inside LateBooks, again as before, we have a Calculate method, but it's a bit different this time. This time we're calling countByDays, which is a helper method made available to us by the Trend class. Now, there are other helpers, so I can count by hours, minutes, months, and weeks, but countByDays works well for our use case.

Now, there are other helpers, so I can count by hours, minutes, months, and weeks, but CountByDays works well for our use case. Once more, we need to pass a model in here so that it knows what it should count. Let's take a quick look at the database so that we can decide what that should be. So you'll see we have our BookCustomerPivot table, which is represented by the LoanPivot model inside our application code, and we have the ReturnedAt column and the DueBackAt column. Now, a LateBook is any loan where the ReturnedAt column is greater than the DueBackAt column, so that's what we need to track. With that in mind, we can use the LoanPivot model here, but I don't just want to pass the fully qualified class name.

With that in mind, we can use the LoanPivot model here, but I don't just want to pass the fully qualified class name. I can actually pass a QueryBuilder instance, so I'm going to ask for any loans using the whereColumn method where the returned_at date is greater than the due_back_at date. Now, by default, all of these helper methods will try to use the created_at column for the base of the query. In our case, that won't work. We want to use the due_back_at column, so I'll pass a third parameter where I can enter due_back_at in order to alter the defaults.

Adding Dashboard Card5:34

We want to use the DueBackAt column, so I'll pass a third parameter where I can enter DueBackAt in order to alter the defaults. That should be it for the implementation, but we need to decide where to surface it in our admin panel. I don't think the Books index makes sense, and I don't think the Customers index makes sense. We want to bring back the dashboard from previous episodes, don't we? Let's go do that. In our custom menu in the NovaServiceProvider, I'll add a new menu item for a dashboard,

In our custom menu in the NovaServiceProvider, I'll add a new menu item for a dashboard, and I'm going to pull in the main dashboard. I'll alter the name to Overview, which I think makes more sense. If we jump into the dashboard, currently it returns a card called Help, and that's the card you see where it points you to different learning resources that Nova provides. So instead of showing Help here, I'm going to return a LateBooks instance like so. And in the browser, we now have the Overview dashboard here at the top.

I'm going to return a LateBooks instance like so. And in the browser, we now have the Overview dashboard here at the top. When I click it, I see LateBooks. I have my range picker here, so LateBooks in the last 30 days. You can see we have a few. If I click 60 days, I have a few more. And 90 days, well, we don't actually have any LateBooks for the last 30 days of 90 days, but you can see our results here squashed up a little to the right. Now, why is this figure zero? Well, the default for a trend is that it will pick the very last value,

Now, why is this figure zero? Well, the default for a trend is that it will pick the very last value, the latest value to display. In our case, we don't want that. We actually want to show the sum of everything, all LateBooks in the last range, so in the last 30 days in this case. Thankfully, that's a very easy tweak. Let's jump back into LateBooks. And after countByDays, I'm going to chain on a method called showSumValue. Now instead of zero, we see five LateBooks in the last 30 days.

And after count by days, I'm going to chain on a method called showSumValue. Now instead of zero, we see five LateBooks in the last 30 days. We see 14 LateBooks in the last 60 days, and so on and so forth. Much better for our use case. Now, where are these ranges that we see actually coming from? Well, inside our metric, there is a rangers method where we can customize what is displayed in that dropdown. In our case, 90 days might not make sense, but 10 days might make more sense. So we can add that in here. The key is the actual value that will be used inside the method defined at the top,

Creating Table Metric7:54

So we can add that in here. The key is the actual value that will be used inside the method defined at the top, and the value is the label you want to actually display in the front end. Now when we refresh, yeah, the default is 10 days, and we can switch to 30 days, we can switch to 60 days. And you can add as many different ranges as makes sense for your particular use case. Okay, now let's take a look at our third and final metric, and that's the table metric. In our application, we have reviews. And when someone creates a review, it starts its life as unverified. Until it's verified, it will not show up in the front end.

And when someone creates a review, it starts its life as unverified. Until it's verified, it will not show up in the front end. So we need some form of to-do list where we can see the reviews that need verifying and take action on them as administrators. The table metric makes perfect sense for this use case. Once more, from the terminal, we'll say php artisan nova, this time table, and I'll call it unverifiedReviews. Much like previous metrics, we have a calculate method, but there is a difference here in that what we return is much more custom.

Much like previous metrics, we have a calculate method, but there is a difference here in that what we return is much more custom. In this case, we're returning a simple metric table row, which is just telling us the version of Nova that we're currently using. What do we want to do? Well, we want to return any review. So let's do that, return any review where the verified_at column is null. Now, there could be hundreds of unverified reviews. We don't want to show them all. So let's grab the latest reviews, and I'll limit it to the top five,

We don't want to show them all. So let's grab the latest reviews, and I'll limit it to the top five, the top five latest reviews. We'll grab them from the database, and then I want to map over them. So I'll receive the review, and for each one, I'll return a metric table row where I want to pass a title. The title is going to be the review's title, and I also want to see who wrote the review. So I'll add a subtitle for this, and I'll use string interpolation to say by, and then we'll add in review.reviewer, and then I want the name of the reviewer,

So I'll add a subtitle for this, and I'll use string interpolation to say by, and then we'll add in review, reviewer, and then I want the name of the reviewer, which is on both the User and the Customer. Now, obviously, if we're accessing a relationship, we want to avoid the n plus one problem. I'll call with, and I'll make sure we've loaded the reviewer in as a relationship, and then I can remove this return here from the bottom. Let's register our metric inside the dashboard again, unverified reviews, and let's see what that looks like inside the browser. So sure enough, we have our unverified reviews.

and let's see what that looks like inside the browser. So sure enough, we have our unverified reviews. You can see them here, but, yeah, it's kind of ruined the look of LateBooks. This one obviously needs more space. Why don't we put it on its own line? In order to do that, I'll wrap our instantiation of unverifiedReviews in brackets, and then I'm going to call the width method and pass full. This will make it take up the full width of available space in the administration panel, and now you can see LateBooks has returned to a nice, manageable size, and unverifiedReviews sits down here at the bottom.

Caching and Table Actions11:01

and now you can see late books has returned to a nice, manageable size, and unverified reviews sits down here at the bottom. There's one thing I think it's important I bring to your attention regarding metrics, and in order to illustrate the point, I'm going to use Ray, my favorite don't-die debugging tool. I actually think it's the best way of debugging Nova, but if you don't want to shell out for Ray, that's absolutely fine. You can use the log tools that Laravel makes available to you. You'll just have to look through the log file once you've finished debugging. In our unverified reviews metric, at the top of the calculate method,

You'll just have to look through the log file once you've finished debugging. In our unverified reviews metric, at the top of the calculate method, I'm going to make a call to Ray, and I'll just output here into the Ray console. Now, with Ray pinned to the browser, I'm going to refresh this dashboard, and I'll refresh it a few times to illustrate my point. You can see every time that we refresh, we hit that calculate method again, which means we hit the database again, and almost all metrics are going to hit the database. As you can imagine, if you have a dashboard filled with 20 different metrics, that's a big load on the database every time you refresh.

As you can imagine, if you have a dashboard filled with 20 different metrics, that's a big load on the database every time you refresh. But most of the time, your metrics don't need to update that often. They can be cached for a reasonable period of time. You don't have to implement the caching yourself either. Nova has caching built in. In any metric, there is a cacheFor method. By default, it's commented out, but we can uncomment it in order to cache for the specified amount of time. In this case, five minutes, but obviously I could add hours instead.

in order to cache for the specified amount of time. In this case, five minutes, but obviously I could add hours instead. I could add days or weeks, and it would cache for that period of time. I think minutes is fine here. Let's go back into the browser, and I'll show you what's changed. So I have Ray pinned again. I'm going to refresh. And when I refresh, yeah, we get here. So it's hit the database once. But when I refresh again, you see Ray's not updating. We're not hitting again because Nova has intelligently cached.

But when I refresh again, you see Ray's not updating. We're not hitting again because Nova has intelligently cached the result of our unverified reviews. So very quick to implement. You can choose the period of time you want to cache for, but I really do recommend you use the caching functionality Nova provides because it makes your administration panel, particularly large dashboards, feel a whole lot faster. And it reduces a ton of load from your database layer. Just before we close out, we see the list of unverified reviews,

And it reduces a ton of load from your database layer. Just before we close out, we see the list of unverified reviews, but currently there's no real way to access them. We'd have to search this review title in order to find it. Thankfully, we can add actions to the table metric. So let's add an action to view this particular resource. Under metric table row, I'm going to chain on an actions method, which is a closure that returns an array, and I'll add a menu item to this array, which is going to be a link.

and I'll add a menu item to this array, which is going to be a link. We'll call it view, and we want to view resources, reviews, and then I'll add the review ID as the target for this particular link. Note with menu item, we don't have to prefix with Nova because we're using link. We can instead use external link if we want to reach for something outside of the administration panel. But yeah, in our case, link works perfectly. Now, bear in mind, when we refresh here,

But yeah, in our case, link works perfectly. Now, bear in mind, when we refresh here, we don't see any actions because we've asked it to cache. So we have to make sure that we clear the cache if we want to see the latest results. But with our cache cleared, we can refresh. We now have a three-dot menu next to each item, and I can click to view that particular review, check the content, and then verify it if I'm happy. Now, I still actually think that it's a little bit difficult

check the content, and then verify it if I'm happy. Now, I still actually think that it's a little bit difficult for a user to verify a review. They have to click to view the review. They have to read it. They have to click edit. They have to fill out this verified_at column and then update it. Very long-winded. I think it would be much nicer if there was a one-click action

Very long-winded. I think it would be much nicer if there was a one-click action inside a review to mark it as verified. Well, that opens up the perfect opportunity to discuss actions in Nova.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟