mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-10 01:01:39 -05:00
Implement live points count update for imports
This commit is contained in:
parent
9cc9632b6d
commit
4a3f7d5e65
11 changed files with 140 additions and 13 deletions
7
app/channels/imports_channel.rb
Normal file
7
app/channels/imports_channel.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class ImportsChannel < ApplicationCable::Channel
|
||||
def subscribed
|
||||
stream_for current_user
|
||||
end
|
||||
end
|
||||
15
app/javascript/channels/imports_channel.js
Normal file
15
app/javascript/channels/imports_channel.js
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import consumer from "./consumer"
|
||||
|
||||
consumer.subscriptions.create("ImportsChannel", {
|
||||
connected() {
|
||||
console.log("Connected to the imports channel!");
|
||||
},
|
||||
|
||||
disconnected() {
|
||||
// Called when the subscription has been terminated by the server
|
||||
},
|
||||
|
||||
received(data) {
|
||||
// Called when there's incoming data on the websocket for this channel
|
||||
}
|
||||
});
|
||||
|
|
@ -1,3 +1,4 @@
|
|||
// Import all the channels to be used by Action Cable
|
||||
import "notifications_channel"
|
||||
import "points_channel"
|
||||
import "imports_channel"
|
||||
|
|
|
|||
51
app/javascript/controllers/imports_controller.js
Normal file
51
app/javascript/controllers/imports_controller.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
import { Controller } from "@hotwired/stimulus";
|
||||
import consumer from "../channels/consumer";
|
||||
|
||||
export default class extends Controller {
|
||||
static targets = ["index"];
|
||||
|
||||
connect() {
|
||||
console.log("Imports controller connected", {
|
||||
hasIndexTarget: this.hasIndexTarget,
|
||||
element: this.element,
|
||||
userId: this.element.dataset.userId
|
||||
});
|
||||
this.setupSubscription();
|
||||
}
|
||||
|
||||
setupSubscription() {
|
||||
const userId = this.element.dataset.userId;
|
||||
console.log("Setting up subscription with userId:", userId);
|
||||
|
||||
this.channel = consumer.subscriptions.create(
|
||||
{ channel: "ImportsChannel" },
|
||||
{
|
||||
connected: () => {
|
||||
console.log("Successfully connected to ImportsChannel");
|
||||
// Test that we can receive messages
|
||||
console.log("Subscription object:", this.channel);
|
||||
},
|
||||
disconnected: () => {
|
||||
console.log("Disconnected from ImportsChannel");
|
||||
},
|
||||
received: (data) => {
|
||||
console.log("Received data:", data);
|
||||
const row = this.element.querySelector(`tr[data-import-id="${data.import.id}"]`);
|
||||
|
||||
if (row) {
|
||||
const pointsCell = row.querySelector('[data-points-count]');
|
||||
if (pointsCell) {
|
||||
pointsCell.textContent = new Intl.NumberFormat().format(data.import.points_count);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
disconnect() {
|
||||
if (this.channel) {
|
||||
this.channel.unsubscribe();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Geojson::ImportParser
|
||||
include Imports::Broadcaster
|
||||
|
||||
attr_reader :import, :json, :user_id
|
||||
|
||||
def initialize(import, user_id)
|
||||
|
|
@ -12,10 +14,12 @@ class Geojson::ImportParser
|
|||
def call
|
||||
data = Geojson::Params.new(json).call
|
||||
|
||||
data.each do |point|
|
||||
data.each.with_index(1) do |point, index|
|
||||
next if point_exists?(point, user_id)
|
||||
|
||||
Point.create!(point.merge(user_id:, import_id: import.id))
|
||||
|
||||
broadcast_import_progress(import, index)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class Gpx::TrackParser
|
||||
include Imports::Broadcaster
|
||||
|
||||
attr_reader :import, :json, :user_id
|
||||
|
||||
def initialize(import, user_id)
|
||||
|
|
@ -13,7 +15,9 @@ class Gpx::TrackParser
|
|||
tracks = json['gpx']['trk']
|
||||
tracks_arr = tracks.is_a?(Array) ? tracks : [tracks]
|
||||
|
||||
tracks_arr.map { parse_track(_1) }.flatten
|
||||
tracks_arr.map { parse_track(_1) }.flatten.each.with_index(1) do |point, index|
|
||||
create_point(point, index)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -22,12 +26,10 @@ class Gpx::TrackParser
|
|||
segments = track['trkseg']
|
||||
segments_array = segments.is_a?(Array) ? segments : [segments]
|
||||
|
||||
segments_array.map do |segment|
|
||||
segment['trkpt'].each { create_point(_1) }
|
||||
end
|
||||
segments_array.map { |segment| segment['trkpt'] }
|
||||
end
|
||||
|
||||
def create_point(point)
|
||||
def create_point(point, index)
|
||||
return if point['lat'].blank? || point['lon'].blank? || point['time'].blank?
|
||||
return if point_exists?(point)
|
||||
|
||||
|
|
@ -40,6 +42,8 @@ class Gpx::TrackParser
|
|||
raw_data: point,
|
||||
user_id:
|
||||
)
|
||||
|
||||
broadcast_import_progress(import, index)
|
||||
end
|
||||
|
||||
def point_exists?(point)
|
||||
|
|
|
|||
16
app/services/imports/broadcaster.rb
Normal file
16
app/services/imports/broadcaster.rb
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Imports::Broadcaster
|
||||
def broadcast_import_progress(import, index)
|
||||
ImportsChannel.broadcast_to(
|
||||
import.user,
|
||||
{
|
||||
action: 'update',
|
||||
import: {
|
||||
id: import.id,
|
||||
points_count: index
|
||||
}
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
|
|
@ -39,18 +39,23 @@
|
|||
<th>Created at</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tbody
|
||||
data-controller="imports"
|
||||
data-imports-target="index"
|
||||
data-user-id="<%= current_user.id %>"
|
||||
>
|
||||
<% @imports.each do |import| %>
|
||||
<tr>
|
||||
<tr data-import-id="<%= import.id %>" id="import-<%= import.id %>">
|
||||
<td>
|
||||
<%= link_to import.name, import, class: 'underline hover:no-underline' %> (<%= import.source %>)
|
||||
 
|
||||
<%= link_to import.name, import, class: 'underline hover:no-underline' %>
|
||||
(<%= import.source %>)
|
||||
|
||||
<%= link_to '🗺️', map_path(import_id: import.id) %>
|
||||
 
|
||||
|
||||
<%= link_to '📋', points_path(import_id: import.id) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= "#{number_with_delimiter import.points_count}" %>
|
||||
<td data-points-count>
|
||||
<%= number_with_delimiter import.points_count %>
|
||||
</td>
|
||||
<td><%= import.created_at.strftime("%d.%m.%Y, %H:%M") %></td>
|
||||
</tr>
|
||||
|
|
|
|||
|
|
@ -21,3 +21,4 @@ pin '@rails/actioncable', to: 'actioncable.esm.js'
|
|||
pin_all_from 'app/javascript/channels', under: 'channels'
|
||||
pin 'notifications_channel', to: 'channels/notifications_channel.js'
|
||||
pin 'points_channel', to: 'channels/points_channel.js'
|
||||
pin 'imports_channel', to: 'channels/imports_channel.js'
|
||||
|
|
|
|||
5
spec/channels/imports_channel_spec.rb
Normal file
5
spec/channels/imports_channel_spec.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
require 'rails_helper'
|
||||
|
||||
RSpec.describe ImportsChannel, type: :channel do
|
||||
pending "add some examples to (or delete) #{__FILE__}"
|
||||
end
|
||||
|
|
@ -16,6 +16,12 @@ RSpec.describe Gpx::TrackParser do
|
|||
it 'creates points' do
|
||||
expect { parser }.to change { Point.count }.by(301)
|
||||
end
|
||||
|
||||
it 'broadcasts importing progress' do
|
||||
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(301).times
|
||||
|
||||
parser
|
||||
end
|
||||
end
|
||||
|
||||
context 'when file has multiple segments' do
|
||||
|
|
@ -24,6 +30,12 @@ RSpec.describe Gpx::TrackParser do
|
|||
it 'creates points' do
|
||||
expect { parser }.to change { Point.count }.by(558)
|
||||
end
|
||||
|
||||
it 'broadcasts importing progress' do
|
||||
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(558).times
|
||||
|
||||
parser
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -33,6 +45,12 @@ RSpec.describe Gpx::TrackParser do
|
|||
it 'creates points' do
|
||||
expect { parser }.to change { Point.count }.by(407)
|
||||
end
|
||||
|
||||
it 'broadcasts importing progress' do
|
||||
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(407).times
|
||||
|
||||
parser
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in a new issue