Commit Graph

765 Commits

Author SHA1 Message Date
Javi Martín
54a48d63e1 Use separate actions to select/deselect investments
This is consistent to what we usually do. Also, we're applying the same
criteria mentioned in commit 72704d776:

> We're also making these actions idempotent, so sending many requests
> to the same action will get the same result, which wasn't the case
> with the `toggle` action. Although it's a low probability case, the
> `toggle` action could result in [selecting an investment] when trying
> to [deselect] it if someone else has [deselected it] it between the
> time the page loaded and the time the admin clicked on the
> "[Selected]" button.
2024-10-28 13:41:50 +01:00
Javi Martín
463112c2ea Use a switch to toggle investment selection
Just like it happened with proposals, the button to select/deselect an
investment wasn't very intuitive; for example, it wasn't obvious that
pressing a button saying "selected" would deselect the investment.

So we're using a switch control, like we do to enable/disable features
since commit fabe97e50.

Note that we're making the text of the switch smaller than in other
places because the text in the investments table it is also smaller
(we're using `font-size: inherit` for that purpose). That made the
button look weird because we were using rems instead of ems for the
width of the button, so we're adjusting that as well.

Also note we're changing the width of the switch to `6em` instead of
`6.25em` (which would be 100px if 1em is 16px). We're doing so because
we used 100 for the minimum width because it's a round number, so
now we're using another round number.
2024-10-28 13:40:27 +01:00
Javi Martín
9e5566cee4 Use a button to toggle investment selection
As mentioned in commit 5311daadf, using buttons for non-GET requests has
several advantages over using links.
2024-10-28 13:39:49 +01:00
Javi Martín
cf0d8258ed Use abilities to allow toggling investment selection
We were checking it in the view, meaning that it was possible to toggle
the selection by sending a custom request even when the investment
wasn't feasible.
2024-10-28 13:39:49 +01:00
Javi Martín
95f36ed52f Simplify code to toggle investment selection
This way it'll be easier to change the link/button used to toggle the
selection.

Note that the conditions in the view seem to be different because we no
longer include the `selected?` condition when rendering the link/button.
However, an investment can only be selected if it's feasible and its
valuation is finished, so writing something like this would have been
redundant:

```ruby
can?(:toggle_selection, investment) &&
  (selected? || investment.feasible? && investment.valuation_finished?)
```

The reason why the previous code was using the `selected?` condition was
to check whether to render the link/button to select or to deselect an
investment. We're now doing that in the Ruby part of the component.
2024-10-28 13:39:42 +01:00
Javi Martín
c78494c100 Extract method to get toggle selection path
This way we simplify the view code.

Since now we only use the `budget` method in one place, we're removing
it.
2024-10-28 13:37:56 +01:00
Javi Martín
fde24870bc Extract component for investment toggle selection
This way it'll be easier to refactor it.
2024-10-28 13:31:34 +01:00
Javi Martín
b9c3e75930 Fix duplicate HTML IDs in investments selection
Since this cell is shown once per row, there were multiple rows with the
same HTML ID on the page.
2024-10-25 17:24:32 +02:00
Javi Martín
73166e164b Simplify HTML for an investment row
Since we define the `data-field` element, we can style each element
individually with CSS.

I'm not sure whether these styles make sense, though. For instance, why
is "Supports" aligned to the center, since it's a number? For now, we're
leaving it as it was.
2024-10-25 17:24:32 +02:00
Javi Martín
607dabbc8a Move admin investments partial to a component
This way it'll be easier to organize the code related to it.
2024-10-25 17:24:32 +02:00
Javi Martín
9330cdb304 Extract methods in investment row component
This way we simplify the code a little bit.
2024-10-25 17:19:52 +02:00
Javi Martín
bb42809168 Move investment partial to a component
This way we'll be able to simplify it a little bit.

Note that the original partial didn't include the whole row and only
the cells. Since, most of the time, we include the whole row in
partials, we're slightly modifying the component.
2024-10-25 17:19:42 +02:00
Javi Martín
4a2fc50c76 Use separate actions to select/deselect proposals
This is consistent to what we usually do. Also, we're applying the same
criteria mentioned in commit 72704d776:

> We're also making these actions idempotent, so sending many requests
> to the same action will get the same result, which wasn't the case
> with the `toggle` action. Although it's a low probability case, the
> `toggle` action could result in [selecting a proposal] when trying to
> [deselect] it if someone else has [deselected it] it between the time
> the page loaded and the time the admin clicked on the "[Selected]"
> button.
2024-10-25 17:12:47 +02:00
Javi Martín
fec44c146c Use a switch to toggle proposal selection
The button to select/deselect a proposal wasn't very intuitive; for
example, it wasn't obvious that pressing a button saying "selected"
would deselect the proposal.

So we're using a switch control, like we do to enable/disable features
since commit fabe97e50.
2024-10-25 17:12:44 +02:00
Javi Martín
b127bd2f51 Use a button to toggle proposal selection
As mentioned in commit 5311daadf, using buttons for non-GET requests has
several advantages over using links.
2024-10-25 17:10:14 +02:00
Javi Martín
43b6ab00e3 Simplify method to get the toggle selection path 2024-10-25 16:40:34 +02:00
Javi Martín
3febe3f0cc Extract methods in toggle selection component 2024-10-25 16:40:34 +02:00
Javi Martín
3cebce9a29 Extract link to toggle selection to a component 2024-10-25 16:40:32 +02:00
taitus
29df39b2fa Add an apply Rails/CompactBlank rubocop rule
In rubocop-rails 2.26.0, the Rails/CompactBlank rule was modified to handle
cases where select(&:present?) is used. After identifying three occurrences
in our code, we've decided to apply this rule as it encourages the use of the
more efficient and clearer method, compact_blank.

By using compact_blank, we improve code clarity and performance, as this method performs the same operation but in a more optimized way.
2024-10-10 10:02:22 +02:00
Javi Martín
8663778245 Add missing folders for custom code
We were loading these folders in `application.rb`, but they didn't exist
by default.
2024-09-02 15:03:24 +02:00
Javi Martín
f8f6844ec3 Simplify common HTML attributes using tag.attributes
The `tag.attributes` method was introduced in Rails 7.0.
2024-07-22 18:35:35 +02:00
Javi Martín
5033691666 Avoid duplicate records in poll answers
Until now, we've stored the text of the answer somebody replied to. The
idea was to handle the scenarios where the user voters for an option but
then that option is deleted and restored, or the texts of the options
are accidentally edited and so the option "Yes" is now "Now" and vice
versa.

However, since commit 3a6e99cb8, options can no longer be edited once
the poll starts, so there's no risk of the option changing once somebody
has voted.

This means we can now store the ID of the option that has been voted.
That'll also help us deal with a bug introduced int 673ec075e, since
answers in different locales are not counted as the same answer. Note we
aren't dealing with this bug right now.

We're still keeping (and storing) the answer as well. There are two
reasons for that.

First, we might add an "open answer" type of questions in the future and
use this column for it.

Second, we've still got logic depending on the answer, and we need to be
careful when changing it because there are existing installations where
the answer is present but the option_id is not.

Note that we're using `dependent: nullify`. The reasoning is that, since
we're storing both the option_id and the answer text, we can still use
the answer text when removing the option. In practice, this won't matter
much, though, since we've got a validation rule that makes it impossible
to destroy options once the poll has started.

Also note we're still allowing duplicate records when the option is nil.
We need to do that until we've removed every duplicate record in the
database.
2024-06-26 20:20:24 +02:00
Javi Martín
03f89c9ca2 Move action to create answers to AnswersController
It was confusing to have the action to create an answer in
`QuestionsController#answer` while the action to destroy it was
`AnswersController#destroy`.
2024-06-26 20:20:24 +02:00
Javi Martín
12e49ff607 Hide languages link when there's only one language
Most existing Consul Democracy installations will have changed their
`config.i18n.available_locales` option so only a few locales are
available. In many cases, only one locale will be available. In these
cases, rendering a form that only offers one option is useless.

We've considered adding a text in this case mentioning that, in order to
enable more languages, they need to configure their
`config.i18n.available_locales`. However, we haven't done it for two
reasons.

First, if they've changed the available locales to just one, there's a
good chance they aren't interested at all in configuring the locales.

And, second, if there's only one available locale, administrators will
learn to ignore the "languages" link, so they won't realize that locales
can be configured if developers change the available locales. If we hide
the link, on the other hand, they will notice that locales can now be
configured once developers change the available locales.

Note we're still allowing access by entering the URL. This is harmless,
though, since people accessing it this way will see a form with only one
possible option and won't be able to modify anything.
2024-06-25 18:58:57 +02:00
Javi Martín
5fa6db2226 Rename HTML attributes referencing poll options
Since now poll question answers have been renamed to poll question
options, using HTML IDs, classes and data attributes named `answer` was
confusing.
2024-06-13 19:13:05 +02:00
Javi Martín
8997ed316c Rename variables describing poll options as answers
Since we've renamed the class to `Option`, having variables, methods and
texts refering to it as `answer` was confusing.
2024-06-13 19:13:05 +02:00
Javi Martín
38b38d1fcc Rename Poll::Question::Answer to Poll::Question::Option
Having a class named `Poll::Question::Answer` and another class named
`Poll::Answer` was so confusing that no developer working on the project
has ever been capable of remembering which is which for more than a few
seconds.

Furthermore, we're planning to add open answers to polls, and we might
add a reference from the `poll_answers` table to the
`poll_question_answers` table to property differentiate between open
answers and closed answers. Having yet another thing named answer would
be more than what our brains can handle (we know it because we did this
once in a prototype).

So we're renaming `Poll::Question::Answer` to `Poll::Question::Option`.
Hopefully that'll make it easier to remember. The name is also (more or
less) consistent with the `Legislation::QuestionOption` class, which is
similar.

We aren't changing the table or columns names for now in order to avoid
possible issues when upgrading (old code running with the new database
tables/columns after running the migrations but before deployment has
finished, for instance). We might do it in the future.

I've tried not to change the internationalization keys either so
existing translations would still be valid. However, since we have to
change the keys in `activerecord.yml` so methods like
`human_attribute_name` keep working, I'm also changing them in places
where similar keys were used (like `poll_question_answer` or
`poll/question/answer`).

Note that it isn't clear whether we should use `option` or
`question_option` in some cases. In order to keep things simple, we're
using `option` where we were using `answer` and `question_option` where
we were using `question_answer`.

Also note we're adding tests for the admin menu component, since at
first I forgot to change the `answers` reference there and all tests
passed.
2024-06-13 19:13:01 +02:00
Javi Martín
6188281d33 Don't use instace variables in component views
Just like we do every else (sometimes even on that very same file), we
use the method instead of the instance variable.

We're doing this change now because we're about to modify one of these
files (the poll question answers documents index component).
2024-06-12 15:16:14 +02:00
Javi Martín
eef9f58410 Extract component to render poll geozones
This way we remove a bit of duplication.

These changes also affect the way geozones are rendered in a couple of
minor ways, making them more consistent:

* No empty list of geozones is rendered when there are no geozones
  (before these changes, an empty list was rendered in the index action
  but not in the show action)
