 Thank you. Thank you for joining us again, the third day of the workshop. We have some exciting topics to cover today. I will just quickly go over the agenda and we will review the exercises. We had two exercises, the translations and the data store one that we did yesterday. And then we will take a little break, a 10 minute break and Austin will give a presentation on performance. This is a new topic. Yeah, it wasn't covered last year. And also the application security so it's, it's very exciting. I hope you look forward to that. And then just like last time we will take a break and then go into break a room sessions. So yeah, and I think I can just jump right into the solutions for the, for the translations exercise. And unless someone, well, I can, I can actually, we can open the questions later. Okay, so you went to the, the link, then you get this, this window. So I'm just going to enter the credentials. Okay, and then I'll go ahead and go and check what we have to do for the, for the tasks. So the to do number one was to import the function 18 and I think this was a little bit tricky because there was, there is a recommendation, if you remember last, sorry, yesterday, that's, yeah, that you need to import locales that, sorry, slash index.js somewhere in your application. And then instead of, if you only import the package here it won't work you will need to import this as well. And you need to do this once. So maybe, yeah, for some that was not clear. So I'm just, yeah, okay, so in any case this is you can also check the, the read me the instructions. And here it says remember the platform generates this file, which must be imported somewhere in the application to make it work. Okay, so I'm going to go ahead and do that and import. And this is for some reason, code sandbox doesn't actually show the locales folder here, but it should work. Okay. And then this is done for for to do one. Then let's check. What do we need to do? We need to add a simple translation to the welcome message here the H1 tag. And we need to have it available in French. And then it says to create, to create the translation file for the French one in the 18 and directory. So check here on the left in the directory inside we have a file that was generated when I created this exercise. And this template. So I did look, look it up what what it stands for so PO means portable object and T is template so portable object template that's the extension that's what it means. You would always have this way generates your. Yeah, when you run yarn start, which was already done for you before. In order to create a French file where you do is just copy the content of this template. Go to the folder. Create a new file. And then, and then now instead of T is just a portable object so this is the file that would contain the translations. So it's not a template. So just make sure that you differentiate between this and yeah. The instruction was to translate this to the afternoon. Yeah. And I'll say this. Sorry, I didn't, I didn't make this translatable yet. So I'm going to have to put this in curly braces. So I'm going to use my function. And then remember that this is this has to be a string literal. So then now I'll go ahead and save and now we should. It should work when I generate the one. It has to pick up the French translation that I just added. So I will open a new terminal. I want to make sure that okay so if you go to settings. You see that this is already in French. And it should already save a new one. When. So let's see if it works. I need to enter this again. There you have it so it's already there you you. Yeah so we have the we have done that the first task. Now the third one was to use interpolation for dynamic values. So instead of a hello user, we want the name, the name of the user to be to be picked up by the translation in a dynamic way. So, from yesterday, if you remember, also in the read me just if you want to have. Like a hint I added this example. So if you have a variable here today state for example one state this is how you would include it in your string, and then you need to pass a second object here assigning this variable to the date to the string will be translated. So now let's go ahead and make this. So instead of user now we have to use a variable name. That's what we want. And you do that in double curly braces. And now we have to pass the key, the objects so this will be the key name and what do we want to do here so as you can see we are. We're getting the data from the use data query, which is me, the resource me and that comes back back from from our request. So then to use this variable data will be data that resource is me. And then what do we want to get we want to get the name. And then here it says, make sure to translate module French as well so we go back to our file, French file and then the translation their name like this. And now we would have to generate this translation again so I'm going to go open a new terminal. And hopefully it will work. Okay, and then, yes, so I'm just going to show you. Okay now it works we have the French translation so the. So if this if that if I was the user of the current user then my name will show up. If someone else is like, yeah, if it's another user then another name would show up so this is dynamic and it's, it's very convenient. Just going to check if the English translation is there. And it is. And this is pretty much it for the, for the tasks. So now, for example if you want to add Spanish translation, you would just create another file like this one so it will be s dot PO. And in this case, you would just copy the contents again from these templates and add the translations, but then your app JS file is already set up so you don't have to do anything, anything else you can just keep adding files here to be able to transmit. And I think this is it. So if anyone has any questions about this. If you believe that you can unmute yourselves. I'm not sure I'll check the chat. Are you still there. No questions. Okay. Yes, this was pretty simple it was demonstrated yesterday as well. So then, I think. I think that's it. Austin will show the, the solutions for the data store exercise. Austin, are you ready? Yeah, sure. Thanks, Deborah. I'm going to demonstrate the second exercise that we had yesterday. And first off, I'll just ask if anyone had any questions about the second exercise or the using the data store. Was everybody able to to successfully use it. Please answer in the poll that I am. I can't do this. I can't create a new poll. And but we can maybe answer in the chat. Say, was it. Were you able to complete it. Maybe Martin can create a poll. And while we're waiting for results of that, I will go ahead and start talking about the data store exercise. And so here we have the, the exercise. Just here in, I'll actually do it in code sandbox so that everyone is on the same page. Go ahead and do that. So we've got our Academy website. Academy 2021 workshop two. Let's go ahead and go to generic dates to apps. And we're going to start the data store sandbox. I do need to fork this sandbox. So now I have my own copy of this. Example, exercise. I'm going to go ahead and open this up as a separate tab as well so that I can. Make this a bit bigger. So here we have the task instructions. We have four tasks here today. The first one is going to be to import a data store provider and render it as a wrapper around the application. And we want to specify the namespace. This one, my custom app namespace 1234. You'll notice that in our d2.config.js, we already have that namespace configured, which means that it has been reserved for this application. So I'm going to go ahead and put this, which start with task one, which is in the app component. So we need to wrap this, this app content with a data store provider. I'm going to start by importing a data store provider, which is a named export of the DHS to slash app service data store package. So now I will render that so I have a data store provider and I'm going to pass it a namespace which is the required. The required property for this component. So I'm going to write my custom app namespace 1234. And I'm going to render the closing tag of the same thing. And there we have a task one complete. So basically this just renders the data store provider around the entire application and uses specifies this specific namespace that we want for our application. And note that this is a pretty unique namespace. Probably there isn't going to be another app that uses my custom app namespace 1234. But then again, I would make this my like the actual name of my application with some numbers after it potentially, just to make sure that no one else would use this. And if someone else copied and pasted this sample code, they would use the same namespace and that would be problematic. So that's something we wouldn't want to happen. I'm going to go ahead and delete this here. And we should still see. I'm just going to download this. We should see that this. So we should see that this. This app doesn't do anything, but it does run. It doesn't run any errors. And, but now we've added this data store provider so we can start moving on to the next tasks. And maybe I got something wrong here, but I think it's correct. We'll see if that changes anything. So let's move on to task number two. So to two was in visualization list to retrieve the user's list of saved saved objects using the use saved object list hook. And this is. So this is going to be using that use save object us hook so first we have to import that. Let's go ahead and do that here. And then we're going to say import use saved object list from DHS to app service data store. Now let's go ahead and retrieve that list. So we're going to get back a list of objects of saved objects. And then we also get back a set of functions which I'm not going to fill out just yet because they aren't need needed for this task. And this is going to use the use saved object list hook. And we're going to get the users saved objects so we're not going to set global or any other properties here. So as Kai or sorry, as someone pointed out yesterday, I believe it was Pete on Slack. This const objects equals an empty array is just a placeholder. And so the, the, the objects is just meant to stop the errors from happening. So let's just use that same objects, your same variable name objects here. And now we'll get a set of objects back from this list. And let's go ahead and refresh this should still not break, but because there's nothing in that in that list of saved objects we shouldn't see anything. But we can if we go to the network tab here. We can get our X HRs. We can see that we are requesting the saved objects from this namespace and getting an empty list back. So now let's go to the next task. Task three is to pass an add function as a prop to the add control component. So I'm going to go ahead and pass an ad function and I need to get this from somewhere. So I'm actually going to pass it here so this is where the ad function gets returned for the the list of saved objects. This will allow us to add a new object when we have one available. The other part of this task was to go to the ad control. And if we look at this we're not receiving any props in this ad control but now we need an ad function. So I'm going to set that up here. So this is going to take an ad function as a prop. So I'm going to set the add a new saved object with the name entered in the input. This is where we should be setting up that or creating that new saved object so I'm going to use that function that we just created called add. And that should be coming here. Yeah, let's add. And we should pass it an object. And that object should have let's use a name with new object, new visualization name, new business. That's what it's called. That's the state function parameter that we're using. So we now have a the ability to add a new visualization. And, but you'll see that this is this is actually a function that returns a promise. And, and we're not waiting for that promise to finish before we're set loading to false so this will set loading to true, and then immediately stop it will immediately set it to false. So there are two things that we could do here. We could either use the then method of this promise to set a loading false after we're done with this. After we're done with adding for, and this is a little bit of a sidebar, but we could turn this into an async function. So this could be. And this equals async. The reason I'm not doing this for the on click event itself is because they're returning a promise sometimes can be a little funky on some DOM handlers, it should be okay on on click but I'm going to do it this way anyway. So we're going to create a new function. And we can then do a wait add, and this will wait for you can only use a wait within async functions if you're not familiar with that. A wait says that we wait for this promise to finish before we move on to this next one. And then we're going to call that function here. So this should work. Let's see how this works here today. We'll see that we actually do have a probably from someone else using this user to create this. This object in the thing, but let's see if we could have this creation of a new object to set up correctly. So let's say test object. And now we'll see that this test object actually does the right thing. And we have created a new object there. We can create a few with the same name to have different IDs so they can be created and deleted independently. So maybe we don't want to keep so once we once we create the test object it seems kind of silly to keep this text here as well. So let's just make this a little bit cleaner and clear that text so before we set loading the false. Let's set this name set new business name to an empty string. Now let's see how this works. Now let's see this is a test. And now we'll see that this this has been cleared. And we try to add a new visualization again it shows us that alert that is set up in this component. So that was task number three. Now let's move on to task number four because we've created a bunch of these things but our delete button doesn't really work yet. And we need to figure out how to how to make that work. So let's go ahead and go to the remove button. And this task four is to get get the remove function for the object with ID ID and use the use the object hook to do that. And so you'll see that in the previous example we use that we passed the add function from the parent component. We could also pass the remove function from the parent component here. But as kind of a demonstration, we're going to have this component be completely independent so it could be nested very far away from the list component and not have access to that remove function. So for this remove function we're going to say we're going to get the value of the use saved object that we that we want and then we're also going to say and remove here. So this is there's there's a few different functions that are returned here. There is update replace and remove from the use saved object hook. And we have to pass it an ID. So we're going to pass it the ID that we were given for this particular component. You'll see that again we have this placeholder that doesn't do anything that's just there to make good get rid of errors before you fill this in. So we're going to get rid of that and now we have this remove function which works. We do note that this value value update and replace are here but they're not used. We can actually get rid of those completely so this should just be like this. So now we have a function here but it's saying that this is not defined. And that's because we haven't imported it yet. So we can import it manually or we can also do what's called auto import, which it knows that there is an export dhs to app service data store called used saved object. So I just click that it will automatically import the correct thing here. So let's get rid of these. And I think we should be done and save this and let's refresh this page. Now let's delete some of these test objects. So you can see that the we can also delete ones in the middle. And we can eventually get to nothing so we can then test object to have visualization we can add and remove objects very easily from this list. Nice. So now we're now we're finished. There is something that this that is a kind of an optimization that you could you might want to add. When you're using the use save object hook just for the functions that are the methods that it returns. So, you know, you know that this this is actually returning the value of this you saved object and you can check more complex application anytime this value changes so you might have an edit form somewhere else on the page, or on a different, different, a router to a different page that lets you edit this object. Anytime you update that this remove button will re render, even though it really doesn't need to. So it will re render because it's expect it's returning a value and it will wants to give you the most up to date value, but we're going to add value in this component itself. So in order to kind of make a little bit of a performance optimization here we can do something. A little bit more advanced that you don't need to but you can say ignore. Oh wait what is this call it's not auto completing for me for some reason. Let's try this again. Right here. But we can do this in the documentation, since the autocomplete has stopped working for some reason on this code sandbox. We look at the documentation here we'll see that each object has two options. And one of those is to ignore updates. So it's sorry that each hook has to two options in the object one is to whether or not it's used as the global store. And the other is whether or not to ignore the updates from other elsewhere in the application. So let's go ahead and pass that to this component as well. I'm sorry not this one. That's true. There we go. So we could we could spend a little bit of time actually looking at this in the react dev tools to see when this component re renders, but we can just test for now that this does still work. And we have our objects working here correctly. Okay. So one thing that we could also test here so let's try this so we have this add function. And let's see if this will work. I'm actually not positive, because we're using the same add function for this you saved object list. So it may not ignore the updates that are done on its own method. So let's try this so let's see if this will actually break our application by not updating when we have when we use add. So actually when we do remove. There we go. So the this object has actually been removed if I refresh the page, it's gone, but it wasn't updating actively in this list so that there, that's where you can see that the ignore updates works when it's. That happens somewhere else in the application if for instance we say new object add. This is a test add help. I am invisible. I just added a bunch of visualizations but they didn't show up in this list. And that's because I set ignore updates the true, which can be a performance benefit when you don't want those updates to appear immediately. If I refresh this page we should see all of those objects have been created. If I delete them it also doesn't delete them from this list and the way this actually works I'm going to get rid of this here and set this to false. The way this works is that we actually so two of these should be gone. We have two left and now I can delete them and they actually are deleted. This works is the, the app service data store actually keeps track of basically a local copy of the saved objects that it knows about. And then it propagates that any changes to that list to all of the places where these hooks are used so that they can be updated in real time when when a change happens. And, and when we say ignore updates, we're not doing that the reason that it's kept locally is that it doesn't we know everything we need to know about the those objects in the in the browser so we don't want to need to send a request to add an object to the server. Wait for it to add and then send another request to get the whole list again when we already have that whole list locally. So just another kind of tidbit and bonus feature of the app service data store here. And that's it. And those were our four tasks that we had there's no no other to do is in any of these files. And we should be good with that does anybody have any questions I see some some in the question in the chat.