diff --git a/app/controllers/sites_controller.rb b/app/controllers/sites_controller.rb
index bec42b39..e911daac 100644
--- a/app/controllers/sites_controller.rb
+++ b/app/controllers/sites_controller.rb
@@ -15,6 +15,19 @@ class SitesController < ApplicationController
fresh_when @sites
end
+ # Genera la caja del estado para HTMX
+ def status
+ authorize site
+
+ render('sites/status', layout: false) if stale? site
+ end
+
+ def button
+ authorize site
+
+ render('sites/build', layout: false)
+ end
+
# No tenemos propiedades de un sitio aún, así que vamos al listado de
# artículos
def show
diff --git a/app/javascript/etc/htmx_abort.js b/app/javascript/etc/htmx_abort.js
new file mode 100644
index 00000000..308d0315
--- /dev/null
+++ b/app/javascript/etc/htmx_abort.js
@@ -0,0 +1,7 @@
+// Cancela las peticiones pendientes de htmx para todos los elementos al
+// cambiar de página.
+document.addEventListener("turbolinks:click", () => {
+ for (const hx of document.querySelectorAll("[hx-get]")) {
+ window.htmx.trigger(hx, "htmx:abort");
+ }
+});
diff --git a/app/javascript/etc/index.js b/app/javascript/etc/index.js
index d4b9f7a3..9ee6a95a 100644
--- a/app/javascript/etc/index.js
+++ b/app/javascript/etc/index.js
@@ -7,3 +7,4 @@ import './timezone'
import './turbolinks-anchors'
import './validation'
import './new_editor'
+import './htmx_abort'
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 9cbc30bf..e10e2b5d 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -9,9 +9,16 @@ try {
host: window.env.PANEL_URL
});
+ const ignoredErrors = ["htmx:afterRequest", "htmx:sendAbort"];
+
console.originalError = console.error;
console.error = (...e) => {
- window.airbrake.notify(e.join(" "));
+ const msg = e.join(" ");
+
+ if (!ignoredErrors.some(x => msg.includes(x))) {
+ window.airbrake.notify(e.join(" "));
+ }
+
return console.originalError(...e);
};
} catch(e) {
@@ -33,3 +40,5 @@ import 'chartkick/chart.js'
Rails.start()
Turbolinks.start()
ActiveStorage.start()
+
+window.htmx = require('htmx.org/dist/htmx.js')
diff --git a/app/policies/site_policy.rb b/app/policies/site_policy.rb
index 2ca96256..ce56a2e7 100644
--- a/app/policies/site_policy.rb
+++ b/app/policies/site_policy.rb
@@ -14,6 +14,10 @@ class SitePolicy
true
end
+ def status?
+ true
+ end
+
# Puede ver la versión privada del sitio?
def private?
edit? && site.deploys.find_by_type('DeployPrivate')
@@ -57,6 +61,10 @@ class SitePolicy
show? && usuarie?
end
+ def button?
+ show?
+ end
+
def enqueue?
build?
end
diff --git a/app/views/posts/index.haml b/app/views/posts/index.haml
index 374f06ee..3ea82309 100644
--- a/app/views/posts/index.haml
+++ b/app/views/posts/index.haml
@@ -3,7 +3,6 @@
= render 'sites/header', site: @site
= render 'sites/status', site: @site
-
= render 'sites/build', site: @site, class: 'btn-block'
%h3= t('posts.new')
diff --git a/app/views/sites/_build.haml b/app/views/sites/_build.haml
index b0961e31..8db4d370 100644
--- a/app/views/sites/_build.haml
+++ b/app/views/sites/_build.haml
@@ -1,9 +1,10 @@
- if policy(site).build?
- = form_tag site_enqueue_path(site),
- method: :post,
- class: 'form-inline inline' do
- = submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'),
- class: "btn btn-secondary #{local_assigns[:class]}",
- title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'),
- data: { disable_with: t('sites.enqueued') },
- disabled: site.enqueued?
+ %div{ 'hx-get': site_button_path(site, class: local_assigns[:class]), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' }
+ = form_tag site_enqueue_path(site),
+ method: :post,
+ class: 'form-inline inline' do
+ = submit_tag site.enqueued? ? t('sites.enqueued') : t('sites.enqueue'),
+ class: "btn btn-secondary #{local_assigns[:class]}",
+ title: site.enqueued? ? t('help.sites.enqueued') : t('help.sites.enqueue'),
+ data: { disable_with: t('sites.enqueued') },
+ disabled: !site.waiting?
diff --git a/app/views/sites/_status.haml b/app/views/sites/_status.haml
index 6a610e73..a3dfd4ad 100644
--- a/app/views/sites/_status.haml
+++ b/app/views/sites/_status.haml
@@ -1,21 +1,24 @@
-- link = nil
-- if site.not_published_yet?
- - message = t('.not_published_yet')
-- elsif site.awaiting_publication?
- - message = t('.awaiting_publication')
-- elsif site.building?
- - if site.average_publication_time_calculable?
- - average_building_time = site.average_publication_time
- - elsif !site.similar_sites?
- - average_building_time = 60
+- cache site do
+ - link = nil
+ - if site.not_published_yet?
+ - message = t('.not_published_yet')
+ - elsif site.awaiting_publication?
+ - message = t('.awaiting_publication')
+ - elsif site.building?
+ - if site.average_publication_time_calculable?
+ - average_building_time = site.average_publication_time
+ - elsif !site.similar_sites?
+ - average_building_time = 60
+ - else
+ - average_building_time = site.average_publication_time_for_similar_sites
+
+ - average_publication_time_human = distance_of_time_in_words average_building_time
+ - message = t('.building', average_time: average_publication_time_human, seconds: average_building_time)
- else
- - average_building_time = site.average_publication_time_for_similar_sites
+ - message = t('.available')
+ - link = true
- - average_publication_time_human = distance_of_time_in_words average_building_time
- - message = t('.building', average_time: average_publication_time_human, seconds: average_building_time)
-- else
- - message = t('.available')
- - link = true
-
-= render 'bootstrap/alert' do
- = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link'
+ -# TODO: Calcular cada cuánto sería óptimo recargar
+ %div{ 'hx-get': site_status_path(site), 'hx-trigger': 'every 10s', 'hx-swap': 'outerHTML' }
+ = render 'bootstrap/alert' do
+ = link_to_if link, message.html_safe, site_build_stats_path(site), class: 'alert-link'
diff --git a/app/views/sites/build.haml b/app/views/sites/build.haml
new file mode 100644
index 00000000..c2becec0
--- /dev/null
+++ b/app/views/sites/build.haml
@@ -0,0 +1 @@
+= render 'sites/build', site: @site, class: params.permit(:class)[:class]
diff --git a/app/views/sites/status.haml b/app/views/sites/status.haml
new file mode 100644
index 00000000..3d9793a5
--- /dev/null
+++ b/app/views/sites/status.haml
@@ -0,0 +1 @@
+= render 'sites/status', site: @site
diff --git a/config/locales/en.yml b/config/locales/en.yml
index fc9d4894..720f784a 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -389,7 +389,7 @@ en:
static_file_migration: 'File migration'
find_and_replace: 'Search and replace'
status:
- building: "Your site is building, refresh this page in ."
+ building: "Your site is building, it will be ready in ."
not_published_yet: "Your site is being published for the first time, please wait up to 1 minute..."
available: "Your site is available! Click here to find all the different ways to visit it."
awaiting_publication: "There are unpublished changes. Click the button below and wait a moment to find them on your site."
diff --git a/config/locales/es.yml b/config/locales/es.yml
index 4bda4982..e7ff0864 100644
--- a/config/locales/es.yml
+++ b/config/locales/es.yml
@@ -394,7 +394,7 @@ es:
static_file_migration: 'Migración de archivos'
find_and_replace: 'Búsqueda y reemplazo'
status:
- building: "Tu sitio se está publicando, recargá esta página en ."
+ building: "Tu sitio se está publicando, estará listo en ."
not_published_yet: "Tu sitio se está publicando por primera vez, por favor espera hasta un minuto..."
available: "¡Tu sitio está disponible! Cliqueá aquí para encontrar todas las formas en que podés visitarlo."
awaiting_publication: "Hay cambios sin publicar, cliqueá el botón debajo y espera un momento para encontrarlos en tu sitio."
diff --git a/config/routes.rb b/config/routes.rb
index 635be07a..d97611fd 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -37,6 +37,9 @@ Rails.application.routes.draw do
get 'pull', to: 'sites#fetch'
post 'pull', to: 'sites#merge'
+ get 'status', to: 'sites#status'
+ get 'button', to: 'sites#button'
+
# Gestionar usuaries
get 'usuaries/invite', to: 'usuaries#invite'
post 'usuaries/invite', to: 'usuaries#send_invitations'
diff --git a/package.json b/package.json
index 2bff3159..74ff491a 100644
--- a/package.json
+++ b/package.json
@@ -21,6 +21,7 @@
"commonmark": "^0.29.0",
"fork-awesome": "^1.1.7",
"fork-ts-checker-webpack-plugin": "^6.1.0",
+ "htmx.org": "^1.9.11",
"input-map": "git+https://0xacab.org/sutty/input-map.git",
"input-tag": "git+https://0xacab.org/sutty/input-tag.git",
"leaflet": "^1.7.1",
diff --git a/yarn.lock b/yarn.lock
index 7e1d597c..829b7ed1 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -4570,6 +4570,11 @@ html-entities@^1.3.1:
resolved "https://registry.npmjs.org/html-entities/-/html-entities-1.4.0.tgz"
integrity sha512-8nxjcBcd8wovbeKx7h3wTji4e6+rhaVuPNpMqwWgnHh+N9ToqsCs6XztWRBPQ+UtzsoMAdKZtUENoVzU/EMtZA==
+htmx.org@^1.9.11:
+ version "1.9.11"
+ resolved "https://registry.yarnpkg.com/htmx.org/-/htmx.org-1.9.11.tgz#00192041ee682d6ca7146d0fbd901169ffe72d87"
+ integrity sha512-WlVuICn8dfNOOgYmdYzYG8zSnP3++AdHkMHooQAzGZObWpVXYathpz/I37ycF4zikR6YduzfCvEcxk20JkIUsw==
+
http-deceiver@^1.2.7:
version "1.2.7"
resolved "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz"