Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Upgrade CONSUL DEMOCRACY to version 2.2.0 #169

Merged
merged 772 commits into from
Jul 22, 2024
Merged

Upgrade CONSUL DEMOCRACY to version 2.2.0 #169

merged 772 commits into from
Jul 22, 2024

Conversation

microweb10
Copy link
Member

Objectives

Upgrade CONSUL DEMOCRACY to version 2.2.0 🎉

Notes

Release notes

javierm and others added 30 commits April 17, 2024 15:18
We moved this file to `app/lib/` in commit cb47714 so it would be in
the autoload_paths. However, this class is loaded by ActiveStorage, with
the following method:

```
def resolve(class_name)
  require "active_storage/service/#{class_name.to_s.underscore}_service"
  ActiveStorage::Service.const_get(:"#{class_name.camelize}Service")
rescue LoadError
  raise "Missing service adapter for #{class_name.inspect}"
end
``

So this file needs to be in the $LOAD_PATH, or else ActiveStorage won't
be able to load it when we disable the `add_autoload_paths_to_load_path`
option, which is the default in Rails 7.1 [1].

Moving it to the `lib` folder solves the issue; as mentioned in the
guide to upgrade to Rails 7.1 [2]:

> The lib directory is not affected by this flag, it is added to
> $LOAD_PATH always.

However, we were also referencing this class in the `Tenant` model,
meaning we needed to autoload it as well somehow. So, instead of
directly referencing this class, we're using `respond_to?` in the Tenant
model.

We're changing the test so it fails when the code calls
`is_a?(ActiveStorage::Service::TenantDiskService)`. We need to change
the active storage configurations in the test because, otherwise, the
moment `ActiveStorage::Blob` is loaded, the `TenantDiskService` class is
also loaded, meaning the test will pass when using `is_a?`.

Note that, since this class isn't in the autoload paths anymore, we need
to add a `require` in the tests. We could add an initializer to require
it; we're not doing it in order to be consistent with what ActiveStorage
does: it only loads the service that's going to be used in the current
Rails environment. If somebody changed their production environment in
order to use (for example), S3, and we added an initializer to require
the TenantDiskService, we would still load the TenantDiskService even if
it isn't going to be used.

[1] https://guides.rubyonrails.org/v7.1/configuring.html#config-add-autoload-paths-to-load-path
[2] https://guides.rubyonrails.org/v7.1/upgrading_ruby_on_rails.html#autoloaded-paths-are-no-longer-in-$load-path
…ant_service_to_load_path

Move custom ActiveStorage service to $LOAD_PATH
As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST requests to the server has a few
issues.
Using the standard `confirm` parameter, we can remove all the custom
code we added to do the same thing.

Since the code is similar, we're doing the same when asking for
confirmation to send notifications.
We weren't testing this action anywhere.
As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST (or, in this case, DELETE) requests to
the server has a few issues.
This is similar to what we do in almost every other page of the admin
section.
As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST (or, in this case, DELETE) requests to
the server has a few issues.
As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST (or, in this case, DELETE) requests to
the server has a few issues.

Note that the AJAX response stopped working after replacing the link
with a button. Not sure about the reason, but, since this is one of the
very few places where we use AJAX calls to delete content, the easiest
solution is to stop using AJAX and be consistent with what we do in the
rest of the admin section.
We were already using button to destroy content blocks from the content
blocks index.

As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST (or, in this case, DELETE) requests to
the server has a few issues.
We were already doing that when deleting content blocks from the index
page, and we also ask for confirmation in almost every page in the admin
section.
Just like we do with the rest of the tables in the admin section.
This way we can simplify setting the title and styling the link in the
header. We're also fixing the unnecessary padding introduced by the
`column` classes, which caused the header not to be aligned with the
rest of the elements surrounding it. We're still keeping it the margin
used in the `row` classes so it's aligned with the rest of the form;
ideally, we would remove the `row` classes in the rest of the form and
in the whole admin section, but this isn't something we can tackle right
now.

Note that, in the CSS, the `margin-left: auto` property needs to be
included after `@include regular-button` because that mixin overwrites
the `margin-left` property. Since we're modifying this code, we're
making it compatible with RTL text, using `$global-left` instead of
`left`.
We were already using buttons to destroy pages from the pages index.

As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST (or, in this case, DELETE) requests to
the server has a few issues.
We were already doing that when deleting pages from the index page, and
we also ask for confirmation in almost every page in the admin section.
As mentioned in commits 5311daa and bb958da, using links combined
with JavaScript to generate POST (or, in this case, PUT) requests to the
server has a few issues.
This way it'll be easier to refactor them. We're also giving a proper
title to the images index page.
Note that we used to have the link to delete images inside the same
<form> tag as the button to update the image. However, using a button
means we're adding a new <form> tag for the action to delete the image.
This isn't valid HTML and, in some browsers, might result in the button
sending the request to the wrong URL.

As explained in commit 5311daa, to avoid this, we'd need to replace
`button_to` with `button_tag` in the action in order to generate a
button without a form.  Then, we could add either a `form` or a
`formaction` attribute to the button.

However, I thik it's easier to move the delete button outside the update
button <form> tag. On the minus side, since the buttons no longer share
a parent, they're harder to style. So we're using a mix of nested flex
layouts with one of the nested elements using a container unit as width.
Since we're at it, we're also improving the styles on small and medium
screens by making sure the "Update" button wraps before the "Delete"
button does (using a container query), by giving enough width to the
column containing this actions on small screens as well (removing
`small-12` and giving it two-thirds of the width on all screen sizes)
and by having a gap between elements.

Note that, at the time of writing, container queries are only supported
by about 91%-93% of the browsers, meaning that some administrators will
see all from controls displayed vertically, one on top of the other, on
all screen sizes. We think this is acceptable, and the page remains
fully functional in this case.
This is consistent with what Rails does.
In commit b3f5705, we changed the key generator hash digest class, and
we wrote:

> Since we haven't seen any Consul Democracy applications using
> encrypted messages and these messages become invalid with this change
> (...)

We didn't realize that ActiveStorage also used the old hash digest class
to generated the signed URLs used to access an image. This doesn't
affect us when we generate images using `image.variant`, because that
generates a new URL on the fly using the new hash digest class. However,
URLs referencing the images generated using the old hash digest class,
like the ones in the HTML content generated with CKEditor, would result
in 404 errors.

So we're rotating the signed IDs generated by earlier versions of
ActiveStorage. This way both new and old images will be correctly
displayed.

Note that, unlike cookies, which will keep working once rotated even if
we delete the code to rotate them, old ActiveStorage URLs will always
need the code rotating them in order to keep working.
…tions_buttons

Use buttons for non-GET actions in the admin section
…torage_messages

Keep rendering pre-Rails7 ActiveStorage images
The `accordion-title` HTML class isn't used since commit 156997d.
So it's consistent with the `Admin::MenuComponent`.
So this is similar to what we're doing in the `Admin::MenuComponent`
class.
So this is similar to what we're doing in the `Admin::MenuComponent`
class.
We were using Foundation's accordion menu to open/close nested lists of
links. Unfortunately, Foundation's accordion makes it impossible to
access links in nested links using the keyboard [1] (note the issue is
closed, but in the latest version of Foundation, 6.8.1, it's still
present, and Foundation's development is mostly discontinued).
Furtheremore, it adds the `menuitem` role to links, but ARIA menus are
not ment for navigation but for application behavior and, since it
doesn't add the `menubar` or `menu` roles to the parent elements, it
results in accessibility issues for people using screen readers (also
reported by the Axe accessibility testing engine).

So we need to implement our own solution. We're using the most commonly
used pattern: a buttton with the `aria-expanded` attribute. And, for
people using browsers where JavaScript hasn't loaded, we're keeping the
submenus open at all times (just like we were doing until now), and
we're disabling the buttons (since they do nothing without JavaScript).
This might not be an ideal solution, but it's probably good enough, and
way better than what we had until now.

We've also considered using the <details> and <summary> elements instead
of using buttons to open/close items on the list. However, these
elements still present some accessibility issues [2], and the transition
between open and closed can't be animated unless we overwrite the
`click` event with JavaScript. The pattern of using these elements to
open/close a nested list of links isn't common either, and some people
using screen readers might get confused when entering/leaving the nested
list.

We tried other approaches to get the animation effect, all of them based
on adding `[aria-expanded="false"]:not([disabled]) + * { display: none;
}` to the CSS file.

Unfortunately, animation using CSS isn't feasible right now because
browsers can't animate a change form `height: 0` to `height: auto`.
There are some hacks like animating the `max-height` or the `flex-grow`
property, but the resulting animation is inconsistent. A perfect
animation can be done using the `grid-template-rows` property [3], but
it requires adding a grid container and only works in Firefox and recent
versions of Chrome and similar browsers.

Getting to a solution with JavaScript was also tricky. With the
following approach, `slideToggle()` opened the menu the first time, even
if it was already open (not sure why):

```
toggle_buttons.on("click", function() {
  $(this).attr("aria-expanded", !JSON.parse($(this).attr("aria-expanded")));
  $(this).next().slideToggle();
});
```

This made the arrow turn after the menu had slided instead of doing it
at the same time:

```
toggle_buttons.on("click", function() {
  var button = $(this);

  button.next().slideToggle(function() {
    button.attr("aria-expanded",
    !JSON.parse(button.attr("aria-expanded")));
  });
}
```

With this, everything disappeared quickly:

```
toggle_buttons.on("click", function() {
  var expanded = JSON.parse($(this).attr("aria-expanded"));

  if (expanded) {
    $(this).next().slideUp();
  } else {
    $(this).next().slideDown();
  }

  $(this).attr("aria-expanded", !expanded);
}
```

So, in the end, we're hiding the nested link lists with JavaScript
instead of CSS.

[1] Issue 12046 in https://github.com/foundation/foundation-sites
[2] https://www.scottohara.me/blog/2022/09/12/details-summary.html
[3] https://css-tricks.com/css-grid-can-do-auto-height-transitions
…nu_expanded

Use buttons to open/close admin navigation submenus
@microweb10 microweb10 merged commit f95fafe into master Jul 22, 2024
18 checks passed
@microweb10 microweb10 deleted the release_2.2.0 branch July 22, 2024 18:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants