Skip to content

Commit

Permalink
wiki docs incorporated/cleaned up - many updates still required
Browse files Browse the repository at this point in the history
  • Loading branch information
dunkOnIT committed Sep 13, 2023
1 parent a9ef6ab commit ad19c13
Show file tree
Hide file tree
Showing 27 changed files with 531 additions and 576 deletions.
1 change: 1 addition & 0 deletions _TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ nav_order: 5
---

## TODO
- [ ] Add "Ruby resources" section
- [x] Add a "DevOps" section under WST processes for deployments and related stuff
- [ ] Read through all pages and edit
- [ ] figure out how to add/link to images, and document that
Expand Down
Binary file added assets/images/auth_popup.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/authorize_button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/browse_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/cost_forecast.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/group_by_instance_type.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/menu_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/new_translation_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/plural_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/success_redirect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/sync_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/images/translate_view.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions contributing/_state_of_the_website.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
title: State of the Website
layout: default
parent: Contributing
---

# Where Are We Now

## Our software

- [New Rails codebase](https://github.com/thewca/worldcubeassociation.org/tree/master/WcaOnRails)
- User account system (with OAuth!)
- [`/results/admin/`](https://www.worldcubeassociation.org/results/admin/) - Results administration panels. Access is enforced by Nginx through our [Rails api](https://github.com/thewca/worldcubeassociation.org/blob/7ad2cc53a14e0da10a39f215aabecc98c5bcd85a/chef/site-cookbooks/wca/templates/worldcubeassociation.org.conf.erb#L53).
- [`/results/admin/phpMyAdmin/`](https://www.worldcubeassociation.org/results/admin/phpMyAdmin/)
- [`/results/`](https://www.worldcubeassociation.org/results/)
- [`/regulations/`](https://www.worldcubeassociation.org/regulations/) - [Regulations](https://www.worldcubeassociation.org/regulations/)

[This milestone](https://github.com/thewca/worldcubeassociation.org/issues?q=is%3Aopen+is%3Aissue+milestone%3A%22Drop+PHP%22) tracks our progress in porting our PHP code to Ruby on Rails.



# What We're Working Towards

# Why Rails?

8 changes: 6 additions & 2 deletions guides/Building-Regulations-locally.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,17 @@ parent: Guides

This page aims to guide you through the process of building the WCA Regulations and Guidelines, which is something that you may want to do when you first clone the website repository.

# Requirements
## Requirements

{: .warning}
> Chef may be deprecated soon - rather rely on the steps described here.
The requirements to build the Regulations locally are pretty small, and can be found in the chef recipes for the [regulations](https://github.com/thewca/worldcubeassociation.org/blob/a604f5a600dc52943101a00e7a3d2e24c086eecd/chef/site-cookbooks/wca/recipes/regulations.rb), but here is a commented step-by-step setup:

The following system packages are needed:
`git`, `python-pip`, `fonts-unfonts-core`, `fonts-wqy-microhei`, `fonts-ipafont`, `lmodern`

I'm fairly confident the first two are likely to be already installed on your system, and the last four are needed to build pdfs for the CJK translations of the Regulations.
The first two are likely to be already installed on your system, and the last four are needed to build pdfs for the CJK translations of the Regulations.
Please note that the name may differ a bit depending on your Linux distribution.

The html/pdf/json generation is done by the [WCA Regulations Compiler](https://github.com/thewca/wca-regulations-compiler), which can be installed through `pip`:
Expand Down
12 changes: 6 additions & 6 deletions guides/Translating-the-website.md
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ Go on the [website](https://internationalize.jonatanklosko.com/) of the applicat

When signed in, you should be able to create a new translation by clicking on "New translation":

![new translation view](http://i.imgur.com/t1d70sK.png)
![new translation view](/assets/images/new_translation_view.png)

Here are the descriptions of the field:

Expand All @@ -185,7 +185,7 @@ Click create once, and you should see your newly created translation under "My T

You should now be on the translate view:

![translate view](http://i.imgur.com/91O6zvO.png)
![translate view](/assets/images/translate_view.png)

Some description:

Expand All @@ -202,13 +202,13 @@ Basically you can enter your translation and press "enter": it will have the sam

If you want to change the translation for a key you already translated you can use the "Browse" view:

![browse view](http://i.imgur.com/cl2Q5gk.png)
![browse view](/assets/images/browse_view.png)

For example the key hierarchy on the previous screen is "fr > countries > XA", so you can click on "countries" and find the "XA" key.

When you're done translating (or at any time), you can download the resulting file through the menu:

![menu view](http://i.imgur.com/6gOslqz.png)
![menu view](/assets/images/menu_view.png)

Then you just have to send it (with your language name in your language) to the software team and voilà!

Expand All @@ -227,7 +227,7 @@ Before actually doing the sync, you will be prompted with a summary of the chang
Conflicts happen when an existing key has been modified in the English locale, after you translated it.
For example the event names changed recently, and this is what I had when synchronizing the French locale:

![sync view](http://i.imgur.com/f4XK9Tx.png)
![sync view](/assets/images/sync_view.png)

If any key has been added, you need to go back to the translation process!

Expand All @@ -246,7 +246,7 @@ There is one specificity that is worth knowing: the key `zero` is always require
In some case it's nicer to be able to override the default value with a nicer "zero" case, eg use "no objects" instead of "0 objects". This is an optional key in the website framework, however we made it required in the app, because it was way easier for us.
This will lead to some confusing cases:

![plural view](http://i.imgur.com/3YdZyJY.png)
![plural view](/assets/images/plural_view.png)

In this particular case, it makes absolutely no sense to provide a `zero` key, since the message is never displayed if there is no registration.
In such cases you can just copy the value of the `other` key.
Expand Down
76 changes: 25 additions & 51 deletions guides/creating-react-components.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ layout: default
## Preamble

The website is historically purely Rails, with a lot of jquery to handle user interaction. With the integration of Webpack to Rails, we started migrated our javascript and css codebase to Webpack, but it's still very much in progress.
The website is historically purely Rails, with a lot of jquery to handle user interaction. With the integration of Webpack to Rails, we started migrating our javascript and css codebase to Webpack, but it's still very much in progress.

This means we serve our assets from two sources: sprockets (assets located in '/assets'), and webpack (assets located in '/packs').

Expand All @@ -23,14 +23,11 @@ out the dependencies and what to include when).

## Creating a new component

Let's assume you want to write a new component to display the website posts,
and you want to name it `PostsWidget`.
Let's assume you want to write a new component to display the website posts, and you want to name it `PostsWidget`.

All of our components live under the aptly named folder `app/webpacker/components`.
You are essentially free to write your code there as you please, but please consider the following as rule of thumb: If it's a simple component that resides within one file, just create it as `PostsWidget.js` and have fun. If it's a complex setup with multiple interacting files, create a folder `components/PostsWidget` and create an `index.js` and other `js` files in there.
All of our components live under the aptly named folder `app/webpacker/components`. You are essentially free to write your code there as you please, but please consider the following as rule of thumb: If it's a simple component that resides within one file, just create it as `PostsWidget.js` and have fun. If it's a complex setup with multiple interacting files, create a folder `components/PostsWidget` and create an `index.js` and other `js` files in there.

The `index.js[x]` file should contain the main component you want to export,
and declare itself in a manner that would work for normal pure-JS projects (i.e. `export`ing the component you want to use in Rails):
The `index.js[x]` file should contain the main component you want to export, and declare itself in a manner that would work for normal pure-JS projects (i.e. `export`ing the component you want to use in Rails):
```javascript
import React from 'react';
import { registerComponent } from '../wca/react-utils';
Expand Down Expand Up @@ -68,21 +65,14 @@ the `app/views/posts/index.html.erb` file would look like this:
</div>
```

The first mandatory argument to `render_react_component` is the name of the component,
the same name used in the JS `export` (actually, there is a JavaScript `require` context running under the hood, so it's literally doing JS `require` with whatever name you pass it).
The second argument is a keyword dict directly containing the properties you want to pass to the component.
The third, optional argument is a keyword dict with other HTML options. For example, `id` may be used to set a specific
id on the `div` holding the component.

In our example we use it to set the `msg` property.
- The first mandatory argument to `render_react_component` is the name of the component, the same name used in the JS `export` (actually, there is a JavaScript `require` context running under the hood, so it's literally doing JS `require` with whatever name you pass it).
- The second argument is a keyword dict directly containing the properties you want to pass to the component.
- The third, optional argument is a keyword dict with other HTML options. For example, `id` may be used to set a specific id on the `div` holding the component. In our example we use it to set the `msg` property.


## Writing UI

Writing a message may be fun, but it doesn't go very far.
We recently switched to [Fomantic UI (FUI)](https://fomantic-ui.com/) (which you may also know as Semantic UI)
as our main framework, it has React bindings through the `semantic-ui-react` package.
Documentation for all usable components is [here](https://react.semantic-ui.com/).
Writing a message may be fun, but it doesn't go very far. We recently switched to [Fomantic UI (FUI)](https://fomantic-ui.com/) (which you may also know as Semantic UI) as our main framework, it has React bindings through the `semantic-ui-react` package. Documentation for all usable components is [here](https://react.semantic-ui.com/).

Basically if you want to include some components from FUI you would do something like that:
```
Expand All @@ -91,32 +81,25 @@ import {
} from 'semantic-ui-react';
```

We don't import the whole FUI CSS by default.
If you're using some components that were not already used by the website, make sure to edit our [global_style.js](https://github.com/thewca/worldcubeassociation.org/blob/0d0137379b5ce1a62e05f0a4dc390fef7aa8292e/WcaOnRails/app/webpacker/packs/global_styles.js) to include the CSS-es relevant to these components.
If what you're using is extremely specific to the widget you're writing, you may consider only including the style in your widget's javascript file.
We don't import the whole FUI CSS by default. If you're using some components that were not already used by the website, make sure to edit our [global_style.js](https://github.com/thewca/worldcubeassociation.org/blob/0d0137379b5ce1a62e05f0a4dc390fef7aa8292e/WcaOnRails/app/webpacker/packs/global_styles.js) to include the CSS-es relevant to these components. If what you're using is extremely specific to the widget you're writing, you may consider only including the style in your widget's javascript file.

If you want to write custom (S)CSS that would be active only when that component is used, you can create a custom (s)css file in the same folder of your component and import it. Webpack will automatically include the style when loading the pack containing your component (again, see the real `posts_widget` example :)).

I won't go much more in details as the rest is just putting together React
components, which is not the scope of that documentation.
I won't go much more in details as the rest is just putting together React components, which is not the scope of that documentation.


## Loading data from the website

Chances are that your new component will want to load some data from the website.
In the case of our `PostsWidget`, we would like to get the list of posts, to display them.
While we're using React to create the *View* for them, the *Model* and *Controller*
part are handled by Rails.
Chances are that your new component will want to load some data from the website. In the case of our `PostsWidget`, we would like to get the list of posts, to display them.
While we're using React to create the *View* for them, the *Model* and *Controller* part are handled by Rails.

Therefore we'll need:
- to make rails give us the list of posts
- somehow load them asynchronously in our component.

### Making the server send json data

The first part is achieved by making the `index` method of the `posts_controller`
reply to us with a json containing the posts data.
Here is roughly what it could look like:
The first part is achieved by making the `index` method of the `posts_controller` reply to us with a json containing the posts data. Here is roughly what it could look like:
```ruby
def index
respond_to do |format|
Expand All @@ -134,19 +117,13 @@ end

It basically tells rails to:
- if the client request json, render the visible posts as json, sorted with the most recent first
- if the client request html (as it would by visiting the index page), we just
render the html page without loading any data (because it will render the component
which itself will request the data as json).
- if the client request html (as it would by visiting the index page), we just render the html page without loading any data (because it will render the component which itself will request the data as json).

You can see the actual implementation of that endpoint (with extra options as which
page to load, how many posts to load, ...) in `app/controller/posts_controller.rb`.
You can see the actual implementation of that endpoint (with extra options as which page to load, how many posts to load, ...) in `app/controller/posts_controller.rb`.

### Using these data in our component

Now that we have an endpoint to fetch data from, we need to use it from our component.
We have a hook that can be used to fetch data from a particular
endpoint.
The `useLoadedData` hook is available in the `requests/loadable` module, and takes one parameter: an url to fetch from.
Now that we have an endpoint to fetch data from, we need to use it from our component. We have a hook that can be used to fetch data from a particular endpoint. The `useLoadedData` hook is available in the `requests/loadable` module, and takes one parameter: an url to fetch from.

To make it clear, let's take this example:
```javascript
Expand Down Expand Up @@ -174,30 +151,27 @@ It would be then used like this: `<PostsWidget initialData={{}} />`.

In the code above, a lot of thing happen under the hood:
- `postsUrl()` returns the route to the posts url (the route can be parametrize with additional data - such as a page number, a tag, or anything else).
- `loadedData` will be filled by `useLoadedData`, and will be `null`
until the data are loaded. When they are, it will contain the server response.
In this case, it will contain a `posts` field with an array of posts.
- `error` will also be provided by `useLoadedData`, and will be set only
if something wrong occurred when fetching the data.
- `loadedData` will be filled by `useLoadedData`, and will be `null` until the data are loaded. When they are, it will contain the server response. In this case, it will contain a `posts` field with an array of posts.
- `error` will also be provided by `useLoadedData`, and will be set only if something wrong occurred when fetching the data.
- `PostsList` is an hypothetical component rendering a list of posts.

As you can see in the example, I used the generic `Loading` and `Errored` component
to handle the cases where the data are loading or could not be fetched.
As you can see in the example, I used the generic `Loading` and `Errored` component to handle the cases where the data are loading or could not be fetched.

Note that you may choose to provide the component with some initial data.
For instance: `<PostsWidget id={} initialData={{posts: [/* some data */]}}/>`
Note that you may choose to provide the component with some initial data. For instance: `<PostsWidget id={} initialData={{posts: [/* some data */]}}/>`

Again you can see a detailed usage in the actual code of `PostsWidget` :)


## Writing data to the website

{: .help}
> This section of the guide needs to be completed.
TODO: a similar `savable` hook is under development.

## I18n
## I18n / Internationalization

Use the `I18n.t` function in place of `t` in Ruby.
This needs to be imported from `i18n`, which is often `import I18n from '../../lib/i18n'`, although you may need to play with the path.
Use the `I18n.t` function in place of `t` in Ruby. This needs to be imported from `i18n`, which is often `import I18n from '../../lib/i18n'`, although you may need to play with the path.

If the translation contains HTML, you can use the `I18nHTMLTranslate` component, which sanatizes first.

Expand Down
4 changes: 3 additions & 1 deletion guides/running_with_rails.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ parent: Guides
{: .help}
> After Monolith Improvements, we should consider whether to deprecate this guide. If we keep it, this page needs some formatting cleanup.
### Run directly with Ruby (lightweight, but it involves manual installation which happens at your own risk and we won't be able to assist with detailed troubleshooting)
This guide describes how to run the website using Rails's `rails server` command instead of [Docker](/contributing/quickstart). Note that Docker is the recommended method - only use this guide if you have a specific reason for using it.

## Run the Server with Rails

- Ensure you have the correct [Ruby version](./.ruby-version) installed. We recommend using a Ruby version manager like [rvm](https://rvm.io/rvm/install) or [rbenv](https://github.com/rbenv/rbenv). They should both read the `.ruby-version` file to use the correct version (`rvm current` or `rbenv version` to confirm).
- Ensure [Bundler 2](https://bundler.io/v2.0/guides/bundler_2_upgrade.html) is installed
Expand Down
Loading

0 comments on commit ad19c13

Please sign in to comment.