mirror of
https://github.com/Freika/dawarich.git
synced 2026-01-11 01:31: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 all the channels to be used by Action Cable
|
||||||
import "notifications_channel"
|
import "notifications_channel"
|
||||||
import "points_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
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Geojson::ImportParser
|
class Geojson::ImportParser
|
||||||
|
include Imports::Broadcaster
|
||||||
|
|
||||||
attr_reader :import, :json, :user_id
|
attr_reader :import, :json, :user_id
|
||||||
|
|
||||||
def initialize(import, user_id)
|
def initialize(import, user_id)
|
||||||
|
|
@ -12,10 +14,12 @@ class Geojson::ImportParser
|
||||||
def call
|
def call
|
||||||
data = Geojson::Params.new(json).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)
|
next if point_exists?(point, user_id)
|
||||||
|
|
||||||
Point.create!(point.merge(user_id:, import_id: import.id))
|
Point.create!(point.merge(user_id:, import_id: import.id))
|
||||||
|
|
||||||
|
broadcast_import_progress(import, index)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class Gpx::TrackParser
|
class Gpx::TrackParser
|
||||||
|
include Imports::Broadcaster
|
||||||
|
|
||||||
attr_reader :import, :json, :user_id
|
attr_reader :import, :json, :user_id
|
||||||
|
|
||||||
def initialize(import, user_id)
|
def initialize(import, user_id)
|
||||||
|
|
@ -13,7 +15,9 @@ class Gpx::TrackParser
|
||||||
tracks = json['gpx']['trk']
|
tracks = json['gpx']['trk']
|
||||||
tracks_arr = tracks.is_a?(Array) ? tracks : [tracks]
|
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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
@ -22,12 +26,10 @@ class Gpx::TrackParser
|
||||||
segments = track['trkseg']
|
segments = track['trkseg']
|
||||||
segments_array = segments.is_a?(Array) ? segments : [segments]
|
segments_array = segments.is_a?(Array) ? segments : [segments]
|
||||||
|
|
||||||
segments_array.map do |segment|
|
segments_array.map { |segment| segment['trkpt'] }
|
||||||
segment['trkpt'].each { create_point(_1) }
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_point(point)
|
def create_point(point, index)
|
||||||
return if point['lat'].blank? || point['lon'].blank? || point['time'].blank?
|
return if point['lat'].blank? || point['lon'].blank? || point['time'].blank?
|
||||||
return if point_exists?(point)
|
return if point_exists?(point)
|
||||||
|
|
||||||
|
|
@ -40,6 +42,8 @@ class Gpx::TrackParser
|
||||||
raw_data: point,
|
raw_data: point,
|
||||||
user_id:
|
user_id:
|
||||||
)
|
)
|
||||||
|
|
||||||
|
broadcast_import_progress(import, index)
|
||||||
end
|
end
|
||||||
|
|
||||||
def point_exists?(point)
|
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>
|
<th>Created at</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody
|
||||||
|
data-controller="imports"
|
||||||
|
data-imports-target="index"
|
||||||
|
data-user-id="<%= current_user.id %>"
|
||||||
|
>
|
||||||
<% @imports.each do |import| %>
|
<% @imports.each do |import| %>
|
||||||
<tr>
|
<tr data-import-id="<%= import.id %>" id="import-<%= import.id %>">
|
||||||
<td>
|
<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 '🗺️', map_path(import_id: import.id) %>
|
||||||
 
|
|
||||||
<%= link_to '📋', points_path(import_id: import.id) %>
|
<%= link_to '📋', points_path(import_id: import.id) %>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td data-points-count>
|
||||||
<%= "#{number_with_delimiter import.points_count}" %>
|
<%= number_with_delimiter import.points_count %>
|
||||||
</td>
|
</td>
|
||||||
<td><%= import.created_at.strftime("%d.%m.%Y, %H:%M") %></td>
|
<td><%= import.created_at.strftime("%d.%m.%Y, %H:%M") %></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|
|
||||||
|
|
@ -21,3 +21,4 @@ pin '@rails/actioncable', to: 'actioncable.esm.js'
|
||||||
pin_all_from 'app/javascript/channels', under: 'channels'
|
pin_all_from 'app/javascript/channels', under: 'channels'
|
||||||
pin 'notifications_channel', to: 'channels/notifications_channel.js'
|
pin 'notifications_channel', to: 'channels/notifications_channel.js'
|
||||||
pin 'points_channel', to: 'channels/points_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
|
it 'creates points' do
|
||||||
expect { parser }.to change { Point.count }.by(301)
|
expect { parser }.to change { Point.count }.by(301)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'broadcasts importing progress' do
|
||||||
|
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(301).times
|
||||||
|
|
||||||
|
parser
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when file has multiple segments' do
|
context 'when file has multiple segments' do
|
||||||
|
|
@ -24,6 +30,12 @@ RSpec.describe Gpx::TrackParser do
|
||||||
it 'creates points' do
|
it 'creates points' do
|
||||||
expect { parser }.to change { Point.count }.by(558)
|
expect { parser }.to change { Point.count }.by(558)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it 'broadcasts importing progress' do
|
||||||
|
expect_any_instance_of(Imports::Broadcaster).to receive(:broadcast_import_progress).exactly(558).times
|
||||||
|
|
||||||
|
parser
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
@ -33,6 +45,12 @@ RSpec.describe Gpx::TrackParser do
|
||||||
it 'creates points' do
|
it 'creates points' do
|
||||||
expect { parser }.to change { Point.count }.by(407)
|
expect { parser }.to change { Point.count }.by(407)
|
||||||
end
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue