trestle 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -0
  3. data/.travis.yml +12 -6
  4. data/CONTRIBUTING.md +38 -0
  5. data/Gemfile +9 -2
  6. data/README.md +5 -0
  7. data/app/assets/bundle/trestle/bundle.css +6 -6
  8. data/app/assets/bundle/trestle/bundle.js +40 -38
  9. data/app/assets/bundle/trestle/fa-brands-400.eot +0 -0
  10. data/app/assets/bundle/trestle/fa-brands-400.svg +41 -41
  11. data/app/assets/bundle/trestle/fa-brands-400.ttf +0 -0
  12. data/app/assets/bundle/trestle/fa-brands-400.woff +0 -0
  13. data/app/assets/bundle/trestle/fa-brands-400.woff2 +0 -0
  14. data/app/assets/bundle/trestle/fa-regular-400.eot +0 -0
  15. data/app/assets/bundle/trestle/fa-regular-400.svg +2 -2
  16. data/app/assets/bundle/trestle/fa-regular-400.ttf +0 -0
  17. data/app/assets/bundle/trestle/fa-regular-400.woff +0 -0
  18. data/app/assets/bundle/trestle/fa-regular-400.woff2 +0 -0
  19. data/app/assets/bundle/trestle/fa-solid-900.eot +0 -0
  20. data/app/assets/bundle/trestle/fa-solid-900.svg +13 -7
  21. data/app/assets/bundle/trestle/fa-solid-900.ttf +0 -0
  22. data/app/assets/bundle/trestle/fa-solid-900.woff +0 -0
  23. data/app/assets/bundle/trestle/fa-solid-900.woff2 +0 -0
  24. data/app/assets/bundle/trestle/flatpickr/ar-dz.js +1 -0
  25. data/app/assets/bundle/trestle/flatpickr/ar.js +1 -1
  26. data/app/assets/bundle/trestle/flatpickr/at.js +1 -1
  27. data/app/assets/bundle/trestle/flatpickr/az.js +1 -1
  28. data/app/assets/bundle/trestle/flatpickr/be.js +1 -1
  29. data/app/assets/bundle/trestle/flatpickr/bg.js +1 -1
  30. data/app/assets/bundle/trestle/flatpickr/bn.js +1 -1
  31. data/app/assets/bundle/trestle/flatpickr/bs.js +1 -1
  32. data/app/assets/bundle/trestle/flatpickr/cat.js +1 -1
  33. data/app/assets/bundle/trestle/flatpickr/ckb.js +1 -0
  34. data/app/assets/bundle/trestle/flatpickr/cs.js +1 -1
  35. data/app/assets/bundle/trestle/flatpickr/cy.js +1 -1
  36. data/app/assets/bundle/trestle/flatpickr/da.js +1 -1
  37. data/app/assets/bundle/trestle/flatpickr/de.js +1 -1
  38. data/app/assets/bundle/trestle/flatpickr/default.js +1 -1
  39. data/app/assets/bundle/trestle/flatpickr/eo.js +1 -1
  40. data/app/assets/bundle/trestle/flatpickr/es.js +1 -1
  41. data/app/assets/bundle/trestle/flatpickr/et.js +1 -1
  42. data/app/assets/bundle/trestle/flatpickr/fa.js +1 -1
  43. data/app/assets/bundle/trestle/flatpickr/fi.js +1 -1
  44. data/app/assets/bundle/trestle/flatpickr/fo.js +1 -1
  45. data/app/assets/bundle/trestle/flatpickr/fr.js +1 -1
  46. data/app/assets/bundle/trestle/flatpickr/ga.js +1 -1
  47. data/app/assets/bundle/trestle/flatpickr/gr.js +1 -1
  48. data/app/assets/bundle/trestle/flatpickr/he.js +1 -1
  49. data/app/assets/bundle/trestle/flatpickr/hi.js +1 -1
  50. data/app/assets/bundle/trestle/flatpickr/hr.js +1 -1
  51. data/app/assets/bundle/trestle/flatpickr/hu.js +1 -1
  52. data/app/assets/bundle/trestle/flatpickr/hy.js +1 -0
  53. data/app/assets/bundle/trestle/flatpickr/id.js +1 -1
  54. data/app/assets/bundle/trestle/flatpickr/is.js +1 -1
  55. data/app/assets/bundle/trestle/flatpickr/it.js +1 -1
  56. data/app/assets/bundle/trestle/flatpickr/ja.js +1 -1
  57. data/app/assets/bundle/trestle/flatpickr/ka.js +1 -1
  58. data/app/assets/bundle/trestle/flatpickr/km.js +1 -1
  59. data/app/assets/bundle/trestle/flatpickr/ko.js +1 -1
  60. data/app/assets/bundle/trestle/flatpickr/kz.js +1 -1
  61. data/app/assets/bundle/trestle/flatpickr/lt.js +1 -1
  62. data/app/assets/bundle/trestle/flatpickr/lv.js +1 -1
  63. data/app/assets/bundle/trestle/flatpickr/mk.js +1 -1
  64. data/app/assets/bundle/trestle/flatpickr/mn.js +1 -1
  65. data/app/assets/bundle/trestle/flatpickr/ms.js +1 -1
  66. data/app/assets/bundle/trestle/flatpickr/my.js +1 -1
  67. data/app/assets/bundle/trestle/flatpickr/nl.js +1 -1
  68. data/app/assets/bundle/trestle/flatpickr/nn.js +1 -0
  69. data/app/assets/bundle/trestle/flatpickr/no.js +1 -1
  70. data/app/assets/bundle/trestle/flatpickr/pa.js +1 -1
  71. data/app/assets/bundle/trestle/flatpickr/pl.js +1 -1
  72. data/app/assets/bundle/trestle/flatpickr/pt.js +1 -1
  73. data/app/assets/bundle/trestle/flatpickr/ro.js +1 -1
  74. data/app/assets/bundle/trestle/flatpickr/ru.js +1 -1
  75. data/app/assets/bundle/trestle/flatpickr/si.js +1 -1
  76. data/app/assets/bundle/trestle/flatpickr/sk.js +1 -1
  77. data/app/assets/bundle/trestle/flatpickr/sl.js +1 -1
  78. data/app/assets/bundle/trestle/flatpickr/sq.js +1 -1
  79. data/app/assets/bundle/trestle/flatpickr/sr-cyr.js +1 -1
  80. data/app/assets/bundle/trestle/flatpickr/sr.js +1 -1
  81. data/app/assets/bundle/trestle/flatpickr/sv.js +1 -1
  82. data/app/assets/bundle/trestle/flatpickr/th.js +1 -1
  83. data/app/assets/bundle/trestle/flatpickr/tr.js +1 -1
  84. data/app/assets/bundle/trestle/flatpickr/uk.js +1 -1
  85. data/app/assets/bundle/trestle/flatpickr/uz.js +1 -1
  86. data/app/assets/bundle/trestle/flatpickr/uz_latn.js +1 -1
  87. data/app/assets/bundle/trestle/flatpickr/vn.js +1 -1
  88. data/app/assets/bundle/trestle/flatpickr/zh-tw.js +1 -1
  89. data/app/assets/bundle/trestle/flatpickr/zh.js +1 -1
  90. data/app/assets/javascripts/trestle/i18n.js.erb +1 -1
  91. data/app/controllers/trestle/dashboard_controller.rb +2 -2
  92. data/app/helpers/trestle/avatar_helper.rb +6 -2
  93. data/app/helpers/trestle/container_helper.rb +12 -4
  94. data/app/helpers/trestle/params_helper.rb +4 -1
  95. data/app/helpers/trestle/url_helper.rb +1 -11
  96. data/app/views/trestle/flash/_alert.html.erb +3 -1
  97. data/app/views/trestle/flash/_debug.html.erb +13 -8
  98. data/app/views/trestle/flash/_flash.html.erb +1 -1
  99. data/config/routes.rb +1 -1
  100. data/frontend/css/components/_alerts.scss +31 -0
  101. data/frontend/css/components/_avatar.scss +14 -0
  102. data/frontend/css/components/_buttons.scss +0 -1
  103. data/frontend/css/components/_datepicker.scss +1 -0
  104. data/frontend/css/components/_modal.scss +2 -0
  105. data/frontend/css/components/_tags.scss +2 -0
  106. data/frontend/css/components/_timestamp.scss +1 -1
  107. data/frontend/css/layout/_sidebar.scss +3 -2
  108. data/frontend/css/variables/_bootstrap.scss +1 -0
  109. data/frontend/css/variables/_trestle.scss +20 -0
  110. data/frontend/js/components/dialog.js +8 -3
  111. data/frontend/theme/trestle/theme/_defaults.scss +4 -4
  112. data/lib/generators/trestle/install/templates/_theme.scss +1 -1
  113. data/lib/generators/trestle/install/templates/trestle.rb.erb +6 -1
  114. data/lib/trestle/adapters/active_record_adapter.rb +16 -0
  115. data/lib/trestle/form/automatic.rb +2 -0
  116. data/lib/trestle/form/field.rb +1 -1
  117. data/lib/trestle/form/renderer.rb +4 -1
  118. data/lib/trestle/registry.rb +61 -0
  119. data/lib/trestle/reloader.rb +1 -1
  120. data/lib/trestle/table/automatic.rb +7 -0
  121. data/lib/trestle/version.rb +1 -1
  122. data/lib/trestle.rb +29 -14
  123. data/package.json +20 -23
  124. data/webpack.config.js +36 -48
  125. data/yarn.lock +2947 -4595
  126. metadata +9 -3
