Plone-React Extensibility story
CC Attribution 3.0 Germany:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal purpose as long as the work is attributed to the author in the manner specified by the author or licensor.
Alba, Víctor Fernández de
Gietema, Rob
How do you extend a Plone-React instance? How to use Create-Plone-React-App for create a basic boilerplate package, how to override components, reuse reducers and actions and create a new ones. How to integrate third party components. Demos and walkthroughs. The Pastanaga SVG icon system. How to add new icons.
 Thank you. Yeah, so I think most people were in the last talk, so you know who I am. Victor, take it away. Yeah. Who are you? Victor. There's only one Victor in the community, so it's me. Yeah, so, same thing. So the talks we have, and we currently have the extensibility one. Yeah, so what will we cover? So the idea of this talk is, so the previous one was more or less what is Volto and what does it look like and what is more or less the code base. This one is more about if I want to use Volto now in a website, what techniques should I use and how can I bootstrap my own product and how I can customize it to add some teaming and custom views and overriding other views and all that stuff. So that's what we'll be showing. Yeah, so you know how you can create your own site. All right, Victor will now take over. Yeah. We had Volto and not a long time ago, Volto was thought also was as we created Volto. It was not very thought to be a library, so we are required a way, an easy way to extend it. Then that's why we call for a GSOC meeting, Nilesh here did, and he will do a talk on that tomorrow. And he will explain you how this extensive way of creating the boiler pair required to use Volto as a library is, which we call it createVoltoApp. So the only thing that we have to do is to yarn global and install this utility that will create that boilerplate. And after we have installed in our system, we can call it and we will have all the, our Volto app in this location, right? It's very much the same, the createReactApp application if you ever use it. So it's an easy way to, an easy entry to create your own Volto app. So you only have to do this, so CD to your recently created directory and then a yarn start and then you will have your Volto app. Yeah, after that, we will have a bunch of files, Rob already showed you the last, during the last talk. Yeah, it looks very much like this, which will, you will have some directories by default, very much the same Volto ones, but empty because they are ready for you to add things. We will cover all them during the talk and all the boilerplate required for the Volto app work, right? So this will be the output of the createVoltoApp command. So yeah, as I said, we'll have several of them. So like the static resources one when we will put our fab icon or roadstick and so on. Then yeah, we also can, yeah. The most important thing that you want to do in our, in our, in our new app is to override components. You have by default what Volto has and it will look like exactly the same like Volto. Then you can start overriding a couple of things, a couple of artifacts. One of them are barely components like the logo one here or the SVG that accompanies the logo component and you do it like, you will do it like in JVOT. If everybody is used to do that, you only have to grab the original one, the original file, then place it in your customization folder, which is here also, the customizations folder. You just will put it here using exactly the same folder structure that Volto has. So that way Volto knows what to customize and when. So having this kind of, so this tree of folders which maps the same that the Volto one has, then you will customize the logo SVG component and you will have another, another, the logo customized with your own logo and it's that easy, you only have to reboot the server and then you'll have it. And the same for every component, right? So it will be the same. So you will have to go to Volto, grab it and copy it here, maintaining the exact structure that Volto has. Alright, so internationalization, as I mentioned in the Volto talk, we're using more or less the same machinery as we currently have in Plone. That is based on React Intel. That's a library created by Yahoo. The React Intel is the React implementation of it, but there's also an implementation for Angular and for Vue and for basically everything. You can use the same machinery. So what we did there was that we created the script called, well, it can be called with Jarn AI18n and what it does, it will extract all the message strings from all the sources. So the same thing as you would expect from Plone, which is actually not really common in the JavaScript world because in JavaScript you have to, usually, have to define your messages somewhere, but we actually have like a nice extraction tool so you can't forget any of those. So what it does, it will extract all the translatable string from all your sources. That will be generated into a JSON file. The JSON file will then be converted and synchronized with a POT file, which we can actually use in our translation system. The POT file is then synchronized, as you would expect, to a POT file so all the new strings will show up or strings will be removed when they are removed. And the final step here is that the POT files are generated back into a JSON file, which can be picked up by the front end again. The change from Volto and from teaming your own site is basically we are extracting all the strings which are in your own app. And the last step here will combine all the translations from Volto itself with your own translations and will merge them together into one big translation file, which can be used to do all the translations. So how can you make text translatable in your own view? There's a really simple component which is called a formatted message. It's a simple React component, can be imported from React Intel, and what you do is you render a component, as you can see here, and you provide an ID and you provide a default message, and that's it. Then it will be translatable. If you want to translate attributes or any other string which is not directly rendered into a view, there's some more steps to take there. What you'll have to do there is you have to define the messages on top of your view. So you have a list of the messages you have to define with the same ID and default message. Then you'll have a decorator for your class, which is inject Intel. What this does is it will add an internationalization property or object actually to your class, which you can use to do some translations, and it has matching prop types, so you don't have to do the whole prop type validation. Then you can translate it in attributes, for example, so if I want to translate the title, I can call the Intel, which was injected into it. There's a format message function, and I will pass in the message I defined on top of my file. Yes, still me. We just decided this morning who's going to do what, so we're looking at who's doing what. So, overriding views. As Victor said, overriding the views is exactly the same as you would overwrite like another resource. As long as you match the exact folder structure which is there in photo, it'll work. So, if you want to overwrite an SVG, match the folder structure, if you want to overwrite a view, just match the same folder structure, copy over the file, make your changes to it, and it'll work. One thing we also added to the runner is it'll actually check if... So, it will go to your customization folder and look for all the files. Then it will look if any of the files exist in the VOLTA package itself. If it does, it'll override it. If it doesn't, it will give you a warning. So, it says, okay, you passed in this view, but there's no matching view in VOLTA, so you probably made... you misspelled something or... So, it actually... it's nice to debug, which usually have something that I really overwrite it. It's not working. Why it's not working? So, it's actually a nice thing to have. Then we have something which are custom views, of course. So, if we want to add another view which is not currently there, what we could do is write it in our own... in our team package. So, for example, the full view, as I said, is not part of VOLTA yet. So, if you want to add that, what we do is we go to the components folder. We add a folder called full view and we create our component there. So, the full view, just JSX, is put on that location. That's step one. So, what will the full view look like? This is a lot of code. If you're not familiar with React, then there's probably a lot to gasp at once, but I will go through it quickly. So, basically, it's a React component which does rendering of the header. It will loop over the items which are in my folder. It will show the title. It will show the image. If there's an image attached, it will show the description and it will show the text. That's basically what this component does. Then we have to make sure that we add it to the index.js file so we can easily import it. This is just your entry point. And the next thing is that we have to make VOLTA aware that your view actually exists. So, how do we do that? We have a config.js file and by default, it will look the same as this except for this part. So, what do we do here? Basically, we define which views are available. We import all the default views from VOLTA itself. And if we want to add some new views to it, we will just extend the property of the layout views in this case. And we say, okay, the ID full view, if the layout is specified like full view, we're going to be rendering the full view in there. And that's it. So, that means that if the backend says, okay, you have to render the full view, we go to the full view components which we created earlier. Yep, same thing as the views are the same stories for custom widgets. So, let's say that we have a custom widget that we want to extend because we, I don't know, we have our own add-on product that requires a specific widget for rendering the form in VOLTA. So, the way of doing things is almost the same like in views. So, we have our components and we will have our component widget there as well, which will live in this location. And then we will have the code for this rating widget. And, yeah, it's, I won't go also with all the code, but we'll do whatever I should do. And then we have also the registration of that widget. So, we have to add it to our index.js, the same thing as we did with the view. And then once we have this declared, we can, in the configuration, in the config.js, we can declare that we have a new widget and we have to do exactly the same as we did with the view. So, we have to import the default widgets from VOLTA and then add ours. So, the rating, we have to add, to map the rating key with our component and then that will be it. So, when the backend says, hey, this widget should have the rating component, then VOLTA will know that he will have to use this component for rendering, not any other. Of course, this, if there's any, so the rating ID should come from PLON, because we already have declared that this widget should use the rating component. So, PLON will return with the PLON recipe I that this widget should match the rating which then VOLTA will map, and VOLTA will know that he will have to render the rating widget instead of any other. And we also is nicking the PASTA-NAGAN icon system, because today is like SVG, SVG, all the things, and we thought that it's a better approach, we needed a better approach that we have now implanted with all the font icon system. And in fact, there's a way of doing that and we implemented it in VOLTA as well. So, the thing is that if we have an SVG and we wanted to use it as an icon, so we can use directly the import from ES6 and then this will be taken over by Webpack, which will apply some nice things that SVG is a package, an NPM package that filters SVGs and like kind of clean them, because the output of the SVGs directly from the authoring systems, like Sketch or like, how is it called, the Adobe one. Yes, they are not very optimized, so SVG will optimize this SVG on the fly so you don't have to do anything really, Webpack is doing for you. And then we have to use this icon component that we built and then use the SVG like this in your code. So, you declare the icon is going to be there and pass the name with the import that you just declared before. And then you will have your SVG there. One of the things, of the good things that is having SVG inline SVG icons is that you can style them with CSS, which is already huge. So, we have very much the same things that we have in font, using font icon systems, font-based icon systems, but you can also animate them, which is also a fancy thing. I don't know if we could find a good use for that, but you can do it. And there's a lot of geese about SVG today in the JavaScript community and we can do a lot of things with that. Another thing that you get with inline SVG is accessibility. So, you can set accessibility properties directly into the SVG. And also, in fact, our custom component, our icon, sorry, there's an error here. It's a typo. In fact, it should be the same like the icon. So, we call the icon component with these props. One of the props should be the name. I don't know why, but it's passed over. Sorry about that. And we can pass several props that will modify the behavior of our icon. We can pass directly our color. So, if we don't, we want to set up the color of that icon directly without using CSS, we can do that. And we can declare it in JavaScript like this. We can set the title of our icon, which could be static like this, or could come from the internationalization clone engine, which happens a lot of times. For example, for when you are rendering the toolbar and you are having lots of literals from that, that you have to map to icons. And then you can set the size, which by default is set to 36 pixels, yeah. But you can modify it. You can set the class name as well in case that you need, as we said before, you need to add fancy CSS to that without having to inline-stall in it. And you can also add a handler for what happens when, for example, when you click on that icon. All of them are props that are optional. And this will be the most simplest one, as I said, where it says, my customers should say icon, and then the name should be there as well. So, my fault. Sorry about that. Yeah. Yes. So, as I said, what you can also change are some of the other settings which are defined there. One of them is all the rich text editor settings. So, by default, the people saw the VoltaTalk, you have, I can show you though. That'd be better. If we go to a specific news item, and when we select some text, we have what you see is what you get editor tool by there. So, we'll have, by default, we have the bold italic one with the link item there. And then we have the block-styled items, like header, H1, H2, like the list, unordered list, block code, and call-outs, which are there. But if you want to remove some of the styles, if you don't want them there, or if you want to extend them, you actually want to have an extra one, you can do that. So, how does that work? So, the first thing we'll be doing is, for instance, if we want to have underline, which is not there by default, maybe for good reasons, but if you do want to have that underline, then you can do so. So, what you'll do is, step one, there's some helper methods which you can import, one of which is the create inline style button, that's part of the draft.js button package, and that will help you to easily create a button, so you don't have to worry about what it should exactly generate. Then we'll import the icon components, which Victor already mentioned, and we'll import the SVG. So, as Victor mentioned, we have a lot of the SVG icons, or actually all of the SVG icons, which are part of PastaNAC, and there are a lot of them. I think there are, I don't know, like a couple of... 250 or something. 250, I just heard. So, that's a lot of them. So, for most of the use cases, there probably is an icon you can find, and if not, then we could add them later, I guess. You can add your own as well. Maybe we shouldn't let developers do that, though, but... Or just add Hello Kitty in there. Yeah, so, the first thing you do is you create the inline style button. What you'll do there is... I think... Oh, this one is missing. Yeah. Training. Yeah, that'll work. No, it's not here. No, it's not here. Yes, I do. It is in... Yeah, so this is what the, for example, the bold one will look like. So, what you do is you provide the styling you want, and these are currently defined in Draft.js. Draft.js has a definition of all the available styles which they have. If you want to... So, they have bold, for example, like, as you can see here, had a two, had a three, an ordered list. These styles can also be extended. So, if you want to have your own custom style, which is, I don't know, like a fancy call out or a quote or whatever, you can add your custom one there. But by default, like all the normal ones are available. So, you specify which style you actually want to apply if you press the button, and then you specify what the button will actually look like. So, in this case, we'll say, okay, so the children, so the button, what it will look like, it will be an icon. It will have a name and it will have a size. And as Victor mentioned, you can also add the title and all the other stuff to it if you want to. Next step is to also set the... To add the button to the toolbar. So, what we'll do there is, in the Convex.js again, we'll have a variable called settings. The settings controls a property called... Really long name though. Rich text there that are inline toolbar buttons. Yeah, that's a lot. Yeah, Alex. Is there any plans to do it like we have current system that you can, via the control panel, just activate and deactivate buttons? Definitely. I agree. All developers but integrators, the administrators of the systems might don't have the capability. Yeah, no, definitely. I mean, so, yes, that's definitely on the roadmap currently. But for that to work, we either have to see if the current settings we have for TinyMC, if they match up with the settings we have, I guess with the buttons, it could very well be. So, we can actually read the registry settings already. So, that's one thing we could definitely do. So, yeah, we could definitely work on that. Yeah, I guess, yeah. And then it's also, I think you can also define on your schema, you can also define custom properties. So, you can actually say this field should, like this rich text field should only have, I don't know, Bolton, italic, for example. And I think we could read those values as well. Yeah. So, currently it doesn't work yet. Yeah, I know, yeah, I remember from TinyMC how it worked. So, yeah. Yeah, so for now, what you do is you have this property called rich text editor in I'm talking about buttons, which is a list of all the buttons which are available. And what we do is we add our button in there, and then we paste in the rest of the buttons. So, that basically means we want to underline button to be the first button. So, if you want to have it like as a second or third, this is just a list. So, you can actually just split these values and put it as a second or third item, whichever you prefer. All right. Then the last topic is the actions and reducers. If you don't know what Redux is, then this will probably go a bit over your head because it's a lot of stuff which is added in there. So, this is not easy to understand. But I'll try to explain it anyway. So, just a short end production of what Redux is. The state machinery which we use on the front end, it is a store which is more or less a store of data in there, which is just one object, a nested object with a lot of items in there. So, it will contain, for instance, all the navigation properties which can be used in the front end. It can contain all the content like the title and description, etc. It can contain all the breadcrumbs data and all of that. So, for the store to actually contain the data, we can fire some actions. So, actions are things like go get the breadcrumbs, get the content or add the content or delete something or update something. All those actions can be called and they will eventually end up in the store. I say eventually because there's some steps in between. The step called reducers. So, reducer is basically a function which takes in the current state of the store, looks at the action and combines the two and returns a new state. So, basically, if you have an action saying get me some items, it will handle that and it will put in a new data in the store. If the action needs some backend calls, we'll use something called middleware. So, middleware is something which is in between the action and the reducer and it can actually do some side effects. So, in this case, side effect is fetch me some data from the actual backend and if I get some data back, then handle that and it will fire a new action with the data in there. I hope this makes a bit sense, but as I said, it's quite complicated matter. All right, so if we want to... So, by default, Volto has a lot of actions and reducers there already. So, for all the common stuff to fetch navigation, to get your breadcrumbs to get... Well, basically everything is an action in Volto. But for some reason, you want to add your own actions and reducers. For example, if you're building your own form product or another add-on product and it has custom rest API calls, then you have to match the actions and the reducers on the front end to call those backend endpoints. So, we'll start for example, in this example, we'll have a FAQ module and what we do is we get the FAQ items. So, we'll start by creating an action type called FAQ. Next, we'll create an action. So, an action will look like this. An action is... What it will return is just a plain object. So, in this case, it will return an object with the type saying get FAQ. There's a request property in there. So, that means that this will... The middle where I pick up everything which has a request key in there and it will do something with it. And in the request, there's an operation. So, get can also be post or patch or any of the other HTTP methods. And there's a path in there. So, at this time, there's a path saying, okay, we want to do... Call the search endpoint and we want to look for a specific portal type FAQ. So, that means we only want to find all the FAQ items. Of course, we'll add the actions and reduce to our index files again so we can easily import it. And then the next step is to add our reducer. So, as I said, what does a reducer look like? So, reducer is a function which has... Which takes a state. By default, it's the initial state, but later on, it's the current state. And it will have an action passed into it. And what it does is it'll process that action and depending on... And then it will return the new state. So, for example, if we do the get FAQ call, the middleware will send a couple of actions depending on the state of the current backend method. So, it will first send out the pending method message. So, it will say, okay, this is pending message. We're still fetching the data. So, our state at the beginning looks like there's no error. We don't have any items yet because we didn't fetch any data. It's not... The loaded state is also false and it's also not loading at the beginning. So, when we do pending call, well, we keep with current state whatever the values are in there. We set the error to null because we don't have an error at this stage. We are loading now because the pending call is fired. So, we say true. And we can use this value in our UI. For example, if the loading is there, we can show a spinner, for example, or any other method indicating that it's loading. And we say loaded is false. Next, when we have the... When the success comes in, we get the current state what we have. We say there's no error because we have a success message. The result is there in the action and the result contains the items which we fetched on the backend and we apply it to the items. We say loaded is true and we say loading is false. So, this is the success handler. And then the last one is the fail. So, if a call for some reason failed, then we'll say, okay, we didn't have any items. We specify the error which comes from the backend, so that might specify what our error is. And we say we're not loading anymore and we're not loading it as well. If there's a... So, here we did a type of action.type to see if we match any of the actions which we have if we have to do something with it. If there's a known action which we don't know anything about, we just return the current state so we don't do anything with it. Can we look to the top one, please? Yeah. Very top. Okay. All right. Then we have the index file of the reducers. So, reducers, there can be multiple reducers, of course. So, all the reducers are combined into one big structure. In Voto, we have a list of all the default reducers. So, those are all the reducers, like as I mentioned earlier, the breadcrumbs and navigation and the content and everything. And if you add your own custom reducer, you can just add it to the list. So, we're now adding the FAQ reducer, which we just created also to the list. So, now we created all the actions and the reducers and everything. So, how do we actually use them in a component? So, the first step is we're importing the get FAQ from the actions. So, that's the action we created because we want to call it at some stage. Next, we are going to bind all the both the data which is in the store and the actions to our component. So, as I said, we have the state which is our global state, which is the store. And we have the FAQ, which is the reducer returned. And that one contains a property called items, which was empty at the beginning. And we'll later on, if we do any fetching of the data, we'll contain the actual data. Next, what we'll do is we imported the action and we will bind it to the store. So, we can actually call the action on the store. We'll have the rest of the view here, which is more or less the same as the summary view we saw earlier. Then we have the lifecycle method. So, this method is more or less an event. So, this one will be called when this component is mounted or when it will mount. This one will be fired. What we do is just before this one will be mounted, we're actually calling the action and to make sure that we're fetching the items from the backend. So, on our initial render, probably the items are not there. But on the second, just a couple of seconds later or milliseconds later, depending on how fast your backend is, the items will show up there. In our render, we have this that props the items, which we mapped from the global state, and we can just map through them. So, in our second call when the items actually come in, we can loop through those items and we can render them and we render the title and the description in this case. And that's what that looks like. Yeah, so as I said, we will be sprinting on Volto on Saturday and Sunday. People of any level can join, so we're trying to keep it as open for everyone as possible. We have some really good tasks to start with to get you up to speed to create a view, for example. And if people say, okay, I already have some experience with React and Volto and I did the training and then maybe you already know some more stuff that you can do, definitely there's a lot of advanced tickets there as well. But anyone can join if you just want to help out. On another topic, let's say you want to change or edit the training material or documentation or anything is always welcome to help out with Volto to make it as accessible for everybody as possible. I want to sneak one thing. Go ahead. I went to a mini kudos section. Go ahead. Improvising, yeah, because Davi Lima helped us a lot during the last Vitovena sprint on the extensibility. So I wanted to remember him and also, of course, again to Albert Casado for all these amazing set of icons that we already know. He's there, all the amazing set of icons that he made for us and we will for sure use in our applications. Thanks again. All the other people that help make Volto true. Cool. Any questions? Yeah. Let's wait for the mic. Sure. Could you go back to the slide where there were the various case statements? Yeah. This one. Yeah. So there seems to be some magic going on there. So my assumption here is that the user has submitted a request. Yes. Right? Yes. At the instant that request is sent, the pending state is returned to the user. Yes. So actually, so what you're looking at now is not magic because this is just really simple, but the magic you're referring to is actually the middleware. I should show you what it looks like. Although I might confuse you more than it'll solve. So this is the middleware. Okay. All right. I'll go through it quickly. So what it does is so middleware is in between the actions and the reducers. So we had the actions which is fired. Then we have middleware which can do something with the actions. Then we have the reducers which actually just handle actions. And at the end we have the store which saves that data. So in this case, we created an API. Middleware which actually looks for something specific in your action. In this case, it'll look for, it will get the action and it will fetch a variable called request which we added. And if it's not present, then it will do not do anything. So we'll just call the next reducer with the current action. If the request is there, so if I actually want to do a backend call, it will immediately send me a request. So it will fire a new action with the same type as we're receiving but adding the pending state to it. And this is the state actually which you saw in the reducer. Next up, it will, so you can also have multiple requests in the same item. So it checks if it's a list and if it is, then it'll fire multiple events. If it's just one, it will fire multiple events. If it's just one, it will do the request itself. And then when the request is done, we have to, the handler, it will have the result and it will fire the same type with a success handler and it will pass in the data. And we have the error, so if the backend call doesn't return something valid, if the backend code doesn't return something valid, it will call the error type with the type and the type fill, so that's what we're checking for there. Thank you. That's really good. So it looks really complex, but maybe it's a good idea. That's all without even changing the URL or refreshing the page or nothing. Yeah, yeah, definitely. Yeah, so it's all Ajax calls. Yeah. Yeah. Cool. Thank you. Sorry, this is probably a bit, I'm not that up with React, but so the server side stuff, right? So we do a lot of stuff with UK government, and they have this GDS standard. And part of that is progressive enhancement, which means that things have to work in some reduced form without JavaScript. Now, obviously, what you're talking about is a lot to do with the editing UI. And I'm not talking about the editing UI, but the server side rendering, what happens if JavaScript is turned off on the static pages, the pages of the website, not the editing UI? So if I'm just a normal user, let's see. Where is this setting? I don't know. Here? Yeah. In the middle, I think, oh, they're changing. And now it's in the console. Can we disable it, right? Can we? Anyone else? In the console, yeah. You can do the setting. Yeah. OK. That's all. Setting. Yeah. Let's see if we can just play. I don't know. You'll be there. I can search. Here. Sorry? You might want to keep the other tools open. Oh. No, I think it'll work. If the setting should work, right? We can do a call also. Hmm? Oh, it wasn't there. OK. Let's keep it open. OK. So this is the, I actually have to build the production one, because that will include the static JS. But if I, so the CSS is not here because this is the developer build. But if I run the production build, then it will include the static CSS, and then this part will work. But as you can see, I can just press all the items without JavaScript, and it will still render everything. So the exact same code, which is used on the front end, is also used on the back end. Is that still faster than rendering for the page tempers? I didn't do any benchmarks, but I think so. Yeah. Yeah. No, it's a hard question. No? No? I have to admit that I don't like the J-Bot way of overriding. And my question is, don't you think it's a better idea to extend the components and only overwrite the parts that you really want to overwrite, and maybe to split the JSX parts of rendering? Because I saw big JSX in the render functions. Yeah. One on this one? Yeah, sure. Thing is, well, there are several things to say about that. It is, although you see a class there in JavaScript when it's transpiled, it's not a class because JSX5 doesn't support classes. So that's a bunch of overhead there. So the whole React community themselves, I don't know if you know the news, but they are moving out of classes as base elements for components. So they even now announced a new way of doing a state in a non-class component, I mean in a function component. And the way that we were used to do extension like in Python, like, yeah, I got this class and then I extend it or I do an inheritance, I inherit from this class and they are half all the class. It doesn't work in the same way than the Python world. So something that seems to us so obvious to do is not that obvious in JavaScript. And we have to keep thinking that we are not talking about Python life unless we see classes there and extends and things like that. So, and also the fact that the React community is moving away from classes is something that we don't have also to have used from. And I'm not good. Yeah, so to add to your point of splitting up the JSX part with the other part, that's definitely something we could do. So some React projects use a special controller class and a few classes basically. So the few classes are really stupid so it only has properties and it will render and the controller class does all the logic. So in cases where you actually want to override stuff, we could split it up. And also if we split up more components into smaller components, then I guess it's also easier because then you don't have to override the whole specific class but just like a really small part of it and then it's more or less the same as you would do. But yeah, as Victor said, it's like JavaScript and Python are different environments so we have to deal with how it works. But yeah, there's definitely steps we can make that it will become easier. Okay, time for the next talk. We have time for two more questions. Or one. Yeah, next talk starts in three minutes. Oh, that's true. I thought it stops in... Okay, thanks very much. Thanks, Rob. Thanks, Victor. Thank you. Thank you. Thank you.
 Thank you. Yeah, so I think most people were in the last talk, so you know who I am. Victor, take it away.  Yeah. Who are you? Victor. There's only one Victor in the community, so it's me.  Yeah, so, same thing. So the talks we have, and we currently have the extensibility one.  Yeah, so what will we cover? So the idea of this talk is, so the previous one was more or less what is Volto  and what does it look like and what is more or less the code base. This one is more about if I want to use Volto now in a website,  what techniques should I use and how can I bootstrap my own product and how I can customize it to add some teaming  and custom views and overriding other views and all that stuff. So that's what we'll be showing.  Yeah, so you know how you can create your own site. All right, Victor will now take over.  Yeah. We had Volto and not a long time ago, Volto was thought also was as we created Volto.  It was not very thought to be a library, so we are required a way, an easy way to extend it.  Then that's why we call for a GSOC meeting, Nilesh here did, and he will do a talk on that tomorrow.  And he will explain you how this extensive way of creating the boiler pair required to use Volto as a library is,  which we call it createVoltoApp. So the only thing that we have to do is to yarn global and install this utility  that will create that boilerplate. And after we have installed in our system, we can call it and we will have  all the, our Volto app in this location, right? It's very much the same, the createReactApp application if you ever use it.  So it's an easy way to, an easy entry to create your own Volto app. So you only have to do this,  so CD to your recently created directory and then a yarn start and then you will have your Volto app.  Yeah, after that, we will have a bunch of files, Rob already showed you the last, during the last talk.  Yeah, it looks very much like this, which will, you will have some directories by default,  very much the same Volto ones, but empty because they are ready for you to add things.  We will cover all them during the talk and all the boilerplate required for the Volto app work, right?  So this will be the output of the createVoltoApp command. So yeah, as I said, we'll have several of them.  So like the static resources one when we will put our fab icon or roadstick and so on.  Then yeah, we also can, yeah.  The most important thing that you want to do in our, in our, in our new app is to override components.  You have by default what Volto has and it will look like exactly the same like Volto.  Then you can start overriding a couple of things, a couple of artifacts.  One of them are barely components like the logo one here or the SVG that accompanies the logo component  and you do it like, you will do it like in JVOT.  If everybody is used to do that, you only have to grab the original one, the original file, then place it in your customization folder,  which is here also, the customizations folder.  You just will put it here using exactly the same folder structure that Volto has.  So that way Volto knows what to customize and when.  So having this kind of, so this tree of folders which maps the same that the Volto one has,  then you will customize the logo SVG component and you will have another, another, the logo customized with your own logo  and it's that easy, you only have to reboot the server and then you'll have it.  And the same for every component, right?  So it will be the same.  So you will have to go to Volto, grab it and copy it here, maintaining the exact structure that Volto has.  Alright, so internationalization, as I mentioned in the Volto talk, we're using more or less the same machinery as we currently have in Plone.  That is based on React Intel.  That's a library created by Yahoo.  The React Intel is the React implementation of it, but there's also an implementation for Angular and for Vue and for basically everything.  You can use the same machinery.  So what we did there was that we created the script called, well, it can be called with Jarn AI18n and what it does,  it will extract all the message strings from all the sources.  So the same thing as you would expect from Plone, which is actually not really common in the JavaScript world because in JavaScript you have to,  usually, have to define your messages somewhere, but we actually have like a nice extraction tool so you can't forget any of those.  So what it does, it will extract all the translatable string from all your sources.  That will be generated into a JSON file.  The JSON file will then be converted and synchronized with a POT file, which we can actually use in our translation system.  The POT file is then synchronized, as you would expect, to a POT file so all the new strings will show up or strings will be removed when they are removed.  And the final step here is that the POT files are generated back into a JSON file, which can be picked up by the front end again.  The change from Volto and from teaming your own site is basically we are extracting all the strings which are in your own app.  And the last step here will combine all the translations from Volto itself with your own translations and will merge them together into one big translation file,  which can be used to do all the translations.  So how can you make text translatable in your own view?  There's a really simple component which is called a formatted message.  It's a simple React component, can be imported from React Intel, and what you do is you render a component, as you can see here,  and you provide an ID and you provide a default message, and that's it.  Then it will be translatable.  If you want to translate attributes or any other string which is not directly rendered into a view, there's some more steps to take there.  What you'll have to do there is you have to define the messages on top of your view.  So you have a list of the messages you have to define with the same ID and default message.  Then you'll have a decorator for your class, which is inject Intel.  What this does is it will add an internationalization property or object actually to your class,  which you can use to do some translations, and it has matching prop types,  so you don't have to do the whole prop type validation.  Then you can translate it in attributes, for example, so if I want to translate the title, I can call the Intel,  which was injected into it.  There's a format message function, and I will pass in the message I defined on top of my file.  Yes, still me.  We just decided this morning who's going to do what, so we're looking at who's doing what.  So, overriding views.  As Victor said, overriding the views is exactly the same as you would overwrite like another resource.  As long as you match the exact folder structure which is there in photo, it'll work.  So, if you want to overwrite an SVG, match the folder structure, if you want to overwrite a view,  just match the same folder structure, copy over the file, make your changes to it, and it'll work.  One thing we also added to the runner is it'll actually check if...  So, it will go to your customization folder and look for all the files.  Then it will look if any of the files exist in the VOLTA package itself.  If it does, it'll override it.  If it doesn't, it will give you a warning.  So, it says, okay, you passed in this view, but there's no matching view in VOLTA,  so you probably made... you misspelled something or...  So, it actually... it's nice to debug, which usually have something that I really overwrite it.  It's not working. Why it's not working?  So, it's actually a nice thing to have.  Then we have something which are custom views, of course.  So, if we want to add another view which is not currently there,  what we could do is write it in our own... in our team package.  So, for example, the full view, as I said, is not part of VOLTA yet.  So, if you want to add that, what we do is we go to the components folder.  We add a folder called full view and we create our component there.  So, the full view, just JSX, is put on that location.  That's step one.  So, what will the full view look like?  This is a lot of code.  If you're not familiar with React, then there's probably a lot to gasp at once,  but I will go through it quickly.  So, basically, it's a React component which does rendering of the header.  It will loop over the items which are in my folder.  It will show the title.  It will show the image.  If there's an image attached, it will show the description and it will show the text.  That's basically what this component does.  Then we have to make sure that we add it to the index.js file so we can easily import it.  This is just your entry point.  And the next thing is that we have to make VOLTA aware that your view actually exists.  So, how do we do that?  We have a config.js file and by default, it will look the same as this except for this part.  So, what do we do here?  Basically, we define which views are available.  We import all the default views from VOLTA itself.  And if we want to add some new views to it, we will just extend the property of the layout views in this case.  And we say, okay, the ID full view, if the layout is specified like full view,  we're going to be rendering the full view in there.  And that's it.  So, that means that if the backend says, okay, you have to render the full view,  we go to the full view components which we created earlier.  Yep, same thing as the views are the same stories for custom widgets.  So, let's say that we have a custom widget that we want to extend because we, I don't know,  we have our own add-on product that requires a specific widget for rendering the form in VOLTA.  So, the way of doing things is almost the same like in views.  So, we have our components and we will have our component widget there as well,  which will live in this location.  And then we will have the code for this rating widget.  And, yeah, it's, I won't go also with all the code, but we'll do whatever I should do.  And then we have also the registration of that widget.  So, we have to add it to our index.js, the same thing as we did with the view.  And then once we have this declared, we can, in the configuration, in the config.js,  we can declare that we have a new widget and we have to do exactly the same as we did with the view.  So, we have to import the default widgets from VOLTA and then add ours.  So, the rating, we have to add, to map the rating key with our component and then that will be it.  So, when the backend says, hey, this widget should have the rating component,  then VOLTA will know that he will have to use this component for rendering, not any other.  Of course, this, if there's any, so the rating ID should come from PLON,  because we already have declared that this widget should use the rating component.  So, PLON will return with the PLON recipe I that this widget should match the rating which then VOLTA will map,  and VOLTA will know that he will have to render the rating widget instead of any other.  And we also is nicking the PASTA-NAGAN icon system,  because today is like SVG, SVG, all the things,  and we thought that it's a better approach, we needed a better approach that we have now implanted with all the font icon system.  And in fact, there's a way of doing that and we implemented it in VOLTA as well.  So, the thing is that if we have an SVG and we wanted to use it as an icon,  so we can use directly the import from ES6 and then this will be taken over by Webpack,  which will apply some nice things that SVG is a package, an NPM package that filters SVGs  and like kind of clean them, because the output of the SVGs directly from the authoring systems,  like Sketch or like, how is it called, the Adobe one.  Yes, they are not very optimized, so SVG will optimize this SVG on the fly  so you don't have to do anything really, Webpack is doing for you.  And then we have to use this icon component that we built  and then use the SVG like this in your code.  So, you declare the icon is going to be there and pass the name with the import that you just declared before.  And then you will have your SVG there.  One of the things, of the good things that is having SVG inline SVG icons  is that you can style them with CSS, which is already huge.  So, we have very much the same things that we have in font, using font icon systems,  font-based icon systems, but you can also animate them, which is also a fancy thing.  I don't know if we could find a good use for that, but you can do it.  And there's a lot of geese about SVG today in the JavaScript community  and we can do a lot of things with that.  Another thing that you get with inline SVG is accessibility.  So, you can set accessibility properties directly into the SVG.  And also, in fact, our custom component, our icon, sorry, there's an error here.  It's a typo. In fact, it should be the same like the icon.  So, we call the icon component with these props.  One of the props should be the name. I don't know why, but it's passed over. Sorry about that.  And we can pass several props that will modify the behavior of our icon.  We can pass directly our color.  So, if we don't, we want to set up the color of that icon directly without using CSS, we can do that.  And we can declare it in JavaScript like this.  We can set the title of our icon, which could be static like this,  or could come from the internationalization clone engine, which happens a lot of times.  For example, for when you are rendering the toolbar and you are having lots of literals from that,  that you have to map to icons.  And then you can set the size, which by default is set to 36 pixels, yeah.  But you can modify it.  You can set the class name as well in case that you need, as we said before,  you need to add fancy CSS to that without having to inline-stall in it.  And you can also add a handler for what happens when, for example, when you click on that icon.  All of them are props that are optional.  And this will be the most simplest one, as I said, where it says,  my customers should say icon, and then the name should be there as well.  So, my fault. Sorry about that.  Yeah.  Yes.  So, as I said, what you can also change are some of the other settings which are defined there.  One of them is all the rich text editor settings.  So, by default, the people saw the VoltaTalk, you have, I can show you though.  That'd be better.  If we go to a specific news item, and when we select some text,  we have what you see is what you get editor tool by there.  So, we'll have, by default, we have the bold italic one with the link item there.  And then we have the block-styled items, like header, H1, H2, like the list,  unordered list, block code, and call-outs, which are there.  But if you want to remove some of the styles, if you don't want them there,  or if you want to extend them, you actually want to have an extra one, you can do that.  So, how does that work?  So, the first thing we'll be doing is, for instance, if we want to have underline,  which is not there by default, maybe for good reasons,  but if you do want to have that underline, then you can do so.  So, what you'll do is, step one, there's some helper methods which you can import,  one of which is the create inline style button, that's part of the draft.js button package,  and that will help you to easily create a button, so you don't have to worry about  what it should exactly generate.  Then we'll import the icon components, which Victor already mentioned,  and we'll import the SVG.  So, as Victor mentioned, we have a lot of the SVG icons, or actually all of the SVG icons,  which are part of PastaNAC, and there are a lot of them.  I think there are, I don't know, like a couple of... 250 or something.  250, I just heard. So, that's a lot of them.  So, for most of the use cases, there probably is an icon you can find, and if not,  then we could add them later, I guess.  You can add your own as well.  Maybe we shouldn't let developers do that, though, but...  Or just add Hello Kitty in there.  Yeah, so, the first thing you do is you create the inline style button.  What you'll do there is... I think... Oh, this one is missing.  Yeah.  Training. Yeah, that'll work. No, it's not here.  No, it's not here.  Yes, I do.  It is in...  Yeah, so this is what the, for example, the bold one will look like.  So, what you do is you provide the styling you want,  and these are currently defined in Draft.js.  Draft.js has a definition of all the available styles which they have.  If you want to... So, they have bold, for example, like, as you can see here,  had a two, had a three, an ordered list.  These styles can also be extended.  So, if you want to have your own custom style, which is, I don't know,  like a fancy call out or a quote or whatever, you can add your custom one there.  But by default, like all the normal ones are available.  So, you specify which style you actually want to apply if you press the button,  and then you specify what the button will actually look like.  So, in this case, we'll say, okay, so the children,  so the button, what it will look like, it will be an icon.  It will have a name and it will have a size.  And as Victor mentioned, you can also add the title and all the other stuff to it if you want to.  Next step is to also set the... To add the button to the toolbar.  So, what we'll do there is, in the Convex.js again, we'll have a variable called settings.  The settings controls a property called... Really long name though.  Rich text there that are inline toolbar buttons. Yeah, that's a lot. Yeah, Alex.  Is there any plans to do it like we have current system that you can, via the control panel, just activate and deactivate buttons?  Definitely. I agree.  All developers but integrators, the administrators of the systems might don't have the capability.  Yeah, no, definitely. I mean, so, yes, that's definitely on the roadmap currently.  But for that to work, we either have to see if the current settings we have for TinyMC,  if they match up with the settings we have, I guess with the buttons, it could very well be.  So, we can actually read the registry settings already.  So, that's one thing we could definitely do.  So, yeah, we could definitely work on that.  Yeah, I guess, yeah. And then it's also, I think you can also define on your schema, you can also define custom properties.  So, you can actually say this field should, like this rich text field should only have, I don't know, Bolton, italic, for example.  And I think we could read those values as well. Yeah.  So, currently it doesn't work yet.  Yeah, I know, yeah, I remember from TinyMC how it worked.  So, yeah.  Yeah, so for now, what you do is you have this property called rich text editor in I'm talking about buttons, which is a list of all the buttons which are available.  And what we do is we add our button in there, and then we paste in the rest of the buttons.  So, that basically means we want to underline button to be the first button.  So, if you want to have it like as a second or third, this is just a list. So, you can actually just split these values and put it as a second or third item, whichever you prefer.  All right.  Then the last topic is the actions and reducers.  If you don't know what Redux is, then this will probably go a bit over your head because it's a lot of stuff which is added in there.  So, this is not easy to understand.  But I'll try to explain it anyway.  So, just a short end production of what Redux is.  The state machinery which we use on the front end, it is a store which is more or less a store of data in there, which is just one object, a nested object with a lot of items in there.  So, it will contain, for instance, all the navigation properties which can be used in the front end.  It can contain all the content like the title and description, etc. It can contain all the breadcrumbs data and all of that.  So, for the store to actually contain the data, we can fire some actions.  So, actions are things like go get the breadcrumbs, get the content or add the content or delete something or update something.  All those actions can be called and they will eventually end up in the store.  I say eventually because there's some steps in between.  The step called reducers.  So, reducer is basically a function which takes in the current state of the store, looks at the action and combines the two and returns a new state.  So, basically, if you have an action saying get me some items, it will handle that and it will put in a new data in the store.  If the action needs some backend calls, we'll use something called middleware.  So, middleware is something which is in between the action and the reducer and it can actually do some side effects.  So, in this case, side effect is fetch me some data from the actual backend and if I get some data back, then handle that and it will fire a new action with the data in there.  I hope this makes a bit sense, but as I said, it's quite complicated matter.  All right, so if we want to...  So, by default, Volto has a lot of actions and reducers there already.  So, for all the common stuff to fetch navigation, to get your breadcrumbs to get...  Well, basically everything is an action in Volto.  But for some reason, you want to add your own actions and reducers.  For example, if you're building your own form product or another add-on product and it has custom rest API calls,  then you have to match the actions and the reducers on the front end to call those backend endpoints.  So, we'll start for example, in this example, we'll have a FAQ module and what we do is we get the FAQ items.  So, we'll start by creating an action type called FAQ.  Next, we'll create an action.  So, an action will look like this.  An action is...  What it will return is just a plain object.  So, in this case, it will return an object with the type saying get FAQ.  There's a request property in there.  So, that means that this will...  The middle where I pick up everything which has a request key in there  and it will do something with it.  And in the request, there's an operation.  So, get can also be post or patch or any of the other HTTP methods.  And there's a path in there.  So, at this time, there's a path saying, okay, we want to do...  Call the search endpoint and we want to look for a specific portal type FAQ.  So, that means we only want to find all the FAQ items.  Of course, we'll add the actions and reduce to our index files again  so we can easily import it.  And then the next step is to add our reducer.  So, as I said, what does a reducer look like?  So, reducer is a function which has...  Which takes a state.  By default, it's the initial state, but later on, it's the current state.  And it will have an action passed into it.  And what it does is it'll process that action  and depending on...  And then it will return the new state.  So, for example, if we do the get FAQ call,  the middleware will send a couple of actions  depending on the state of the current backend method.  So, it will first send out the pending method message.  So, it will say, okay, this is pending message.  We're still fetching the data.  So, our state at the beginning looks like there's no error.  We don't have any items yet because we didn't fetch any data.  It's not... The loaded state is also false  and it's also not loading at the beginning.  So, when we do pending call,  well, we keep with current state whatever the values are in there.  We set the error to null because we don't have an error at this stage.  We are loading now because the pending call is fired.  So, we say true.  And we can use this value in our UI.  For example, if the loading is there, we can show a spinner, for example,  or any other method indicating that it's loading.  And we say loaded is false.  Next, when we have the... When the success comes in,  we get the current state what we have.  We say there's no error because we have a success message.  The result is there in the action  and the result contains the items which we fetched on the backend  and we apply it to the items.  We say loaded is true and we say loading is false.  So, this is the success handler.  And then the last one is the fail.  So, if a call for some reason failed, then we'll say, okay,  we didn't have any items.  We specify the error which comes from the backend,  so that might specify what our error is.  And we say we're not loading anymore and we're not loading it as well.  If there's a...  So, here we did a type of action.type to see if we match any of the actions  which we have if we have to do something with it.  If there's a known action which we don't know anything about,  we just return the current state so we don't do anything with it.  Can we look to the top one, please?  Yeah.  Very top.  Okay.  All right.  Then we have the index file of the reducers.  So, reducers, there can be multiple reducers, of course.  So, all the reducers are combined into one big structure.  In Voto, we have a list of all the default reducers.  So, those are all the reducers, like as I mentioned earlier,  the breadcrumbs and navigation and the content and everything.  And if you add your own custom reducer, you can just add it to the list.  So, we're now adding the FAQ reducer, which we just created also to the list.  So, now we created all the actions and the reducers and everything.  So, how do we actually use them in a component?  So, the first step is we're importing the get FAQ from the actions.  So, that's the action we created because we want to call it at some stage.  Next, we are going to bind all the both the data which is in the store  and the actions to our component.  So, as I said, we have the state which is our global state, which is the store.  And we have the FAQ, which is the reducer returned.  And that one contains a property called items, which was empty at the beginning.  And we'll later on, if we do any fetching of the data, we'll contain the actual data.  Next, what we'll do is we imported the action and we will bind it to the store.  So, we can actually call the action on the store.  We'll have the rest of the view here, which is more or less the same as the summary view we saw earlier.  Then we have the lifecycle method.  So, this method is more or less an event.  So, this one will be called when this component is mounted or when it will mount.  This one will be fired.  What we do is just before this one will be mounted, we're actually calling the action  and to make sure that we're fetching the items from the backend.  So, on our initial render, probably the items are not there.  But on the second, just a couple of seconds later or milliseconds later, depending on how fast your backend is,  the items will show up there.  In our render, we have this that props the items, which we mapped from the global state,  and we can just map through them.  So, in our second call when the items actually come in, we can loop through those items  and we can render them and we render the title and the description in this case.  And that's what that looks like.  Yeah, so as I said, we will be sprinting on Volto on Saturday and Sunday.  People of any level can join, so we're trying to keep it as open for everyone as possible.  We have some really good tasks to start with to get you up to speed to create a view, for example.  And if people say, okay, I already have some experience with React and Volto and I did the training  and then maybe you already know some more stuff that you can do, definitely there's a lot of advanced tickets there as well.  But anyone can join if you just want to help out.  On another topic, let's say you want to change or edit the training material or documentation  or anything is always welcome to help out with Volto to make it as accessible for everybody as possible.  I want to sneak one thing.  Go ahead.  I went to a mini kudos section.  Go ahead.  Improvising, yeah, because Davi Lima helped us a lot during the last Vitovena sprint on the extensibility.  So I wanted to remember him and also, of course, again to Albert Casado for all these amazing set of icons that we already know.  He's there, all the amazing set of icons that he made for us and we will for sure use in our applications.  Thanks again.  All the other people that help make Volto true.  Cool.  Any questions?  Yeah.  Let's wait for the mic.  Sure. Could you go back to the slide where there were the various case statements?  Yeah.  This one.  Yeah.  So there seems to be some magic going on there.  So my assumption here is that the user has submitted a request.  Yes.  Right?  Yes.  At the instant that request is sent, the pending state is returned to the user.  Yes.  So actually, so what you're looking at now is not magic because this is just really simple, but the magic you're referring to is actually the middleware.  I should show you what it looks like.  Although I might confuse you more than it'll solve.  So this is the middleware.  Okay.  All right.  I'll go through it quickly.  So what it does is so middleware is in between the actions and the reducers.  So we had the actions which is fired.  Then we have middleware which can do something with the actions.  Then we have the reducers which actually just handle actions.  And at the end we have the store which saves that data.  So in this case, we created an API.  Middleware which actually looks for something specific in your action.  In this case, it'll look for, it will get the action and it will fetch a variable called request which we added.  And if it's not present, then it will do not do anything.  So we'll just call the next reducer with the current action.  If the request is there, so if I actually want to do a backend call, it will immediately send me a request.  So it will fire a new action with the same type as we're receiving but adding the pending state to it.  And this is the state actually which you saw in the reducer.  Next up, it will, so you can also have multiple requests in the same item.  So it checks if it's a list and if it is, then it'll fire multiple events.  If it's just one, it will fire multiple events.  If it's just one, it will do the request itself.  And then when the request is done, we have to, the handler, it will have the result  and it will fire the same type with a success handler and it will pass in the data.  And we have the error, so if the backend call doesn't return something valid,  if the backend code doesn't return something valid,  it will call the error type with the type and the type  fill, so that's what we're checking for there.  Thank you.  That's really good.  So it looks really complex, but maybe it's a good idea.  That's all without even changing the URL  or refreshing the page or nothing.  Yeah, yeah, definitely.  Yeah, so it's all Ajax calls.  Yeah.  Yeah.  Cool.  Thank you.  Sorry, this is probably a bit, I'm not that up with React,  but so the server side stuff, right?  So we do a lot of stuff with UK government,  and they have this GDS standard.  And part of that is progressive enhancement,  which means that things have to work in some reduced form  without JavaScript.  Now, obviously, what you're talking about  is a lot to do with the editing UI.  And I'm not talking about the editing UI,  but the server side rendering, what  happens if JavaScript is turned off on the static pages,  the pages of the website, not the editing UI?  So if I'm just a normal user, let's see.  Where is this setting?  I don't know.  Here?  Yeah.  In the middle, I think, oh, they're changing.  And now it's in the console.  Can we disable it, right?  Can we?  Anyone else?  In the console, yeah.  You can do the setting.  Yeah.  OK.  That's all.  Setting.  Yeah.  Let's see if we can just play.  I don't know.  You'll be there.  I can search.  Here.  Sorry?  You might want to keep the other tools open.  Oh.  No, I think it'll work.  If the setting should work, right?  We can do a call also.  Hmm?  Oh, it wasn't there.  OK.  Let's keep it open.  OK.  So this is the, I actually have to build the production one,  because that will include the static JS.  But if I, so the CSS is not here because this is the developer  build.  But if I run the production build, then it will include the  static CSS, and then this part will work.  But as you can see, I can just press all the items without  JavaScript, and it will still render everything.  So the exact same code, which is used on the front end, is also  used on the back end.  Is that still faster than rendering for the page tempers?  I didn't do any benchmarks, but I think so.  Yeah.  Yeah.  No, it's a hard question.  No?  No?  I have to admit that I don't like the J-Bot way of overriding.  And my question is, don't you think it's a better idea to extend  the components and only overwrite the parts that you really want  to overwrite, and maybe to split the JSX parts of rendering?  Because I saw big JSX in the render functions.  Yeah.  One on this one?  Yeah, sure.  Thing is, well, there are several things to say about that.  It is, although you see a class there in JavaScript when it's  transpiled, it's not a class because JSX5 doesn't support  classes.  So that's a bunch of overhead there.  So the whole React community themselves, I don't know if you know  the news, but they are moving out of classes as base elements  for components.  So they even now announced a new way of doing a state in a  non-class component, I mean in a function component.  And the way that we were used to do extension like in Python,  like, yeah, I got this class and then I extend it or I do an  inheritance, I inherit from this class and they are half all the  class.  It doesn't work in the same way than the Python world.  So something that seems to us so obvious to do is not that  obvious in JavaScript.  And we have to keep thinking that we are not talking about Python  life unless we see classes there and extends and things like that.  So, and also the fact that the React community is moving away from  classes is something that we don't have also to have used from.  And I'm not good.  Yeah, so to add to your point of splitting up the JSX part with  the other part, that's definitely something we could do.  So some React projects use a special controller class and a few  classes basically.  So the few classes are really stupid so it only has properties and  it will render and the controller class does all the logic.  So in cases where you actually want to override stuff, we could  split it up.  And also if we split up more components into smaller components,  then I guess it's also easier because then you don't have to  override the whole specific class but just like a really small part  of it and then it's more or less the same as you would do.  But yeah, as Victor said, it's like JavaScript and Python are  different environments so we have to deal with how it works.  But yeah, there's definitely steps we can make that it will  become easier.  Okay, time for the next talk.  We have time for two more questions.  Or one.  Yeah, next talk starts in three minutes.  Oh, that's true.  I thought it stops in...  Okay, thanks very much.  Thanks, Rob.  Thanks, Victor.  Thank you.  Thank you.  Thank you.
2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_0_431.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_432_767.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_768_1175.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_1176_1415.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_1416_1523.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_1524_1835.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_1836_2267.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_2268_2807.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_2808_3107.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_3108_3599.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_3600_4847.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_4848_4895.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_4896_6347.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_6348_7679.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_7680_12215.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_12216_13535.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_13536_14903.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_14904_16115.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_16116_16163.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_16164_16451.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_16452_18407.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_18408_18755.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_18756_19175.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_19176_19331.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_19332_22103.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_22104_28799.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_28800_29075.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_29076_29927.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_29928_33335.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_33336_33407.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_33408_33491.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_33492_33623.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_33624_40751.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_40752_41063.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_41064_41207.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_41208_42215.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_42216_42791.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_42792_43751.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_43752_45071.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_45072_45335.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_45336_46307.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_46308_49967.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_49968_51539.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_51540_53111.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_53112_53951.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_53952_54347.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_54348_56099.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_56100_61547.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_61548_62939.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_62940_70223.png 2018_Day2_Plone-React_Extensibility_story_by_Victo__G9WW18AASw_70224_70257.png