* The text clarifying the geozone restriction is always shown (before
  these changes, it was shown in the index action but not in the show
  action)

We've added tests for these cases.
2024-06-10 17:11:30 +02:00
Javi Martín
5dc98929fc Move poll header partial to a component
This way it'll be easier to write tests for it when we change
it.
2024-06-10 16:53:13 +02:00
Javi Martín
bb574db1ea Allow customizing the text to display poll dates
Since we were using `I18n.t`, our monkey-patch of the `t` helper wasn't
being applied.
2024-06-07 16:20:38 +02:00
Javi Martín
d9662164b8 Remove unused code to display polls with no dates
When this code was added, in commit 1a20a3ce4, we had no validation
rules checking the presence of the start and end dates of a poll. Now we
do, so we don't have to check this condition in the view.
2024-06-07 16:19:29 +02:00
Javi Martín
7b3b41386e Fix styles for poll dates
We accidentally introduced a typo in commit f497227e3 which caused the
dates to be rendered outside the element where the dates styles are
applied.
2024-06-07 15:52:02 +02:00
Javi Martín
08ca920819 Simplify conditions to render poll status icons
We were using a redundant `elsif` instead of an `else`. We were also
using a negative condition in the main `if`, which made the code a bit
harder to read.

Since we usually use `current_user` instead of `user_signed_in?`, we're
also changing that for consistency.Extract component to render the status of a poll
2024-06-07 15:52:02 +02:00
Javi Martín
765ab758dc Extract component to render a poll in the poll index
This is consistent with the way we've got partials to render debates,
proposals and legislation processes on their index pages.

