super 0.0.2 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (110) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +11 -0
  3. data/README.md +68 -76
  4. data/app/assets/javascripts/super/application.js +1252 -316
  5. data/app/assets/stylesheets/super/application.css +102704 -17321
  6. data/app/controllers/super/application_controller.rb +49 -71
  7. data/app/views/layouts/super/application.html.erb +10 -8
  8. data/app/views/super/application/_collection_header.html.erb +15 -0
  9. data/app/views/super/application/_filter.html.erb +14 -0
  10. data/app/views/super/application/_filter_type_select.html.erb +31 -0
  11. data/app/views/super/application/_filter_type_text.html.erb +22 -0
  12. data/app/views/super/application/_filter_type_timestamp.html.erb +35 -0
  13. data/app/views/super/application/_flash.html.erb +13 -13
  14. data/app/views/super/application/_form_field__destroy.html.erb +9 -0
  15. data/app/views/super/application/_form_field_select.html.erb +23 -0
  16. data/app/views/super/application/_form_field_text.html.erb +13 -0
  17. data/app/views/super/application/_form_fieldset.html.erb +8 -0
  18. data/app/views/super/application/_form_has_many.html.erb +21 -0
  19. data/app/views/super/application/_form_has_one.html.erb +11 -0
  20. data/app/views/super/application/_form_inline_errors.html.erb +10 -0
  21. data/app/views/super/application/_member_header.html.erb +16 -0
  22. data/app/views/super/application/_super_layout.html.erb +29 -0
  23. data/app/views/super/application/_super_pagination.html.erb +16 -0
  24. data/app/views/super/application/_super_panel.html.erb +7 -0
  25. data/app/views/super/application/_super_schema_display_actions.html.erb +5 -0
  26. data/app/views/super/application/_super_schema_display_index.html.erb +24 -0
  27. data/app/views/super/application/_super_schema_display_show.html.erb +8 -0
  28. data/app/views/super/application/_super_schema_form.html.erb +15 -0
  29. data/app/views/super/application/edit.html.erb +1 -6
  30. data/app/views/super/application/index.html.erb +1 -1
  31. data/app/views/super/application/new.html.erb +1 -6
  32. data/app/views/super/application/show.html.erb +1 -1
  33. data/app/views/super/feather/{_chevron_down.svg → _chevron_down.html} +0 -0
  34. data/config/locales/en.yml +5 -0
  35. data/docs/README.md +6 -0
  36. data/docs/cheat.md +41 -0
  37. data/docs/faq.md +44 -0
  38. data/docs/quick_start.md +45 -0
  39. data/docs/webpacker.md +17 -0
  40. data/docs/yard_customizations.rb +41 -0
  41. data/frontend/super-frontend/build.js +14 -12
  42. data/frontend/super-frontend/dist/application.css +102704 -17321
  43. data/frontend/super-frontend/dist/application.js +1252 -316
  44. data/frontend/super-frontend/package.json +11 -4
  45. data/frontend/super-frontend/postcss.config.js +4 -4
  46. data/frontend/super-frontend/src/javascripts/super/application.ts +18 -0
  47. data/frontend/super-frontend/src/javascripts/super/apply_template_controller.ts +19 -0
  48. data/frontend/super-frontend/src/javascripts/super/rails__ujs.d.ts +1 -0
  49. data/frontend/super-frontend/src/javascripts/super/toggle_pending_destruction_controller.ts +15 -0
  50. data/frontend/super-frontend/src/stylesheets/super/application.css +63 -0
  51. data/frontend/super-frontend/tailwind.config.js +12 -4
  52. data/frontend/super-frontend/tsconfig.json +13 -0
  53. data/frontend/super-frontend/yarn.lock +1891 -1798
  54. data/lib/generators/super/install/install_generator.rb +16 -0
  55. data/lib/generators/super/webpacker/webpacker_generator.rb +8 -0
  56. data/lib/super.rb +16 -6
  57. data/lib/super/action_inquirer.rb +14 -1
  58. data/lib/super/assets.rb +1 -0
  59. data/lib/super/client_error.rb +43 -0
  60. data/lib/super/compatibility.rb +25 -0
  61. data/lib/super/configuration.rb +66 -44
  62. data/lib/super/controls.rb +26 -15
  63. data/lib/super/controls/optional.rb +54 -0
  64. data/lib/super/controls/required.rb +41 -0
  65. data/lib/super/controls/steps.rb +128 -0
  66. data/lib/super/display/schema_types.rb +90 -18
  67. data/lib/super/engine.rb +7 -0
  68. data/lib/super/error.rb +9 -8
  69. data/lib/super/filter.rb +137 -0
  70. data/lib/super/filter/operator.rb +103 -0
  71. data/lib/super/filter/schema_types.rb +118 -0
  72. data/lib/super/form.rb +48 -0
  73. data/lib/super/form/schema_types.rb +96 -21
  74. data/lib/super/layout.rb +47 -0
  75. data/lib/super/link.rb +110 -0
  76. data/lib/super/navigation/automatic.rb +2 -0
  77. data/lib/super/pagination.rb +80 -8
  78. data/lib/super/panel.rb +30 -0
  79. data/lib/super/partial.rb +23 -0
  80. data/lib/super/partial/resolving.rb +24 -0
  81. data/lib/super/plugin.rb +34 -63
  82. data/lib/super/schema.rb +65 -1
  83. data/lib/super/version.rb +1 -1
  84. data/lib/super/view_helper.rb +43 -0
  85. metadata +132 -33
  86. data/app/views/super/application/_form.html.erb +0 -15
  87. data/app/views/super/application/_form_field.html.erb +0 -7
  88. data/app/views/super/application/_form_generic_select.html.erb +0 -19
  89. data/app/views/super/application/_form_generic_text.html.erb +0 -7
  90. data/app/views/super/application/_index.html.erb +0 -60
  91. data/app/views/super/application/_show.html.erb +0 -12
  92. data/frontend/super-frontend/src/javascripts/super/application.js +0 -11
  93. data/lib/super/display.rb +0 -9
  94. data/lib/super/inline_callback.rb +0 -82
  95. data/lib/super/test_support/copy_app_templates/20190216224956_create_members.rb +0 -11
  96. data/lib/super/test_support/copy_app_templates/20190803143320_create_ships.rb +0 -11
  97. data/lib/super/test_support/copy_app_templates/20190806014121_add_ship_to_members.rb +0 -5
  98. data/lib/super/test_support/copy_app_templates/member.rb +0 -16
  99. data/lib/super/test_support/copy_app_templates/members_controller.rb +0 -52
  100. data/lib/super/test_support/copy_app_templates/routes.rb +0 -10
  101. data/lib/super/test_support/copy_app_templates/seeds.rb +0 -2
  102. data/lib/super/test_support/copy_app_templates/ship.rb +0 -3
  103. data/lib/super/test_support/copy_app_templates/ships_controller.rb +0 -47
  104. data/lib/super/test_support/fixtures/members.yml +0 -336
  105. data/lib/super/test_support/fixtures/ships.yml +0 -10
  106. data/lib/super/test_support/generate_copy_app.rb +0 -52
  107. data/lib/super/test_support/generate_dummy.rb +0 -94
  108. data/lib/super/test_support/starfleet_seeder.rb +0 -49
  109. data/lib/super/view.rb +0 -25
  110. data/lib/tasks/super_tasks.rake +0 -4
@@ -1,116 +1,94 @@
1
1
  module Super
2
+ # Provides a default implementation for each of the resourceful actions
2
3
  class ApplicationController < ActionController::Base
3
- include Super::InlineCallback
4
- include Pluggable.new(:super_application_controller)
5
-
6
- register_inline_callback(:index_paginate, on: :index, after: :yield)
4
+ include ClientError::Handling
7
5
 
8
6
  helper_method :action_inquirer
9
7
  helper_method :controls
10
8
 
11
- rescue_from Error::ClientError do |exception|
12
- code, default_message =
13
- case exception
14
- when Error::UnprocessableEntity
15
- [422, "Unprocessable entity"]
16
- when Error::NotFound
17
- [404, "Not found"]
18
- when Error::Forbidden
19
- [403, "Forbidden"]
20
- when Error::Unauthorized
21
- [401, "Unauthorized"]
22
- when Error::BadRequest, Error::ClientError
23
- [400, "Bad request"]
24
- end
25
-
26
- flash.now.alert =
27
- if exception.message == exception.class.name.to_s
28
- default_message
29
- else
30
- exception.message
31
- end
9
+ # Displays a list of records to the user
10
+ def index
11
+ @records = controls.load_records(action: action_inquirer, params: params)
12
+ @display = controls.display_schema(action: action_inquirer)
13
+ @view = controls.build_index_view
14
+ end
32
15
 
33
- render "nothing", status: code
16
+ # Displays a specific record to the user
17
+ def show
18
+ @record = controls.load_record(action: action_inquirer, params: params)
19
+ @display = controls.display_schema(action: action_inquirer)
20
+ @view = controls.build_show_view
34
21
  end
35
22
 
36
- def index
37
- with_inline_callbacks do
38
- @resources = controls.scope(action: action_inquirer)
39
- end
23
+ # Displays a form to allow the user to create a new record
24
+ def new
25
+ @record = controls.build_record(action: action_inquirer)
26
+ @form = controls.form_schema(action: action_inquirer)
27
+ @view = controls.build_new_view
40
28
  end
41
29
 
30
+ # Creates a record, or shows the validation errors
42
31
  def create
43
- @resource = controls.scope(action: action_inquirer).build(create_permitted_params)
32
+ @record = controls.build_record_with_params(action: action_inquirer, params: params)
44
33
 
45
- if @resource.save
46
- redirect_to polymorphic_path(Super.configuration.path_parts(@resource))
34
+ if controls.save_record(action: action_inquirer, record: @record, params: params)
35
+ redirect_to polymorphic_path(Super.configuration.path_parts(@record))
47
36
  else
37
+ @form = controls.form_schema(action: action_inquirer_for("new"))
38
+ @view = controls.build_new_view
48
39
  render :new, status: :bad_request
49
40
  end
50
41
  end
51
42
 
52
- def new
53
- @resource = controls.scope(action: action_inquirer).build
54
- end
55
-
43
+ # Displays a form to allow the user to update an existing record
56
44
  def edit
57
- @resource = controls.scope(action: action_inquirer).find(params[:id])
58
- end
59
-
60
- def show
61
- @resource = controls.scope(action: action_inquirer).find(params[:id])
45
+ @record = controls.load_record(action: action_inquirer, params: params)
46
+ @form = controls.form_schema(action: action_inquirer)
47
+ @view = controls.build_edit_view
62
48
  end
63
49
 
50
+ # Updates a record, or shows validation errors
64
51
  def update
65
- @resource = controls.scope(action: action_inquirer).find(params[:id])
52
+ @record = controls.load_record(action: action_inquirer, params: params)
66
53
 
67
- if @resource.update(update_permitted_params)
68
- redirect_to polymorphic_path(Super.configuration.path_parts(@resource))
54
+ if controls.update_record(action: action_inquirer, record: @record, params: params)
55
+ redirect_to polymorphic_path(Super.configuration.path_parts(@record))
69
56
  else
57
+ @form = controls.form_schema(action: action_inquirer_for("edit"))
58
+ @view = controls.build_edit_view
70
59
  render :edit, status: :bad_request
71
60
  end
72
61
  end
73
62
 
63
+ # Deletes a record, or shows validation errors
74
64
  def destroy
75
- @resource = controls.scope(action: action_inquirer).find(params[:id])
76
- if @resource.destroy
65
+ @record = controls.load_record(action: action_inquirer, params: params)
66
+
67
+ if controls.destroy_record(action: action_inquirer, record: @record, params: params)
77
68
  redirect_to polymorphic_path(Super.configuration.path_parts(controls.model))
78
69
  else
79
- redirect_to polymorphic_path(Super.configuration.path_parts(@resource))
70
+ flash.alert = "Couldn't delete record"
71
+ redirect_to polymorphic_path(Super.configuration.path_parts(@record))
80
72
  end
73
+ rescue ActiveRecord::InvalidForeignKey => e
74
+ flash.alert = "Couldn't delete record: #{e.class}"
75
+ redirect_to polymorphic_path(Super.configuration.path_parts(@record))
81
76
  end
82
77
 
83
78
  private
84
79
 
