mensa 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/gem-push.yml +11 -0
- data/.gitignore +12 -0
- data/Gemfile +10 -8
- data/Gemfile.lock +299 -0
- data/MIT-LICENSE +20 -0
- data/Procfile +2 -0
- data/README.md +76 -18
- data/Rakefile +5 -13
- data/app/assets/config/mensa_manifest.js +5 -0
- data/app/assets/images/mensa/.keep +0 -0
- data/app/assets/stylesheets/mensa/application.css +11 -0
- data/app/components/mensa/add_filter/component.css +13 -0
- data/app/components/mensa/add_filter/component.html.slim +16 -0
- data/app/components/mensa/add_filter/component.rb +13 -0
- data/app/components/mensa/add_filter/component_controller.js +84 -0
- data/app/components/mensa/application_component.rb +12 -0
- data/app/components/mensa/cell/component.css +0 -0
- data/app/components/mensa/cell/component.html.slim +1 -0
- data/app/components/mensa/cell/component.rb +15 -0
- data/app/components/mensa/control_bar/component.css +5 -0
- data/app/components/mensa/control_bar/component.html.slim +15 -0
- data/app/components/mensa/control_bar/component.rb +21 -0
- data/app/components/mensa/filters/component.css +14 -0
- data/app/components/mensa/filters/component.html.slim +14 -0
- data/app/components/mensa/filters/component.rb +13 -0
- data/app/components/mensa/filters/component_controller.js +14 -0
- data/app/components/mensa/header/component.css +54 -0
- data/app/components/mensa/header/component.html.slim +8 -0
- data/app/components/mensa/header/component.rb +19 -0
- data/app/components/mensa/row_action/component.css +0 -0
- data/app/components/mensa/row_action/component.html.slim +6 -0
- data/app/components/mensa/row_action/component.rb +19 -0
- data/app/components/mensa/search/component.css +13 -0
- data/app/components/mensa/search/component.html.slim +17 -0
- data/app/components/mensa/search/component.rb +13 -0
- data/app/components/mensa/search/component_controller.js +62 -0
- data/app/components/mensa/table/component.css +0 -0
- data/app/components/mensa/table/component.html.slim +7 -0
- data/app/components/mensa/table/component.rb +16 -0
- data/app/components/mensa/table/component_controller.js +72 -0
- data/app/components/mensa/table_row/component.css +0 -0
- data/app/components/mensa/table_row/component.html.slim +6 -0
- data/app/components/mensa/table_row/component.rb +19 -0
- data/app/components/mensa/view/component.css +82 -0
- data/app/components/mensa/view/component.html.slim +17 -0
- data/app/components/mensa/view/component.rb +16 -0
- data/app/components/mensa/views/component.css +13 -0
- data/app/components/mensa/views/component.html.slim +18 -0
- data/app/components/mensa/views/component.rb +14 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/controllers/mensa/application_controller.rb +4 -0
- data/app/controllers/mensa/tables/filters_controller.rb +29 -0
- data/app/controllers/mensa/tables_controller.rb +37 -0
- data/app/helpers/mensa/application_helper.rb +5 -0
- data/app/helpers/mensa/tables_helper.rb +5 -0
- data/app/javascript/mensa/application.js +3 -0
- data/app/javascript/mensa/controllers/alert_controller.js +7 -0
- data/app/javascript/mensa/controllers/application.js +8 -0
- data/app/javascript/mensa/controllers/application_controller.js +57 -0
- data/app/javascript/mensa/controllers/index.js +24 -0
- data/app/jobs/mensa/application_job.rb +7 -0
- data/app/jobs/mensa/export_job.rb +91 -0
- data/app/models/concerns/.keep +0 -0
- data/app/models/mensa/application_record.rb +5 -0
- data/app/models/mensa/table_view.rb +5 -0
- data/app/tables/mensa/action.rb +26 -0
- data/app/tables/mensa/base.rb +103 -0
- data/app/tables/mensa/cell.rb +50 -0
- data/app/tables/mensa/column.rb +85 -0
- data/app/tables/mensa/config/action_dsl.rb +12 -0
- data/app/tables/mensa/config/column_dsl.rb +23 -0
- data/app/tables/mensa/config/dsl_logic.rb +90 -0
- data/app/tables/mensa/config/filter_dsl.rb +8 -0
- data/app/tables/mensa/config/render_dsl.rb +8 -0
- data/app/tables/mensa/config/table_dsl.rb +71 -0
- data/app/tables/mensa/config_readers.rb +13 -0
- data/app/tables/mensa/filter.rb +31 -0
- data/app/tables/mensa/row.rb +36 -0
- data/app/tables/mensa/scope.rb +99 -0
- data/app/views/layouts/mensa/application.html.slim +11 -0
- data/app/views/mensa/tables/filters/show.turbo_stream.slim +8 -0
- data/app/views/mensa/tables/index.html.slim +93 -0
- data/app/views/mensa/tables/show.html.slim +5 -0
- data/app/views/mensa/tables/show.turbo_stream.slim +5 -0
- data/bin/importmap +4 -0
- data/bin/rails +14 -0
- data/config/importmap.rb +8 -0
- data/config/locales/en.yml +8 -0
- data/config/locales/nl.yml +11 -0
- data/config/routes.rb +7 -0
- data/db/migrate/20240201184752_create_mensa_table_views.rb +15 -0
- data/lib/generators/mensa/install_generator.rb +24 -0
- data/lib/generators/mensa/tailwind_config_generator.rb +24 -0
- data/lib/generators/mensa/templates/config/initializers/mensa.rb +22 -0
- data/lib/mensa/configuration.rb +90 -0
- data/lib/mensa/engine.rb +37 -0
- data/lib/mensa/version.rb +1 -3
- data/lib/mensa.rb +24 -5
- data/lib/tasks/mensa_tasks.rake +13 -0
- data/mensa.gemspec +42 -0
- data/package.json +10 -0
- data/vendor/javascript/@rails--request.js.js +2 -0
- data/yarn.lock +837 -0
- metadata +245 -18
- data/.rubocop.yml +0 -13
- data/CHANGELOG.md +0 -5
- data/CODE_OF_CONDUCT.md +0 -84
- data/LICENSE.txt +0 -21
- data/sig/mensa.rbs +0 -4
@@ -0,0 +1,90 @@
|
|
1
|
+
module Mensa::Config
|
2
|
+
module DslLogic
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
attr_reader :config, :values
|
6
|
+
|
7
|
+
delegate :default_config, to: :class
|
8
|
+
|
9
|
+
def initialize(name, &)
|
10
|
+
@config = {}
|
11
|
+
@config[:name] = name if name
|
12
|
+
@config = @config.merge(default_config.deep_dup)
|
13
|
+
|
14
|
+
instance_eval(&) if block_given?
|
15
|
+
end
|
16
|
+
|
17
|
+
class_methods do
|
18
|
+
attr_reader :default_config
|
19
|
+
|
20
|
+
def option(name, default: nil, config_name: nil, dsl: nil, dsl_hash: nil, dsl_array: nil)
|
21
|
+
if dsl
|
22
|
+
dsl_option(name, dsl)
|
23
|
+
elsif dsl_hash
|
24
|
+
dsl_hash(name, dsl_hash, config_name: config_name)
|
25
|
+
elsif dsl_array
|
26
|
+
dsl_array(name, dsl_array, config_name: config_name)
|
27
|
+
else
|
28
|
+
simple_option(name, default: default)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
###
|
33
|
+
# Define a accessor method
|
34
|
+
#
|
35
|
+
# def name(value = nil, &)
|
36
|
+
# config[:name] = block || value
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# by calling simple_option :name
|
40
|
+
#
|
41
|
+
def simple_option(option_name, default: nil)
|
42
|
+
@default_config ||= {}
|
43
|
+
@default_config[option_name.to_sym] = default
|
44
|
+
|
45
|
+
define_method(option_name) do |value = nil, &block|
|
46
|
+
config[option_name.to_sym] = block || value
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
###
|
51
|
+
# Define a DSL method
|
52
|
+
#
|
53
|
+
# def render(name, &)
|
54
|
+
# config[:render] = Mensa::RenderDsl.new(name, &).config
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
# by calling define_dsl :render, Mensa::RenderDsl
|
58
|
+
#
|
59
|
+
def dsl_option(option_name, klass)
|
60
|
+
define_method(option_name) do |name = nil, &block|
|
61
|
+
config[option_name.to_sym] = block && klass.new(name, &block).config
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def dsl_hash(option_name, klass, config_name:)
|
66
|
+
config_name = config_name || option_name.to_s.pluralize.to_sym
|
67
|
+
|
68
|
+
@default_config ||= {}
|
69
|
+
@default_config[option_name.to_sym] = {}
|
70
|
+
|
71
|
+
define_method(option_name) do |name = nil, &block|
|
72
|
+
config[config_name] ||= {}
|
73
|
+
config[config_name][name] = klass.new(nil, &block).config
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def dsl_array(option_name, klass, config_name: option_name.to_s.pluralize.to_sym)
|
78
|
+
config_name = config_name || option_name.to_s.pluralize.to_sym
|
79
|
+
|
80
|
+
@default_config ||= {}
|
81
|
+
@default_config[name.to_sym] = []
|
82
|
+
|
83
|
+
define_method(option_name) do |name = nil, &block|
|
84
|
+
config[config_name] ||= []
|
85
|
+
config[config_name] << klass.new(name, &block).config
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# class UsersTable < Mensa::Base
|
2
|
+
# definition do
|
3
|
+
# model User
|
4
|
+
#
|
5
|
+
# render do # default Standard components
|
6
|
+
# html # Mensa::TableComponent::Default
|
7
|
+
# json # Mensa::JsonRenderer::Default
|
8
|
+
# xlsx # Mensa::XlsxRenderer::Default
|
9
|
+
# end
|
10
|
+
#
|
11
|
+
# column(:first_name) do
|
12
|
+
# filter
|
13
|
+
# # render do
|
14
|
+
# # html do |c|
|
15
|
+
# # link_to(edit_contact_path(c)) do
|
16
|
+
# # content_tag("i", nil, class: "fal fa-book")
|
17
|
+
# # end
|
18
|
+
# # end
|
19
|
+
# # end
|
20
|
+
# end
|
21
|
+
# column :last_name do
|
22
|
+
# filter
|
23
|
+
# end
|
24
|
+
# column :email
|
25
|
+
# column :phone_number
|
26
|
+
# column :state
|
27
|
+
# column :city
|
28
|
+
# column :created_at
|
29
|
+
#
|
30
|
+
# order last_name: :asc
|
31
|
+
# link { |user| edit_user_path(user) }
|
32
|
+
#
|
33
|
+
# supports_views true
|
34
|
+
#
|
35
|
+
# action :activate do
|
36
|
+
# link { |user| edit_user_path(user) }
|
37
|
+
# icon "fa-check"
|
38
|
+
# end
|
39
|
+
# action :delete do
|
40
|
+
# link { |user| edit_user_path(user) }
|
41
|
+
# link_attributes "data-turbo-method" => "delete"
|
42
|
+
# icon "fa-xmark"
|
43
|
+
# end
|
44
|
+
# end
|
45
|
+
|
46
|
+
module Mensa::Config
|
47
|
+
class TableDsl
|
48
|
+
include DslLogic
|
49
|
+
|
50
|
+
option :model, default: -> { self.class.name.demodulize.to_s.classify.constantize rescue raise "No model found for #{self.class.name}" }
|
51
|
+
option :column, dsl_hash: Mensa::Config::ColumnDsl
|
52
|
+
option :link
|
53
|
+
|
54
|
+
# Default sort order {column: direction, column: direction}
|
55
|
+
option :order, default: {}
|
56
|
+
|
57
|
+
# Order of columns in the table
|
58
|
+
option :column_order
|
59
|
+
|
60
|
+
# Actions
|
61
|
+
option :action, dsl_hash: Mensa::Config::ActionDsl
|
62
|
+
|
63
|
+
dsl_option :render, Mensa::Config::RenderDsl
|
64
|
+
|
65
|
+
option :supports_views, default: false
|
66
|
+
option :show_header, default: true
|
67
|
+
option :view_columns_sorting, default: true
|
68
|
+
option :view_condensed, default: false
|
69
|
+
option :view_condensed_toggle, default: true
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mensa
|
4
|
+
class Filter
|
5
|
+
include ConfigReaders
|
6
|
+
attr_reader :column, :value, :config, :table
|
7
|
+
|
8
|
+
config_reader :scope
|
9
|
+
|
10
|
+
def initialize(value, column:, config:, table:)
|
11
|
+
@value = value
|
12
|
+
@column = column
|
13
|
+
@config = config
|
14
|
+
@table = table
|
15
|
+
end
|
16
|
+
|
17
|
+
def collection
|
18
|
+
return unless config&.key?(:collection)
|
19
|
+
|
20
|
+
if config[:collection].is_a? Proc
|
21
|
+
table.original_view_context.instance_exec(&config[:collection])
|
22
|
+
else
|
23
|
+
config[:collection]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_s
|
28
|
+
"#{column.human_name}: #{value}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mensa
|
4
|
+
class Row
|
5
|
+
attr_reader :table, :view_context, :record
|
6
|
+
|
7
|
+
def initialize(table, record)
|
8
|
+
@table = table
|
9
|
+
@record = record
|
10
|
+
end
|
11
|
+
|
12
|
+
def value(column)
|
13
|
+
if column.attribute && record.respond_to?(column.attribute)
|
14
|
+
record.public_send(column.attribute)
|
15
|
+
elsif column.method && record.respond_to?(column.method)
|
16
|
+
record.public_send(column.method)
|
17
|
+
elsif record.respond_to?(column.name)
|
18
|
+
record.public_send(column.name)
|
19
|
+
elsif record.respond_to?(:[])
|
20
|
+
record[column.name]
|
21
|
+
else
|
22
|
+
"-"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def link_attributes
|
27
|
+
return {} unless link
|
28
|
+
|
29
|
+
{ href: link, data: { controller: "satis-link", action: "click->satis-link#follow tap->satis-link#follow" } }
|
30
|
+
end
|
31
|
+
|
32
|
+
def link
|
33
|
+
table.original_view_context.instance_exec(record, &table.link) if table.link
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mensa
|
4
|
+
module Scope
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the records we want to display, using the Active Record Query Interface
|
11
|
+
# By default it returns all records
|
12
|
+
def scope
|
13
|
+
model.all
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns the scope, but filtered
|
17
|
+
def filtered_scope
|
18
|
+
return @filtered_scope if @filtered_scope
|
19
|
+
|
20
|
+
@filtered_scope = scope
|
21
|
+
# See https://github.com/textacular/textacular
|
22
|
+
# This has problems - not all table fields are searched
|
23
|
+
@filtered_scope = @filtered_scope.basic_search(params[:query]) if params[:query]
|
24
|
+
|
25
|
+
if params[:filters]
|
26
|
+
params[:filters].each do |column_name, value|
|
27
|
+
next unless (column = column(column_name))
|
28
|
+
|
29
|
+
@filtered_scope = if column.filter&.scope
|
30
|
+
@filtered_scope.instance_exec(Helper.normalize(value), &column.filter.scope)
|
31
|
+
else
|
32
|
+
@filtered_scope.where(column.attribute_for_condition => Helper.normalize(value))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
@filtered_scope
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns the filtered_columns, but ordered, we always reorder, scope shouldn't include ordering
|
41
|
+
def ordered_scope
|
42
|
+
return @ordered_scope if @ordered_scope
|
43
|
+
|
44
|
+
@ordered_scope = filtered_scope
|
45
|
+
@ordered_scope = @ordered_scope.reorder(order_hash)
|
46
|
+
|
47
|
+
@ordered_scope
|
48
|
+
end
|
49
|
+
|
50
|
+
# Return the ordered_scope, but with only the columns selected
|
51
|
+
def selected_scope
|
52
|
+
return @selected_scope if @selected_scope
|
53
|
+
|
54
|
+
@selected_scope = ordered_scope
|
55
|
+
@selected_scope = @selected_scope.select([:id] + columns.map(&:attribute).compact)
|
56
|
+
|
57
|
+
Rails.logger.debug("*" * 80)
|
58
|
+
Rails.logger.debug("Selected scope")
|
59
|
+
Rails.logger.debug(@selected_scope.to_sql)
|
60
|
+
Rails.logger.debug("*" * 80)
|
61
|
+
|
62
|
+
|
63
|
+
@selected_scope
|
64
|
+
end
|
65
|
+
|
66
|
+
def paged_scope
|
67
|
+
pagy_object
|
68
|
+
@records
|
69
|
+
end
|
70
|
+
|
71
|
+
def pagy_details
|
72
|
+
pagy_object
|
73
|
+
@pagy_details
|
74
|
+
end
|
75
|
+
|
76
|
+
private
|
77
|
+
|
78
|
+
def pagy_object
|
79
|
+
return if @pagy_details && @records
|
80
|
+
|
81
|
+
@pagy_details, @records = selected_scope.is_a?(Array) ? pagy_array(ordered_scope) : pagy(selected_scope)
|
82
|
+
end
|
83
|
+
|
84
|
+
# Though this works, perhaps moving this in column(s) is nicer
|
85
|
+
def order_hash(new_params = {})
|
86
|
+
(params[:order] || config[:order]).merge(new_params.symbolize_keys)
|
87
|
+
.reject { |name, direction| direction.blank? }
|
88
|
+
.transform_values { |value| value.to_sym }
|
89
|
+
end
|
90
|
+
|
91
|
+
module Helper
|
92
|
+
class << self
|
93
|
+
def normalize(query)
|
94
|
+
query.to_s.gsub(/\s(?![\&\!\|])/, '\\\\ ')
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
= turbo_stream.update params[:target] do
|
2
|
+
= sts.form_for(Mensa::Tables::FiltersController::Filter.new, url: '#') do |f|
|
3
|
+
- if @column.filter.collection
|
4
|
+
= f.input :value, collection: @column.filter.collection, input_html: { "data-action"=> "keydown.esc->mensa-add-filter#reset keydown.enter->mensa-add-filter#filterValueEntered", autofocus: "autofocus" }, label: @column.human_name
|
5
|
+
- else
|
6
|
+
= f.input :value, input_html: { "data-action"=> "keydown.esc->mensa-add-filter#reset keydown.enter->mensa-add-filter#filterValueEntered", autofocus: "autofocus" }, label: @column.human_name
|
7
|
+
a.sts-table__add_filter__popover_container__clear
|
8
|
+
| Clear
|
@@ -0,0 +1,93 @@
|
|
1
|
+
button data-controller="alert" data-action="alert#alert"
|
2
|
+
| Click me
|
3
|
+
|
4
|
+
<ul role="list" class="divide-y divide-gray-100">
|
5
|
+
<li class="flex justify-between gap-x-6 py-5">
|
6
|
+
<div class="flex min-w-0 gap-x-4">
|
7
|
+
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" src="https://images.unsplash.com/photo-1494790108377-be9c29b29330?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
|
8
|
+
<div class="min-w-0 flex-auto">
|
9
|
+
<p class="text-sm font-semibold leading-6 text-gray-900">Leslie Alexander</p>
|
10
|
+
<p class="mt-1 truncate text-xs leading-5 text-gray-500">leslie.alexander@example.com</p>
|
11
|
+
</div>
|
12
|
+
</div>
|
13
|
+
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
14
|
+
<p class="text-sm leading-6 text-gray-900">Co-Founder / CEO</p>
|
15
|
+
<p class="mt-1 text-xs leading-5 text-gray-500">Last seen <time datetime="2023-01-23T13:23Z">3h ago</time></p>
|
16
|
+
</div>
|
17
|
+
</li>
|
18
|
+
<li class="flex justify-between gap-x-6 py-5">
|
19
|
+
<div class="flex min-w-0 gap-x-4">
|
20
|
+
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" src="https://images.unsplash.com/photo-1519244703995-f4e0f30006d5?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
|
21
|
+
<div class="min-w-0 flex-auto">
|
22
|
+
<p class="text-sm font-semibold leading-6 text-gray-900">Michael Foster</p>
|
23
|
+
<p class="mt-1 truncate text-xs leading-5 text-gray-500">michael.foster@example.com</p>
|
24
|
+
</div>
|
25
|
+
</div>
|
26
|
+
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
27
|
+
<p class="text-sm leading-6 text-gray-900">Co-Founder / CTO</p>
|
28
|
+
<p class="mt-1 text-xs leading-5 text-gray-500">Last seen <time datetime="2023-01-23T13:23Z">3h ago</time></p>
|
29
|
+
</div>
|
30
|
+
</li>
|
31
|
+
<li class="flex justify-between gap-x-6 py-5">
|
32
|
+
<div class="flex min-w-0 gap-x-4">
|
33
|
+
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" src="https://images.unsplash.com/photo-1506794778202-cad84cf45f1d?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
|
34
|
+
<div class="min-w-0 flex-auto">
|
35
|
+
<p class="text-sm font-semibold leading-6 text-gray-900">Dries Vincent</p>
|
36
|
+
<p class="mt-1 truncate text-xs leading-5 text-gray-500">dries.vincent@example.com</p>
|
37
|
+
</div>
|
38
|
+
</div>
|
39
|
+
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
40
|
+
<p class="text-sm leading-6 text-gray-900">Business Relations</p>
|
41
|
+
<div class="mt-1 flex items-center gap-x-1.5">
|
42
|
+
<div class="flex-none rounded-full bg-emerald-500/20 p-1">
|
43
|
+
<div class="h-1.5 w-1.5 rounded-full bg-emerald-500"></div>
|
44
|
+
</div>
|
45
|
+
<p class="text-xs leading-5 text-gray-500">Online</p>
|
46
|
+
</div>
|
47
|
+
</div>
|
48
|
+
</li>
|
49
|
+
<li class="flex justify-between gap-x-6 py-5">
|
50
|
+
<div class="flex min-w-0 gap-x-4">
|
51
|
+
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" src="https://images.unsplash.com/photo-1517841905240-472988babdf9?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
|
52
|
+
<div class="min-w-0 flex-auto">
|
53
|
+
<p class="text-sm font-semibold leading-6 text-gray-900">Lindsay Walton</p>
|
54
|
+
<p class="mt-1 truncate text-xs leading-5 text-gray-500">lindsay.walton@example.com</p>
|
55
|
+
</div>
|
56
|
+
</div>
|
57
|
+
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
58
|
+
<p class="text-sm leading-6 text-gray-900">Front-end Developer</p>
|
59
|
+
<p class="mt-1 text-xs leading-5 text-gray-500">Last seen <time datetime="2023-01-23T13:23Z">3h ago</time></p>
|
60
|
+
</div>
|
61
|
+
</li>
|
62
|
+
<li class="flex justify-between gap-x-6 py-5">
|
63
|
+
<div class="flex min-w-0 gap-x-4">
|
64
|
+
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" src="https://images.unsplash.com/photo-1438761681033-6461ffad8d80?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
|
65
|
+
<div class="min-w-0 flex-auto">
|
66
|
+
<p class="text-sm font-semibold leading-6 text-gray-900">Courtney Henry</p>
|
67
|
+
<p class="mt-1 truncate text-xs leading-5 text-gray-500">courtney.henry@example.com</p>
|
68
|
+
</div>
|
69
|
+
</div>
|
70
|
+
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
71
|
+
<p class="text-sm leading-6 text-gray-900">Designer</p>
|
72
|
+
<p class="mt-1 text-xs leading-5 text-gray-500">Last seen <time datetime="2023-01-23T13:23Z">3h ago</time></p>
|
73
|
+
</div>
|
74
|
+
</li>
|
75
|
+
<li class="flex justify-between gap-x-6 py-5">
|
76
|
+
<div class="flex min-w-0 gap-x-4">
|
77
|
+
<img class="h-12 w-12 flex-none rounded-full bg-gray-50" src="https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80" alt="">
|
78
|
+
<div class="min-w-0 flex-auto">
|
79
|
+
<p class="text-sm font-semibold leading-6 text-gray-900">Tom Cook</p>
|
80
|
+
<p class="mt-1 truncate text-xs leading-5 text-gray-500">tom.cook@example.com</p>
|
81
|
+
</div>
|
82
|
+
</div>
|
83
|
+
<div class="hidden shrink-0 sm:flex sm:flex-col sm:items-end">
|
84
|
+
<p class="text-sm leading-6 text-gray-900">Director of Product</p>
|
85
|
+
<div class="mt-1 flex items-center gap-x-1.5">
|
86
|
+
<div class="flex-none rounded-full bg-emerald-500/20 p-1">
|
87
|
+
<div class="h-1.5 w-1.5 rounded-full bg-emerald-500"></div>
|
88
|
+
</div>
|
89
|
+
<p class="text-xs leading-5 text-gray-500">Online</p>
|
90
|
+
</div>
|
91
|
+
</div>
|
92
|
+
</li>
|
93
|
+
</ul>
|
data/bin/importmap
ADDED
data/bin/rails
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# This command will automatically be run when you run "rails" with Rails gems
|
3
|
+
# installed from the root of your application.
|
4
|
+
|
5
|
+
ENGINE_ROOT = File.expand_path("..", __dir__)
|
6
|
+
ENGINE_PATH = File.expand_path("../lib/mensa/engine", __dir__)
|
7
|
+
APP_PATH = File.expand_path("../test/dummy/config/application", __dir__)
|
8
|
+
|
9
|
+
# Set up gems listed in the Gemfile.
|
10
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
11
|
+
require "bundler/setup" if File.exist?(ENV["BUNDLE_GEMFILE"])
|
12
|
+
|
13
|
+
require "rails/all"
|
14
|
+
require "rails/engine/commands"
|
data/config/importmap.rb
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
pin "mensa", to: "mensa/application.js", preload: true
|
2
|
+
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
|
3
|
+
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
|
4
|
+
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
|
5
|
+
pin '@fortawesome/fontawesome-free', to: 'https://ga.jspm.io/npm:@fortawesome/fontawesome-free@6.1.1/js/all.js'
|
6
|
+
pin_all_from Mensa::Engine.root.join("app/javascript/mensa/controllers"), under: "mensa/controllers", to: "mensa/controllers", preload: false
|
7
|
+
pin_all_from Mensa::Engine.root.join("app/components/mensa"), under: "mensa/components", to: "mensa", preload: false
|
8
|
+
pin "@rails/request.js", to: "@rails--request.js.js" # @0.0.9
|
data/config/routes.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateMensaTableViews < ActiveRecord::Migration[7.1]
|
2
|
+
def change
|
3
|
+
create_table :mensa_table_views, id: :uuid do |t|
|
4
|
+
t.string :table_name
|
5
|
+
t.string :name
|
6
|
+
t.jsonb :data
|
7
|
+
|
8
|
+
t.references :user, null: true, foreign_key: true, type: :uuid
|
9
|
+
|
10
|
+
t.timestamps
|
11
|
+
end
|
12
|
+
add_index :mensa_table_views, :table_name, unique: false
|
13
|
+
add_index :mensa_table_views, :data, using: :gin
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mensa
|
4
|
+
class InstallGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../templates", __FILE__)
|
6
|
+
|
7
|
+
def create_initializer_file
|
8
|
+
template "config/initializers/mensa.rb"
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_route
|
12
|
+
return if Rails.application.routes.routes.detect { |route| route.app.app == Mensa::Engine }
|
13
|
+
route %(mount Mensa::Engine => "/mensa")
|
14
|
+
end
|
15
|
+
|
16
|
+
def copy_migrations
|
17
|
+
rake "mensa:install:migrations"
|
18
|
+
end
|
19
|
+
|
20
|
+
def tailwindcss_config
|
21
|
+
rake "mensa:tailwindcss:config"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module Mensa
|
4
|
+
module Generators
|
5
|
+
class TailwindConfigGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path('../templates', __dir__)
|
7
|
+
desc 'Configures tailwind.config.js and application.tailwindcss.css'
|
8
|
+
|
9
|
+
def add_content_to_tailwind_config
|
10
|
+
inject_into_file "config/tailwind.config.js", before: "],\n theme: {" do
|
11
|
+
" // Mensa content\n" +
|
12
|
+
%w[/app/views/**/* /app/helpers/**/* /app/controllers/**/* /app/components/**/* /app/javascript/**/*.js /app/assets/**/*.css].map { |path| " \"#{Mensa::Engine.root}#{path}\"" }.join(",\n") +
|
13
|
+
",\n "
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_content_application_tailwind_css
|
18
|
+
inject_into_file "app/assets/stylesheets/application.tailwind.css", before: "@tailwind base;" do
|
19
|
+
"@import '#{Mensa::Engine.root}/app/assets/stylesheets/mensa/application.css';\n"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
Mensa.setup do |config|
|
2
|
+
# Callbacks for exporting of tables
|
3
|
+
config.callbacks = {
|
4
|
+
export_started: lambda do |user_id, table_name|
|
5
|
+
end,
|
6
|
+
export_completed: lambda do |user_id, table_name, context, attachment|
|
7
|
+
end
|
8
|
+
}
|
9
|
+
|
10
|
+
# Override icons in use
|
11
|
+
config.icons = {
|
12
|
+
order_indicator_asc: "fa-solid fa-sort-up",
|
13
|
+
order_indicator_desc: "fa-solid fa-sort-down",
|
14
|
+
order_indicator: "fa-solid fa-sort",
|
15
|
+
control_bar_search: "fa-solid fa-magnifying-glass",
|
16
|
+
control_bar_filter: "fa-solid fa-filter",
|
17
|
+
control_bar_edit: "fa-solid fa-table-columns",
|
18
|
+
control_bar_compress: "fa-solid fa-compress",
|
19
|
+
control_bar_export: "fa-solid fa-file-export",
|
20
|
+
search: "fa-solid fa-magnifying-glass",
|
21
|
+
}
|
22
|
+
end
|