perilune 0.1.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.
Files changed (37) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +28 -0
  3. data/Rakefile +8 -0
  4. data/app/assets/config/perilune_manifest.js +1 -0
  5. data/app/assets/stylesheets/perilune/application.css +15 -0
  6. data/app/controllers/perilune/application_controller.rb +6 -0
  7. data/app/controllers/perilune/home_controller.rb +7 -0
  8. data/app/controllers/perilune/tasks_controller.rb +48 -0
  9. data/app/helpers/perilune/application_helper.rb +22 -0
  10. data/app/jobs/perilune/application_job.rb +6 -0
  11. data/app/jobs/perilune/tasks/executor_job.rb +37 -0
  12. data/app/mailers/perilune/application_mailer.rb +8 -0
  13. data/app/models/perilune/application_record.rb +7 -0
  14. data/app/models/perilune/task.rb +23 -0
  15. data/app/operations/perilune/tasks/create_operation.rb +51 -0
  16. data/app/operations/perilune/tasks/exports/create_operation.rb +44 -0
  17. data/app/operations/perilune/tasks/find_operation.rb +7 -0
  18. data/app/operations/perilune/tasks/search_operation.rb +8 -0
  19. data/app/serializers/perilune/tasks/serializer.rb +18 -0
  20. data/app/views/kaminari/_first_page.html.haml +5 -0
  21. data/app/views/kaminari/_gap.html.haml +1 -0
  22. data/app/views/kaminari/_last_page.html.haml +5 -0
  23. data/app/views/kaminari/_next_page.html.haml +5 -0
  24. data/app/views/kaminari/_page.html.haml +4 -0
  25. data/app/views/kaminari/_paginator.html.haml +11 -0
  26. data/app/views/kaminari/_prev_page.html.haml +5 -0
  27. data/app/views/layouts/perilune/application.html.haml +66 -0
  28. data/app/views/perilune/home/index.html.haml +19 -0
  29. data/app/views/perilune/tasks/index.html.haml +43 -0
  30. data/app/views/perilune/tasks/show.html.haml +44 -0
  31. data/config/routes.rb +6 -0
  32. data/lib/perilune/engine.rb +7 -0
  33. data/lib/perilune/tasks/mixin.rb +64 -0
  34. data/lib/perilune/version.rb +5 -0
  35. data/lib/perilune.rb +8 -0
  36. data/lib/tasks/perilune_tasks.rake +5 -0
  37. metadata +186 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: fb116ba6c86f1c24f6981261f9c69335e2b152c1167708c411c41a408dd43893