85
- def index_paginate
86
- @pagination = Pagination.new(
87
- total_count: @resources.size,
88
- limit: Super.configuration.index_resources_per_page,
89
- query_params: request.GET,
90
- page_query_param: :page
91
- )
92
-
93
- @resources = @resources
94
- .limit(@pagination.limit)
95
- .offset(@pagination.offset)
96
- end
97
-
98
80
  def controls
99
81
  Super::Controls.new(new_controls)
100
82
  end
101
83
 
102
- def create_permitted_params
103
- controls.permitted_params(params, action: action_inquirer)
104
- end
105
-
106
- def update_permitted_params
107
- controls.permitted_params(params, action: action_inquirer)
84
+ def action_inquirer
85
+ @action_inquirer ||= action_inquirer_for(params[:action])
108
86
  end
109
87
 
110
- def action_inquirer
111
- @action_inquirer ||= ActionInquirer.new(
112
- ActionInquirer.default_resources,
113
- params[:action]
88
+ def action_inquirer_for(action)
89
+ ActionInquirer.new(
90
+ ActionInquirer.default_for_resources,
91
+ action
114
92
  )
115
93
  end
116
94
  end
@@ -1,5 +1,5 @@
1
1
  <!DOCTYPE html>
2
- <html class="bg-white">
2
+ <html class="bg-gray-100">
3
3
  <head>
4
4
  <title><%= Super.configuration.title %></title>
5
5
  <%= csrf_meta_tags %>
@@ -7,6 +7,8 @@
7
7
  <%= csp_meta_tag %>
8
8
  <% end -%>
9
9
 
10
+ <meta name="viewport" content="width=device-width, initial-scale=1">
11
+
10
12
  <% if Super.configuration.asset_handler.sprockets? %>
11
13
  <%= stylesheet_link_tag "super/application", media: "all" %>
12
14
  <%= javascript_include_tag "super/application" %>
@@ -16,10 +18,10 @@
16
18
  <% end %>
17
19
  </head>
18
20
 
19
- <body class="font-sans bg-white">
21
+ <body class="font-sans pb-4">
20
22
  <div class="px-4">
21
23
  <header class="pt-4">
22
- <h1 class="text-base font-bold mr-6"><%= Super.configuration.title %></h1>
24
+ <h1 class="text-lg font-bold mr-6 mb-1"><%= Super.configuration.title %></h1>
23
25
  <%
24
26
  route_namespace = Super.configuration.route_namespace.map(&:to_s).join("/")
25
27
  Super::Navigation::Automatic.new(route_namespace: route_namespace).each do |text, href| %>
@@ -29,13 +31,13 @@
29
31
 
30
32
  <%= render "flash" %>
31
33
 
32
- <div class="pt-8"></div>
33
-
34
- <% if content_for?(:header) %>
35
- <%= yield :header %>
36
- <% end %>
34
+ <div class="pt-4"></div>
37
35
 
38
36
  <%= yield %>
37
+
38
+ <div class="pt-8 text-sm text-gray-800">
39
+ <%= t("super.layout.powered_by", env: Rails.env.capitalize, version: Super::VERSION) %>
40
+ </div>
39
41
  </div>
40
42
  </body>
41
43
  </html>
@@ -0,0 +1,15 @@
1
+ <header class="flex justify-between content-end">
2
+ <h1 class="text-xl">
3
+ <%= controls.title %>
4
+ </h1>
5
+ <div>
6
+ <% controls.collection_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
+ params: params
12
+ ) %>
13
+ <% end %>
14
+ </div>
15
+ </header>
@@ -0,0 +1,14 @@
1
+ <%= render(Super::Panel.new) do %>
2
+ <h1 class="text-xl">Filters</h1>
3
+ <%= form_for(filter, url: filter.url, method: :get, as: :q, html: { class: "mt-4" }) do |form| %>
4
+ <% filter.each_field do |filter_field| %>
5
+ <div class="mt-4">
6
+ <%= render(filter_field, form: form) %>
7
+ </div>
8
+ <% end %>
9
+
10
+ <div>
11
+ <%= form.submit "Filter", class: "super-button super-button--border-gray mt-6" %>
12
+ </div>
13
+ <% end %>
14
+ <% end %>
@@ -0,0 +1,31 @@
1
+ <div class="super-field-group">
2
+ <%= form.fields_for(filter_type_select.field_name, filter_type_select) do |form_field| %>
3
+ <%= form_field.label(:q, filter_type_select.humanized_field_name) %>
4
+ <div class="super-input-select inline-block">
5
+ <%= form_field.select(
6
+ :op,
7
+ filter_type_select.operators,
8
+ {},
9
+ { class: "super-input super-input-select-field" }
10
+ ) %>
11
+ <div class="super-input-select-icon text-gray-700">
12
+ <span class="h-4 w-4">
13
+ <%= render "super/feather/chevron_down" %>
14
+ </span>
15
+ </div>
16
+ </div>
17
+ <div class="super-input-select mt-3">
18
+ <%= form_field.select(
19
+ :q,
20
+ filter_type_select.field_type.collection,
21
+ { include_blank: true },
22
+ { class: "super-input super-input-select-field" }
23
+ ) %>
24
+ <div class="super-input-select-icon text-gray-700">
25
+ <span class="h-4 w-4">
26
+ <%= render "super/feather/chevron_down" %>
27
+ </span>
28
+ </div>
29
+ </div>
30
+ <% end %>
31
+ </div>
@@ -0,0 +1,22 @@
1
+ <div class="super-field-group">
2
+ <%= form.fields_for(filter_type_text.field_name, filter_type_text) do |form_field| %>
3
+ <%= form_field.label(:q, filter_type_text.humanized_field_name) %>
4
+ <div class="relative inline-block">
5
+ <%= form_field.select(
6
+ :op,
7
+ filter_type_text.operators,
8
+ {},
9
+ { class: "super-input super-input-select-field" }
10
+ ) %>
11
+ <div class="super-input-select-icon text-gray-700">
12
+ <span class="h-4 w-4">
13
+ <%= render "super/feather/chevron_down" %>
14
+ </span>
15
+ </div>
16
+ </div>
17
+ <%= form_field.text_field(
18
+ :q,
19
+ class: "super-input w-full mt-3"
20
+ ) %>
21
+ <% end %>
22
+ </div>
@@ -0,0 +1,35 @@
1
+ <div class="super-field-group">
2
+ <%= form.fields_for(filter_type_timestamp.field_name, filter_type_timestamp) do |form_field| %>
3
+ <%= form_field.label(:q0, filter_type_timestamp.humanized_field_name) %>
4
+ <div class="relative inline-block mt-2">
5
+ <%= form_field.select(
6
+ :op,
7
+ filter_type_timestamp.operators,
8
+ {},
9
+ { class: "super-input super-input-select-field" }
10
+ ) %>
11
+ <div class="super-input-select-icon text-gray-700">
12
+ <span class="h-4 w-4">
13
+ <%= render "super/feather/chevron_down" %>
14
+ </span>
15
+ </div>
16
+ </div>
17
+ <div class="flex items-center mt-3">
18
+ <div class="flex-initial">
19
+ <%= form_field.text_field(
20
+ :q0,
21
+ class: "super-input w-full"
22
+ ) %>
23
+ </div>
24
+ <div class="flex-initial px-2">
25
+ &ndash;
26
+ </div>
27
+ <div class="flex-initial">
28
+ <%= form_field.text_field(
29
+ :q1,
30
+ class: "super-input w-full"
31
+ ) %>
32
+ </div>
33
+ </div>
34
+ <% end %>
35
+ </div>
@@ -1,17 +1,17 @@
1
- <%
2
- colors = {
1
+ <% if flash.any? %>
2
+ <% colors = {
3
3
  "notice" => { bg: "bg-blue-100", fg: "text-blue-400", border: "border-blue-600" },
4
4
  "alert" => { bg: "bg-red-100", fg: "text-red-400", border: "border-red-600" },
5
- }
6
- %>
5
+ } %>
7
6
 
