kadmin 0.1.7 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +9 -1
- data/app/assets/stylesheets/kadmin/application.scss +9 -0
- data/app/assets/stylesheets/kadmin/{finder.scss → typeahead-select.scss} +0 -0
- data/app/decorators/kadmin/finder_decorator.rb +33 -0
- data/app/decorators/kadmin/pager_decorator.rb +33 -0
- data/app/views/kadmin/components/_finder.html.erb +18 -0
- data/app/views/kadmin/components/finder/_empty.html.erb +3 -0
- data/app/views/kadmin/components/finder/_form.erb +10 -0
- data/app/views/kadmin/components/finder/_header.html.erb +7 -0
- data/app/views/kadmin/{_alerts.html.erb → helpers/_alerts.html.erb} +0 -0
- data/app/views/kadmin/helpers/_form_errors.html.erb +10 -0
- data/app/views/layouts/kadmin/application.html.erb +2 -2
- data/config/locales/de.yml +5 -0
- data/config/locales/en.yml +5 -0
- data/lib/kadmin/finder.rb +15 -6
- data/lib/kadmin/form.rb +94 -44
- data/lib/kadmin/pager.rb +14 -3
- data/lib/kadmin/version.rb +1 -1
- data/test/dummy/app/controllers/admin/application_controller.rb +1 -1
- data/test/dummy/app/controllers/admin/{persons_controller.rb → people_controller.rb} +23 -20
- data/test/dummy/app/models/person.rb +6 -1
- data/test/dummy/app/views/admin/people/_form.html.erb +34 -0
- data/test/dummy/app/views/admin/people/_table.html.erb +33 -0
- data/test/dummy/app/views/admin/people/edit.html.erb +4 -0
- data/test/dummy/app/views/admin/people/index.html.erb +3 -0
- data/test/dummy/app/views/admin/people/new.html.erb +5 -0
- data/test/dummy/app/views/admin/people/show.html.erb +3 -0
- data/test/dummy/config/application.rb +6 -0
- data/test/dummy/config/locales/en.yml +13 -25
- data/test/dummy/config/routes.rb +2 -3
- data/test/dummy/db/dummy_development.sqlite3 +0 -0
- data/test/dummy/db/dummy_test.sqlite3 +0 -0
- data/test/dummy/db/migrate/20161006114509_create_people.rb +1 -1
- data/test/dummy/db/schema.rb +1 -1
- data/test/dummy/lib/forms/group_form.rb +1 -13
- data/test/dummy/lib/forms/person_form.rb +4 -13
- data/test/dummy/log/development.log +12819 -0
- data/test/dummy/log/test.log +38 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/-F/-FsNbFK52v0pNBxKy1HNNm6PvilpJ-x7Wnv9h6tmyB0.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/0n/0n6SGYdqNeEUJSsu-imL90L-yIUKPi_NDSkmMySPdWQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/0t/0tn2q8esWnF5fEcbJLYg62c_FP9JanA9PSXdq_tYLYY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/1I/1IRm2UzZL2EDGDrmidisFycmYvgjxsm88Qhn2Xgpob8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/1M/1MqoHGqxGd5cjs2GFOFxmpuvnUUEqu7VgvlhIQiJyOg.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/55/55XufN8FnqyYo8_Q9Fjekgd9NNgLIf51DyqmHCunvXE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/5i/5i0sweEEf0_vvcK_Zu6WD6pyCfLIOQE-861C6dFShUY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/63/637_sfmF7zODk6Dzv4BT1sf91iXjjlcxAvnToFqUlDI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/6M/6MU_r-ycVrZjzTQTJGMi6ufWq8z7emfSF41_aIN-KB8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/7q/7qsE29MVuPYwZNAgNwNeH8xVhpOsc_b6ieDbhbhvqpw.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/8P/8PiD2jpkOTKwCqmTucDpZfcaYIoDaLpRmCTDikmBAMk.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/8T/8TAB-jrsQAvLWhG3fwfbx6ZVwjI7j6sAWWQTfPn91iU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/8g/8gcjIdXkz5dMqwDP6vmyotAcXH7cn0PUj3_5Wmp3CtI.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/8m/8m_OIflQITiNEo__Te4xgHNCGjqG1584BRqm-cjmjcs.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/9L/9LEx970_JauYhUWfuivS75eV0Iyfbt9ubccTHIsAfYw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/9_/9_pVK00xoiNV1Rlusq__AhBd-RI2wkk8CYsmetStEr0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/9y/9yz1HSty42fFgm9G7oOB99fA470iGKKnSXO5t5PEHXw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/C_/C_apQOWNpEW8SnzKgrc57IADlEkNTHj8h_oDFtY9064.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Cy/Cy_UGoqxMmEq4sj5RxYjcR-aIdYvnjZvP_Pnrz1_9e8.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/DP/DPzrQSMXLpVyt0hbMLGC5DJZyW9kFE4CP0vt6WNOp48.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/GW/GW4OJ-JDKmC4uwvYKzjrIhVq-P4t_9zaLGKSydO1f-U.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/H8/H8slRzi1H2WqciDo1jBGxJw6DZeRgEuv5MXdQ-y6mWg.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Iy/IyL_kOqVN1xwoPTt5LY6WW15l0RdXMbqH4eG9BIy9eo.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Iy/IyfLjIElmUEnBz0fjO4ofGF04F_HqLxAbuft8mp0yBU.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/JR/JRJaUThDzGQo0YF40Lfk5goZBKJKxJJBtxXLmxwRx2w.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Lf/Lf6bmdizyOM18a9qBS2SAloyVi3kwlh5LDQ9rf09AVs.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Lf/lFitMap7CRaoT13khB0t9biKi45L1Gx053Qqb0V7xZ0.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/NL/NLORenk-WvjF2ETu3Vd8oPQSkm56nqI0w4FNB4PlOhw.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/O3/o3x01lJRlMuBMc1c5TIFuEysbQ5hJ-u8oDEu3O8LYpM.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Oe/Oe-3DQv4rb1wBwCSKfPxsFWLQEG2uwzsN3r1NlhUtGg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/QR/qrn7imioXU-GzX_YDKunySyxOQQPdYnm8cFRc9_0Bbg.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Qk/qK1FqgxCmejbunaDgFtqgzegZ-MWYa9sGmkdsy2hXbg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Sj/Sj9P9v_5nRDm_FbYyYHC7B00vqxjZxYc27y9Cm2vpb4.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/UG/UGW_N3c5WIGHIsGBAlRBI-sD2QLfW6LMGFiCsdfC2xE.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/VZ/VZjlQNeP2hr_AciJNPbb7z4G6K4AKe3Z0gn4WdC7-Tc.cache +3 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/WK/WKjVrAg3EXJ83bQHhANNBB8gXiSSQwcWJfzQUOrfly4.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/WS/WSKgaB4x1F6sDxk0fM4Fk8nA4EVyHSSJesu1-X82yjQ.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/YY/YyJCDg1eiYs1CZSWGv3k7E8PC2u8ujMHnHruKAZB_ns.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/Yt/ytqIuGGRQKNExye5HUeNNpLiTb2bz_DUdCNF-PNgG5s.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/ZN/ZNsrQk4C9XhLrV8_ccxeh7iUpUxCU8p6HzJnLQ1JzTs.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/_c/_chctmRf-pIheCJNY7hl-Sx59opmqdxFL2PevfZwq2o.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/a2/a2cuBhgUfDqIn_cESf3bZCYgOfUL1pr90zUxIqJ9kKk.cache +2 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/aP/aPmiEIWGz1eNfYaCxOihmOj8gH_FiMuy2vyfa2dSm74.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/br/BRgaKx5w_y5SAfZ01RZMdp6Z7-ggaICbwPGgGGYnMvo.cache +4 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/cc/cc_H3Ys29GBr0Mwo8mhwVpU1ZD29Orm_zrrlsK04ZxY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/cp/cpltkoEnlCxGELgo5pzYraQtUFtncB66ULMh61y9UmU.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/d2/d2pyKhpApMC_82fcSpBr3rJiQi0GXmd5nAxW4gjjbqI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/dG/DgWTCx-Rb2jbSHoEnFqjHWsBClV-3r80EPU7mB2IOlg.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/fb/fbnO4L8jq7mKY_872G6-R_1g55VkHGsFLV5_L9N_8JY.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/gK/gKggrFUEs3kvWMzHpuEICvH6zL86Giqv50EMpi91rUk.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/n1/n1pvlbASbj39sCgVSMFGCy33gQAhAGlLscNk8Q_hGA0.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/r8/r8Tej1MuIktw1pbDz86gRXteeQymjEsgGYzC6nBpwxI.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/tK/tKjzj5lmM8TAi-WoE8QAQEBI5vJv7bmYYxuEH1UXb9c.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/tb/TbBwthojLrWKVI_yFccgzGN9cXRY9iHGWVV3lr8uXTM.cache +1 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/tq/TQpnYfdZO_10UMuNVcEY29LaqvuW8gtzhA6qvSt4iQM.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/u7/u75Pn-UKc5QtTrPD6IPz43HZYUDrevf8iMkv7_LabOA.cache +0 -0
- data/test/dummy/tmp/cache/assets/sprockets/v3.0/zE/zEE95VsN7pfJ2w6HuECxe6KtA0vg0I7liX2HuPK92Tk.cache +1 -0
- metadata +137 -14
- data/test/dummy/app/views/admin/persons/_form.html.erb +0 -0
- data/test/dummy/app/views/admin/persons/edit.html.erb +0 -0
- data/test/dummy/app/views/admin/persons/index.html.erb +0 -0
- data/test/dummy/app/views/admin/persons/new.html.erb +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6ab1df6f025d446075d7ea0ff8e6f5e6267e5048
|
|
4
|
+
data.tar.gz: e01b485202b100b31014c57680fe99ded5017518
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 221c1f51318638636bbafbd2c7dd135cd21f69f0cf4df6edbd97be4eda02ee07e2b3013a041aa9138b4c106eaf296747f0139ee7df80d6ff1e7392260cbd944e
|
|
7
|
+
data.tar.gz: cbc7767909e0b85ff93f7fa6ee6a08d4d03d57ac4ad0db975b35f9d8b79fd17bc487f290313c25f8e3f712aadb0fc4f588583f572631cb081984632b6f7926ef
|
data/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Kadmin
|
|
2
2
|
|
|
3
|
-
[](https://github.com/barcoo/kadmin/releases/tag/0.2.2)
|
|
4
4
|
|
|
5
5
|
Collection of utility, configuration, etc., for admin areas in different projects.
|
|
6
6
|
|
|
@@ -33,3 +33,11 @@ When you want to create a new release, use the rake task ```cim:release``` (in t
|
|
|
33
33
|
```shell
|
|
34
34
|
bundle exec rake cim:release
|
|
35
35
|
```
|
|
36
|
+
|
|
37
|
+
## Roadmap
|
|
38
|
+
|
|
39
|
+
TODOs:
|
|
40
|
+
|
|
41
|
+
* [ ] Finish form objects (destruction and creation) + tests + examples
|
|
42
|
+
* [ ] Make a generic typehead-select form object
|
|
43
|
+
* [x] Wrap Finder objects + view helpers
|
|
@@ -2,6 +2,15 @@
|
|
|
2
2
|
@import "bootstrap-sprockets";
|
|
3
3
|
@import "bootstrap";
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Highlights fields properly when they have errors
|
|
7
|
+
* Rails automatically appends .field_with_errors on any form element whose model
|
|
8
|
+
* attributes has an error (as marked in model.errors)
|
|
9
|
+
*/
|
|
10
|
+
.field_with_errors {
|
|
11
|
+
@extend .has-error;
|
|
12
|
+
}
|
|
13
|
+
|
|
5
14
|
a.thumbnail {
|
|
6
15
|
max-width: 100%;
|
|
7
16
|
overflow: hidden;
|
|
File without changes
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Kadmin
|
|
2
|
+
class FinderDecorator
|
|
3
|
+
# @return [Kadmin::Finder] underlying finder model
|
|
4
|
+
attr_reader :finder
|
|
5
|
+
|
|
6
|
+
delegate :filters, :scope, :results, to: :finder
|
|
7
|
+
|
|
8
|
+
def initialize(finder)
|
|
9
|
+
@finder = finder
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# @return [String] human readable, singular/plural form of the finder's model
|
|
13
|
+
def resource_name
|
|
14
|
+
return @finder.scope.model_name.human(count: pager.displayed_items)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# @return [String] a description of the current applied filters
|
|
18
|
+
def applied_filters
|
|
19
|
+
filters = @finder.filters.reduce([]) do |acc, (name, filter)|
|
|
20
|
+
next(acc) if filter.value.blank?
|
|
21
|
+
acc << %(<strong>#{filter.value}</strong> on <em>#{name}</em>).html_safe
|
|
22
|
+
end
|
|
23
|
+
applied_filters = "(filtering: #{filters.join('; ')})" unless filters.empty?
|
|
24
|
+
|
|
25
|
+
return applied_filters
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Kadmin::PagerDecorator] decorated pager of the underlying finder
|
|
29
|
+
def pager
|
|
30
|
+
return @pager ||= Kadmin::PagerDecorator.new(@finder.pager)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
module Kadmin
|
|
2
|
+
class PagerDecorator
|
|
3
|
+
# @return [Kadmin::Pager] underlying pager model
|
|
4
|
+
attr_reader :pager
|
|
5
|
+
|
|
6
|
+
delegate :total, :size, :offset, :pages, :current_page, :contains?, :next_page?,
|
|
7
|
+
:previous_page?, :offset_at, :current_page?,
|
|
8
|
+
to: :pager
|
|
9
|
+
|
|
10
|
+
def initialize(pager)
|
|
11
|
+
@pager = pager
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
# @return [Integer] the current number of items displayed for this page
|
|
15
|
+
def displayed_items
|
|
16
|
+
return page_end - offset
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# @return [Integer] the index number of the last item for this page
|
|
20
|
+
def page_end
|
|
21
|
+
return [next_page_offset, total].min
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# @return [Integer] the index number of the start item for this page
|
|
25
|
+
def page_start
|
|
26
|
+
return offset + 1
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def next_page_offset
|
|
30
|
+
return @pager.offset_at(current_page + 1)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<%= render partial: 'kadmin/components/finder/header', locals: { finder: finder } %>
|
|
2
|
+
|
|
3
|
+
<div class='container-fluid'>
|
|
4
|
+
<% if finder.filters.present? %>
|
|
5
|
+
<div class='row'>
|
|
6
|
+
<%= render partial: 'kadmin/components/finder/form', locals: { finder: finder } %>
|
|
7
|
+
</div>
|
|
8
|
+
<% end %>
|
|
9
|
+
|
|
10
|
+
<div class='row' style='padding-top: 15px'>
|
|
11
|
+
<% if finder.results.empty? %>
|
|
12
|
+
<%= render partial: 'kadmin/components/finder/empty', locals: { finder: finder } %>
|
|
13
|
+
<% else %>
|
|
14
|
+
<%= yield %>
|
|
15
|
+
<%= paginate(finder.pager, [15, 30, 50, 100]) %>
|
|
16
|
+
<% end %>
|
|
17
|
+
</div>
|
|
18
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<%= form_tag(request.path, method: 'get', class: 'form-inline') do %>
|
|
2
|
+
<div class='form-group'>
|
|
3
|
+
<%= link_to('Create', url_for(action: :new), class: 'btn btn-primary') %>
|
|
4
|
+
<% finder.filters.each do |name, filter| %>
|
|
5
|
+
<%= text_field_tag("filter_#{name}", filter&.value, class: 'form-control', placeholder: "Filter by #{name}...") %>
|
|
6
|
+
<% end %>
|
|
7
|
+
<%= submit_tag('Filter', class: 'btn btn-default form-control') %>
|
|
8
|
+
<%= link_to('Clear', request.path, class: 'btn btn-danger form-control') %>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
File without changes
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<% if model.errors.present? %>
|
|
2
|
+
<%= alert('danger') do %>
|
|
3
|
+
<p><%= glyphicon('exclamation-sign') %> <%= t('kadmin.forms.please_correct') %></p>
|
|
4
|
+
<ul>
|
|
5
|
+
<% model.errors.full_messages.each do |message| %>
|
|
6
|
+
<li><%= message.html_safe %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
<% end %>
|
|
10
|
+
<% end %>
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
<% if content_for?(:sidebar) %>
|
|
47
47
|
<!-- main -->
|
|
48
48
|
<div class="col-sm-8 col-md-8 col-lg-9 main">
|
|
49
|
-
<%= render partial: 'kadmin/alerts' %>
|
|
49
|
+
<%= render partial: 'kadmin/helpers/alerts' %>
|
|
50
50
|
<%= yield %>
|
|
51
51
|
</div>
|
|
52
52
|
<!-- sidebar -->
|
|
@@ -55,7 +55,7 @@
|
|
|
55
55
|
</div>
|
|
56
56
|
<% else %>
|
|
57
57
|
<div class="col-sm-12 col-md-12 main">
|
|
58
|
-
<%= render partial: 'kadmin/alerts' %>
|
|
58
|
+
<%= render partial: 'kadmin/helpers/alerts' %>
|
|
59
59
|
<%= yield %>
|
|
60
60
|
</div>
|
|
61
61
|
<% end %>
|
data/config/locales/de.yml
CHANGED
|
@@ -6,9 +6,14 @@ de:
|
|
|
6
6
|
please_login: Bitte melden Sie sich an
|
|
7
7
|
unauthorized: Unberechtigte Zugriff
|
|
8
8
|
unauthorized_message: Sie haben für die gewünschte Seite leider keine Zugriffsrechte; falls Sie haben sollten, bitte das Apps & Services Team kontaktieren
|
|
9
|
+
components:
|
|
10
|
+
finder:
|
|
11
|
+
empty: Nichts zu zeigen
|
|
9
12
|
dash_message: Schaue Dir mal die Bereiche in der Navigationsleiste oben. Wenn es irgenwelche Probleme gibt, oder es fehlt Dir Zugriffsrechte, bitte das Apps & Services Team kontaktieren.
|
|
10
13
|
error: Fehler
|
|
11
14
|
errors:
|
|
12
15
|
not_found: Objekt nicht gefunden
|
|
13
16
|
params_missing: Fehlenden erforderlichen Parameter
|
|
17
|
+
forms:
|
|
18
|
+
please_correct: "Bitte die folgende Felde korrigieren:"
|
|
14
19
|
welcome: Willkommen zurück, %{user}!
|
data/config/locales/en.yml
CHANGED
|
@@ -6,9 +6,14 @@ en:
|
|
|
6
6
|
please_login: Please authenticate yourself
|
|
7
7
|
unauthorized: Unauthorized access
|
|
8
8
|
unauthorized_message: You are not authorized to access this resource; if you think you should be, contact the Apps & Services team
|
|
9
|
+
components:
|
|
10
|
+
finder:
|
|
11
|
+
empty: Nothing to show
|
|
9
12
|
dash_message: See the top navigation bar for the different admin sections. If you are missing authorizations, or if there is any issue at all, contact the Apps & Services team!
|
|
10
13
|
error: Error
|
|
11
14
|
errors:
|
|
12
15
|
not_found: Requested object not found
|
|
13
16
|
params_missing: Missing required parameters
|
|
17
|
+
forms:
|
|
18
|
+
please_correct: "Please correct the following:"
|
|
14
19
|
welcome: Welcome %{user}!
|
data/lib/kadmin/finder.rb
CHANGED
|
@@ -17,16 +17,19 @@ module Kadmin
|
|
|
17
17
|
@scope = scope
|
|
18
18
|
@pager = nil
|
|
19
19
|
@filters = {}
|
|
20
|
+
@results = nil
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
# @param [String] name the filter name (should be unique)
|
|
23
24
|
# @param [String, Array<String>] column the column(s) name to filter on
|
|
24
25
|
# @param [String, Array<String>] value the value or values to look for (OR'd)
|
|
25
26
|
def filter(name:, column:, value:)
|
|
26
|
-
if column.present? &&
|
|
27
|
+
if column.present? && !@filters.key?(name)
|
|
27
28
|
@filters[name] = Kadmin::Finder::Filter.new(column, value)
|
|
28
|
-
|
|
29
|
-
|
|
29
|
+
if value.present?
|
|
30
|
+
@scope = @scope.where("#{@scope.table_name}.`#{column}` LIKE ?", value.tr('*', '%'))
|
|
31
|
+
@pager&.total = @scope.count
|
|
32
|
+
end
|
|
30
33
|
end
|
|
31
34
|
|
|
32
35
|
return self
|
|
@@ -47,10 +50,16 @@ module Kadmin
|
|
|
47
50
|
end
|
|
48
51
|
|
|
49
52
|
# @return [ActiveRecord::Relation] the filtered (and optionally paginated) results
|
|
50
|
-
def
|
|
51
|
-
results
|
|
52
|
-
|
|
53
|
+
def results
|
|
54
|
+
return @results ||= begin
|
|
55
|
+
results = @scope
|
|
56
|
+
results = @pager.page(results) unless @pager.nil?
|
|
57
|
+
results
|
|
58
|
+
end
|
|
59
|
+
end
|
|
53
60
|
|
|
61
|
+
def find!
|
|
62
|
+
@results = nil
|
|
54
63
|
return results
|
|
55
64
|
end
|
|
56
65
|
end
|
data/lib/kadmin/form.rb
CHANGED
|
@@ -36,7 +36,7 @@ module Kadmin
|
|
|
36
36
|
# @return [ActiveModel::Model] underlying model to populate
|
|
37
37
|
attr_reader :model
|
|
38
38
|
|
|
39
|
-
delegate :id, :persisted?, to: :model
|
|
39
|
+
delegate :id, :persisted?, :to_key, :to_query, :to_param, :type_for_attribute, to: :model
|
|
40
40
|
|
|
41
41
|
def initialize(model)
|
|
42
42
|
@errors = ActiveModel::Errors.new(self)
|
|
@@ -44,52 +44,23 @@ module Kadmin
|
|
|
44
44
|
@form_input = {}
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# Populates the model based on the form input. The input is typically obtained
|
|
50
|
-
# from the controller's params method, but can be any hash which conforms to
|
|
51
|
-
# whatever the form object is expecting.
|
|
52
|
-
# If some input was previously parsed, there is no "rollback" on the state
|
|
53
|
-
# of the model; it should be done prior to reparsing if it is necessary.
|
|
54
|
-
# @param [Hash<String, Object>] form_input a hash representing the raw form input
|
|
55
|
-
def assign_attributes(form_input)
|
|
56
|
-
@errors.clear
|
|
57
|
-
form_input.each do |attr, value|
|
|
58
|
-
setter = "#{attr}="
|
|
59
|
-
send(setter, value) if respond_to?(setter)
|
|
60
|
-
end
|
|
47
|
+
def to_model
|
|
48
|
+
return @model
|
|
61
49
|
end
|
|
62
50
|
|
|
63
|
-
# @!
|
|
51
|
+
# @!group Attributes assignment/manipulation
|
|
64
52
|
|
|
65
|
-
#
|
|
53
|
+
# Allows parsing of multi parameter attributes, such as those returned by
|
|
54
|
+
# the form helpers date_select, datetime_select, etc.
|
|
55
|
+
# Also allows nested attributes, but this is not currently in use.
|
|
56
|
+
include ActiveRecord::AttributeAssignment
|
|
66
57
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
# Overload if you need to validate associations.
|
|
72
|
-
# @example
|
|
73
|
-
# class PersonForm < Form
|
|
74
|
-
# def model_valid?
|
|
75
|
-
# super
|
|
76
|
-
# if @model&.child&.changed? && !@model.child.valid?
|
|
77
|
-
# @errors.add(:base, :invalid, message: 'child model is invalid')
|
|
78
|
-
# end
|
|
79
|
-
# end
|
|
80
|
-
# end
|
|
81
|
-
def model_valid?
|
|
82
|
-
unless @model.valid?
|
|
83
|
-
@model.errors.each do |attribute, error|
|
|
84
|
-
@errors.add(attribute, error)
|
|
85
|
-
end
|
|
86
|
-
end
|
|
58
|
+
# For now, we overload the method to accept all attributes.
|
|
59
|
+
# This is removed in Rails 5, so once we upgrade we can remove the overload.
|
|
60
|
+
def sanitize_for_mass_assignment(attributes)
|
|
61
|
+
return attributes
|
|
87
62
|
end
|
|
88
63
|
|
|
89
|
-
# @!endgroup
|
|
90
|
-
|
|
91
|
-
# @!group Helper methods
|
|
92
|
-
|
|
93
64
|
class << self
|
|
94
65
|
# Delegates the list of attributes to the model, both readers and writers.
|
|
95
66
|
# If the attribute value passed is a hash and not a symbol, assumes it is
|
|
@@ -98,23 +69,102 @@ module Kadmin
|
|
|
98
69
|
# delegate_attributes :first_name, { last_name: [:reader] }
|
|
99
70
|
# @param [Array<Symbol, Hash<Symbol, Array<Symbol>>>] attributes list of attributes to delegate to the model
|
|
100
71
|
def delegate_attributes(*attributes)
|
|
101
|
-
delegates = attributes.
|
|
72
|
+
delegates = attributes.each_with_object([]) do |attribute, acc|
|
|
102
73
|
case attribute
|
|
103
74
|
when Hash
|
|
104
75
|
key, value = attribute.first
|
|
105
76
|
acc << key if value.include?(:reader)
|
|
106
77
|
acc << "#{key}=" if value.include?(:writer)
|
|
107
78
|
when Symbol, String
|
|
108
|
-
acc
|
|
79
|
+
acc.push(attribute, "#{attribute}=")
|
|
109
80
|
else
|
|
110
81
|
raise(ArgumentError, 'Attribute must be one of: Hash, Symbol, String')
|
|
111
82
|
end
|
|
83
|
+
end
|
|
112
84
|
|
|
113
|
-
|
|
85
|
+
delegate(*delegates, to: :model)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Delegates a specified associations to other another form object
|
|
89
|
+
# @example
|
|
90
|
+
# delegate_associations :child, :parent, to: 'Forms::PersonForm'
|
|
91
|
+
cattr_accessor(:associations) { {} }
|
|
92
|
+
def delegate_association(association, to:)
|
|
93
|
+
self.associations[association] = to
|
|
94
|
+
|
|
95
|
+
# add a reader attribute
|
|
96
|
+
class_eval <<~METHOD, __FILE__, __LINE__ + 1
|
|
97
|
+
def #{association}
|
|
98
|
+
return self.associated_forms['#{association}']
|
|
99
|
+
end
|
|
100
|
+
METHOD
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def associated_forms
|
|
105
|
+
return @associated_forms ||= begin
|
|
106
|
+
self.class.associations.map do |name, form_class_name|
|
|
107
|
+
form_class = form_class_name.constantize
|
|
108
|
+
form_class.new(@model.public_send(name))
|
|
114
109
|
end
|
|
115
110
|
end
|
|
116
111
|
end
|
|
117
112
|
|
|
118
113
|
# @!endgroup
|
|
114
|
+
|
|
115
|
+
# @!group Validation
|
|
116
|
+
|
|
117
|
+
validate :validate_model
|
|
118
|
+
def validate_model
|
|
119
|
+
unless @model.valid?
|
|
120
|
+
@model.errors.each do |attribute, error|
|
|
121
|
+
@errors.add(attribute, error)
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
protected :validate_model
|
|
126
|
+
|
|
127
|
+
validate :validate_associated_forms
|
|
128
|
+
def validate_associated_forms
|
|
129
|
+
self.associated_forms.each do |_name, form|
|
|
130
|
+
next if form.valid?
|
|
131
|
+
form.errors.each do |_attribute, _error|
|
|
132
|
+
@errors.add(:base, :association_error, "associated #{form.model_name.human} form has some errors")
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
protected :validate_associated_forms
|
|
137
|
+
|
|
138
|
+
# @!endgroup
|
|
139
|
+
|
|
140
|
+
# @!group Persistence
|
|
141
|
+
|
|
142
|
+
def save
|
|
143
|
+
saved = false
|
|
144
|
+
@model.class.transaction do
|
|
145
|
+
saved = @model.save
|
|
146
|
+
self.associated_forms.each do |_name, form|
|
|
147
|
+
saved &&= form.save
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
raise ActiveRecord::Rollback unless saved
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
return saved
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def save!
|
|
157
|
+
saved = false
|
|
158
|
+
@model.class.transaction do
|
|
159
|
+
saved = @model.save!
|
|
160
|
+
self.associated_forms.each do |_name, form|
|
|
161
|
+
saved &&= form.save! # no need to raise anything, save! will do so
|
|
162
|
+
end
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
return saved
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
# @!endgroup
|
|
119
169
|
end
|
|
120
170
|
end
|