avo-hq / avo

Build Ruby on Rails apps 10x faster
https://avohq.io
Other
1.53k stars 256 forks source link

Auto-Refresh for Resources #3232

Open m7madmagdy opened 2 months ago

m7madmagdy commented 2 months ago

Feature

It would be beneficial to have an auto-refresh option for resources in Avo, such as refresh_every on the cards where real-time updates are critical for users to track changes without manually refreshing the page.

Current workarounds

I found the refresh_every on Cards but there is no built-in way to achieve this at the moment on resources. Users need to refresh the page manually to see updated data.

Screenshots or screen recordings

image Screenshot from 2024-09-10 13-13-50

Additional context

Auto-refresh features are commonly seen in dashboards like those in logistics or tracking systems where real-time updates are essential. Examples can be seen in other admin panel frameworks or platforms that deal with constantly changing data like order statuses in e-commerce systems.

Paul-Bob commented 2 months ago

Hello @m7madmagdy this is indeed a cool to have feature.

We aren't able to focus on it right now but we would merge a PR for it.

You already can achieve this using a combo of features, using self.components and a stimulus controller.

  1. Use a custom index component:
    class Avo::Resources::User < Avo::BaseResource
    self.components = {
    resource_index_component: Avo::Views::RefreshResourceIndexComponent,
    }
    end
  2. Generate the custom component

app/components/avo/views/refresh_resource_index_component.rb

class Avo::Views::RefreshResourceIndexComponent < Avo::Views::ResourceIndexComponent
  def initialize(**args)
    @args = args
  end
end

app/components/avo/views/refresh_resource_index_component.html.erb

<%= turbo_frame_tag(
  :refresh,
  target: "_top",
  data: { 
    controller: "refresh", 
    refresh_src_value: helpers.resources_users_path # use hardcoded for 1 resource or figure out a mechanism when applied to multiple resources 
  }
) do %>
  <%= render Avo::Views::ResourceIndexComponent.new(**@args) %>
<% end %>
  1. Generate the stimulus controller:

app/javascript/controllers/refresh_controller.js

import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
  static values = { src: String}

  connect() {
    const seconds = 10;
    const frame = this.element;
    const src = this.srcValue;

    setInterval(function() { 
      frame.src = src;
    }, seconds * 1000);
  }
}
m7madmagdy commented 2 months ago

@Paul-Bob Hi, I did everything that you mentioned above, but there is nothing changed, the orders page does not refresh after 5 seconds or anytime

m7madmagdy commented 2 months ago

Also, I registered the refresh controller inside the hive.custom.js such as avo.custom.js

import NestedForm from 'stimulus-rails-nested-form'
import RefreshController from './controllers/refresh_controller'

// Hook into the stimulus instance provided by Avo
const application = window.Stimulus
application.register('nested-form', NestedForm)
application.register('refresh-resource', RefreshController)

 // eslint-disable-next-line no-console
 console.log('Hi from Hive custom JS 👋')
Paul-Bob commented 2 months ago

Could you please start by debugging the component? Add some HTML to the custom component and verify if the refresh component is used. If the correct component is used, please add some console logs to the Stimulus controller connect method to verify that is properly connecting

m7madmagdy commented 1 month ago

@Paul-Bob Thanks it works :D

Paul-Bob commented 1 month ago

Cool! Could you please share the problem/solution? May help someone (and TBH I'm a little curious :D)

m7madmagdy commented 1 month ago

First of all the code you introduced works fine, but I didn't make assets precompile as well, once @AhmedAliIbrahim called me and made assets precompile and linked the order resource with the stimulus controller it worked fine

m7madmagdy commented 1 month ago

Hi @Paul-Bob I found this case in this implementation

This screenshot of the orders page refreshes well without any error

Screenshot from 2024-09-21 14-32-06

But if I go through the orders' owner to show his orders it refreshes after the time and append the parent top of orders in orders has many section tab

screencapture-localhost-3000-admin-resources-users-1-2024-09-21-14_31_45

It must be like this to get only owner orders

screencapture-localhost-3000-admin-resources-users-1-2024-09-21-14_35_12

Paul-Bob commented 1 month ago

Hello @m7madmagdy it is happening because the original approach was for an index view and the has_many field uses that index view. I think hhe issue is that the turbo_frame is not getting included in the refresh_src_value

m7madmagdy commented 1 month ago

Hello @Paul-Bob, I'm sorry but I don't aware about hotwire, can you suggest a solution to handle index view and has-many view

Paul-Bob commented 1 month ago

Sure, on the app/components/avo/views/refresh_resource_index_component.html.erb when passing the refresh_src_value include the turbo_frame param on the URL.

<%= turbo_frame_tag(
  :refresh,
  target: "_top",
  data: { 
    controller: "refresh", 
    refresh_src_value: helpers.resources_users_path(turbo_frame: params[:turbo_frame]) # use hardcoded for 1 resource or figure out a mechanism when applied to multiple resources 
  }
) do %>
  <%= render Avo::Views::ResourceIndexComponent.new(**@args) %>
<% end %>

This should do the trick

m7madmagdy commented 1 month ago

This didn't work correctly, so I used this condition to refresh only the orders' index page

<% if controller_name == "orders" && action_name == "index" %>
  <%= turbo_frame_tag(
    :refresh,
    target: "_top",
    data: { 
      controller: "refresh", 
      refresh_src_value: helpers.resources_orders_path
    }
  ) do %>
    <%= render Avo::Views::ResourceIndexComponent.new(**@args) %>
  <% end %>
<% else %>
  <%= render Avo::Views::ResourceIndexComponent.new(**@args) %>
<% end %>