super 0.0.3 → 0.0.8

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