Commit 9f3dfe11 authored by Alessandro Giansanti's avatar Alessandro Giansanti

more docs

parent c035837b
......@@ -15,9 +15,6 @@ This React project was bootstrapped with [Create React App](https://create-react
- [`yarn compile`](#yarn-compile)
- [`yarn build`](#yarn-build)
- [Libraries](#libraries)
- [App Architecture](./ARCHITECTURE.md)
- [Localization](./LOCALIZATION.md)
- [Todo](./TODO.md)
## Deploying MoodleNet
......@@ -37,6 +34,7 @@ docker-compose version 1.23.2
```sh
$ git clone https://gitlab.com/moodlenet/frontend.git moodlenet
...
$ cd moodlenet
```
......@@ -44,21 +42,20 @@ $ cd moodlenet
First make sure to configure your domain name or subdomain to point to your server's IP address.
We need to set some environment variables in order for MoodleNet to function, a list of which can be found in these files:
- `.env` - If you have a domain configured to point to your server, replace every instance of 'localhost' with 'your-domain-here.tld' and those of 'http:' with 'https:' (the 's' is critical) - **If you want to connect your instance with the MoodleNet "mothership" for indexing public content, search, and discovery**, and you agree with the [Terms for Instance Administrators](https://moodle.net/terms/admins/index.html), set CONNECT_WITH_MOTHERSHIP to true, otherwise set it to false. You should then email moodlenet-moderators@moodle.com to request an API key.
- `.env.secrets.example` (which you must copy to `.env.secrets`) - set each password and secret with something random and secure - MAIL_DOMAIN and MAIL_KEY are needed to configure transactional email, sign up at [Mailgun](https://www.mailgun.com/) and then configure the domain name and key
We need to set some environment variables in order for MoodleNet to function, a list of which can be found in these files: - `.env` - If you have a domain configured to point to your server, replace every instance of 'localhost' with 'your-domain-here.tld' and those of 'http:' with 'https:' (the 's' is critical) - **If you want to connect your instance with the MoodleNet "mothership" for indexing public content, search, and discovery**, and you agree with the [Terms for Instance Administrators](https://moodle.net/terms/admins/index.html), set CONNECT_WITH_MOTHERSHIP to true, otherwise set it to false. You should then email moodlenet-moderators@moodle.com to request an API key. - `.env.secrets.example` (which you must copy to `.env.secrets`) - set each password and secret with something random and secure - MAIL_DOMAIN and MAIL_KEY are needed to configure transactional email, sign up at [Mailgun](https://www.mailgun.com/) and then configure the domain name and key
4. Once configured, build the docker image:
```
```sh
$ docker-compose build
...
```
Or if you're building on a Raspberry Pi:
```
```sh
$ docker-compose -f docker-compose.pi.yml build
...
```
5. Try it out
......@@ -71,33 +68,36 @@ c) Start the docker containers with docker-compose:
```sh
$ docker-compose up
...
```
Or if you're running on a Raspberry Pi:
```
```sh
$ docker-compose -f docker-compose.pi.yml up
...
```
6. The MoodleNet backend and frontend should now be running at [http://localhost/](http://localhost/) on your machine and at https://your-domain-name.tld/ with SSL certificates automatically configured thanks to letsencrypt.org (if your domain was correctly configured).
Once you've signed up, you may want to make yourself an instance admin, by running this in the backend console (see above): `MoodleNet.ReleaseTasks.make_instance_admin("your_username")`
6. The MoodleNet backend and frontend should now be running at [http://localhost/](http://localhost/) on your machine and at `https://your-domain-name.tld/` with SSL certificates automatically configured thanks to letsencrypt.org (if your domain was correctly configured).
Once you've signed up, you may want to make yourself an instance admin, by running this in the backend console (see above): `MoodleNet.ReleaseTasks.make_instance_admin("your_username")`
7. If that worked, start the app as a daemon next time:
```sh
$ docker-compose up -d
...
```
Or if you're running on a Raspberry Pi:
```
```sh
$ docker-compose -f docker-compose.pi.yml up -d
...
```
## Structure
### High level folder structure:
### High level folder structure
| Folder | Description |
| --------- | ----------------------------------------------------------------- |
......@@ -105,7 +105,7 @@ $ docker-compose -f docker-compose.pi.yml up -d
| `/public` | files that will be copied into the `build` folder |
| `/src` | the application source |
### Application source folder structure:
### Application source folder structure
| Folder | Description |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
......@@ -138,7 +138,7 @@ Adds a locale for localisation, with [lingui library](https://lingui.js.org/ref/
### `yarn extract`
Extracts new/updated strings from the codebase into JSON files for localisation (they need to be encapsulated with [lingui library](https://lingui.js.org/ref/react.html)'s <Trans>).
Extracts new/updated strings from the codebase into JSON files for localisation (they need to be encapsulated with [lingui library](https://lingui.js.org/ref/react.html)'s `<Trans>`).
### `yarn compile`
......@@ -157,17 +157,17 @@ Builds a `Storybook` static app out of the storybook's `tsx`|`mdx` modules assoc
### `yarn gqlcode`
Generates typed modules based on `src/**/*.graphql` files and `.env.development`'s `REACT_APP_GRAPHQL_ENDPOINT` Backend GraphQL schema endpoint.
Generates typed modules based on `src/**/*.graphql` files and `.env.development`'s `REACT_APP_GRAPHQL_ENDPOINT` Backend GraphQL exposed schema.
## Libraries
This section mentions notable libraries and tools used within the application and provides links to their documentation.
- React, UI framework (https://reactjs.org/docs/getting-started.html)
- TypeScript, programming language (https://www.typescriptlang.org)
- webpack, build tool (https://webpack.js.org)
- React Apollo, GraphQL client (https://www.apollographql.com/docs/react/)
- Phoenix.js, Phoenix channels JS client (https://hexdocs.pm/phoenix/js/index.html)
- GraphQL Code Generator (https://graphql-code-generator.com/)
- Formik form management (https://formik.org/)
- LinguiJs localisation library (https://lingui.js.org/)
- React, UI framework [https://reactjs.org/docs/getting-started.html](https://reactjs.org/docs/getting-started.html)
- TypeScript, programming language [https://www.typescriptlang.org](https://www.typescriptlang.org)
- webpack, build tool [https://webpack.js.org](https://webpack.js.org)
- React Apollo, GraphQL client [https://www.apollographql.com/docs/react/](https://www.apollographql.com/docs/react/)
- Phoenix.js, Phoenix channels JS client [https://hexdocs.pm/phoenix/js/index.html](https://hexdocs.pm/phoenix/js/index.html)
- GraphQL Code Generator [https://graphql-code-generator.com/](https://graphql-code-generator.com/)
- Formik form management [https://formik.org/](https://formik.org/)
- LinguiJs localisation library [https://lingui.js.org/](https://lingui.js.org/)
......@@ -34,7 +34,7 @@ A 3 layered MVP(ish) pattern ...
- **Apollo Client `src/apollo/`** : main `ApolloClient` configuration and instantiation
- **Contexts `src/context/`** : global application `React.Context`s - Localization, Algolia, Page, ...(more to come)
- **Routers `src/router/`** : Stateless React components interfacing `react-router` APIs to routable page-controllers
- **Routes `src/routes/`** : Stateless React components interfacing `react-router` APIs to routable page-controllers
## Application Layers
......@@ -81,8 +81,16 @@ Some data pre-digesting may occour in FE when makes sense.
For GraphQL related APIs FE modules are paired with a `.graphql` file defining query|mutations and importing controllers `.graphql` fragment definitions to ensure exhaustiveness of selections.
### Apollo Client
### Contexts
### Routers
Currently available global contexts are:
- Algolia (src/context/global/algolia.tsx) configures and provides `InstantSearch` for algolia search features
- Localization (src/context/global/localizationCtx.tsx) configures and provides `lingui` features
- Page (src/context/global/algolia.tsx) provides simple APIs to modify page headers (currently only title but more to come)
### Routes
`src/routes/` folder contains simple tsx modules defining conventionally exporting a set of properties useful for page routing management across the app.
more on routes [here](./ROUTES.md)
......@@ -43,40 +43,79 @@ Examples of using the LinguiJS library are given below.
<Trans>Sign in using your social media account</Trans>
```
### Interpolated language string
It is very common to interpolate values into language strings. This can be done using the `Trans` and `Plural`
components, where the interpolated string names are denoted with curly braces (but still within the actual string)
and the component is given a key/value hash via a `values` prop, where a key of the hash is the name of a string
to be interpolated. For example, from the Login page:
```jsx
<Trans id="You don't need an account to browse {site_name}." values={{ site_name: 'MoodleNet' }} />
```
It is possible then to have `site_name` or any other interpolated string value produced dynamically and inserted
during runtime. If interpolated values also require localisation then you would use a language string hash,
as above in [Language strings as reference](#language-strings-as-reference), making sure to use the `i18nMark`
function to mark them for extraction by the LinguiJS CLI.
### Language strings as reference
When the string is not passed to (as props or directly as children) to the `Trans` component it will not be picked up automatically by the LinguiJS extract script.
In order to "mark" the string as a language string to be included in the compiled language files we must:
- wrap it in a call to `i18nMark` in case of static strings
- produce a `MesageDescriptor` with `t` tag-function in case of interpolated strings.
#### Simple strings
- Import the [`i18nMark` function](https://lingui.js.org/ref/react.html#i18nmark).
```js
import { i18nMark } from '@lingui/react'
```
- Define the language string however you like. It is usually the case that a file will contain more than one
language string accessed via reference, in this case organise the strings within an object with properties
that describe their purpose. For example, from the Login page:
```js
const tt = {
//...
validation: {
email: i18nMark('The email field cannot be empty'),
//...
}
}
````
- _Note:_ the `validation.email` string is wrapped in a call to `i18nMark`. As the string is not passed to (as props
or directly as children) to the `Trans` component it will not be picked up automatically by the LinguiJS extract
script. In order to "mark" the string as a language string to be included in the compiled language files we must
wrap it in a call to `i18nMark`.
- Then consume the strings. Again, for example, from the Login page:
- Define the language string however you like. For example, from the Login page:
```js
const emailRequiredMessage = i18nMark('The email field cannot be empty')
```
- _Note:_ the `emailRequiredMessage` string is wrapped in a call to `i18nMark`.
- Then consume the strings.
```jsx
validation.push({
field: ValidationField.email,
type: ValidationType.error,
message: tt.validation.email // <- notice the string reference here
} as ValidationObject);
<span class="error">
<Trans>{emailRequiredMessage}</Trans>
</span>
```
#### Interpolated strings
- Import the [`t` tag-function](https://lingui.js.org/ref/macro.html#t).
```js
import { t } from '@lingui/macro'
```
- Define `MessageDescriptor`. For example, for an unavailable username in signup page:
```js
const userNameUnavailable = t`Username {userName} is already taken. Choose another one`
```
- _Note:_ the `userNameUnavailable` is not a string it is a [`MessageDescriptor`](https://lingui.js.org/ref/macro.html#js-macros) constructed by the `t` tag-function
- to get an interpolated translation string it has to be consumed by the `i18n._` function exposed by the globally injected Localization `Context`:
```jsx
import { LocaleContext } from 'context/global/localizationCtx';
...
const {i18n} = useContext(LocaleContext)
...
const userUnavailableString = i18n._({ ...userNameUnavailable, values:{ userName: 'nick' } })
passInterpolatedTranslatedStringToSomeFunction(userUnavailableString)
```
### Plural language strings
......@@ -89,23 +128,7 @@ language contains pluralization.
The LinguiJS documentation is very comprehensive and should be referred to for usage of the `Plural` component:
https://lingui.js.org/ref/react.html#plural
### Interpolated language string
It is very common to interpolate values into language strings. This can be done using the `Trans` and `Plural`
components, where the interpolated string names are denoted with curly braces (but still within the actual string)
and the component is given a key/value hash via a `values` prop, where a key of the hash is the name of a string
to be interpolated. For example, from the Login page:
```jsx
<Trans id="You don't need an account to browse {site_name}." values={{ site_name: 'MoodleNet' }} />
```
It is possible then to have `site_name` or any other interpolated string value produced dynamically and inserted
during runtime. If interpolated values also require localisation then you would use a language string hash,
as above in [Language strings as reference](#language-strings-as-reference), making sure to use the `i18nMark`
function to mark them for extraction by the LinguiJS CLI.
[https://lingui.js.org/ref/react.html#plural](https://lingui.js.org/ref/react.html#plural)
## Updating language files
......
# Routes Modules
Routing is based on [`react-router`](https://reactrouter.com/web/guides/quick-start).
Routes are defined in `src/routes/` folder.
Each route (with any applicable sub-route) is defined in a single tsx module defining and exporting:
- `RouteProps` to be consumed in `src/containers/App/Router.tsx`
- a simple Stateless `React.FC` component taking `RouteComponentProps` and feeding the wrapping page-controller-component
- a `locationHelper` (`routes/lib/helper#locationHelper`) for an easy and safe url construction for application components
## How to
A router module would typically define an interface with string properties representing `react-router`
......@@ -13,7 +13,7 @@
"add-locale": "lingui add-locale",
"extract": "lingui extract --clean",
"compile": "lingui compile",
"docs": "typedoc --out docs src",
"docs": "typedoc --out docs --includes ./doc/ src",
"storybook": "start-storybook -p 5000 --docs",
"build-storybook": "build-storybook --docs -c .storybook",
"build-deploy-storybook": "./storybook_deploy.sh",
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment