super 0.0.3 → 0.0.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (120) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/CONTRIBUTING.md +56 -0
  4. data/README.md +65 -76
  5. data/STABILITY.md +50 -0
  6. data/app/assets/javascripts/super/application.js +1186 -11151
  7. data/app/assets/stylesheets/super/application.css +93514 -27381
  8. data/app/controllers/super/application_controller.rb +49 -72
  9. data/app/views/layouts/super/application.html.erb +24 -14
  10. data/app/views/super/application/_collection_header.html.erb +15 -0
  11. data/app/views/super/application/_filter.html.erb +14 -0
  12. data/app/views/super/application/_filter_type_select.html.erb +31 -0
  13. data/app/views/super/application/_filter_type_text.html.erb +22 -0
  14. data/app/views/super/application/_filter_type_timestamp.html.erb +35 -0
  15. data/app/views/super/application/_flash.html.erb +13 -13
  16. data/app/views/super/application/_form_field__destroy.html.erb +7 -3
  17. data/app/views/super/application/_form_field_select.html.erb +14 -8
  18. data/app/views/super/application/_form_field_text.html.erb +13 -5
  19. data/app/views/super/application/_form_fieldset.html.erb +1 -1
  20. data/app/views/super/application/_form_has_many.html.erb +5 -5
  21. data/app/views/super/application/_form_inline_errors.html.erb +1 -1
  22. data/app/views/super/application/_member_header.html.erb +16 -0
  23. data/app/views/super/application/_super_layout.html.erb +29 -0
  24. data/app/views/super/application/_super_pagination.html.erb +16 -0
  25. data/app/views/super/application/_super_panel.html.erb +7 -0
  26. data/app/views/super/application/_super_schema_display_actions.html.erb +5 -0
  27. data/app/views/super/application/_super_schema_display_index.html.erb +24 -0
  28. data/app/views/super/application/_super_schema_display_show.html.erb +8 -0
  29. data/app/views/super/application/_super_schema_form.html.erb +15 -0
  30. data/app/views/super/application/edit.html.erb +1 -6
  31. data/app/views/super/application/index.html.erb +1 -1
  32. data/app/views/super/application/new.html.erb +1 -6
  33. data/app/views/super/application/show.html.erb +1 -1
  34. data/app/views/super/feather/{_chevron_down.svg → _chevron_down.html} +0 -0
  35. data/config/locales/en.yml +5 -0
  36. data/docs/README.md +6 -0
  37. data/docs/cheat.md +41 -0
  38. data/docs/faq.md +44 -0
  39. data/docs/quick_start.md +45 -0
  40. data/docs/webpacker.md +17 -0
  41. data/docs/yard_customizations.rb +41 -0
  42. data/frontend/super-frontend/build.js +12 -12
  43. data/frontend/super-frontend/dist/application.css +93514 -27381
  44. data/frontend/super-frontend/dist/application.js +1186 -11151
  45. data/frontend/super-frontend/package.json +8 -4
  46. data/frontend/super-frontend/postcss.config.js +4 -4
  47. data/frontend/super-frontend/src/javascripts/super/application.ts +11 -9
  48. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +19 -0
  49. data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +1 -1
  50. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.ts +15 -0
  51. data/frontend/super-frontend/src/stylesheets/super/application.css +63 -0
  52. data/frontend/super-frontend/tailwind.config.js +12 -4
  53. data/frontend/super-frontend/yarn.lock +1429 -1372
  54. data/lib/generators/super/install/install_generator.rb +16 -0
  55. data/lib/generators/super/resource/templates/resources_controller.rb.tt +1 -31
  56. data/lib/generators/super/webpacker/webpacker_generator.rb +10 -1
  57. data/lib/super.rb +26 -5
  58. data/lib/super/action_inquirer.rb +2 -2
  59. data/lib/super/assets.rb +108 -38
  60. data/lib/super/client_error.rb +43 -0
  61. data/lib/super/compatibility.rb +25 -0
  62. data/lib/super/configuration.rb +21 -69
  63. data/lib/super/controls.rb +9 -37
  64. data/lib/super/controls/optional.rb +79 -0
  65. data/lib/super/controls/required.rb +13 -0
  66. data/lib/super/controls/steps.rb +114 -0
  67. data/lib/super/display.rb +66 -3
  68. data/lib/super/display/guesser.rb +34 -0
  69. data/lib/super/display/schema_types.rb +55 -25
  70. data/lib/super/engine.rb +7 -1
  71. data/lib/super/error.rb +9 -9
  72. data/lib/super/filter.rb +12 -0
  73. data/lib/super/filter/form_object.rb +97 -0
  74. data/lib/super/filter/guesser.rb +30 -0
  75. data/lib/super/filter/operator.rb +103 -0
  76. data/lib/super/filter/plugin.rb +47 -0
  77. data/lib/super/filter/schema_types.rb +112 -0
  78. data/lib/super/form.rb +35 -0
  79. data/lib/super/form/builder.rb +48 -0
  80. data/lib/super/form/guesser.rb +27 -0
  81. data/lib/super/form/schema_types.rb +20 -23
  82. data/lib/super/form/strong_params.rb +29 -0
  83. data/lib/super/layout.rb +47 -0
  84. data/lib/super/link.rb +110 -0
  85. data/lib/super/pagination.rb +74 -8
  86. data/lib/super/panel.rb +30 -0
  87. data/lib/super/partial.rb +23 -0
  88. data/lib/super/partial/resolving.rb +24 -0
  89. data/lib/super/plugin.rb +34 -63
  90. data/lib/super/schema.rb +12 -22
  91. data/lib/super/schema/common.rb +25 -0
  92. data/lib/super/schema/guesser.rb +77 -0
  93. data/lib/super/version.rb +1 -1
  94. data/lib/super/view_helper.rb +43 -0
  95. metadata +133 -33
  96. data/app/views/super/application/_form.html.erb +0 -14
  97. data/app/views/super/application/_index.html.erb +0 -60
  98. data/app/views/super/application/_show.html.erb +0 -12
  99. data/frontend/super-frontend/src/javascripts/super/nested_attributes_controller.ts +0 -33
  100. data/lib/super/inline_callback.rb +0 -82
  101. data/lib/super/test_support/copy_app_templates/controllers/favorite_things_controller.rb +0 -50
  102. data/lib/super/test_support/copy_app_templates/controllers/members_controller.rb +0 -57
  103. data/lib/super/test_support/copy_app_templates/controllers/ships_controller.rb +0 -47
  104. data/lib/super/test_support/copy_app_templates/migrations/20190216224956_create_members.rb +0 -11
  105. data/lib/super/test_support/copy_app_templates/migrations/20190803143320_create_ships.rb +0 -11
  106. data/lib/super/test_support/copy_app_templates/migrations/20190806014121_add_ship_to_members.rb +0 -5
  107. data/lib/super/test_support/copy_app_templates/migrations/20191126050453_create_favorite_things.rb +0 -10
  108. data/lib/super/test_support/copy_app_templates/models/favorite_thing.rb +0 -7
  109. data/lib/super/test_support/copy_app_templates/models/member.rb +0 -23
  110. data/lib/super/test_support/copy_app_templates/models/ship.rb +0 -3
  111. data/lib/super/test_support/copy_app_templates/routes.rb +0 -11
  112. data/lib/super/test_support/copy_app_templates/seeds.rb +0 -2
  113. data/lib/super/test_support/fixtures/favorite_things.yml +0 -9
  114. data/lib/super/test_support/fixtures/members.yml +0 -336
  115. data/lib/super/test_support/fixtures/ships.yml +0 -10
  116. data/lib/super/test_support/generate_copy_app.rb +0 -41
  117. data/lib/super/test_support/generate_dummy.rb +0 -93
  118. data/lib/super/test_support/starfleet_seeder.rb +0 -50
  119. data/lib/super/view.rb +0 -25
  120. data/lib/tasks/super_tasks.rake +0 -4
