perilune 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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: []