@@ -2,6 +2,6 @@
2
2
  <%= render "trestle/flash/alert", html_class: "alert-success", icon: icon("alert-icon far fa-check-circle"), alert: normalize_flash_alert(flash[:message]) %>
3
3
  <% elsif flash[:error] -%>
4
4
  <%= render layout: "trestle/flash/alert", locals: { html_class: "alert-danger", icon: icon("alert-icon far fa-times-circle"), alert: normalize_flash_alert(flash[:error]) } do %>
5
- <%= render "trestle/flash/debug" if debug_form_errors? %>
5
+ <%= render "trestle/flash/debug", errors: instance.errors if debug_form_errors? %>
6
6
  <% end %>
7
7
  <% end -%>
data/config/routes.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  Trestle::Engine.routes.draw do
2
- Trestle.admins.each do |name, admin|
2
+ Trestle.registry.each do |admin|
3
3
  instance_eval(&admin.routes)
4
4
  end
5
5
 
@@ -32,13 +32,18 @@
32
32
 
33
33
  .alert-icon {
34
34
  margin-right: $alert-padding-x;
35
+
35
36
  font-size: 40px;
37
+ width: 40px;
38
+
39
+ text-align: center;
36
40
 
37
41
  @include media-breakpoint-down(sm) {
38
42
  margin-left: $alert-padding-x * 0.25;
39
43
  margin-right: $alert-padding-x * 0.75;
40
44
 
41
45
  font-size: 32px;
46
+ width: 32px;
42
47
  }
43
48
  }