@@ -1,4 +1,4 @@
1
- <fieldset class="border border-gray-300 rounded p-4">
1
+ <fieldset class="border border-gray-300 rounded pb-4 px-4 mt-4 shadow" data-controller="toggle-pending-destruction">
2
2
  <% if form_fieldset.label.present? %>
3
3
  <legend class="bg-white p-1 -mx-1"><%= form_fieldset.label %></legend>
4
4
  <% end %>
@@ -1,4 +1,4 @@
1
- <div data-controller="nested-attributes">
1
+ <div data-controller="apply-template">
2
2
  <%= form.fields_for(form_has_many.reader) do |ff| %>
3
3
  <%= render "form_fieldset", form_fieldset: form_has_many, form: ff %>
4
4
  <% end %>
@@ -7,15 +7,15 @@
7
7
  form.fields_for(
8
8
  form_has_many.reader,
9
9
  form.object.public_send(form_has_many.reader).build,
10
- child_index: "TEMPLATE"
10
+ child_index: "TEMPLATEINDEX"
11
11
  ) do |ff|
12
12
  %>
13
- <template data-target="nested-attributes.template">
13
+ <template data-apply-template-target="template">
14
14
  <%= render "form_fieldset", form_fieldset: form_has_many, form: ff %>
15
15
  </template>
