marty 6.1.0 → 8.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.gitlab-ci.yml +17 -3
- data/.rubocop.yml +5 -0
- data/.rubocop_todo.yml +3 -2
- data/Gemfile +2 -1
- data/app/assets/javascripts/marty/extjs/extensions/marty.js +23 -1
- data/app/assets/stylesheets/marty/application.css +4 -1
- data/app/assets/stylesheets/marty/dark_mode.css +17 -0
- data/app/components/marty/auth_app.rb +10 -1
- data/app/components/marty/auth_app/client/auth_app.js +4 -0
- data/app/components/marty/extras/layout.rb +2 -2
- data/app/components/marty/extras/misc.rb +1 -1
- data/app/components/marty/log_view.rb +0 -1
- data/app/components/marty/main_auth_app.rb +9 -12
- data/app/components/marty/promise_view.rb +5 -0
- data/app/components/marty/promise_view/client/promise_view.js +11 -0
- data/app/components/marty/schedule_jobs_dashboard.rb +30 -96
- data/app/components/marty/schedule_jobs_grid.rb +118 -0
- data/app/controllers/marty/application_controller.rb +6 -2
- data/app/models/marty/base.rb +48 -48
- data/app/models/marty/config.rb +14 -2
- data/app/models/marty/user.rb +12 -0
- data/app/services/marty/background_job/fetch_missing_in_schedule_cron_jobs.rb +19 -0
- data/app/services/marty/enums/report.rb +18 -0
- data/app/services/marty/promises/delorean/create.rb +16 -27
- data/app/services/marty/promises/ruby/create.rb +10 -1
- data/app/views/layouts/marty/application.html.erb +4 -1
- data/app/views/marty/diagnostic/op.html.erb +3 -1
- data/config/locales/en.yml +2 -0
- data/db/migrate/512_add_promise_priority.rb +9 -0
- data/db/migrate/513_add_priority_to_promise_view.rb +44 -0
- data/db/migrate/514_remove_marty_events.rb +13 -0
- data/delorean/enum_report.dl +11 -0
- data/delorean/table_report.dl +7 -0
- data/docker-compose.dummy.yml +7 -4
- data/lib/marty.rb +5 -2
- data/lib/marty/api/base.rb +15 -9
- data/lib/marty/cache_adapters.rb +2 -0
- data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -5
- data/lib/marty/cache_adapters/memory_and_redis.rb +93 -0
- data/lib/marty/cache_adapters/redis.rb +63 -0
- data/lib/marty/delayed_job/scheduled_job_plugin.rb +33 -0
- data/lib/marty/diagnostic/database.rb +1 -2
- data/lib/marty/logger.rb +50 -17
- data/lib/marty/monkey.rb +26 -6
- data/lib/marty/promise_ruby_job.rb +2 -0
- data/lib/marty/rails_app.rb +29 -0
- data/lib/marty/railtie.rb +1 -0
- data/lib/marty/version.rb +1 -1
- data/marty.gemspec +1 -0
- data/spec/controllers/job_controller_spec.rb +2 -2
- data/spec/dummy/app/components/gemini/cm_auth_app.rb +12 -0
- data/spec/dummy/app/components/gemini/simple_view.rb +17 -0
- data/spec/dummy/app/jobs/test_failing_job.rb +14 -0
- data/spec/dummy/app/models/gemini/helper.rb +90 -1
- data/spec/dummy/config/application.rb +1 -0
- data/spec/dummy/db/migrate/20191101132729_add_activity_flag_to_simple.rb +10 -0
- data/spec/dummy/delorean/blame_report.dl +1 -0
- data/spec/dummy/delorean/enum_report.dl +1 -0
- data/spec/dummy/delorean/marty_fields.dl +1 -0
- data/spec/dummy/delorean/table_report.dl +1 -0
- data/spec/features/data_blame_report_spec.rb +66 -0
- data/spec/features/data_grid_spec.rb +1 -1
- data/spec/features/enum_values_report_spec.rb +76 -0
- data/spec/features/inline_editing_spec.rb +33 -0
- data/spec/features/rule_spec.rb +1 -1
- data/spec/features/schedule_jobs_dashboard_spec.rb +1 -1
- data/spec/features/scripting_spec.rb +1 -1
- data/spec/features/user_list_report_spec.rb +74 -0
- data/spec/fixtures/misc/struct_compare_tests.txt +15 -5
- data/spec/job_helper.rb +39 -0
- data/spec/jobs/cron_job_spec.rb +91 -0
- data/spec/lib/mcfly_model_spec.rb +9 -0
- data/spec/models/promise_spec.rb +168 -1
- data/spec/other/diagnostic/delayed_job_workers_spec.rb +1 -1
- data/spec/performance/caching_spec.rb +99 -0
- data/spec/services/background_job/fetch_missing_in_schedule_cron_jobs_spec.rb +34 -0
- data/spec/support/delayed_job_helpers.rb +3 -3
- data/spec/support/shared_connection.rb +9 -1
- data/spec/support/structure_compare.rb +19 -3
- metadata +39 -6
- data/app/components/marty/event_view.rb +0 -129
- data/app/models/marty/event.rb +0 -317
- data/spec/dummy/db/migrate/20160923183516_add_bulk_pricing_event_ops.rb +0 -8
- data/spec/dummy/delorean/blame_report.dl +0 -268
- data/spec/dummy/delorean/marty_fields.dl +0 -63
- data/spec/dummy/delorean/table_report.dl +0 -34
- data/spec/models/event_spec.rb +0 -272
@@ -0,0 +1,118 @@
|
|
1
|
+
class Marty::ScheduleJobsGrid < Marty::Grid
|
2
|
+
ACCESSIBLE_BY = [:admin]
|
3
|
+
|
4
|
+
has_marty_permissions(
|
5
|
+
read: ACCESSIBLE_BY,
|
6
|
+
create: ACCESSIBLE_BY,
|
7
|
+
update: ACCESSIBLE_BY,
|
8
|
+
delete: ACCESSIBLE_BY,
|
9
|
+
destroy: ACCESSIBLE_BY,
|
10
|
+
job_run: ACCESSIBLE_BY,
|
11
|
+
edit_window__edit_form__submit: ACCESSIBLE_BY,
|
12
|
+
add_window__add_form__submit: ACCESSIBLE_BY
|
13
|
+
)
|
14
|
+
|
15
|
+
def configure(c)
|
16
|
+
super
|
17
|
+
|
18
|
+
c.title ||= I18n.t('schedule_jobs_dashboard_view_title', default: 'Schedule Jobs Dashboard')
|
19
|
+
c.model = 'Marty::BackgroundJob::Schedule'
|
20
|
+
c.paging = :buffered
|
21
|
+
c.editing = :in_form
|
22
|
+
c.multi_select = false
|
23
|
+
|
24
|
+
c.attributes = [
|
25
|
+
:job_class,
|
26
|
+
:cron,
|
27
|
+
:state
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
def default_context_menu
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
|
35
|
+
def default_bbar
|
36
|
+
super + [:do_job_run]
|
37
|
+
end
|
38
|
+
|
39
|
+
attribute :job_class do |c|
|
40
|
+
c.width = 400
|
41
|
+
end
|
42
|
+
|
43
|
+
attribute :cron do |c|
|
44
|
+
c.width = 400
|
45
|
+
end
|
46
|
+
|
47
|
+
attribute :state do |c|
|
48
|
+
c.width = 150
|
49
|
+
editor_config = {
|
50
|
+
trigger_action: :all,
|
51
|
+
xtype: :combo,
|
52
|
+
store: Marty::BackgroundJob::Schedule::ALL_STATES,
|
53
|
+
forceSelection: true,
|
54
|
+
}
|
55
|
+
|
56
|
+
c.column_config = { editor: editor_config }
|
57
|
+
c.field_config = editor_config
|
58
|
+
end
|
59
|
+
|
60
|
+
action :do_job_run do |a|
|
61
|
+
a.text = 'Run'
|
62
|
+
a.tooltip = 'Run'
|
63
|
+
a.icon_cls = 'fa fa-play glyph'
|
64
|
+
a.disabled = true
|
65
|
+
end
|
66
|
+
|
67
|
+
endpoint :edit_window__edit_form__submit do |params|
|
68
|
+
result = super(params)
|
69
|
+
next result if result.empty?
|
70
|
+
|
71
|
+
obj_hash = result.first
|
72
|
+
Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
|
73
|
+
|
74
|
+
result
|
75
|
+
end
|
76
|
+
|
77
|
+
endpoint :add_window__add_form__submit do |params|
|
78
|
+
result = super(params)
|
79
|
+
next result if result.empty?
|
80
|
+
|
81
|
+
obj_hash = result.first
|
82
|
+
Marty::BackgroundJob::UpdateSchedule.call(id: obj_hash['id'], job_class: obj_hash['job_class'])
|
83
|
+
|
84
|
+
result
|
85
|
+
end
|
86
|
+
|
87
|
+
endpoint :multiedit_window__multiedit_form__submit do |_params|
|
88
|
+
client.netzke_notify 'Multiediting is disabled for cron schedules'
|
89
|
+
end
|
90
|
+
|
91
|
+
endpoint :destroy do |params|
|
92
|
+
res = params.each_with_object({}) do |id, hash|
|
93
|
+
job_class = model.find_by(id: id)&.job_class
|
94
|
+
result = super([id])
|
95
|
+
|
96
|
+
# Do nothing If it wasn't destroyed
|
97
|
+
next hash.merge(result) unless result[id.to_i] == 'ok'
|
98
|
+
|
99
|
+
Marty::BackgroundJob::UpdateSchedule.call(id: id, job_class: job_class)
|
100
|
+
hash.merge(result)
|
101
|
+
end
|
102
|
+
|
103
|
+
res
|
104
|
+
end
|
105
|
+
|
106
|
+
endpoint :job_run do
|
107
|
+
begin
|
108
|
+
s = Marty::BackgroundJob::Schedule.find(client_config['selected'])
|
109
|
+
klass = s.job_class
|
110
|
+
klass.constantize.new.perform
|
111
|
+
rescue StandardError => e
|
112
|
+
next client.netzke_notify(e.message)
|
113
|
+
end
|
114
|
+
client.netzke_notify("#{klass.demodulize} ran successfully.")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
ScheduleJobsGrid = Marty::ScheduleJobsGrid
|
@@ -113,8 +113,8 @@ class Marty::ApplicationController < ActionController::Base
|
|
113
113
|
end
|
114
114
|
|
115
115
|
def failed_authentication(login)
|
116
|
-
|
117
|
-
|
116
|
+
logger.info("Failed authentication for '#{login}' " +
|
117
|
+
"from #{request.remote_ip} at #{Time.now.utc}")
|
118
118
|
end
|
119
119
|
|
120
120
|
def successful_authentication(user)
|
@@ -122,4 +122,8 @@ class Marty::ApplicationController < ActionController::Base
|
|
122
122
|
"from #{request.remote_ip} at #{Time.now.utc}")
|
123
123
|
set_user(user)
|
124
124
|
end
|
125
|
+
|
126
|
+
def toggle_dark_mode
|
127
|
+
cookies[:dark_mode] = cookies[:dark_mode] != 'true'
|
128
|
+
end
|
125
129
|
end
|
data/app/models/marty/base.rb
CHANGED
@@ -2,62 +2,62 @@ class Marty::Base < ActiveRecord::Base
|
|
2
2
|
self.table_name_prefix = 'marty_'
|
3
3
|
self.abstract_class = true
|
4
4
|
|
5
|
-
def self.mcfly_pt(pt)
|
6
|
-
tb = table_name
|
7
|
-
where("#{tb}.obsoleted_dt >= ? AND #{tb}.created_dt < ?", pt, pt)
|
8
|
-
end
|
9
|
-
|
10
5
|
class << self
|
11
6
|
attr_accessor :struct_attrs
|
12
|
-
end
|
13
7
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
8
|
+
def get_struct_attrs
|
9
|
+
self.struct_attrs ||=
|
10
|
+
attribute_names - Mcfly::COLUMNS.to_a -
|
11
|
+
(const_defined?('MCFLY_UNIQUENESS') &&
|
12
|
+
const_get('MCFLY_UNIQUENESS') || []).map(&:to_s)
|
13
|
+
end
|
20
14
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
# otherwise raise with error line
|
26
|
-
raise "Marty::Base: no attributes for #{self}"
|
27
|
-
|
28
|
-
# for more detailed debugging use this code instead
|
29
|
-
# st = caller.detect{|s|s.starts_with?('DELOREAN__')}
|
30
|
-
# re = /DELOREAN__([A-Z][a-zA-Z0-9]*)[:]([0-9]+)[:]in `([a-z_0-9]+)__D'/
|
31
|
-
# m = re.match(st)
|
32
|
-
# if !m
|
33
|
-
# st = "No attributes #{st} #{self}"
|
34
|
-
# puts st unless File.readlines(Rails.root.join('tmp','dlchk')).
|
35
|
-
# map(&:chop).detect{|l|l==st}
|
36
|
-
# else
|
37
|
-
# loc = "#{m[1]}::#{self}::#{m[2]}"
|
38
|
-
# str = "*** No attributes %-40s %-20s %s" % [loc, m[3], attr]
|
39
|
-
# puts str unless File.readlines(Rails.root.join('tmp','dlchk')).
|
40
|
-
# map(&:chop).detect{|l|l==str}
|
41
|
-
# end
|
42
|
-
end
|
15
|
+
def mcfly_pt(pt)
|
16
|
+
tb = table_name
|
17
|
+
where("#{tb}.obsoleted_dt >= ? AND #{tb}.created_dt < ?", pt, pt)
|
18
|
+
end
|
43
19
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
20
|
+
def get_final_attrs
|
21
|
+
final_attrs = get_struct_attrs
|
22
|
+
return final_attrs if final_attrs.present?
|
23
|
+
|
24
|
+
# otherwise raise with error line
|
25
|
+
raise "Marty::Base: no attributes for #{self}"
|
26
|
+
|
27
|
+
# for more detailed debugging use this code instead
|
28
|
+
# st = caller.detect{|s|s.starts_with?('DELOREAN__')}
|
29
|
+
# re = /DELOREAN__([A-Z][a-zA-Z0-9]*)[:]([0-9]+)[:]in `([a-z_0-9]+)__D'/
|
30
|
+
# m = re.match(st)
|
31
|
+
# if !m
|
32
|
+
# st = "No attributes #{st} #{self}"
|
33
|
+
# puts st unless File.readlines(Rails.root.join('tmp','dlchk')).
|
34
|
+
# map(&:chop).detect{|l|l==st}
|
35
|
+
# else
|
36
|
+
# loc = "#{m[1]}::#{self}::#{m[2]}"
|
37
|
+
# str = "*** No attributes %-40s %-20s %s" % [loc, m[3], attr]
|
38
|
+
# puts str unless File.readlines(Rails.root.join('tmp','dlchk')).
|
39
|
+
# map(&:chop).detect{|l|l==str}
|
40
|
+
# end
|
41
|
+
end
|
48
42
|
|
49
|
-
|
50
|
-
|
43
|
+
def make_hash(inst)
|
44
|
+
fa = get_final_attrs
|
45
|
+
inst.attributes.slice(*fa)
|
46
|
+
end
|
51
47
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
48
|
+
def make_openstruct(inst)
|
49
|
+
return nil unless inst
|
50
|
+
|
51
|
+
fa = get_final_attrs
|
52
|
+
os = OpenStruct.new(inst.attributes.slice(*fa))
|
53
|
+
if self == Marty::DataGrid
|
54
|
+
def os.lookup_grid_distinct_entry(pt, params)
|
55
|
+
dgh = to_h.stringify_keys.slice(
|
56
|
+
'id', 'group_id', 'created_dt', 'metadata', 'data_type')
|
57
|
+
Marty::DataGrid.lookup_grid_distinct_entry_h(pt, params, dgh)
|
58
|
+
end
|
59
59
|
end
|
60
|
+
os
|
60
61
|
end
|
61
|
-
os
|
62
62
|
end
|
63
63
|
end
|
data/app/models/marty/config.rb
CHANGED
@@ -23,6 +23,19 @@ class Marty::Config < Marty::Base
|
|
23
23
|
self.value = [v]
|
24
24
|
end
|
25
25
|
|
26
|
+
def self.fetch(*args)
|
27
|
+
unless (1..2).cover?(args.size)
|
28
|
+
raise ArgumentError, 'wrong number of arguments '\
|
29
|
+
"(given #{args.size}, expected 1..2)"
|
30
|
+
end
|
31
|
+
|
32
|
+
entry = find_by_key(args[0])
|
33
|
+
return entry.get_value if entry
|
34
|
+
return args[1] if args.size > 1
|
35
|
+
|
36
|
+
raise KeyError, "key not found: \"#{args[0]}\""
|
37
|
+
end
|
38
|
+
|
26
39
|
def self.[]=(key, value)
|
27
40
|
entry = find_by_key(key)
|
28
41
|
if !entry
|
@@ -36,8 +49,7 @@ class Marty::Config < Marty::Base
|
|
36
49
|
end
|
37
50
|
|
38
51
|
def self.[](key)
|
39
|
-
|
40
|
-
entry and entry.get_value
|
52
|
+
fetch(key, nil)
|
41
53
|
end
|
42
54
|
|
43
55
|
def self.del(key)
|
data/app/models/marty/user.rb
CHANGED
@@ -102,6 +102,18 @@ class Marty::User < Marty::Base
|
|
102
102
|
mr.any? { |ur| ur.role == role }
|
103
103
|
end
|
104
104
|
|
105
|
+
delorean_fn :export_for_report do
|
106
|
+
Marty::User.includes(:user_roles).map do |user|
|
107
|
+
{
|
108
|
+
'login' => user.login,
|
109
|
+
'firstname' => user.firstname,
|
110
|
+
'lastname' => user.lastname,
|
111
|
+
'active' => user.active,
|
112
|
+
'roles' => user.roles.sort.join(', ')
|
113
|
+
}
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
105
117
|
private
|
106
118
|
|
107
119
|
def verify_changes
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Marty
|
2
|
+
module BackgroundJob
|
3
|
+
module FetchMissingInScheduleCronJobs
|
4
|
+
def self.call
|
5
|
+
in_dashboard = Marty::BackgroundJob::Schedule.pluck(:job_class)
|
6
|
+
|
7
|
+
names_conditions = in_dashboard.map do |job_class_name|
|
8
|
+
"%job_class: #{job_class_name}\n%"
|
9
|
+
end
|
10
|
+
|
11
|
+
Delayed::Job.
|
12
|
+
where.not(cron: nil).
|
13
|
+
where.not(cron: '').
|
14
|
+
where("handler ILIKE '%job_class:%'").
|
15
|
+
where.not('handler ILIKE ANY ( array[?] )', names_conditions)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Marty
|
2
|
+
module Enums
|
3
|
+
module Report
|
4
|
+
extend Delorean::Functions
|
5
|
+
|
6
|
+
delorean_fn :call do
|
7
|
+
ActiveRecord::Base.connection.execute(
|
8
|
+
'SELECT
|
9
|
+
t.typname AS enum_name,
|
10
|
+
e.enumlabel AS value
|
11
|
+
FROM pg_type t
|
12
|
+
JOIN pg_enum e ON t.oid = e.enumtypid
|
13
|
+
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace'
|
14
|
+
).to_a
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -5,14 +5,24 @@ module Marty
|
|
5
5
|
def self.call(params:, script:, node_name:, attr:, args:, tag:)
|
6
6
|
default_timeout = Marty::Promise::DEFAULT_PROMISE_TIMEOUT
|
7
7
|
|
8
|
-
|
9
|
-
timeout = params['p_timeout'] || default_timeout
|
10
|
-
hook = params['p_hook']
|
8
|
+
promise_params = params.with_indifferent_access
|
11
9
|
|
10
|
+
title = promise_params['p_title'] || "#{script}::#{node_name.demodulize}"
|
11
|
+
timeout = promise_params['p_timeout'] || default_timeout
|
12
|
+
hook = promise_params['p_hook']
|
13
|
+
|
14
|
+
default_priority = 0
|
15
|
+
pid = promise_params[:_parent_id]
|
16
|
+
if pid
|
17
|
+
ppr = Marty::Promise.find_by(id: pid)
|
18
|
+
default_priority = ppr.priority if ppr
|
19
|
+
end
|
20
|
+
priority = promise_params['p_priority'] || default_priority
|
12
21
|
promise = Marty::Promise.create(
|
13
22
|
title: title,
|
14
|
-
user_id:
|
15
|
-
parent_id:
|
23
|
+
user_id: promise_params[:_user_id],
|
24
|
+
parent_id: promise_params[:_parent_id],
|
25
|
+
priority: priority,
|
16
26
|
promise_type: 'delorean'
|
17
27
|
)
|
18
28
|
|
@@ -30,7 +40,7 @@ module Marty
|
|
30
40
|
hook
|
31
41
|
)
|
32
42
|
|
33
|
-
job = Delayed::Job.enqueue(promise_job)
|
43
|
+
job = Delayed::Job.enqueue(promise_job, priority: priority)
|
34
44
|
rescue StandardError => e
|
35
45
|
# log "CALLERR #{exc}"
|
36
46
|
res = ::Delorean::Engine.grok_runtime_exception(e)
|
@@ -46,27 +56,6 @@ module Marty
|
|
46
56
|
promise.job_id = job.id
|
47
57
|
promise.save!
|
48
58
|
|
49
|
-
evh = params['p_event']
|
50
|
-
if evh
|
51
|
-
event, klass, subject_id, operation = evh.values_at(
|
52
|
-
'event',
|
53
|
-
'klass',
|
54
|
-
'id',
|
55
|
-
'operation'
|
56
|
-
)
|
57
|
-
|
58
|
-
if event
|
59
|
-
event.promise_id = promise.id
|
60
|
-
event.save!
|
61
|
-
else
|
62
|
-
Marty::Event.create!(
|
63
|
-
promise_id: promise.id,
|
64
|
-
klass: klass,
|
65
|
-
subject_id: subject_id,
|
66
|
-
enum_event_operation: operation
|
67
|
-
)
|
68
|
-
end
|
69
|
-
end
|
70
59
|
Marty::PromiseProxy.new(promise.id, timeout, attr)
|
71
60
|
end
|
72
61
|
end
|
@@ -11,10 +11,19 @@ module Marty
|
|
11
11
|
timeout = promise_params['p_timeout'] || default_timeout
|
12
12
|
hook = promise_params['p_hook']
|
13
13
|
|
14
|
+
default_priority = 0
|
15
|
+
pid = promise_params[:_parent_id]
|
16
|
+
if pid
|
17
|
+
ppr = Marty::Promise.find_by(id: pid)
|
18
|
+
default_priority = ppr.priority if ppr
|
19
|
+
end
|
20
|
+
|
21
|
+
priority = promise_params['p_priority'] || default_priority
|
14
22
|
promise = Marty::Promise.create(
|
15
23
|
title: title,
|
16
24
|
user_id: promise_params[:_user_id],
|
17
25
|
parent_id: promise_params[:_parent_id],
|
26
|
+
priority: priority,
|
18
27
|
promise_type: 'ruby'
|
19
28
|
)
|
20
29
|
|
@@ -28,7 +37,7 @@ module Marty
|
|
28
37
|
hook
|
29
38
|
)
|
30
39
|
|
31
|
-
job = Delayed::Job.enqueue(promise_job)
|
40
|
+
job = Delayed::Job.enqueue(promise_job, priority: priority)
|
32
41
|
rescue StandardError => e
|
33
42
|
res = { 'error' => e.message }
|
34
43
|
promise.set_start
|
@@ -5,11 +5,14 @@
|
|
5
5
|
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.2.0/css/all.css"
|
6
6
|
integrity="sha384-hWVjflwFxL6sNzntih27bfxkr27PmbbK/iSvJ+a4+0owXq79v+lsFkW54bOGbiDQ"
|
7
7
|
crossorigin="anonymous">
|
8
|
-
<title><%=
|
8
|
+
<title><%= ::Marty::RailsApp.application_name %></title>
|
9
9
|
<%= load_netzke theme: Rails.configuration.marty.extjs_theme %>
|
10
10
|
<%= csrf_meta_tag %>
|
11
11
|
<%= javascript_include_tag 'marty/application' %>
|
12
12
|
<%= stylesheet_link_tag 'marty/application' %>
|
13
|
+
<% if cookies[:dark_mode] == 'true' %>
|
14
|
+
<%= stylesheet_link_tag 'marty/dark_mode', media: 'all', 'data-turbolinks-track': 'reload' %>
|
15
|
+
<% end %>
|
13
16
|
</head>
|
14
17
|
<body>
|
15
18
|
<%= yield %>
|