4
+ data.tar.gz: ad39ec022a048edde5c3e18df3e3e62dd5eb75a117ce8a5103dab4c4516876ae
5
+ SHA512:
6
+ metadata.gz: 70f2a6f2fcf043f114818939c498fd85a14e183dd78bd3bdb91a2a32608ad94a5fea982c193b912e82530b9f66c95005ca662ca493370265e822d70146d65851
7
+ data.tar.gz: c271e506ffd1642a4de1f11e2e81c7abcdbe7566d285e3b67bcee169b52491e67a9c48514b4c1ae8170440c4404faa41bd4af7decd3db48c44727f48c2ebc9a9
data/README.md ADDED
@@ -0,0 +1,28 @@
1
+ # Perilune
2
+ Short description and motivation.
3
+
4
+ ## Usage
5
+ How to use my plugin.
6
+
7
+ ## Installation
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem "perilune"
12
+ ```
13
+
14
+ And then execute:
15
+ ```bash
16
+ $ bundle
17
+ ```
18
+
19
+ Or install it yourself as:
20
+ ```bash
21
+ $ gem install perilune
22
+ ```
23
+
24
+ ## Contributing
25
+ Contribution directions go here.
26
+
27
+ ## License
28
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require "bundler/setup"
2
+
3
+ APP_RAKEFILE = File.expand_path("spec/dummy/Rakefile", __dir__)
4
+ load "rails/tasks/engine.rake"
5
+
6
+ load "rails/tasks/statistics.rake"
7
+
8
+ require "bundler/gem_tasks"
@@ -0,0 +1 @@
1
+ //= link_directory ../stylesheets/perilune .css
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any other CSS/SCSS
10
+ * files in this directory. Styles in this file should be added after the last require_* statement.
11
+ * It is generally better to create a new file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class ApplicationController < ActionController::Base
5
+ end
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class HomeController < Perilune::ApplicationController
5
+ def index; end
6
+ end
7
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class TasksController < Perilune::ApplicationController
5
+ before_action :set_resources, only: %i[index]
6
+ before_action :set_resource, only: %i[show]
7
+
8
+ def index; end
9
+
10
+ def show; end
11
+
12
+ private
13
+
14
+ def set_resources
15
+ resource_search_operation.perform
16
+ raise resource_search_operation.result.error unless resource_search_operation.success?
17
+
18
+ @resources = resource_search_operation.result.value
19
+ end
20
+
21
+ def resource_search_operation
22
+ @resource_search_operation ||= Perilune::Tasks::SearchOperation.new(
23
+ query: {},
24
+ limit: {},
25
+ includes: [],
26
+ order: 'id DESC',
27
+ page: params[:page] || 1,
28
+ per: 25,
29
+ domain: :perilune
30
+ )
31
+ end
32
+
33
+ def set_resource
34
+ resource_find_operation.perform
35
+ raise resource_find_operation.result.error unless resource_find_operation.success?
36
+
37
+ @resource = resource_find_operation.result.value
38
+ end
39
+
40
+ def resource_find_operation
41
+ @resource_find_operation ||= Perilune::Tasks::FindOperation.new(
42
+ id: params[:id],
43
+ limit: {},
44
+ domain: :perilune
45
+ )
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module ApplicationHelper
5
+ def task_state(task) # rubocop:disable Metrics/MethodLength
6
+ case task.state.to_sym
7
+ when :draft
8
+ content_tag(:div, task.state,
9
+ class: 'inline-flex items-center px-2.5 py-0.5 rounded-sm text-sm font-medium uppercase bg-gray-500 text-gray-50') # rubocop:disable Layout/LineLength
10
+ when :uploaded
11
+ content_tag(:div, task.state,
12
+ class: 'inline-flex items-center px-2.5 py-0.5 rounded-sm text-sm font-medium uppercase bg-yellow-500 text-yellow-50') # rubocop:disable Layout/LineLength
13
+ when :processed
14
+ content_tag(:div, task.state,
15
+ class: 'inline-flex items-center px-2.5 py-0.5 rounded-sm text-sm font-medium uppercase bg-blue-500 text-blue-50') # rubocop:disable Layout/LineLength
16
+ when :failed
17
+ content_tag(:div, task.state,
18
+ class: 'inline-flex items-center px-2.5 py-0.5 rounded-sm text-sm font-medium uppercase bg-red-500 text-red-50') # rubocop:disable Layout/LineLength
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class ApplicationJob < ActiveJob::Base
5
+ end
6
+ end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ class ExecutorJob < ApplicationJob
6
+ queue_as :default
7
+
8
+ class UndefinedTaskKlass < StandardError; end
9
+
10
+ def perform(task_id)
11
+ @task_id = task_id
12
+ executor.execute
13
+ executor.success? ? success : failure
14
+ end
15
+
16
+ private
17
+
18
+ def task
19
+ @task ||= Perilune::Task.find(@task_id)
20
+ end
21
+
22
+ def success
23
+ task.update(state: 'processed')
24
+ end
25
+
26
+ def failure
27
+ task.update(state: 'failed', error_data: { executor_error: executor.errors })
28
+ end
29
+
30
+ def executor
31
+ raise UndefinedTaskKlass unless Object.const_defined?(task.task_klass)
32
+
33
+ @executor ||= task.task_klass.constantize.new(file: task.file.download, task: task)
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class ApplicationMailer < ActionMailer::Base
5
+ default from: 'from@example.com'
6
+ layout 'mailer'
7
+ end
8
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class ApplicationRecord < ActiveRecord::Base
5
+ self.abstract_class = true
6
+ end
7
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class Task < ApplicationRecord
5
+ self.table_name = 'perilune_tasks'
6
+ validates :state, inclusion: {
7
+ in: %w[draft uploaded processed failed],
8
+ message: '%<value>s is not a valid state'
9
+ }
10
+ validates :task_klass, presence: true
11
+ has_one_attached :file
12
+
13
+ def file_name
14
+ file.filename.to_s
15
+ end
16
+
17
+ def file_url
18
+ file.url
19
+ rescue StandardError
20
+ nil
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ class CreateOperation
6
+ include LedgerSync::Domains::Operation::Mixin
7
+
8
+ class Contract < LedgerSync::Ledgers::Contract
9
+ params do
10
+ required(:file).maybe(type?: File)
11
+ required(:file).maybe(type?: Tempfile)
12
+ required(:task_klass).filled(:string)
13
+ optional(:tags).filled(:array)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def operate
20
+ attach!
21
+ if task.save
22
+ Perilune::Tasks::ExecutorJob.perform_later(task.id)
23
+ success(true)
24
+ else
25
+ failure(task.errors.full_messages)
26
+ end
27
+ end
28
+
29
+ def task
30
+ @task ||= Perilune::Task.new(
31
+ state: 'draft',
32
+ task_klass: params[:task_klass],
33
+ tags: params[:tags]
34
+ )
35
+ end
36
+
37
+ def attach!
38
+ task.file.attach(
39
+ io: params[:file],
40
+ key: "perilune/#{ActiveStorage::Blob.generate_unique_secure_token}",
41
+ filename: "#{params[:task_klass]}_#{Time.zone.now.to_i}"
42
+ )
43
+ end
44
+
45
+ # override to use common serializer for all domain
46
+ def serializer_for(*)
47
+ Perilune::Tasks::Serializer.new
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ module Exports
6
+ class CreateOperation
7
+ include LedgerSync::Domains::Operation::Mixin
8
+
9
+ class Contract < LedgerSync::Ledgers::Contract
10
+ params do
11
+ required(:task_klass).filled(:string)
12
+ required(:attrs).filled(:hash)
13
+ optional(:tags).filled(:array)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def operate
20
+ if task.save
21
+ Perilune::Tasks::ExecutorJob.perform_later(task.id)
22
+ success(true)
23
+ else
24
+ failure(task.errors.full_messages)
25
+ end
26
+ end
27
+
28
+ def task
29
+ @task ||= Perilune::Task.new(
30
+ state: 'draft',
31
+ task_klass: params[:task_klass],
32
+ attrs: params[:attrs],
33
+ tags: params[:tags]
34
+ )
35
+ end
36
+
37
+ # override to use common serializer for all domain
38
+ def serializer_for(*)
39
+ Perilune::Tasks::Serializer.new
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ class FindOperation < LedgerSync::Domains::Operation::Find; end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ class SearchOperation < LedgerSync::Domains::Operation::Search
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ class Serializer < LedgerSync::Domains::Serializer
6
+ attribute :id
7
+ attribute :task_klass
8
+ attribute :attrs
9
+ attribute :state
10
+ attribute :tags
11
+ attribute :error_data
12
+ attribute :created_at
13
+ attribute :updated_at
14
+ attribute :file_name
15
+ attribute :file_url
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,5 @@
1
+ - unless current_page.first?
2
+ = link_to url, remote: remote, class: 'relative inline-flex items-center px-2 py-2. rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50' do
3
+ %span.sr-only= raw(t 'views.pagination.first')
4
+ %svg.h-4.w-4{:fill => "none", :stroke => "currentColor", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
5
+ %path{:d => "M11 19l-7-7 7-7m8 14l-7-7 7-7", "stroke-linecap" => "round", "stroke-linejoin" => "round", "stroke-width" => "2"}
@@ -0,0 +1 @@
1
+ = link_to raw(t 'views.pagination.truncate'), '#', class: 'relative inline-flex items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700'
@@ -0,0 +1,5 @@
1
+ - unless current_page.last?
2
+ = link_to url, remote: remote, class: 'relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50' do
3
+ %span.sr-only= raw(t 'views.pagination.last')
4
+ %svg.h-4.w-4{:fill => "none", :stroke => "currentColor", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
5
+ %path{:d => "M13 5l7 7-7 7M5 5l7 7-7 7", "stroke-linecap" => "round", "stroke-linejoin" => "round", "stroke-width" => "2"}
@@ -0,0 +1,5 @@
1
+ - unless current_page.last?
2
+ = link_to url, rel: 'next', remote: remote, class: 'relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50' do
3
+ %span.sr-only= raw(t 'views.pagination.next')
4
+ %svg.h-4.w-4{:fill => "none", :stroke => "currentColor", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
5
+ %path{:d => "M9 5l7 7-7 7", "stroke-linecap" => "round", "stroke-linejoin" => "round", "stroke-width" => "2"}
@@ -0,0 +1,4 @@
1
+ - if page.current?
2
+ = link_to page, url, remote: remote, rel: page.rel, class: 'hidden md:inline-flex relative items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50'
3
+ - else
4
+ = link_to page, url, remote: remote, rel: page.rel, class: 'hidden md:inline-flex relative items-center px-4 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-700 hover:bg-gray-50'
@@ -0,0 +1,11 @@
1
+ = paginator.render do
2
+ %nav.relative.z-0.inline-flex.shadow-sm.-space-x-px{"aria-label" => "Pagination"}
3
+ = first_page_tag unless current_page.first?
4
+ = prev_page_tag unless current_page.first?
5
+ - each_page do |page|
6
+ - if page.left_outer? || page.right_outer? || page.inside_window?
7
+ = page_tag page
8
+ - elsif !page.was_truncated?
9
+ = gap_tag
10
+ = next_page_tag unless current_page.last?
11
+ = last_page_tag unless current_page.last?
@@ -0,0 +1,5 @@
1
+ - unless current_page.first?
2
+ = link_to url, rel: 'prev', remote: remote, class: 'relative inline-flex items-center px-2 py-2 border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50' do
3
+ %span.sr-only= raw(t 'views.pagination.previous')
4
+ %svg.h-4.w-4{:fill => "none", :stroke => "currentColor", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
5
+ %path{:d => "M15 19l-7-7 7-7", "stroke-linecap" => "round", "stroke-linejoin" => "round", "stroke-width" => "2"}
@@ -0,0 +1,66 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %meta{:charset => "utf-8"}/
5
+ %meta{:content => "width=device-width, initial-scale=1.0", :name => "viewport"}/
6
+ %meta{:content => "IE=edge", "http-equiv" => "X-UA-Compatible"}/
7
+ %title= content_for?(:page_title) ? sanitize(yield(:page_title), tags: []) : "Perilune"
8
+ = csrf_meta_tags
9
+ = csp_meta_tag
10
+ %link{:href => "https://fonts.googleapis.com/css?family=Open+Sans:300,400,600,700&display=swap", :rel => "stylesheet"}/
11
+ / Favicons
12
+ %link{:rel => 'apple-touch-icon', :sizes => '180x180', :href => "#{main_app.root_url}favicons/apple-touch-icon.png"}
13
+ %link{:rel => 'icon', :sizes => '16x16', :href => "#{main_app.root_url}perilune/favicons/favicon-16x16.png"}
14
+ %link{:rel => 'icon', :sizes => '32x32', :href => "#{main_app.root_url}perilune/favicons/favicon-32x32.png"}
15
+ %link{:rel => 'icon', :sizes => '48x48', :href => "#{main_app.root_url}perilune/favicons/favicon.ico"}
16
+ %link{:rel => 'mask-icon', :href => "#{main_app.root_url}perilune/favicons/safari-pinned-tab.svg"}
17
+ %link{:rel => 'manifest', :href => "#{main_app.root_url}perilune/favicons/site.webmanifest"}
18
+ %meta{:content => "#{main_app.root_url}perilune/favicons/ms-tile-150x150.png", :name => "msapplication-TileImage"}/
19
+ = action_cable_meta_tag
20
+
21
+ %script{:src => "https://cdn.tailwindcss.com"}
22
+
23
+ %body
24
+ - if user_signed_in?
25
+ %input{id: 'user_locale', type: 'hidden', value: current_user.full_time_zone}
26
+ .min-h-screen.bg-gray-100
27
+ %nav.bg-white.shadow-sm{'x-data' => "{ isMobileVisible: false }"}
28
+ / Desktop menu
29
+ .max-w-7xl.mx-auto.px-4.sm:px-6.lg:px-8
30
+ .flex.justify-between.h-16
31
+ .flex
32
+ .flex-shrink-0.flex.items-center.px-6
33
+ = link_to perilune.root_path, class: 'h-8 w-auto font-mono' do
34
+ %span.bg-clip-text.text-transparent.bg-gradient-to-r.bg-blue-200.from-blue-300.to-purple-400.text-2xl.font-bold Perilune
35
+ .hidden.sm:-my-px.sm:ml-6.sm:flex.sm:space-x-8
36
+ = link_to perilune.root_path, class: "border-transparent text-gray-500 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium hover:text-gray-700 hover:text-gray-300" do
37
+ Dashboard
38
+ = link_to perilune.tasks_path, class: "border-transparent text-gray-500 inline-flex items-center px-1 pt-1 border-b-2 text-sm font-medium hover:text-gray-700 hover:text-gray-300" do
39
+ Tasks
40
+
41
+ / Mobile menu, show/hide based on menu state.
42
+ #mobile-menu.sm:hidden{':class' => "isMobileVisible ? 'visible' : 'hidden'"}
43
+ .pt-2.pb-3.space-y-1
44
+ = link_to perilune.root_path, class: "text-gray-600 border-transparent block pl-3 pr-4 py-2 border-l-4 text-base font-medium hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800" do
45
+ Dashboard
46
+ = link_to perilune.tasks_path, class: "text-gray-600 border-transparent block pl-3 pr-4 py-2 border-l-4 text-base font-medium hover:bg-gray-50 hover:border-gray-300 hover:text-gray-800" do
47
+ Tasks
48
+
49
+
50
+ .py-10
51
+ %main
52
+ .max-w-7xl.mx-auto.sm:px-6.lg:px-8
53
+ .mt-2.mx-6
54
+ - flash.each do |type, message|
55
+ - case type
56
+ - when :error
57
+ %div.p-4.mb-4.rounded-md.text-sm.font-medium.bg-red-100.text-red-800=message
58
+ - when :alert
59
+ %div.p-4.mb-4.rounded-md.text-sm.font-medium.bg-yellow-100.text-yellow-800=message
60
+ - when :notice
61
+ %div.p-4.mb-4.rounded-md.text-sm.font-medium.bg-indigo-100.text-indigo-800=message
62
+ - else
63
+ %div.p-4.mb-4.rounded-md.text-sm.font-medium.bg-indigo-100.text-indigo-800=message
64
+ = yield
65
+
66
+ = yield :javascript
@@ -0,0 +1,19 @@
1
+
2
+
3
+ .bg-white.overflow-hidden.shadow.rounded-lg
4
+ .px-4.py-5.sm:p-6
5
+ %div.mb-4
6
+ %span.text-2xl.font-bold perilune
7
+ [
8
+ = succeed '-i-loon' do
9
+ %span.font-bold per
10
+ ]
11
+ %hr
12
+ %div.mt-4
13
+ .italic noun
14
+ %div.mt-2.ml-8
15
+ %span.text-gray-400 1
16
+ %span.ml-2 the point in a lunar orbit that is nearest to the moon.
17
+ %div.mt-2.ml-8
18
+ %span.text-gray-400 2
19
+ %span.ml-2 that thing that processes your files and makes your life a bit easier.
@@ -0,0 +1,43 @@
1
+ .flex.flex-col
2
+ .-my-2.overflow-x-auto.sm:-mx-6.lg:-mx-8
3
+ .py-2.align-middle.inline-block.min-w-full.sm:px-6.lg:px-8
4
+ .shadow.overflow-hidden.border-b.border-gray-200.sm:rounded-lg
5
+ %table.min-w-full.divide-y.divide-gray-200
6
+ %thead.bg-gray-50
7
+ %tr
8
+ %th.px-6.py-3.text-left.text-xs.font-medium.text-gray-500.uppercase.tracking-wider{:scope => "col"} ID
9
+ %th.px-6.py-3.text-left.text-xs.font-medium.text-gray-500.uppercase.tracking-wider{:scope => "col"} Task
10
+ %th.px-6.py-3.text-left.text-xs.font-medium.text-gray-500.uppercase.tracking-wider{:scope => "col"} State
11
+ %th.px-6.py-3.text-left.text-xs.font-medium.text-gray-500.uppercase.tracking-wider{:scope => "col"} Tags
12
+ %th.px-6.py-3.text-left.text-xs.font-medium.text-gray-500.uppercase.tracking-wider{:scope => "col"} Created At
13
+ %th.relative.px-6.py-3{:scope => "col"}
14
+ %span.sr-only Edit
15
+ %tbody
16
+ - @resources.each do |resource|
17
+ %tr.bg-white
18
+ %td.px-6.py-4.whitespace-nowrap.text-sm.font-medium.text-gray-600
19
+ = link_to resource.id, perilune.task_path(resource), class: 'text-indigo-400 hover:text-indigo-900'
20
+ %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500
21
+ .rounded-sm.font-mono.text-sm.px-2.w-auto.max-w-max.break-normal.text-purple-500.bg-blue-100= resource.task_klass
22
+ %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500= task_state(resource)
23
+ %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500
24
+ - resource.tags.each do |tag|
25
+ %span.inline-flex.items-center.px-3.py-0.5.rounded-full.text-sm.font-medium.bg-blue-100.text-blue-800= tag
26
+ %td.px-6.py-4.whitespace-nowrap.text-sm.text-gray-500= resource.created_at.to_s
27
+ %td.px-6.py-4.whitespace-nowrap.text-right.text-sm.font-medium
28
+ = link_to perilune.task_path(resource) do
29
+ %svg.h-6.w-6.text-indigo-400.hover:text-indigo-900{:fill => "none", :stroke => "currentColor", :viewbox => "0 0 24 24", :xmlns => "http://www.w3.org/2000/svg"}
30
+ %path{:d => "M13 9l3 3m0 0l-3 3m3-3H8m13 0a9 9 0 11-18 0 9 9 0 0118 0z", "stroke-linecap" => "round", "stroke-linejoin" => "round", "stroke-width" => "2"}
31
+
32
+ .mt-2
33
+ .flex-1.flex.items-center.justify-between
34
+ %div.hidden.sm:block
35
+ %p.text-sm.text-gray-400
36
+ - unless @resources.total_count.zero?
37
+ Showing
38
+ %span.font-medium= (@resources.current_page - 1) * @resources.limit_value + 1
39
+ to
40
+ %span.font-medium= [(@resources.current_page - 1) * @resources.limit_value + @resources.limit_value, @resources.total_count].min
41
+ of
42
+ = pluralize(@resources.total_count, 'task')
43
+ = paginate @resources
@@ -0,0 +1,44 @@
1
+ .bg-white.shadow.overflow-hidden.sm:rounded-lg
2
+ .px-4.py-5.sm:px-6
3
+ %h3.text-lg.leading-6.font-medium.text-gray-900 Task ##{@resource.id}
4
+ .border-t.border-gray-200.px-4.py-5.sm:p-0
5
+ %dl.sm:divide-y.sm:divide-gray-200
6
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
7
+ %dt.text-sm.font-medium.text-gray-500 Task Klass
8
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2
9
+ .rounded-sm.font-mono.text-sm.px-2.w-auto.max-w-max.break-normal.text-purple-500.bg-blue-100 #{@resource.task_klass}
10
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
11
+ %dt.text-sm.font-medium.text-gray-500 Task Attributes
12
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2
13
+ %code #{@resource.attrs}
14
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
15
+ %dt.text-sm.font-medium.text-gray-500 State
16
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2 #{task_state(@resource)}
17
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
18
+ %dt.text-sm.font-medium.text-gray-500 Tags
19
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2
20
+ - @resource.tags.each do |tag|
21
+ %span.inline-flex.items-center.px-3.py-0.5.rounded-full.text-sm.font-medium.bg-blue-100.text-blue-800= tag
22
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
23
+ %dt.text-sm.font-medium.text-gray-500 Created At
24
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2 #{@resource.created_at.to_s}
25
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
26
+ %dt.text-sm.font-medium.text-gray-500 Updated At
27
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2 #{@resource.updated_at.to_s}
28
+ - if @resource.state.to_sym == :failed
29
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
30
+ %dt.text-sm.font-medium.text-gray-500 Error
31
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2
32
+ %code #{@resource.error_data}
33
+ .py-4.sm:py-5.sm:grid.sm:grid-cols-3.sm:gap-4.sm:px-6
34
+ %dt.text-sm.font-medium.text-gray-500 Attachment
35
+ %dd.mt-1.text-sm.text-gray-900.sm:mt-0.sm:col-span-2
36
+ %ul.border.border-gray-200.rounded-md.divide-y.divide-gray-200{:role => "list"}
37
+ %li.pl-3.pr-4.py-3.flex.items-center.justify-between.text-sm
38
+ .w-0.flex-1.flex.items-center
39
+ / Heroicon name: solid/paper-clip
40
+ %svg.flex-shrink-0.h-5.w-5.text-gray-400{"aria-hidden" => "true", :fill => "currentColor", :viewbox => "0 0 20 20", :xmlns => "http://www.w3.org/2000/svg"}
41
+ %path{"clip-rule" => "evenodd", :d => "M8 4a3 3 0 00-3 3v4a5 5 0 0010 0V7a1 1 0 112 0v4a7 7 0 11-14 0V7a5 5 0 0110 0v4a3 3 0 11-6 0V7a1 1 0 012 0v4a1 1 0 102 0V7a3 3 0 00-3-3z", "fill-rule" => "evenodd"}
42
+ %span.ml-2.flex-1.w-0.truncate #{@resource.file_name}
43
+ .ml-4.flex-shrink-0
44
+ = link_to 'Download', @resource.file_url, class: 'font-medium text-indigo-400 hover:text-indigo-900'
data/config/routes.rb ADDED
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ Perilune::Engine.routes.draw do
4
+ root to: 'home#index'
5
+ resources :tasks, only: %i[index show]
6
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ class Engine < ::Rails::Engine
5
+ isolate_namespace Perilune
6
+ end
7
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ module Tasks
5
+ module Mixin
6
+ def self.included(base)
7
+ base.include InstanceMethods
8
+ end
9
+
10
+ module InstanceMethods
11
+ attr_reader :file, :task, :errors
12
+
13
+ delegate :trace, to: :tracer
14
+
15
+ def initialize(file:, task:)
16
+ @file = file
17
+ @task = task
18
+ end
19
+
20
+ def execute
21
+ operate
22
+ rescue StandardError => e
23
+ failure(e.message)
24
+ end
25
+
26
+ def tags
27
+ task.tags
28
+ end
29
+
30
+ def failure(message)
31
+ @errors = message
32
+ end
33
+
34
+ def success?
35
+ errors.blank?
36
+ end
37
+
38
+ def operate(*)
39
+ raise StandardError, 'operate function is not defined'
40
+ end
41
+
42
+ def tracer_config
43
+ @tracer_config ||= Trifle::Logger::Configuration.new
44
+ @tracer_config.on(:wrapup) do |tracer|
45
+ entry = Perilune::Task.find_by(id: tracer.reference)
46
+ next if entry.nil?
47
+
48
+ entry.update(
49
+ tracer_data: tracer.data,
50
+ state: tracer.state
51
+ )
52
+ end
53
+ @tracer_config
54
+ end
55
+
56
+ def tracer
57
+ @tracer ||= Trifle::Logger.tracer = Trifle::Logger::Tracer::Hash.new(
58
+ key: task.id, reference: task.id, config: tracer_config
59
+ )
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Perilune
4
+ VERSION = '0.1.0'
5
+ end
data/lib/perilune.rb ADDED
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'perilune/engine'
4
+ require 'perilune/tasks/mixin'
5
+
6
+ module Perilune
7
+ # Your code goes here...
8
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+ # desc "Explaining what the task does"
3
+ # task :perilune do
4
+ # # Task goes here
5
+ # end
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: perilune
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kartavya Pareek
8
+ - Jozef Vaclavik
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2022-03-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: ledger_sync-domains
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - "~>"
19
+ - !ruby/object:Gem::Version
20
+ version: 1.1.1
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - "~>"
26
+ - !ruby/object:Gem::Version
27
+ version: 1.1.1
28
+ - !ruby/object:Gem::Dependency
29
+ name: rails
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - "~>"
33
+ - !ruby/object:Gem::Version
34
+ version: 7.0.0
35
+ - - ">="
36
+ - !ruby/object:Gem::Version
37
+ version: 7.0.0.0
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - "~>"
43
+ - !ruby/object:Gem::Version
44
+ version: 7.0.0
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 7.0.0.0
48
+ - !ruby/object:Gem::Dependency
49
+ name: trifle-logger
50
+ requirement: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ - !ruby/object:Gem::Dependency
63
+ name: dotenv-rails
64
+ requirement: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ type: :development
70
+ prerelease: false
71
+ version_requirements: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ - !ruby/object:Gem::Dependency
77
+ name: factory_bot_rails
78
+ requirement: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ type: :development
84
+ prerelease: false
85
+ version_requirements: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ - !ruby/object:Gem::Dependency
91
+ name: pg
92
+ requirement: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ type: :development
98
+ prerelease: false
99
+ version_requirements: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ - !ruby/object:Gem::Dependency
105
+ name: rspec-rails
106
+ requirement: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ type: :development
112
+ prerelease: false
113
+ version_requirements: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ description: Description of Perilune.
119
+ email:
120
+ - hi@dropbot.sh
121
+ executables: []
122
+ extensions: []
123
+ extra_rdoc_files: []
124
+ files:
125
+ - README.md
126
+ - Rakefile
127
+ - app/assets/config/perilune_manifest.js
128
+ - app/assets/stylesheets/perilune/application.css
129
+ - app/controllers/perilune/application_controller.rb
130
+ - app/controllers/perilune/home_controller.rb
131
+ - app/controllers/perilune/tasks_controller.rb
132
+ - app/helpers/perilune/application_helper.rb
133
+ - app/jobs/perilune/application_job.rb
134
+ - app/jobs/perilune/tasks/executor_job.rb
135
+ - app/mailers/perilune/application_mailer.rb
136
+ - app/models/perilune/application_record.rb
137
+ - app/models/perilune/task.rb
138
+ - app/operations/perilune/tasks/create_operation.rb
139
+ - app/operations/perilune/tasks/exports/create_operation.rb
140
+ - app/operations/perilune/tasks/find_operation.rb
141
+ - app/operations/perilune/tasks/search_operation.rb
142
+ - app/serializers/perilune/tasks/serializer.rb
143
+ - app/views/kaminari/_first_page.html.haml
144
+ - app/views/kaminari/_gap.html.haml
145
+ - app/views/kaminari/_last_page.html.haml
146
+ - app/views/kaminari/_next_page.html.haml
147
+ - app/views/kaminari/_page.html.haml
148
+ - app/views/kaminari/_paginator.html.haml
149
+ - app/views/kaminari/_prev_page.html.haml
150
+ - app/views/layouts/perilune/application.html.haml
151
+ - app/views/perilune/home/index.html.haml
152
+ - app/views/perilune/tasks/index.html.haml
153
+ - app/views/perilune/tasks/show.html.haml
154
+ - config/routes.rb
155
+ - lib/perilune.rb
156
+ - lib/perilune/engine.rb
157
+ - lib/perilune/tasks/mixin.rb
158
+ - lib/perilune/version.rb
159
+ - lib/tasks/perilune_tasks.rake
160
+ homepage: https://engineering.dropbot.sh
161
+ licenses:
162
+ - MIT
163
+ metadata:
164
+ homepage_uri: https://engineering.dropbot.sh
165
+ source_code_uri: https://github.com/sandbite/perilune
166
+ changelog_uri: https://github.com/sandbite/perilune/blob/main/CHANGELOG.md
167
+ post_install_message:
168
+ rdoc_options: []
169
+ require_paths:
170
+ - lib
171
+ required_ruby_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '2.7'
176
+ required_rubygems_version: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - ">="
179
+ - !ruby/object:Gem::Version
180
+ version: '0'
181
+ requirements: []
182
+ rubygems_version: 3.2.9
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: Summary of Perilune.
186
+ test_files: []