Note that, while adding the tests for the status icon, we're keeping one
system test because it also tests the process of voting. We're adding a
new, similar component test, where the voter is created in the database,
so all possible statuses are tested in the component.
2024-06-07 15:52:02 +02:00
Javi Martín
ee64efe659 Use the Do Not Track parameter in vimeo videos
With this parameter, Vimeo no longer uses cookies that identifies users
browsing our site.

They do still store some cookies, though; quoting from Vimeo player
parameters overview:

> When DNT is enabled, Vimeo deploys one essential cookie via the
> embeddable player:
> The __cf_bm cookie, which is part of Cloudflare's Bot Management
> service and helps mitigate risk associated with spam and bot traffic.

Not sure whether this counts as essential cookies in our case; they're
essential for Vimeo, but for us, they're third-party cookies, after all.

[1] https://help.vimeo.com/hc/en-us/articles/12426260232977-Player-parameters-overview
2024-06-07 15:28:42 +02:00
Javi Martín
442156b1cc Don't use cookies when embedding youtube videos
When embedding a video in our site YouTube stores cookies in the user's
computer that aren't necessary to watch the video, so we'd have to make
people accept those cookies before letting them watch the video.

Using a URL that doesn't use cookies, like mentioned in YouTube Help
[1], is easier, though, and respects people's privacy without affecting
the user experience.

That I've found some references saying that youtube does store cookies
once you hit the "play" button even when using the nocookie server [2].
Not sure whether that's an old behavior or I'm doing something wrong,
but I don't see this is the case; even after playing the video, cookies
aren't stored on my browser.

[1] https://support.google.com/youtube/answer/171780#zippy=%2Cturn-on-privacy-enhanced-mode
[2] https://www.cnet.com/news/privacy/youtubes-new-nocookie-feature-continues-to-serve-cookies/
2024-06-06 17:35:27 +02:00
Javi Martín
cc8acdcc87 Make method name consistent in embedded video component
We were using `reg_exp` as the method name, when it returned
`VIMEO_REGEX` or `YOUTUBE_REGEX`.

So using `regex` as the method name is less confusing.
2024-06-06 17:35:27 +02:00
Javi Martín
fee5b8a13c Remove redundant code in embedded video component
When using `<%= `, `nil` is converted to an empty string, so there's no
need to explicitely return an empty string.
2024-06-06 17:35:27 +02:00
Javi Martín
b07132d8d4 Extract methods in embedded video component
No that it's no longer a helper, we can extract method without fearing
they will have the same name as other helper methods.
2024-06-06 17:35:27 +02:00
Javi Martín
579e332cf8 Extract component to render an embedded video 2024-06-06 17:35:27 +02:00
Javi Martín
c367f21705 Add buttons to check all/none available languages
Although most Consul Democracy installations will only have a few
available languages using `config.i18n.available_locales`, there's a
chance some installation will keep every language as available and will
enable the desired ones using the admin interface. In these cases,
enabling (or disabling) every language would be tedious, particularly
when casually experimenting in a staging environment or while using the
official Consul Democracy demo.

So we're adding buttons to simplify the process. Since some
installations might have only a couple of available languages, and in
this case these buttons would be pretty much useless, we're only showing
them when there are many languages available.
2024-06-06 16:28:19 +02:00
Javi Martín
673eb1358a Group buttons to check all/none elements
Since they're related, we're making them part of the same list. Instead
of finding a way to have the `Select` prefix they had as a label for the
list, we're including the "prefix" they had inside their texts, so the
text of a button doesn't need any additional context.
2024-06-06 16:28:19 +02:00
Javi Martín
f47179ff68 Use buttons to check/uncheck all options
People using screen readers usually expect links to take them somewhere
else in the page on to a different page, while they expect buttons to
change something on the page.

Since we're in the latter scenario, using a button is more accessible.
It's also more natural; with a button, we don't need to provide `#` as
the URL or stop the default event when the button is clicked. And,
unlike links, buttons can be activated with either the space or the
enter key. Finally, clicking a link pointing to `#` with the middle
mouse button opens a useless new tab, while buttons do nothing in this
case.

Now that we only have one "All" link on the page, we no longer need to
specify which "All" link we're clicking or which "All" link we are
checking, so we're simplifying the code doing so.
2024-06-06 16:18:33 +02:00
Javi Martín
fdf1fd5f5f Move links to check all/none on RTL languages
Since we don't usually style HTML classes starting with `js-`, we're
renaming it, so it's consistent with the `CheckAllNone` name used in the
`check_all_none.js` file.
2024-06-06 16:09:18 +02:00
Javi Martín
26a43ee0d2 Add a proper title to moderation index pages
Since this is already a component, we can use the `header` method
without much refactoring.
2024-06-06 16:09:18 +02:00
Javi Martín
0c59c2dfb4 Extract model to handle locales settings
This way we can simplify the view, particularly the form. However, we're
still adding some complexity to the form so inputs are inside labels and
so the collection is easier to style with CSS.
2024-06-05 16:10:56 +02:00
Javi Martín
78bbf430d5 Add a form to edit available locales
We're using different controls depending on the number of available
locales.

When there are only a few locales, the solution is obvious: radio
buttons to select the default language, and checkboxes to select the
available ones are simple and intuitive.

With many languages, showing two consecutive lists of 30 languages could
be confusing, though, particularly on small devices, where scrolling
through both lists could be hard.

So, in this case, we're rendering a <select> to choose the default
language. For selecting the available languages, however, we're sticking
to checkboxes because all the other existing options (like multiple
selects) are hard to use. We think it's OK because the form doesn't have
any additional fields, and there's only one big list of options to
scroll through.

While testing the application, we noticed that if we use the
`admin-fieldset-separator` styles when there's only one fieldset, it's
harder to notice that there's an additional field to select the default
language. So we're only using the `admin-fieldset-separator` styles when
all the fields are grouped in fieldsets.

Regarding the help text for the fieldset, if we leave the help text
outside the <legend> tag, people using screen readers won't hear about
this content. However, if we include it inside the <legend> tag, some
screen readers might read it every time they move to a different
checkbox (or radio button), which can be annoying. Since I don't think
these help messages are really essential, I'm leaving them out of the
<legend> tag. It's also easier to style them if they're outside the
<legend> tag.

Note we're using `display: table` for the labels, for the reasons
mentioned in commit 923c2a7ee.

Also note that, when there's only one available locale, this section is
useless. In this case, we aren't disabling it for now because there's a
chance people see it in the official Consul Democracy demo and then
wonder why it isn't available on their installation. We might disable it
in the future, though.
2024-06-05 16:10:56 +02:00
Javi Martín
647121d13e Allow different locales per tenant
Note that, currently, we take these settings from the database but we
don't provide a way to edit them through the admin interface, so the
locales must be manually introduced through a Rails console.

While we did consider using a comma-separated list, we're using spaces
in order to be consistent with the way we store the allowed content
types settings.

The `enabled_locales` nomenclature, which contrasts with
`available_locales`, is probably subconsciously based on similar
patterns like the one Nginx uses to enable sites.

Note that we aren't using `Setting.enabled_locales` in the globalize
initializer when setting the fallbacks. This means the following test
(which we could add to the shared globalizable examples) would fail:

```
it "Falls back to an enabled locale if the fallback is not enabled" do
  Setting["locales.default"] = "en"
  Setting["locales.enabled"] = "fr en"
  allow(I18n.fallbacks).to receive(:[]).and_return([:fr, :es])
  Globalize.set_fallbacks_to_all_available_locales

  I18n.with_locale(:fr) do
    expect(record.send(attribute)).to eq "In English"
  end
end
```

The reason is that the code making this test pass could be:

```
def Globalize.set_fallbacks_to_all_available_locales
  Globalize.fallbacks = I18n.available_locales.index_with do |locale|
    ((I18n.fallbacks[locale] & Setting.enabled_locales) + Setting.enabled_locales).uniq
  end
end
```

However, this would make it impossible to run `rake db:migrate` on new
applications because the initializer would try to load the `Setting`
model but the `settings` table wouldn't exist at that point.

Besides, this is a really rare case that IMHO we don't need to support.
For this scenario, an installation would have to enable a locale, create
records with contents in that locale, then disable that locale and have
that locale as a fallback for a language where content for that record
wasn't created. If that happened, it would be solved by creating content
for that record in every enabled language.
2024-06-05 16:10:56 +02:00
Javi Martín
26b48e527a Move information texts form partial to a component
This way it'll be easierto write tests for it when we change it.
2024-06-05 16:10:56 +02:00