.. -*- coding: utf-8 -*-
.. _TutosMuseumsEnhanceViews:
Enhance views
-------------
In :ref:`TutosMuseumsGettingStarted`, we saw how to develop our views by writing html code
directly in CubicWeb views. In this part, we will see how to customize our web application
using different methods : with pyramid views using jinja2 templates and with React.
Pyramid and Jinja2
~~~~~~~~~~~~~~~~~~
React in a CubicWeb view
~~~~~~~~~~~~~~~~~~~~~~~~
In this section, we want to add a map in museum pages to display where is the museum associated
with the page.
To do this, we will use `React simple maps`_, a React_ library. Our goal is to add a react
component inside our museum primary view.
First, we will setup our environment. At logilab, we use Typescript_ when it is possible,
so we will use it also in this tutorial. As module builder, we will use Webpack_.
.. _`React simple maps`: https://www.react-simple-maps.io/
.. _React: https://reactjs.org/
.. _Typescript: https://www.typescriptlang.org/
.. _Webpack: https://webpack.js.org/
Thus, we need to create three files at the root of our cube: `package.json`, `tsconfig.json`
and `webpack.config.js`. A lot of documentation can be find on the Web about how to configure
a React/Typescript environment, so we are not going to dwell on it in this tutorial; and we
will simply copy and paste the following files.
`package.json`:
.. sourcecode:: json
{
"name": "cubicweb_tuto",
"version": "1.0.0",
"description": "Summary ------- A cube for new CW tutorial",
"directories": {
"test": "test"
},
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack",
"watch": "webpack --watch --mode=development"
},
"author": "Logilab",
"license": "GPL-2.0-or-later",
"dependencies": {
"@types/react": "^17.0.0",
"@types/react-dom": "^17.0.0",
"@types/react-simple-maps": "^1.0.3",
"prop-types": "^15.7.2",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-simple-maps": "^2.3.0",
"ts-loader": "^8.0.14",
"typescript": "^4.1.3",
"webpack": "^5.18.0",
"webpack-cli": "^4.4.0"
}
}
`tsconfig.json`:
.. sourcecode:: json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"jsx": "react",
"strict": true,
"esModuleInterop": true
}
}
`webpack.config.js`:
.. sourcecode:: javascript
const path = require("path");
module.exports = {
entry: {
"map.js": "./appjs/geomap.tsx",
},
output: {
filename: "[name]",
path: path.resolve(__dirname, "./cubicweb_tuto/data/")
},
resolve: {
extensions: [".tsx", ".ts", ".jsx", ".js"]
},
module: {
rules: [
{
test: [/\.tsx?$/],
exclude: /node_modules/,
use: ["ts-loader"]
}
]
},
plugins: []
};
Now we have our configuration files, we have to install NodeJS_ and then install our project
using `npm`.
.. _NodeJS: https://nodejs.org/
.. code-block:: console
sudo apt-get install nodejs
npm install
They are two last things to do:
* create a component to display a museum on the map;
* integrate our component in a CubicWeb view.
By convention, we put our js files in a `appjs` directory, and bundle are built in
`cubicweb_tuto/data` (as you can see in our `webpack.config.js`). Then, we will create a file
`geomap.tsx` in `appjs/`.
For our component, we will need three parameters: our museum name, its latitude and its longitude.
These parameters will be defined in our CubicWeb view when we will call our script. Our file
`geomap.tsx` can be written like this:
.. sourcecode:: javascript
import React from 'react';
import ReactDOM from 'react-dom';
import {
ComposableMap,
Geographies,
Geography,
Marker,
Point
} from "react-simple-maps";
const geoUrl = "https://raw.githubusercontent.com/zcreativelabs/react-simple-maps/master/topojson-maps/world-110m.json";
declare const data: {
name: string,
latitude: number,
longitude: number,
}
const MapChart = () => {
return (
')
self.w(' ')
self.content_navigation_components("navcontenttop")
self.render_entity_attributes(entity)
if self.main_related_section:
self.render_entity_relations(entity)
self.render_map(entity)
self.content_navigation_components("navcontentbottom")
self.w(" ")
# side boxes
if boxes or hasattr(self, "render_side_related"):
self.w(" | ")
self.w(' ')
self.render_side_boxes(boxes)
self.w(" ")
self.w(" |