16
16
  <% end %>
17
17
 
18
- <button data-action="nested-attributes#add" class="bg-blue-700 hover:bg-blue-800 text-white py-2 px-4 rounded mt-2">
18
+ <a href="#" data-action="apply-template#call" class="super-button super-button--fill-blue mt-2 inline-block">
19
19
  Add <%= form_has_many.label %>
20
- </button>
20
+ </a>
21
21
  </div>
@@ -1,5 +1,5 @@
1
1
  <% if form.object %>
2
- <% form.object.errors.full_messages_for(column).each do |error_message| %>
2
+ <% Super::ViewHelper.errors_accounting_for_reflections(form.object, column).each do |error_message| %>
3
3
  <p class="text-red-400 text-xs italic pt-1"><%= error_message %></p>
4
4
  <% end %>
5
5
  <% else %>
@@ -0,0 +1,16 @@
1
+ <header class="flex justify-between content-end">
2
+ <h1 class="text-xl">
3
+ <%= controls.title %>
4
+ </h1>
5
+ <div>
6
+ <% controls.member_actions(action: action_inquirer).each do |link| %>
7
+ <%= link.to_s(
8
+ default_options: {
9
+ class: "super-button super-button--border-blue super-button-sm inline-block ml-2"
10
+ },
11
+ record: @record,
12
+ params: params
13
+ ) %>
14
+ <% end %>
15
+ </div>
16
+ </header>
@@ -0,0 +1,29 @@
1
+ <% super_layout.resolve(self) %>
2
+
3
+ <% super_layout.resolved_headers.each do |partial| %>
4
+ <%= Super::Partial.render(partial, template: self) %>
5
+ <% end %>
6
+
7
+ <% if super_layout.resolved_asides.empty? %>
8
+ <% super_layout.resolved_mains.each do |partial| %>
9
+ <%= Super::Partial.render(partial, template: self) %>
10
+ <% end %>
11
+ <% else %>
12
+ <div class="clearfix -mx-2">
13
+ <div class="md:float-left md:w-9/12 px-2">
14
+ <% super_layout.resolved_mains.each do |partial| %>
15
+ <%= Super::Partial.render(partial, template: self) %>
16
+ <% end %>
17
+ </div>
18
+
19
+ <div class="md:float-right md:w-3/12 px-2">
20
+ <% super_layout.resolved_asides.each do |partial| %>
21
+ <%= Super::Partial.render(partial, template: self) %>
22
+ <% end %>
23
+ </div>
24
+ </div>
25
+ <% end %>
26
+
27
+ <% super_layout.resolved_footers.each do |partial| %>
28
+ <%= Super::Partial.render(partial, template: self) %>
29
+ <% end %>
@@ -0,0 +1,16 @@
1
+ <% if @pagination.necessary? %>
2
+ <div class="flex justify-end mr-2">
3
+ <div class="mt-4">
4
+ <% @pagination.each do |page_query_params, is_current_page, display| %>
5
+ <%= link_to(
6
+ display,
7
+ polymorphic_path(
8
+ Super.configuration.path_parts(controls.model),
9
+ page_query_params
10
+ ),
11
+ class: "inline-block ml-2 text-lg #{is_current_page ? " text-gray-900" : ""}"
12
+ ) %>
13
+ <% end %>
14
+ </div>
15
+ </div>
16
+ <% end %>
@@ -0,0 +1,7 @@
1
+ <% if super_panel.resolve(self, block_given? ? Proc.new { yield } : nil).resolved_parts.any? %>
2
+ <div class="border rounded shadow border-gray-400 bg-white px-5 pt-4 pb-8 mt-6">
3
+ <% super_panel.resolved_parts.each do |partial| %>
4
+ <%= Super::Partial.render(partial, template: self) %>
5
+ <% end %>
6
+ </div>
7
+ <% end %>
@@ -0,0 +1,5 @@
1
+ <div>
2
+ <% controls.member_actions(action: action_inquirer).each do |link| %>
3
+ <span class="pr-2 last:pr-0"><%= link.to_s(record: record, params: params) %></span>
4
+ <% end %>
5
+ </div>
@@ -0,0 +1,24 @@
1
+ <div class="mt-4 overflow-x-auto lg:overflow-x-visible">
2
+ <table class="w-full border-separate relative" cellspacing="0" cellpadding="0">
3
+ <thead class="">
4
+ <tr class="">
5
+ <% super_schema_display_index.each_attribute_name do |attribute_name| %>
6
+ <th class="p-2 first:pl-6 border-b border-b-2 border-gray-400 text-gray-600 text-left text-sm font-normal bg-white sticky top-0 z-10">
7
+ <%= controls.model.human_attribute_name(attribute_name) %>
8
+ </th>
9
+ <% end %>
10
+ </tr>
11
+ </thead>
12
+ <tbody class="">
13
+ <% @records.each.with_index do |record, row_index| %>
14
+ <tr id="record-pk-<%= record.id %>" class="group">
15
+ <% super_schema_display_index.each_attribute_name do |attribute_name| %>
16
+ <td class="py-1 px-2 first:pl-5 border-transparent border-t border-b group-hover:bg-blue-200 first:border-l first:rounded-l-lg last:border-r last:rounded-r-lg bg-white <%= Super::ViewHelper.classes(["bg-gray-100", row_index.odd?]) %>">
17
+ <%= super_schema_display_index.render_field(template: self, record: record, column: attribute_name) %>
18
+ </td>
19
+ <% end %>
20
+ </tr>
21
+ <% end %>
22
+ </tbody>
23
+ </table>
24
+ </div>
@@ -0,0 +1,8 @@
1
+ <table class="max-w-full leading-loose mt-4">
2
+ <% super_schema_display_show.each_attribute_name do |attribute_name| %>
3
+ <tr>
4
+ <th class="text-right px-4"><%= controls.model.human_attribute_name(attribute_name) %></th>
5
+ <td><%= super_schema_display_show.render_field(template: self, record: @record, column: attribute_name) %></td>
6
+ </tr>
7
+ <% end %>
8
+ </table>
@@ -0,0 +1,15 @@
1
+ <%= form_for(Super.configuration.path_parts(@record), builder: Super::Form::Builder) do |f| %>
2
+ <div class="max-w-3xl">
3
+ <% super_schema_form.each_attribute do |field, type| %>
4
+ <%= render(
5
+ type,
6
+ form: f,
7
+ column: field
8
+ ) %>
9
+ <% end %>
10
+
11
+ <div>
12
+ <%= f.submit class: "super-button super-button--fill-blue mt-2" %>
13
+ </div>
14
+ </div>
15
+ <% end %>
@@ -1,6 +1 @@
1
- <%= render(
2
- partial: "form",
3
- locals: {
4
- resource: @resource,
5
- }
6
- ) %>
1
+ <%= render(@view) %>
@@ -1 +1 @@
1
- <%= render("index") %>
1
+ <%= render(@view) %>
@@ -1,6 +1 @@
1
- <%= render(
2
- partial: "form",
3
- locals: {
4
- resource: @resource,
5
- }
6
- ) %>
1
+ <%= render(@view) %>
@@ -1 +1 @@
1
- <%= render("show") %>
1
+ <%= render(@view) %>
@@ -0,0 +1,5 @@
1
+ ---
2
+ en:
3
+ super:
4
+ layout:
5
+ powered_by: "%{env} environment. Powered by Super %{version}."
@@ -0,0 +1,6 @@
1
+ # Docs
2
+
3
+ * [Quick start](./quick_start.md)
4
+ * [Webpacker](./webpacker.md)
5
+ * [Controls](./controls.md)
6
+ * [FAQ](./faq.md)
@@ -0,0 +1,41 @@
1
+ <!--
2
+ # @title Cheat sheet
3
+ -->
4
+
5
+ # Cheat sheet
6
+
7
+ ## Controls
8
+
9
+ Controls are the primary way to "control" the behavior of your admin pages.
10
+ They only work with Active Record models
11
+
12
+ Controls have several required and optional methods. Note that all arguments
13
+ must be defined, even if they are ignored.
14
+
15
+
16
+ ### Required methods
17
+
18
+ The following are the methods that must be defined in the `Controls` class.
19
+
20
+ * **`#model()`**
21
+ The model that your controller is working with
22
+ * **`#permitted_params(params, action:)`**
23
+ The strong parameters definition
24
+ * **`#display_schema(action:)`**
25
+ The display schema definition for the `#index` and `#show` pages
26
+ * **`#form_schema(action:)`**
27
+ The form schema definition for the `#new` and `#edit` pages
28
+
29
+
30
+ ### Optional methods
31
+
32
+ The following are the methods that can be defined in the `Controls` class.
33
+
34
+ * **`#title()`**
35
+ The title to show on the main panel
36
+ * **`#collection_actions(action:)`**
37
+ The list of collection-level links
38
+ * **`#member_actions(action:)`**
39
+ The list of member-level links and `#show` pages
40
+ * **`#scope(action:)`**
41
+ The starting point of the query/relation. Defaults to `#all`
@@ -0,0 +1,44 @@
1
+ <!--
2
+ # @title FAQ
3
+ -->
4
+
5
+ # FAQ
6
+
7
+ ## How do I handle authorization?
8
+
9
+ Assuming you already have authentication set up, it should only require defining
10
+ a `Controls#initialize` that accepts an authenticated user. From there, you can
11
+ customize `Controls#scope` to have the required behavior.
12
+
13
+ ```ruby
14
+ class PostsController < AdminController
15
+ def new_controls
16
+ Controls.new(current_user)
17
+ end
18
+
19
+ class Controls
20
+ def initialize(current_user)
21
+ @current_user = current_user
22
+ end
23
+
24
+ def model
25
+ Post
26
+ end
27
+
28
+ def scope(action:)
29
+ # Example: admins can read and write; customer support can only read
30
+ if @current_user.admin?
31
+ return model.all
32
+ end
33
+
34
+ if action.read?
35
+ return model.all
36
+ end
37
+
38
+ raise Super::Error::Forbidden
39
+ end
40
+
41
+ # ...
42
+ end
43
+ end
44
+ ```
@@ -0,0 +1,45 @@
1
+ <!--
2
+ # @title Quick start
3
+ -->
4
+
5
+ # Quick start
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem "super"
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ ```bash
18
+ bundle install
19
+ bundle exec rails generate super:install # check out the `--help` option!
20
+ ```
21
+
22
+ Super supports using Webpacker instead of Sprockets. For more information,
23
+ see the [Webpacker guide](./webpacker.md).
24
+
25
+ ## Usage
26
+
27
+ ### Creating new admin pages
28
+
29
+ ```bash
30
+ bundle exec rails generate super:resource Thing # check out the `--help` option!
31
+ ```
32
+
33
+ The example above will create a controller called `Admin::ThingsController`. It
34
+ generates a `Controls` class inside the controller as well; it's where most
35
+ configuration lives. See the documentation on [Controls](./controls.md) for more
36
+ info.
37
+
38
+ You'll have to manually update your routes file. It'll probably look something
39
+ like the following:
40
+
41
+ ```ruby
42
+ namespace :admin do
43
+ resources :things
44
+ end
45
+ ```
@@ -0,0 +1,17 @@
1
+ <!--
2
+ # @title Webpacker
3
+ -->
4
+
5
+ # Installation with Webpacker
6
+
7
+ Super supports using Webpacker instead of Sprockets. Note though that you need
8
+ to set up ERB templates under Webpacker. There are no other requirements or
9
+ dependencies.
10
+
11
+ After adding `super` to your Gemfile and running the installation generator
12
+ according to the [Quick start guide](./quick_start.md), run the following:
13
+
14
+ ```bash
15
+ bundle exec rails webpacker:install:erb # if you haven't already
16
+ bundle exec rails generate super:webpacker
17
+ ```
@@ -0,0 +1,41 @@
1
+ require "yard"
2
+
3
+ module FixRelativeLinks
4
+ def resolve_links(html)
5
+ html = html.gsub(%r{<a href="([^"]+)">([^<]+)</a>}) do
6
+ resolve_link_to_docs_subdir(full_match: $&, href: $1, content: $2)
7
+ end
8
+
9
+ html = html.gsub(%r{(<pre[^<]+)?<code[^>]*>([^<]+)</code>}) do
10
+ resolve_link_to_code(full_match: $&, pre: $1, code: $2)
11
+ end
12
+
13
+ super(html)
14
+ end
15
+
16
+ def resolve_link_to_docs_subdir(full_match:, href:, content:)
17
+ if href =~ /\bdocs\b/
18
+ %({file:#{href} #{content}})
19
+ else
20
+ full_match
21
+ end
22
+ end
23
+
24
+ def resolve_link_to_code(full_match:, pre:, code:)
25
+ if pre
26
+ return full_match
27
+ end
28
+
29
+ if code.include?("\n")
30
+ return full_match
31
+ end
32
+
33
+ if !code.start_with?("Super::")
34
+ return full_match
35
+ end
36
+
37
+ "{#{code}}"
38
+ end
39
+ end
40
+
41
+ YARD::Templates::Template.extra_includes << FixRelativeLinks
@@ -1,17 +1,17 @@
1
- const Bundler = require('parcel-bundler');
2
- const fs = require('fs');
3
- const path = require('path');
1
+ const Bundler = require("parcel-bundler");
2
+ const fs = require("fs");
3
+ const path = require("path");
4
4
 
5
5
  const entryFiles = [
6
- 'src/stylesheets/super/application.css',
7
- 'src/javascripts/super/application.ts',
6
+ "src/stylesheets/super/application.css",
7
+ "src/javascripts/super/application.ts",
8
8
  ];
9
9
 
10
10
  const options = {
11
- outDir: '../../app/assets',
12
- watch: process.argv.includes('--watch'),
13
- cacheDir: 'tmp/parcel/cache',
14
- global: 'Super',
11
+ outDir: "../../app/assets",
12
+ watch: process.argv.includes("--watch"),
13
+ cacheDir: "tmp/parcel/cache",
14
+ global: "Super",
15
15
  contentHash: false,
16
16
  minify: false,
17
17
  sourceMaps: false,
@@ -20,10 +20,10 @@ const options = {
20
20
 
21
21
  const bundler = new Bundler(entryFiles, options);
22
22
 
23
- bundler.on('bundled', function (bundle) {
24
- bundle.childBundles.forEach(function (childBundle) {
23
+ bundler.on("bundled", function(bundle) {
24
+ bundle.childBundles.forEach(function(childBundle) {
25
25
  var basename = path.basename(childBundle.name);
26
- var destDir = path.join(__dirname, 'dist');
26
+ var destDir = path.join(__dirname, "dist");
27
27
  var destPath = path.join(destDir, basename);
28
28
 
29
29
  console.log(destPath);