8000 proof of concept for auto-reloading asyn cview models by czhu12 · Pull Request #102 · czhu12/canine · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

proof of concept for auto-reloading asyn cview models #102

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions app/helpers/loggable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ def info(line, color: nil)
output = "\e[#{color}m#{line}\e[0m"
Rails.logger.info(line)
ensure_log_output

# This has to be buffered somehow, otherwise the log output will be saved too often
log_output.update(output: log_output.output.to_s + output + "\n")
end

Expand Down
13 changes: 12 additions & 1 deletion app/javascript/controllers/async_renderer_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,18 @@ export default class extends Controller {
static targets = ["frame"]
static values = {
viewModel: String,
params: String
params: String,
refreshInterval: Number
}

connect() {
this.render();
}

disconnect() {
clearInterval(this.refreshInterval);
}

async render() {
const params = JSON.parse(this.paramsValue)
const queryString = new URLSearchParams(params).toString();
Expand All @@ -22,5 +27,11 @@ export default class extends Controller {
} else {
this.frameTarget.innerHTML = `<div class="text-error flex items-center gap-2"><iconify-icon icon="lucide:triangle-alert" width="24" height="24"></iconify-icon> Failed to load</div>`;
}
// Reset the timer here
if (this.refreshIntervalValue) {
this.refreshInterval = setTimeout(() => {
this.render();
}, this.refreshIntervalValue);
}
}
}
31 changes: 26 additions & 5 deletions app/javascript/controllers/logs_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,35 @@ import { Controller } from "@hotwired/stimulus"

export default class extends Controller {
static targets = ["container"]
static values = {
loggableId: String
}

scrollPositionId() {
return `canine-scrollposition-${this.loggableIdValue}`;
}

connect() {
console.log("connected")
// Scroll to the bottom of the container
this.scrollToBottom();
const scrollPosition = localStorage.getItem(this.scrollPositionId());
if (scrollPosition) {
this.containerTarget.scrollTo(0, scrollPosition);
} else {
// Scroll to bottom
this.scrollToBottom();
}
}

disconnect() {
localStorage.removeItem(this.scrollPositionId());
}

// Add event listener for Turbo Frame load
document.addEventListener('turbo:frame-load', this.scrollToBottom.bind(this));
updateScroll(event) {
// If scroll is at the bottom, don't save the scroll position
if (event.target.scrollTop === event.target.scrollHeight) {
localStorage.removeItem(this.scrollPositionId());
} else {
localStorage.setItem(this.scrollPositionId(), event.target.scrollTop);
}
}

scrollToBottom() {
Expand Down
8 changes: 0 additions & 8 deletions app/models/log_output.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,4 @@ class LogOutput < ApplicationRecord
include ActionView::RecordIdentifier

belongs_to :loggable, polymorphic: true

after_update_commit :broadcast_log_output

private

def broadcast_log_output
broadcast_replace_to dom_id(loggable, :logs), target: dom_id(loggable, :logs), partial: "log_outputs/logs", locals: { loggable: loggable }
end
end
1 change: 1 addition & 0 deletions app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class User < ApplicationRecord
has_many :projects, through: :accounts
has_many :add_ons, through: :accounts
has_many :services, through: :accounts
has_many :builds, through: :projects
attr_readonly :admin

# has_many :notifications, as: :recipient, dependent: :destroy, class_name: "Noticed::Notification"
Expand Down
45 changes: 45 additions & 0 deletions app/view_models/async/logs/log_view_model.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
class Async::Logs::LogViewModel < Async::BaseViewModel
include LogColorsHelper
expects :loggable_type, :loggable_id

def loggable
loggable_type = params[:loggable_type]
loggable_id = params[:loggable_id]

if loggable_type == "AddOn"
current_user.add_ons.find(loggable_id)
elsif loggable_type == "Build"
current_user.builds.find(loggable_id)
elsif loggable_type == "Cluster"
current_user.clusters.find(loggable_id)
elsif loggable_type == "Deployment"
current_user.deployments.find(loggable_id)
else
raise "Unknown loggable type: #{loggable_type}"
end
end

def async_render
template = <<-HTML
<div
class="bg-gray-900 text-gray-100 rounded-lg shadow-lg"
data-controller="logs"
data-logs-loggable-id-value="<%= loggable.id %>"
>
<div class="overflow-auto h-96 bg-gray-800 p-2 rounded" data-logs-target="container" data-action="scroll->logs#updateScroll">
<pre class="text-sm font-mono whitespace-pre-wrap"><%= ansi_to_tailwind(loggable.log_output&.output || "Your logs will appear here...").html_safe %></pre>
</div>
</div>
HTML

ERB.new(template).result(binding)
end

def render_error
"<div class='text-yellow-500'>Error fetching logs.</div>"
end

def initial_render
"<div class='loading loading-spinner loading-sm'></div>"
end
end
16 changes: 9 additions & 7 deletions app/views/log_outputs/_logs.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
<div class="bg-gray-900 text-gray-100 rounded-lg shadow-lg" data-controller="logs" id="<%= dom_id(loggable, :logs) %>">
<div class="overflow-auto h-96 bg-gray-800 p-2 rounded" data-logs-target="container">
<pre class="text-sm font-mono whitespace-pre-wrap"><%= ansi_to_tailwind(loggable.log_output&.output || "Your logs will appear here...").html_safe %></pre>
</div>
</div>

<%= turbo_stream_from dom_id(loggable, :logs) %>
<%= render(
"shared/partials/async_renderer",
view_model: Async::Logs::LogViewModel.new(
current_user,
loggable_type: loggable.class.name,
loggable_id: loggable.id,
),
refresh_interval: 5000
) %>
1 change: 1 addition & 0 deletions app/views/shared/partials/_async_renderer.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
data-controller="async-renderer"
data-async-renderer-view-model-value="<%= view_model.name %>"
data-async-renderer-params-value="<%= view_model.params.to_json %>"
data-async-renderer-refresh-interval-value="<%= defined?(refresh_interval) ? refresh_interval : nil %>"
>
<div data-async-renderer-target="frame">
<%= view_model.initial_render.html_safe %>
Expand Down
0