8
- <div data-flash="anchor">
9
- <% flash.each do |level, messages| %>
10
- <% Array(messages).each do |message| %>
11
- <% color = colors[level.to_s] || colors["notice"] %>
12
- <div class="<%= "%<bg>s %<fg>s border-l-4 %<border>s p-4 mt-2" % color %>">
13
- <%= message %>
14
- </div>
7
+ <div class="mt-8">
8
+ <% flash.each do |level, messages| %>
9
+ <% Array(messages).each do |message| %>
10
+ <% color = colors[level.to_s] || colors["notice"] %>
11
+ <div class="<%= "%<bg>s %<fg>s border-l-4 %<border>s p-4 mt-2" % color %>">
12
+ <%= message %>
13
+ </div>
14
+ <% end %>
15
15
  <% end %>
16
- <% end %>
17
- </div>
16
+ </div>
17
+ <% end %>
@@ -0,0 +1,9 @@
1
+ <% if !local_assigns[:ungrouped] %>
2
+ <div class="super-field-group">
3
+ <% end %>
4
+ <%= form.check_box(column, data: { action: "toggle-pending-destruction#call" }) %>
5
+ <%= form.label(column) %>
6
+ <%= render "form_inline_errors", form: form, column: column %>
7
+ <% if !local_assigns[:ungrouped] %>
8
+ </div>
9
+ <% end %>
@@ -0,0 +1,23 @@
1
+ <% if !local_assigns[:ungrouped] %>
2
+ <div class="super-field-group">
3
+ <% end %>
4
+ <% if !local_assigns[:hide_label] %>
5
+ <%= form.label(column, class: "block") %>
6
+ <% end %>
7
+ <div class="<%= Super::ViewHelper.classes("super-input-select", ["mt-1", !local_assigns[:hide_label]]) %>">
8
+ <%= form.select(
9
+ column,
10
+ form_field_select[:collection],
11
+ { include_blank: true }.merge(form_field_select[:options] || {}),
12
+ { class: "super-input super-input-select-field" }
13
+ ) %>
14
+ <div class="super-input-select-icon text-gray-700">
15
+ <span class="h-4 w-4">
16
+ <%= render "super/feather/chevron_down" %>
17
+ </span>
18
+ </div>
19
+ </div>
20
+ <%= render "form_inline_errors", form: form, column: column %>
21
+ <% if !local_assigns[:ungrouped] %>
22
+ </div>
23
+ <% end %>
@@ -0,0 +1,13 @@
1
+ <% if !local_assigns[:ungrouped] %>
2
+ <div class="super-field-group">
3
+ <% end %>
4
+ <% if !local_assigns[:hide_label] %>
5
+ <%= form.label(column, class: "block") %>
6
+ <% end %>
7
+ <div class="<%= Super::ViewHelper.classes(["mt-1", !local_assigns[:hide_label]]) %>">
8
+ <%= form.text_field(column, class: "super-input w-full") %>
9
+ <%= render "form_inline_errors", form: form, column: column %>
10
+ </div>
11
+ <% if !local_assigns[:ungrouped] %>
12
+ </div>
13
+ <% end %>
@@ -0,0 +1,8 @@
1
+ <fieldset class="border border-gray-300 rounded pb-4 px-4 mt-4 shadow" data-controller="toggle-pending-destruction">
2
+ <% if form_fieldset.label.present? %>
3
+ <legend class="bg-white p-1 -mx-1"><%= form_fieldset.label %></legend>
4
+ <% end %>
5
+ <% form_fieldset.nested_fields.each do |field, type| %>
6
+ <%= render(type, form: form, column: field) %>
7
+ <% end %>
8
+ </fieldset>
@@ -0,0 +1,21 @@
1
+ <div data-controller="apply-template">
2
+ <%= form.fields_for(form_has_many.reader) do |ff| %>
3
+ <%= render "form_fieldset", form_fieldset: form_has_many, form: ff %>
4
+ <% end %>
5
+
6
+ <%=
7
+ form.fields_for(
8
+ form_has_many.reader,
9
+ form.object.public_send(form_has_many.reader).build,
10
+ child_index: "TEMPLATEINDEX"
11
+ ) do |ff|
12
+ %>
13
+ <template data-apply-template-target="template">
14
+ <%= render "form_fieldset", form_fieldset: form_has_many, form: ff %>
15
+ </template>
16
+ <% end %>
17
+
18
+ <a href="#" data-action="apply-template#call" class="super-button super-button--fill-blue mt-2 inline-block">
19
+ Add <%= form_has_many.label %>
20
+ </a>
21
+ </div>