ixport 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +92 -6
- data/app/controllers/ixport/application_controller.rb +6 -2
- data/app/controllers/ixport/export_templates_controller.rb +52 -0
- data/app/controllers/ixport/exports_controller.rb +18 -0
- data/app/controllers/ixport/imports_controller.rb +4 -3
- data/app/controllers/ixport/previews_controller.rb +2 -2
- data/app/controllers/ixport/runs_controller.rb +13 -1
- data/app/helpers/ixport/imports_helper.rb +13 -0
- data/app/models/ixport/csv_writer.rb +19 -0
- data/app/models/ixport/export_template.rb +19 -0
- data/app/models/ixport/import.rb +71 -19
- data/app/models/ixport/null_reporter.rb +11 -0
- data/app/models/ixport/row_walk.rb +15 -6
- data/app/models/ixport/wallflower_runner.rb +10 -0
- data/app/models/ixport/wallflower_task_runner.rb +14 -0
- data/app/views/ixport/export_templates/edit.html.erb +14 -0
- data/app/views/ixport/export_templates/new.html.erb +11 -0
- data/app/views/ixport/exports/index.html.erb +23 -0
- data/app/views/ixport/imports/index.html.erb +17 -0
- data/app/views/ixport/imports/show.html.erb +30 -15
- data/config/routes.rb +4 -0
- data/lib/generators/ixport/install/install_generator.rb +3 -0
- data/lib/generators/ixport/install/templates/add_error_message_to_ixport_imports.rb.erb +5 -0
- data/lib/generators/ixport/install/templates/add_wallflower_task_to_ixport_imports.rb.erb +6 -0
- data/lib/generators/ixport/install/templates/create_ixport_export_templates.rb.erb +12 -0
- data/lib/generators/ixport/update/update_generator.rb +28 -0
- data/lib/ixport/background_runner.rb +23 -0
- data/lib/ixport/configuration.rb +3 -1
- data/lib/ixport/engine.rb +4 -1
- data/lib/ixport/exporter.rb +27 -0
- data/lib/ixport/importer.rb +7 -3
- data/lib/ixport/registrations.rb +29 -3
- data/lib/ixport/version.rb +1 -1
- data/lib/ixport.rb +2 -0
- data/the_local/agents/ixport-develop.md +235 -37
- data/the_local/agents/ixport-info.md +61 -26
- data/the_local/agents/ixport-install.md +66 -38
- data/the_local/interface.yml +37 -1
- metadata +18 -1
|
@@ -7,4 +7,21 @@
|
|
|
7
7
|
<div data-import><%= link_to registration.title, new_import_path(key: registration.key) %></div>
|
|
8
8
|
<% end %>
|
|
9
9
|
<% end %>
|
|
10
|
+
<% if @imports.any? %>
|
|
11
|
+
<%= ui_section(title: "Your imports") do %>
|
|
12
|
+
<% @imports.each do |import| %>
|
|
13
|
+
<div data-past-import>
|
|
14
|
+
<%= link_to import_step_path(import), data: { step_link: true } do %><span data-import-title><%= import.title %></span><% end %>
|
|
15
|
+
<span data-file-name><%= import.file.filename.to_s %></span>
|
|
16
|
+
<span data-status><%= import.status.capitalize %></span>
|
|
17
|
+
<span data-made-on><%= import.created_at.strftime("%b %-d, %Y") %></span>
|
|
18
|
+
<% if import.finished? %>
|
|
19
|
+
<span>Added <span data-added><%= import.added_count %></span></span>
|
|
20
|
+
<span>Updated <span data-updated><%= import.updated_count %></span></span>
|
|
21
|
+
<span>Refused <span data-refused><%= import.refusals.size %></span></span>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
24
|
+
<% end %>
|
|
25
|
+
<% end %>
|
|
26
|
+
<% end %>
|
|
10
27
|
<% end %>
|
|
@@ -1,20 +1,35 @@
|
|
|
1
|
-
|
|
1
|
+
<% heading = if @import.running?
|
|
2
|
+
"Import running"
|
|
3
|
+
elsif @import.failed?
|
|
4
|
+
"Import failed"
|
|
5
|
+
else
|
|
6
|
+
"Import finished"
|
|
7
|
+
end %>
|
|
8
|
+
<%= ui_show_page(title: heading, back_url: root_path) %>
|
|
2
9
|
<%= ui_page(max_width: :md) do %>
|
|
3
|
-
<%= ui_page_header(title:
|
|
4
|
-
|
|
5
|
-
<%=
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
10
|
+
<%= ui_page_header(title: heading) %>
|
|
11
|
+
<% if @import.running? %>
|
|
12
|
+
<%= ui_alert(type: :info, message: tag.span("This import is running.", data: { import_running: true })) %>
|
|
13
|
+
<% else %>
|
|
14
|
+
<% if @import.failed? %>
|
|
15
|
+
<%= ui_alert(type: :error, message: tag.span(@import.error_message, data: { import_error: true })) %>
|
|
16
|
+
<p>Rows saved before it stopped stay saved.</p>
|
|
17
|
+
<% end %>
|
|
18
|
+
<%= ui_grid(cols: { default: 1, sm: 2 }) do %>
|
|
19
|
+
<%= ui_stat_card(label: "Added", value: tag.span(@import.added_count, data: { result_count: "added" })) %>
|
|
20
|
+
<%= ui_stat_card(label: "Updated", value: tag.span(@import.updated_count, data: { result_count: "updated" })) %>
|
|
21
|
+
<% end %>
|
|
22
|
+
<% if @import.refusals.any? %>
|
|
23
|
+
<%= ui_section(title: "Refused") do %>
|
|
24
|
+
<ul>
|
|
25
|
+
<% @import.refusals.each do |refusal| %>
|
|
26
|
+
<%= tag.li(data: { refused_row: true }) do %>
|
|
27
|
+
Row <%= tag.span(refusal.row_number, data: { row_number: true }) %>
|
|
28
|
+
<%= tag.span(refusal.reason, data: { reason: true }) %>
|
|
29
|
+
<% end %>
|
|
15
30
|
<% end %>
|
|
16
|
-
|
|
17
|
-
|
|
31
|
+
</ul>
|
|
32
|
+
<% end %>
|
|
18
33
|
<% end %>
|
|
19
34
|
<% end %>
|
|
20
35
|
<% end %>
|
data/config/routes.rb
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
Ixport::Engine.routes.draw do
|
|
2
2
|
root "imports#index"
|
|
3
|
+
resources :exports, only: %i[index show] do
|
|
4
|
+
resources :templates, only: %i[new create], controller: "export_templates"
|
|
5
|
+
end
|
|
6
|
+
resources :export_templates, only: %i[show edit update destroy]
|
|
3
7
|
resources :imports, only: %i[new create show] do
|
|
4
8
|
resource :mapping, only: %i[show update]
|
|
5
9
|
resource :preview, only: :show
|
|
@@ -15,6 +15,9 @@ module Ixport
|
|
|
15
15
|
def copy_migrations
|
|
16
16
|
migration_template "create_ixport_imports.rb.erb", "db/migrate/create_ixport_imports.rb"
|
|
17
17
|
migration_template "create_ixport_import_refusals.rb.erb", "db/migrate/create_ixport_import_refusals.rb"
|
|
18
|
+
migration_template "create_ixport_export_templates.rb.erb", "db/migrate/create_ixport_export_templates.rb"
|
|
19
|
+
migration_template "add_wallflower_task_to_ixport_imports.rb.erb", "db/migrate/add_wallflower_task_to_ixport_imports.rb"
|
|
20
|
+
migration_template "add_error_message_to_ixport_imports.rb.erb", "db/migrate/add_error_message_to_ixport_imports.rb"
|
|
18
21
|
end
|
|
19
22
|
end
|
|
20
23
|
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
class CreateIxportExportTemplates < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
|
|
2
|
+
def change
|
|
3
|
+
create_table :ixport_export_templates do |t|
|
|
4
|
+
t.string :key, null: false
|
|
5
|
+
t.string :name, null: false
|
|
6
|
+
t.json :columns, null: false
|
|
7
|
+
t.references :person, polymorphic: true, null: false
|
|
8
|
+
t.references :account, polymorphic: true, null: true
|
|
9
|
+
t.timestamps
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/active_record"
|
|
5
|
+
|
|
6
|
+
module Ixport
|
|
7
|
+
module Generators
|
|
8
|
+
class UpdateGenerator < Rails::Generators::Base
|
|
9
|
+
include ActiveRecord::Generators::Migration
|
|
10
|
+
|
|
11
|
+
source_root File.expand_path("../install/templates", __dir__)
|
|
12
|
+
|
|
13
|
+
desc "Updates Ixport: copies the migrations added since it was installed."
|
|
14
|
+
|
|
15
|
+
def copy_export_templates_migration
|
|
16
|
+
migration_template "create_ixport_export_templates.rb.erb", "db/migrate/create_ixport_export_templates.rb"
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def copy_wallflower_task_migration
|
|
20
|
+
migration_template "add_wallflower_task_to_ixport_imports.rb.erb", "db/migrate/add_wallflower_task_to_ixport_imports.rb"
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def copy_error_message_migration
|
|
24
|
+
migration_template "add_error_message_to_ixport_imports.rb.erb", "db/migrate/add_error_message_to_ixport_imports.rb"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ixport
|
|
4
|
+
class ImportFailed < StandardError; end
|
|
5
|
+
|
|
6
|
+
def self.background_runner
|
|
7
|
+
case configuration.background_runner
|
|
8
|
+
when nil then nil
|
|
9
|
+
when :wallflower then WallflowerRunner
|
|
10
|
+
else configuration.background_runner.to_s.constantize
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.run_import(import, reporter: NullReporter.new)
|
|
15
|
+
import.run!(reporter: reporter)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.install_background_runner!
|
|
19
|
+
return unless configuration.background_runner == :wallflower
|
|
20
|
+
|
|
21
|
+
Wallflower.register_kind(:ixport_import, title: "Import", runner: "Ixport::WallflowerTaskRunner")
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/ixport/configuration.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Ixport
|
|
4
4
|
class Configuration
|
|
5
|
-
attr_accessor :authentication_method, :current_person_method, :current_account_method, :layout, :inline_row_limit
|
|
5
|
+
attr_accessor :authentication_method, :current_person_method, :current_account_method, :layout, :inline_row_limit, :background_runner, :base_controller
|
|
6
6
|
|
|
7
7
|
def initialize
|
|
8
8
|
@authentication_method = :authenticate_user!
|
|
@@ -10,6 +10,8 @@ module Ixport
|
|
|
10
10
|
@current_account_method = :current_account
|
|
11
11
|
@layout = "application"
|
|
12
12
|
@inline_row_limit = 1_000
|
|
13
|
+
@background_runner = nil
|
|
14
|
+
@base_controller = "::ApplicationController"
|
|
13
15
|
end
|
|
14
16
|
end
|
|
15
17
|
|
data/lib/ixport/engine.rb
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Ixport
|
|
4
|
+
class Exporter
|
|
5
|
+
Column = Struct.new(:key, :label, :through, keyword_init: true)
|
|
6
|
+
|
|
7
|
+
attr_reader :person, :account
|
|
8
|
+
|
|
9
|
+
def initialize(person:, account:)
|
|
10
|
+
@person = person
|
|
11
|
+
@account = account
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def self.column(key, label:, through: nil)
|
|
15
|
+
columns << Column.new(key: key.to_sym, label: label, through: through)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.columns
|
|
19
|
+
@columns ||= []
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def value(record, column)
|
|
23
|
+
source = column.through ? record.public_send(column.through) : record
|
|
24
|
+
source&.public_send(column.key)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
data/lib/ixport/importer.rb
CHANGED
|
@@ -19,12 +19,16 @@ module Ixport
|
|
|
19
19
|
@fields ||= []
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def self.match_on(
|
|
23
|
-
@
|
|
22
|
+
def self.match_on(*keys)
|
|
23
|
+
@match_fields = keys.map(&:to_sym)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def self.match_fields
|
|
27
|
+
@match_fields || []
|
|
24
28
|
end
|
|
25
29
|
|
|
26
30
|
def self.match_field
|
|
27
|
-
|
|
31
|
+
match_fields.first
|
|
28
32
|
end
|
|
29
33
|
end
|
|
30
34
|
end
|
data/lib/ixport/registrations.rb
CHANGED
|
@@ -1,12 +1,20 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Ixport
|
|
4
|
-
|
|
4
|
+
module AccessRule
|
|
5
|
+
def allows?(person, account)
|
|
6
|
+
allow.nil? || allow.call(person, account)
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
Registration = Struct.new(:key, :title, :importer, :allow, keyword_init: true) { include AccessRule }
|
|
11
|
+
ExportRegistration = Struct.new(:key, :title, :exporter, :chosen, :allow, keyword_init: true) { include AccessRule }
|
|
5
12
|
|
|
6
13
|
class MissingImporter < StandardError; end
|
|
14
|
+
class MissingExporter < StandardError; end
|
|
7
15
|
|
|
8
|
-
def self.register_import(key, title:, importer:)
|
|
9
|
-
registrations[key.to_sym] = Registration.new(key: key.to_sym, title: title, importer: importer.to_s)
|
|
16
|
+
def self.register_import(key, title:, importer:, allow: nil)
|
|
17
|
+
registrations[key.to_sym] = Registration.new(key: key.to_sym, title: title, importer: importer.to_s, allow: allow)
|
|
10
18
|
end
|
|
11
19
|
|
|
12
20
|
def self.registration(key)
|
|
@@ -23,9 +31,27 @@ module Ixport
|
|
|
23
31
|
|
|
24
32
|
raise MissingImporter, "Ixport import #{registration.key} names the importer #{registration.importer}, which does not exist."
|
|
25
33
|
end
|
|
34
|
+
export_registrations.each_value do |registration|
|
|
35
|
+
next if registration.exporter.safe_constantize
|
|
36
|
+
|
|
37
|
+
raise MissingExporter, "Ixport export #{registration.key} names the exporter #{registration.exporter}, which does not exist."
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def self.register_export(key, title:, exporter:, chosen: false, allow: nil)
|
|
42
|
+
export_registrations[key.to_sym] = ExportRegistration.new(key: key.to_sym, title: title, exporter: exporter.to_s, chosen: chosen, allow: allow)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def self.export_registration(key)
|
|
46
|
+
export_registrations.fetch(key.to_sym)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def self.export_registrations
|
|
50
|
+
@export_registrations ||= {}
|
|
26
51
|
end
|
|
27
52
|
|
|
28
53
|
def self.reset_registrations!
|
|
29
54
|
@registrations = {}
|
|
55
|
+
@export_registrations = {}
|
|
30
56
|
end
|
|
31
57
|
end
|
data/lib/ixport/version.rb
CHANGED