super 0.0.0 → 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/LICENSE +165 -0
- data/README.md +102 -8
- data/app/assets/config/super_manifest.js +1 -0
- data/app/assets/javascripts/super/application.js +3483 -0
- data/app/assets/stylesheets/super/application.css +35265 -0
- data/app/controllers/super/application_controller.rb +84 -0
- data/app/views/layouts/super/application.html.erb +39 -0
- data/app/views/super/application/_form.html.erb +13 -0
- data/app/views/super/application/_form_field.html.erb +7 -0
- data/app/views/super/application/_form_generic_select.html.erb +19 -0
- data/app/views/super/application/_form_generic_text.html.erb +7 -0
- data/app/views/super/application/_index.html.erb +58 -0
- data/app/views/super/application/edit.html.erb +7 -0
- data/app/views/super/application/index.html.erb +1 -0
- data/app/views/super/application/new.html.erb +7 -0
- data/app/views/super/application/show.html.erb +10 -0
- data/app/views/super/feather/README.md +32 -0
- data/app/views/super/feather/_chevron_down.svg +1 -0
- data/frontend/super-frontend/build.js +34 -0
- data/frontend/super-frontend/dist/application.css +35265 -0
- data/frontend/super-frontend/dist/application.js +3483 -0
- data/frontend/super-frontend/package.json +14 -0
- data/frontend/super-frontend/postcss.config.js +6 -0
- data/frontend/super-frontend/src/javascripts/super/application.js +11 -0
- data/frontend/super-frontend/src/stylesheets/super/application.css +14 -0
- data/frontend/super-frontend/tailwind.config.js +7 -0
- data/frontend/super-frontend/yarn.lock +5355 -0
- data/lib/generators/super/install/USAGE +32 -0
- data/lib/generators/super/install/install_generator.rb +47 -0
- data/lib/generators/super/install/templates/base_controller.rb.tt +2 -0
- data/lib/generators/super/install/templates/initializer.rb.tt +5 -0
- data/lib/generators/super/resource/USAGE +9 -0
- data/lib/generators/super/resource/resource_generator.rb +54 -0
- data/lib/generators/super/resource/templates/resource_dashboard.rb.tt +65 -0
- data/lib/generators/super/resource/templates/resources_controller.rb.tt +9 -0
- data/lib/generators/super/webpacker/USAGE +14 -0
- data/lib/generators/super/webpacker/templates/pack_super_application.js.erb.tt +2 -0
- data/lib/generators/super/webpacker/webpacker_generator.rb +17 -0
- data/lib/super.rb +17 -4
- data/lib/super/assets.rb +62 -0
- data/lib/super/configuration.rb +88 -0
- data/lib/super/controls.rb +25 -0
- data/lib/super/display.rb +9 -0
- data/lib/super/display/schema_types.rb +41 -0
- data/lib/super/engine.rb +5 -0
- data/lib/super/error.rb +8 -0
- data/lib/super/form/schema_types.rb +47 -0
- data/lib/super/inline_callback.rb +82 -0
- data/lib/super/navigation/automatic.rb +69 -0
- data/lib/super/pagination.rb +59 -0
- data/lib/super/plugin.rb +89 -0
- data/lib/super/schema.rb +24 -0
- data/lib/super/test_support/fixtures/members.yml +336 -0
- data/lib/super/test_support/fixtures/ships.yml +10 -0
- data/lib/super/test_support/setup.rb +79 -0
- data/lib/super/test_support/starfleet_seeder.rb +49 -0
- data/lib/super/test_support/templates/20190216224956_create_members.rb +11 -0
- data/lib/super/test_support/templates/20190803143320_create_ships.rb +11 -0
- data/lib/super/test_support/templates/20190806014121_add_ship_to_members.rb +5 -0
- data/lib/super/test_support/templates/admin/members_controller.rb +9 -0
- data/lib/super/test_support/templates/admin/ships_controller.rb +9 -0
- data/lib/super/test_support/templates/admin_controller.rb +2 -0
- data/lib/super/test_support/templates/member.rb +16 -0
- data/lib/super/test_support/templates/member_dashboard.rb +90 -0
- data/lib/super/test_support/templates/routes.rb +10 -0
- data/lib/super/test_support/templates/seeds.rb +2 -0
- data/lib/super/test_support/templates/ship.rb +3 -0
- data/lib/super/test_support/templates/ship_dashboard.rb +79 -0
- data/lib/super/version.rb +1 -1
- data/lib/super/view.rb +25 -0
- metadata +131 -12
- data/LICENSE.txt +0 -40
@@ -0,0 +1,25 @@
|
|
1
|
+
module Super
|
2
|
+
class Controls
|
3
|
+
def initialize(dashboard)
|
4
|
+
@dashboard = dashboard
|
5
|
+
end
|
6
|
+
|
7
|
+
attr_reader :dashboard
|
8
|
+
|
9
|
+
def method_missing(method_name, *args)
|
10
|
+
if @dashboard.respond_to?(method_name)
|
11
|
+
@dashboard.public_send(method_name, *args)
|
12
|
+
else
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def respond_to_missing?(method_name, _ = false)
|
18
|
+
if @dashboard.respond_to?(method_name)
|
19
|
+
true
|
20
|
+
else
|
21
|
+
super
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Super
|
2
|
+
class Display
|
3
|
+
# This schema type is meant to be used for +#index+ or +#show+ actions to
|
4
|
+
# transform database fields into something that is human friendly.
|
5
|
+
#
|
6
|
+
# Note: The constants under "Defined Under Namespace" are considered
|
7
|
+
# private.
|
8
|
+
#
|
9
|
+
# class MemberDashboard
|
10
|
+
# # ...
|
11
|
+
#
|
12
|
+
# def show_schema
|
13
|
+
# Super::Schema.new(Super::Display::SchemaTypes.new) do |fields, type|
|
14
|
+
# fields[:name] = type.dynamic { |name| name }
|
15
|
+
# fields[:rank] = type.dynamic { |rank| rank }
|
16
|
+
# fields[:position] = type.dynamic { |position| position }
|
17
|
+
# fields[:ship] = type.dynamic { |ship| "#{ship.name} (Ship ##{ship.id})" }
|
18
|
+
# fields[:created_at] = type.dynamic { |created_at| created_at.iso8601 }
|
19
|
+
# fields[:updated_at] = type.dynamic { |updated_at| updated_at.iso8601 }
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # ...
|
24
|
+
# end
|
25
|
+
class SchemaTypes
|
26
|
+
class Dynamic
|
27
|
+
def initialize(transform_block)
|
28
|
+
@transform_block = transform_block
|
29
|
+
end
|
30
|
+
|
31
|
+
def present(field)
|
32
|
+
@transform_block.call(field)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def dynamic(&transform_block)
|
37
|
+
Dynamic.new(transform_block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
data/lib/super/engine.rb
CHANGED
data/lib/super/error.rb
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
module Super
|
2
|
+
class Form
|
3
|
+
# This schema type is used on your +#edit+ and +#new+ forms
|
4
|
+
#
|
5
|
+
# Note: The constants under "Defined Under Namespace" are considered
|
6
|
+
# private.
|
7
|
+
#
|
8
|
+
# class MemberDashboard
|
9
|
+
# # ...
|
10
|
+
#
|
11
|
+
# def new_schema
|
12
|
+
# Super::Schema.new(Super::Form::SchemaTypes.new) do |fields, type|
|
13
|
+
# fields[:name] = type.generic("write_type_text")
|
14
|
+
# fields[:rank] = type.generic("write_type_select", collection: Member.ranks.keys)
|
15
|
+
# fields[:position] = type.generic("write_type_text")
|
16
|
+
# fields[:ship_id] = type.generic(
|
17
|
+
# "write_type_select",
|
18
|
+
# collection: Ship.all.map { |s| ["#{s.name} (Ship ##{s.id})", s.id] },
|
19
|
+
# )
|
20
|
+
# end
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# # ...
|
24
|
+
# end
|
25
|
+
class SchemaTypes
|
26
|
+
class Generic
|
27
|
+
def initialize(partial_path:, extras:)
|
28
|
+
@partial_path = partial_path
|
29
|
+
@extras = extras
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_partial_path
|
33
|
+
@partial_path
|
34
|
+
end
|
35
|
+
|
36
|
+
def [](key)
|
37
|
+
@extras[key]
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def generic(partial_path, extras = nil)
|
42
|
+
extras ||= {}
|
43
|
+
Generic.new(partial_path: partial_path, extras: extras)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Super
|
2
|
+
module InlineCallback
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
register_inline_callback(:yield, on: :index)
|
7
|
+
end
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def inline_callback_registry
|
11
|
+
@inline_callback_registry ||= {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def inline_callback_defined?(action)
|
15
|
+
action = action.to_sym
|
16
|
+
|
17
|
+
inline_callback_registry.key?(action)
|
18
|
+
end
|
19
|
+
|
20
|
+
def inline_callbacks_for(action, check_ancestors = true)
|
21
|
+
action = action.to_sym
|
22
|
+
|
23
|
+
inline_callback_registry[action] ||= {}
|
24
|
+
|
25
|
+
if check_ancestors
|
26
|
+
ancestors.each do |ancestor|
|
27
|
+
if ancestor.respond_to?(:inline_callback_defined?)
|
28
|
+
if ancestor.inline_callback_defined?(action)
|
29
|
+
parent_class_callbacks = ancestor.inline_callbacks_for(action, false)
|
30
|
+
inline_callback_registry[action] = parent_class_callbacks.merge(inline_callback_registry[action])
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
if ancestor == Super::ApplicationController
|
35
|
+
break
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
inline_callback_registry[action]
|
41
|
+
end
|
42
|
+
|
43
|
+
def register_inline_callback(callback, on:, after: nil)
|
44
|
+
action = on.to_sym
|
45
|
+
after = after.to_sym if after.respond_to?(:to_sym)
|
46
|
+
|
47
|
+
callbacks = inline_callbacks_for(action)
|
48
|
+
if !callbacks.key?(callback)
|
49
|
+
callbacks[callback] = []
|
50
|
+
end
|
51
|
+
|
52
|
+
if after
|
53
|
+
callbacks[callback].push(after)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def with_inline_callbacks
|
59
|
+
action = params[:action].to_sym
|
60
|
+
|
61
|
+
callbacks = self.class.inline_callbacks_for(action)
|
62
|
+
|
63
|
+
each_node = -> (&b) { callbacks.each_key(&b) }
|
64
|
+
each_child = -> (cb, &b) { callbacks[cb].each(&b) }
|
65
|
+
|
66
|
+
yield_called = false
|
67
|
+
|
68
|
+
TSort.tsort_each(each_node, each_child) do |callback|
|
69
|
+
if callback == :yield
|
70
|
+
yield_called = true
|
71
|
+
yield
|
72
|
+
else
|
73
|
+
send(callback)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
if !yield_called
|
78
|
+
yield
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Super
|
2
|
+
class Navigation
|
3
|
+
class Automatic
|
4
|
+
def initialize(route_namespace:)
|
5
|
+
route_namespace = route_namespace.to_s
|
6
|
+
|
7
|
+
if route_namespace.include?("/")
|
8
|
+
raise "Can't be nested namespace"
|
9
|
+
end
|
10
|
+
|
11
|
+
@route_namespace = route_namespace
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
if !block_given?
|
16
|
+
return enum_for(:each)
|
17
|
+
end
|
18
|
+
|
19
|
+
navigable_namespace_routes = Rails.application.routes.routes.select do |route|
|
20
|
+
path_spec = route.path.spec
|
21
|
+
|
22
|
+
next if route.verb != "GET"
|
23
|
+
next if !path_spec.respond_to?(:right)
|
24
|
+
next if path_spec.right.left.to_s != @route_namespace
|
25
|
+
next if route.required_parts.any?
|
26
|
+
next if route.defaults.empty?
|
27
|
+
|
28
|
+
true
|
29
|
+
end
|
30
|
+
|
31
|
+
navigable_defaults = navigable_namespace_routes.map do |route|
|
32
|
+
controller_name = route.defaults[:controller] + "_controller"
|
33
|
+
_controller =
|
34
|
+
begin
|
35
|
+
controller_name.camelize.constantize
|
36
|
+
rescue NameError
|
37
|
+
warn("[super] Couldn't find controller: #{controller_name}")
|
38
|
+
next
|
39
|
+
end
|
40
|
+
|
41
|
+
route.defaults
|
42
|
+
end
|
43
|
+
|
44
|
+
grouped_navigable_defaults =
|
45
|
+
navigable_defaults.compact.uniq.group_by { |d| d[:controller] }
|
46
|
+
|
47
|
+
grouped_navigable_defaults.each do |controller, defaults|
|
48
|
+
actions = defaults.map { |d| [d[:action], d[:action]] }.to_h
|
49
|
+
action = actions["index"] || actions["show"]
|
50
|
+
|
51
|
+
next if action.nil?
|
52
|
+
|
53
|
+
path =
|
54
|
+
begin
|
55
|
+
Rails.application.routes.url_for(
|
56
|
+
controller: controller,
|
57
|
+
action: action,
|
58
|
+
only_path: true
|
59
|
+
)
|
60
|
+
rescue ActionController::UrlGenerationError
|
61
|
+
next
|
62
|
+
end
|
63
|
+
|
64
|
+
yield(controller.split("/").last.humanize, path)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Super
|
2
|
+
class Pagination
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :current_pageno
|
6
|
+
attr_reader :limit
|
7
|
+
|
8
|
+
def initialize(total_count:, limit:, query_params:, page_query_param:)
|
9
|
+
@total_count = total_count.to_i
|
10
|
+
@limit = limit.to_i
|
11
|
+
@query_params = query_params
|
12
|
+
@page_query_param = page_query_param
|
13
|
+
|
14
|
+
self.current_pageno = query_params[page_query_param]
|
15
|
+
end
|
16
|
+
|
17
|
+
def offset
|
18
|
+
limit * (current_pageno - 1)
|
19
|
+
end
|
20
|
+
|
21
|
+
def current_pageno=(pageno)
|
22
|
+
pageno = pageno.to_i
|
23
|
+
|
24
|
+
@current_pageno =
|
25
|
+
if pageno.zero?
|
26
|
+
1
|
27
|
+
else
|
28
|
+
pageno
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def each
|
33
|
+
if !block_given?
|
34
|
+
return enum_for(:each)
|
35
|
+
end
|
36
|
+
|
37
|
+
quotient, remainder = @total_count.divmod(@limit)
|
38
|
+
pages =
|
39
|
+
if remainder.zero?
|
40
|
+
quotient
|
41
|
+
else
|
42
|
+
quotient + 1
|
43
|
+
end
|
44
|
+
|
45
|
+
(1..pages).each do |pageno|
|
46
|
+
is_current_page = pageno == current_pageno
|
47
|
+
display = pageno.to_s
|
48
|
+
page_query_params = @query_params.dup
|
49
|
+
if pageno == 1
|
50
|
+
page_query_params.delete(:page)
|
51
|
+
else
|
52
|
+
page_query_params[@page_query_param] = pageno
|
53
|
+
end
|
54
|
+
|
55
|
+
yield(page_query_params, is_current_page, display)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/super/plugin.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
module Super
|
2
|
+
class Pluggable < Module
|
3
|
+
def initialize(registry_name)
|
4
|
+
@registry_name = registry_name
|
5
|
+
end
|
6
|
+
|
7
|
+
def included(base)
|
8
|
+
super
|
9
|
+
|
10
|
+
PluginRegistry.base_set(@registry_name, base)
|
11
|
+
|
12
|
+
plugins = PluginRegistry.plugins_for(@registry_name)
|
13
|
+
|
14
|
+
plugins.each do |klass, method_name|
|
15
|
+
base.public_send(method_name, klass)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
class PluginRegistry
|
21
|
+
class << self
|
22
|
+
def include_to(name, klass)
|
23
|
+
plugin_push(name.to_sym, :include, klass)
|
24
|
+
end
|
25
|
+
|
26
|
+
def prepend_to(name, klass)
|
27
|
+
plugin_push(name.to_sym, :prepend, klass)
|
28
|
+
end
|
29
|
+
|
30
|
+
def plugins_for(name)
|
31
|
+
name = name.to_sym
|
32
|
+
|
33
|
+
plugins.fetch(name) { {} }
|
34
|
+
end
|
35
|
+
|
36
|
+
def base_set(name, klass)
|
37
|
+
name = name.to_sym
|
38
|
+
|
39
|
+
if !klass.kind_of?(Class)
|
40
|
+
raise Error::InvalidPluginArgument,
|
41
|
+
"Received `#{klass}` which must be a class"
|
42
|
+
end
|
43
|
+
|
44
|
+
bases[name] = klass
|
45
|
+
|
46
|
+
true
|
47
|
+
end
|
48
|
+
|
49
|
+
def base_get(name)
|
50
|
+
name = name.to_sym
|
51
|
+
|
52
|
+
bases[name]
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def plugin_push(name, method_name, klass)
|
58
|
+
if ![:include, :prepend].include?(method_name)
|
59
|
+
raise Error::InvalidPluginArgument,
|
60
|
+
"Received `#{method_name.inspect}`, must be either :include or :prepend"
|
61
|
+
end
|
62
|
+
|
63
|
+
if !klass.kind_of?(Module)
|
64
|
+
raise Error::InvalidPluginArgument,
|
65
|
+
"Received `#{klass}` which must be a module"
|
66
|
+
end
|
67
|
+
|
68
|
+
plugins[name] ||= {}
|
69
|
+
plugins[name][klass] = method_name
|
70
|
+
|
71
|
+
base = base_get(name)
|
72
|
+
|
73
|
+
if base
|
74
|
+
base.public_send(method_name, klass)
|
75
|
+
end
|
76
|
+
|
77
|
+
true
|
78
|
+
end
|
79
|
+
|
80
|
+
def plugins
|
81
|
+
@plugins ||= {}
|
82
|
+
end
|
83
|
+
|
84
|
+
def bases
|
85
|
+
@bases ||= {}
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|