44
49
 
@@ -74,10 +79,16 @@
74
79
  border-color: $border;
75
80
 
76
81
  a {
82
+ color: $color;
83
+
77
84
  &:hover, &:focus {
78
85
  color: mix($color, $background, 80%);
79
86
  }
80
87
  }
88
+
89
+ code {
90
+ color: $color;
91
+ }
81
92
  }
82
93
 
83
94
  .alert-success {
@@ -88,6 +99,26 @@
88
99
  @include alert-variant($alert-danger-bg, $alert-danger-border, $alert-danger-color);
89
100
  }
90
101
 
102
+ .alert-info {
103
+ @include alert-variant($alert-info-bg, $alert-info-border, $alert-info-color);
104
+ }
105
+
106
+ .alert-warning {
107
+ @include alert-variant($alert-warning-bg, $alert-warning-border, $alert-warning-color);
108
+ }
109
+
110
+ .alert-light {
111
+ @include alert-variant($alert-light-bg, $alert-light-border, $alert-light-color);
112
+ }
113
+
114
+ .alert-dark {
115
+ @include alert-variant($alert-dark-bg, $alert-dark-border, $alert-dark-color);
116
+ }
117
+
118
+ .alert-primary {
119
+ @include alert-variant($alert-primary-bg, $alert-primary-border, $alert-primary-color);
120
+ }
121
+
91
122
 
92
123
  // Debug errors
93
124
 
@@ -41,3 +41,17 @@
41
41
  font-weight: 500;
42
42
  }
43
43
  }
44
+
45
+ .avatar-sm {
46
+ width: 24px !important;
47
+ height: 24px !important;
48
+ }
49
+
50
+ .avatar-lg {
51
+ width: 64px !important;
52
+ height: 64px !important;
53
+
54
+ .avatar-fallback {
55
+ font-size: 1.5rem;
56
+ }
57
+ }
@@ -1,5 +1,4 @@
1
1
  .btn {
2
- border-width: 0;
3
2
  box-shadow: none;
4
3
 
5
4
  &.loading {
@@ -13,6 +13,7 @@
13
13
 
14
14
  &:hover, &:focus {
15
15
  color: #aaa;
16
+ text-decoration: none;
16
17
  }
17
18
 
18
19
  &::before {
@@ -24,6 +24,8 @@
24
24
  }
25
25
 
26
26
  &.background {
27
+ overflow-y: hidden;
28
+
27
29
  .modal-dialog {
28
30
  transform: scale(0.9);
29
31
  opacity: 0.75;
@@ -16,6 +16,8 @@
16
16
  }
17
17
 
18
18
  a.tag {
19
+ font-weight: inherit;
20
+
19
21
  &:hover, &:focus {
20
22
  text-decoration: none;
21
23
  color: $tag-hover-color;
@@ -4,7 +4,7 @@
4
4
 
5
5
  small {
6
6
  display: block;
7
- color: #666;
7
+ opacity: 0.75;
8
8
  }
9
9
 
10
10
  &.timestamp-inline,
@@ -16,11 +16,13 @@
16
16
  height: $header-height;
17
17
 
18
18
  display: flex;
19
- align-items: center;
19
+ align-items: stretch;
20
20
 
21
21
  .navbar-toggler {
22
22
  outline: none;
23
23
 
24
+ align-self: center;
25
+
24
26
  margin-left: $grid-gutter-width / 2;
25
27
  margin-right: $grid-gutter-width / 2;
26
28
 
@@ -44,7 +46,6 @@
44
46
  display: flex;
45
47
  align-items: center;
46
48
 
47
- height: 100%;
48
49
  padding: 10px 15px;
49
50
 
50
51
  font-size: 1.4rem;
@@ -7,6 +7,7 @@ $theme-colors: (
7
7
  "warning": #f3bd71,
8
8
  "danger": #e17572,
9
9
  "light": #bbbbbb,
10
+ "dark": #444444,
10
11
 
11
12
  // Backwards compatibility
12
13
  "default": #bbbbbb
@@ -101,6 +101,26 @@ $alert-danger-bg: #de7471;
101
101
  $alert-danger-color: white;
102
102
  $alert-danger-border: #d85956;
103
103
 
104
+ $alert-info-bg: darken(theme-color("info"), 10%);
105
+ $alert-info-color: white;
106
+ $alert-info-border: darken($alert-info-bg, 10%);
107
+
108
+ $alert-warning-bg: darken(theme-color("warning"), 5%);
109
+ $alert-warning-color: white;
110
+ $alert-warning-border: darken($alert-warning-bg, 5%);
111
+
112
+ $alert-light-bg: theme-color("light");
113
+ $alert-light-color: $body-color;
114
+ $alert-light-border: darken($alert-light-bg, 5%);
115
+
116
+ $alert-dark-bg: theme-color("dark");
117
+ $alert-dark-color: white;
118
+ $alert-dark-border: darken($alert-dark-bg, 10%);
119
+
120
+ $alert-primary-bg: darken(theme-color("primary"), 5%);
121
+ $alert-primary-color: white;
122
+ $alert-primary-border: darken($alert-primary-bg, 10%);
123
+
104
124
 
105
125
  // Modals
106
126
 
@@ -20,14 +20,19 @@ function createElement () {
20
20
  focus: false
21
21
  })
22
22
 
23
- // Remove dialog elements once hidden
24
23
  $el.on('hidden.bs.modal', function () {
24
+ // Restore modal-open class on body if background modals still visible
25
+ if ($el.prevAll('.modal.show').length) {
26
+ $(document.body).addClass('modal-open')
27
+ }
28
+
29
+ // Remove dialog elements once hidden
25
30
  $el.remove()
26
31
  })
27
32
 
28
33
  // Restore the next visible modal to the foreground
29
34
  $el.on('hide.bs.modal', function () {
30
- $el.prevAll('.modal.in').last().removeClass('background')
35
+ $el.prevAll('.modal.show').last().removeClass('background')
31
36
  })
32
37
 
33
38
  // Set X-Trestle-Dialog header on AJAX requests initiated from the dialog
@@ -120,7 +125,7 @@ export default class Dialog {
120
125
  this.$el.modal('show')
121
126
 
122
127
  // Background any existing visible modals
123
- this.$el.prevAll('.modal.in').addClass('background')
128
+ this.$el.prevAll('.modal.show').addClass('background')
124
129
  }
125
130
 
126
131
  hide () {
@@ -8,7 +8,7 @@ $theme-colors: (
8
8
  $theme-color-interval: 8% !default;
9
9
 
10
10
  // The yiq lightness value that determines when the lightness of color changes from "dark" to "light". Acceptable values are between 0 and 255.
11
- $yiq-contrasted-threshold: 150 !default;
11
+ $yiq-contrasted-threshold: 175 !default;
12
12
 
13
13
  // Customize the light and dark text colors for use in our YIQ color contrast function.
14
14
  $yiq-text-dark: #212529 !default;
@@ -115,9 +115,9 @@ $badge-focus-width: $input-btn-focus-width !default;
115
115
 
116
116
  // Alerts
117
117
 
118
- $alert-bg-level: -10 !default;
119
- $alert-border-level: -9 !default;
120
- $alert-color-level: 6 !default;
118
+ $alert-bg-level: 2 !default;
119
+ $alert-border-level: 3 !default;
120
+ $alert-color-level: -12 !default;
121
121
 
122
122
 
123
123
  // Progress bars
@@ -9,5 +9,5 @@
9
9
  //
10
10
  // $theme-colors: (
11
11
  // "primary": #337ab7,
12
- // "secondary": #b3b53d
12
+ // "secondary": #719dc3
13
13
  // );
@@ -15,7 +15,7 @@ Trestle.configure do |config|
15
15
  #
16
16
  # config.site_logo_small = "logo-small.png"
17
17
 
18
- # Speficy a favicon to be used within the admin.
18
+ # Specify a favicon to be used within the admin.
19
19
  #
20
20
  # config.favicon = "favicon.ico"
21
21
 
@@ -103,6 +103,11 @@ Trestle.configure do |config|
103
103
  #
104
104
  # config.persistent_params << :query
105
105
 
106
+ # List of methods to try calling on an instance when displayed by the `display` helper.
107
+ # Defaults to [:display_name, :full_name, :name, :title, :username, :login, :email].
108
+ #
109
+ # config.display_methods.unshift(:admin_label)
110
+
106
111
  # Customize the default adapter class used by all admin resources.
107
112
  # See the documentation on Trestle::Adapters::Adapter for details on
108
113
  # the adapter methods that can be customized.
@@ -60,6 +60,8 @@ module Trestle
60
60
  Attribute::Association.new(column.name, class: -> { reflection.klass }, name: name, polymorphic: reflection.polymorphic?, type_column: reflection.foreign_type)
61
61
  elsif column.name.end_with?("_type") && (name = column.name.sub(/_type$/, '')) && (reflection = model.reflections[name])
62
62
  # Ignore type columns for polymorphic associations
63
+ elsif enum_column?(column)
64
+ Attribute.new(column.name, :enum, values: enum_values(column))
63
65
  else
64
66
  Attribute.new(column.name, column.type, array_column?(column) ? { array: true } : {})
65
67
  end
@@ -81,6 +83,20 @@ module Trestle
81
83
  def array_column?(column)
82
84
  column.respond_to?(:array?) && column.array?
83
85
  end
86
+
87
+ def enum_column?(column)
88
+ model.defined_enums.key?(column.name)
89
+ end
90
+
91
+ def enum_values(column)
92
+ model.defined_enums[column.name].map { |key, value|
93
+ [value, enum_human_name(column, key)]
94
+ }
95
+ end
96
+
97
+ def enum_human_name(column, value)
98
+ human_attribute_name([column.name.pluralize, value].join("."), default: value.humanize)
99
+ end
84
100
  end
85
101
  end
86
102
  end
@@ -32,6 +32,8 @@ module Trestle
32
32
  datetime_field attribute.name
33
33
  when :boolean
34
34
  check_box attribute.name
35
+ when :enum
36
+ collection_radio_buttons attribute.name, attribute.options[:values] || [], :first, :last
35
37
  when :json, :jsonb
36
38
  value = instance.public_send(attribute.name)
37
39
  text_area attribute.name, value: value.try(:to_json)
@@ -45,7 +45,7 @@ module Trestle
45
45
  end
46
46
 
47
47
  def readonly?
48
- options[:readonly] || admin.readonly?
48
+ options[:readonly] || admin.try(:readonly?)
49
49
  end
50
50
 
51
51
  def normalize_options!
@@ -4,6 +4,9 @@ require "action_view/helpers"
4
4
  module Trestle
5
5
  class Form
6
6
  class Renderer
7
+ def self.ruby2_keywords(*)
8
+ end unless respond_to?(:ruby2_keywords, true)
9
+
7
10
  include ::ActionView::Context
8
11
  include ::ActionView::Helpers::CaptureHelper
9
12
 
@@ -40,7 +43,7 @@ module Trestle
40
43
  concat(result)
41
44
  end
42
45
 
43
- def method_missing(name, *args, &block)
46
+ ruby2_keywords def method_missing(name, *args, &block)
44
47
  target = @form.respond_to?(name) ? @form : @template
45
48
 
46
49
  if block_given? && !RAW_BLOCK_HELPERS.include?(name)
@@ -0,0 +1,61 @@
1
+ module Trestle
2
+ class Registry
3
+ include Enumerable
4
+
5
+ # The admins hash is left exposed for backwards compatibility
6
+ attr_reader :admins
7
+
8
+ def initialize
9
+ reset!
10
+ end
11
+
12
+ def each(&block)
13
+ @admins.values.sort_by(&:admin_name).each(&block)
14
+ end
15
+
16
+ def reset!
17
+ @admins = {}
18
+ @models = {}
19
+ end
20
+
21
+ def empty?
22
+ none?
23
+ end
24
+
25
+ def register(admin, register_model: true)
26
+ @admins[admin.admin_name] = admin
27
+
28
+ if register_model && register_admin_for_model_loookup?(admin)
29
+ @models[admin.model.name] ||= admin
30
+ end
31
+
32
+ admin
33
+ end
34
+
35
+ def lookup_admin(admin)
36
+ # Given object is already an admin class
37
+ return admin if admin.is_a?(Class) && admin < Trestle::Admin
38
+
39
+ @admins[admin.to_s]
40
+ end
41
+ alias lookup lookup_admin
42
+
43
+ def lookup_model(model)
44
+ # Lookup each class in the model's ancestor chain
45
+ while model
46
+ admin = @models[model.name]
47
+ return admin if admin
48
+
49
+ model = model.superclass
50
+ end
51
+
52
+ # No admin found
53
+ nil
54
+ end
55
+
56
+ private
57
+ def register_admin_for_model_loookup?(admin)
58
+ admin.respond_to?(:model) && !(admin.respond_to?(:singular?) && admin.singular?)
59
+ end
60
+ end
61
+ end
@@ -26,7 +26,7 @@ module Trestle
26
26
  end
27
27
 
28
28
  def clear
29
- Trestle.admins = {}
29
+ Trestle.registry.reset!
30
30
  end
31
31
 
32
32
  def load_paths
@@ -14,6 +14,13 @@ module Trestle
14
14
  case attribute.type
15
15
  when :association
16
16
  Column.new(attribute.association_name, sort: false)
17
+ when :enum
18
+ Column.new(attribute.name, align: :center, sort: attribute.name) do |instance|
19
+ if value = instance.public_send(attribute.name)
20
+ full_attribute_name = [attribute.name.to_s.pluralize, value].join(".")
21
+ status_tag(admin.human_attribute_name(full_attribute_name, default: value.humanize))
22
+ end
23
+ end
17
24
  else
18
25
  Column.new(attribute.name, link: index.zero?, align: (:center if [:datetime, :boolean].include?(attribute.type)))
19
26
  end
@@ -1,3 +1,3 @@
1
1
  module Trestle
2
- VERSION = "0.9.5"
2
+ VERSION = "0.9.6"
3
3
  end
data/lib/trestle.rb CHANGED
@@ -23,27 +23,29 @@ module Trestle
23
23
  require_relative "trestle/tab"
24
24
  require_relative "trestle/table"
25
25
  require_relative "trestle/admin"
26
+ require_relative "trestle/registry"
26
27
  require_relative "trestle/resource"
27
28
 
28
- mattr_accessor :admins
29
- self.admins = {}
29
+ # The registry records all active Trestle admins and facilitates lookups.
30
+ mattr_accessor :registry
31
+ self.registry = Registry.new
30
32
 
31
- def self.admin(name, options={}, &block)
32
- register(Admin::Builder.create(name, options, &block))
33
+ class << self
34
+ # Expose registry methods on Trestle module
35
+ delegate :register, :lookup, :lookup_model, :admins, to: :registry
33
36
  end
34
37
 
35
- def self.resource(name, options={}, &block)
36
- register(Resource::Builder.create(name, options, &block))
38
+ # Builds and registers a new plain admin
39
+ def self.admin(name, **options, &block)
40
+ register(Admin::Builder.create(name, options, &block))
37
41
  end
38
42
 
39
- def self.register(admin)
40
- self.admins[admin.admin_name] = admin
43
+ # Builds and registers a new admin resource
44
+ def self.resource(name, register_model: true, **options, &block)
45
+ register(Resource::Builder.create(name, options, &block), register_model: register_model)
41
46
  end
42
47
 
43
- def self.lookup(admin)
44
- return admin if admin.is_a?(Class) && admin < Trestle::Admin
45
- self.admins[admin.to_s]
46
- end
48
+ # Configuration methods
47
49
 
48
50
  def self.config
49
51
  @configuration ||= Configuration.new
@@ -53,14 +55,27 @@ module Trestle
53
55
  config.configure(&block)
54
56
  end
55
57
 
58
+ # Builds the global navigation by combining the menu options from the
59
+ # Trestle configuration along with menu blocks from admin resources.
56
60
  def self.navigation(context)
57
- blocks = config.menus + admins.values.map(&:menu).compact
61
+ blocks = config.menus + registry.map(&:menu).compact
58
62
  Navigation.build(blocks, context)
59
63
  end
60
64
 
65
+ # Returns the I18n fallbacks for the given locale.
66
+ #
67
+ # This is used from within a Sprockets asset (JavaScript)
68
+ # to determine which locale files to include.
69
+ #
70
+ # Examples
71
+ #
72
+ # Trestle.i18n_fallbacks("pt-BR") => ["pt-BR", "pt"]
73
+ # Trestle.i18n_fallbacks("ca") => ["ca", "es-ES", "es"] %>
74
+ #
75
+ # Returns an array of locale Strings.
61
76
  def self.i18n_fallbacks(locale=I18n.locale)
62
77
  if I18n.respond_to?(:fallbacks)
63
- I18n.fallbacks[locale]
78
+ I18n.fallbacks[locale].map(&:to_s)
64
79
  elsif locale.to_s.include?("-")
65
80
  fallback = locale.to_s.split("-").first
66
81
  [locale, fallback]
data/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trestle",
3
- "version": "0.9.0",
3
+ "version": "0.9.6",
4
4
  "description": "A modern, responsive admin framework for Ruby on Rails",
5
5
  "homepage": "https://trestle.io",
6
6
  "repository": "https://github.com/TrestleAdmin/trestle.git",
@@ -13,36 +13,33 @@
13
13
  "watch": "webpack --mode development --watch"
14
14
  },
15
15
  "devDependencies": {
16
- "@babel/core": "^7.6.0",
17
- "@babel/preset-env": "^7.6.0",
18
- "autoprefixer": "^9.6.1",
16
+ "@babel/core": "^7.14.6",
17
+ "@babel/preset-env": "^7.14.7",
18
+ "autoprefixer": "^10.2.6",
19
19
  "babel-loader": "^8.0.6",
20
- "copy-webpack-plugin": "^5.0.4",
21
- "css-loader": "^3.2.0",
22
- "expose-loader": "^0.7.5",
23
- "file-loader": "^6.0.0",
24
- "mini-css-extract-plugin": "^0.9.0",
25
- "node-sass": "^4.14.1",
26
- "optimize-css-assets-webpack-plugin": "^5.0.3",
27
- "postcss-loader": "^3.0.0",
28
- "sass-loader": "^8.0.0",
29
- "uglify-js": "^3.9.3",
30
- "uglifyjs-webpack-plugin": "^2.2.0",
31
- "url-loader": "^4.1.0",
32
- "webpack": "^4.40.2",
33
- "webpack-cli": "^3.3.9"
20
+ "copy-webpack-plugin": "^9.0.1",
21
+ "css-loader": "^5.2.6",
22
+ "css-minimizer-webpack-plugin": "^3.0.2",
23
+ "expose-loader": "^3.0.0",
24
+ "mini-css-extract-plugin": "^2.0.0",
25
+ "node-sass": "^7.0.1",
26
+ "postcss": "^8.3.5",
27
+ "postcss-loader": "^6.1.1",
28
+ "sass-loader": "^12.1.0",
29
+ "webpack": "^5.42.0",
30
+ "webpack-cli": "^4.7.2"
34
31
  },
35
32
  "dependencies": {
36
- "@fortawesome/fontawesome-free": "^5.11.1",
37
- "@rails/ujs": "^6.0.3",
33
+ "@fortawesome/fontawesome-free": "^5.15.3",
34
+ "@rails/ujs": "^6.1.3-1",
38
35
  "bootstrap": "^4.5.0",
39
- "bootstrap-confirmation2": "^4.1.0",
36
+ "bootstrap-confirmation2": "^4.2.1",
40
37
  "bs-custom-file-input": "^1.3.2",
41
38
  "flatpickr": "^4.6.2",
42
- "jquery": "^3.5.1",
39
+ "jquery": "^3.6.0",
43
40
  "magnific-popup": "^1.1.0",
44
41
  "popper.js": "^1.15.0",
45
42
  "select2": "^4.0.10",
46
- "select2-theme-bootstrap4": "^0.2.0-beta.4"
43
+ "select2-theme-bootstrap4": "^1.0.0"
47
44
  }
48
45
  }