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
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Mensa
|
4
|
+
module Options
|
5
|
+
module ClassMethods
|
6
|
+
def option(name, default: nil)
|
7
|
+
attr_accessor(name)
|
8
|
+
schema[name] = default
|
9
|
+
end
|
10
|
+
|
11
|
+
def schema
|
12
|
+
@schema ||= {}
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def set_defaults!
|
17
|
+
self.class.schema.each do |name, default|
|
18
|
+
instance_variable_set("@#{name}", default)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(cls)
|
23
|
+
cls.extend(ClassMethods)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class Configuration
|
28
|
+
include Options
|
29
|
+
|
30
|
+
option :logger, default: Rails.logger
|
31
|
+
option :base_controller, default: "::ApplicationController"
|
32
|
+
|
33
|
+
# TODO: add all icons below
|
34
|
+
option :icons, default: {
|
35
|
+
order_indicator_asc: "fa-solid fa-sort-up",
|
36
|
+
order_indicator_desc: "fa-solid fa-sort-down",
|
37
|
+
order_indicator: "fa-solid fa-sort",
|
38
|
+
control_bar_search: "fa-solid fa-magnifying-glass",
|
39
|
+
control_bar_filter: "fa-solid fa-filter",
|
40
|
+
control_bar_edit: "fa-solid fa-table-columns",
|
41
|
+
control_bar_compress: "fa-solid fa-compress",
|
42
|
+
control_bar_export: "fa-solid fa-file-export",
|
43
|
+
search: "fa-solid fa-magnifying-glass"
|
44
|
+
}
|
45
|
+
# PRO
|
46
|
+
# option :icons, default: {
|
47
|
+
# order_indicator_asc: "fa-regular fa-arrow-up-short-wide",
|
48
|
+
# order_indicator_desc: "fa-regular fa-arrow-down-wide-short",
|
49
|
+
# order_indicator: "fa-regular fa-arrow-down-arrow-up",
|
50
|
+
# control_bar_search: "fa-light fa-magnifying-glass",
|
51
|
+
# control_bar_filter: "fa-light fa-bars-filter",
|
52
|
+
# control_bar_edit: "fa-light fa-columns-3",
|
53
|
+
# control_bar_compress: "fa-light fa-compress",
|
54
|
+
# control_bar_export: "fa-light fa-file-export",
|
55
|
+
# search: "fa-light fa-magnifying-glass"
|
56
|
+
# }
|
57
|
+
|
58
|
+
option :callbacks, default: {
|
59
|
+
# Callback is called when the export is started,
|
60
|
+
# the return value is passed as context to the export_complete callback
|
61
|
+
export_started: lambda do |user_id, table_name|
|
62
|
+
end,
|
63
|
+
export_complete: lambda do |user_id, table_name, context, attachment|
|
64
|
+
end
|
65
|
+
}
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
set_defaults!
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
module Configurable
|
73
|
+
attr_writer :config
|
74
|
+
|
75
|
+
def config
|
76
|
+
@config ||= Configuration.new
|
77
|
+
end
|
78
|
+
|
79
|
+
def configure
|
80
|
+
yield(config)
|
81
|
+
end
|
82
|
+
|
83
|
+
alias setup configure
|
84
|
+
|
85
|
+
def reset_config!
|
86
|
+
@config = Configuration.new
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
data/lib/mensa/engine.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'pagy'
|
2
|
+
require 'satis'
|
3
|
+
require 'textacular'
|
4
|
+
require 'caxlsx_rails'
|
5
|
+
require 'slim'
|
6
|
+
require 'tailwindcss-rails'
|
7
|
+
require "importmap-rails"
|
8
|
+
require "turbo-rails"
|
9
|
+
require "stimulus-rails"
|
10
|
+
|
11
|
+
module Mensa
|
12
|
+
class Engine < ::Rails::Engine
|
13
|
+
isolate_namespace Mensa
|
14
|
+
|
15
|
+
initializer 'mensa.assets' do |app|
|
16
|
+
app.config.assets.paths << root.join("app/javascript")
|
17
|
+
app.config.assets.paths << root.join("app/components")
|
18
|
+
app.config.assets.paths << Mensa::Engine.root.join("vendor/javascript")
|
19
|
+
app.config.assets.precompile += %w[mensa_manifest]
|
20
|
+
end
|
21
|
+
|
22
|
+
initializer 'mensa.importmap', before: "importmap" do |app|
|
23
|
+
app.config.importmap.paths << root.join("config/importmap.rb")
|
24
|
+
app.config.importmap.cache_sweepers << root.join("app/javascript")
|
25
|
+
app.config.importmap.cache_sweepers << root.join("app/components")
|
26
|
+
app.config.importmap.cache_sweepers << Mensa::Engine.root.join("vendor/javascript")
|
27
|
+
end
|
28
|
+
|
29
|
+
initializer 'mensa.helper' do
|
30
|
+
Rails.application.reloader.to_prepare do
|
31
|
+
ActiveSupport.on_load(:action_controller) do
|
32
|
+
Satis.add_helper(:table, ::Mensa::Table::Component)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/mensa/version.rb
CHANGED
data/lib/mensa.rb
CHANGED
@@ -1,8 +1,27 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require "mensa/version"
|
2
|
+
require "mensa/engine"
|
3
|
+
require 'mensa/configuration'
|
4
|
+
require "importmap-rails"
|
4
5
|
|
5
6
|
module Mensa
|
6
|
-
|
7
|
-
|
7
|
+
extend Configurable
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def for_name(name, config = {})
|
11
|
+
instance = class_for_name(name).new(config)
|
12
|
+
instance.name = name
|
13
|
+
instance
|
14
|
+
end
|
15
|
+
|
16
|
+
def class_for_name(name)
|
17
|
+
class_name = "#{name}_table".camelcase
|
18
|
+
unless class_name.safe_constantize
|
19
|
+
module_class_name = name.to_s.split('_', 2).map(&:camelcase).join('::') + 'Table'
|
20
|
+
class_name = module_class_name if module_class_name.safe_constantize
|
21
|
+
end
|
22
|
+
Kernel.const_get("::#{class_name}")
|
23
|
+
rescue NameError
|
24
|
+
raise NotImplementedError, "No '#{name}' table defined."
|
25
|
+
end
|
26
|
+
end
|
8
27
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
namespace :mensa do
|
2
|
+
namespace :tailwindcss do
|
3
|
+
desc "Configure your Tailwind CSS"
|
4
|
+
task :config do
|
5
|
+
Rails::Generators.invoke("mensa:tailwind_config", ["--force"])
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
if Rake::Task.task_defined?("tailwindcss:build")
|
11
|
+
Rake::Task["tailwindcss:build"].enhance(["mensa:tailwindcss:config"])
|
12
|
+
Rake::Task["tailwindcss:watch"].enhance(["mensa:tailwindcss:config"])
|
13
|
+
end
|
data/mensa.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require_relative "lib/mensa/version"
|
2
|
+
|
3
|
+
Gem::Specification.new do |spec|
|
4
|
+
spec.name = "mensa"
|
5
|
+
spec.version = Mensa::VERSION
|
6
|
+
spec.authors = ["Tom de Grunt"]
|
7
|
+
spec.email = ["tom@degrunt.nl"]
|
8
|
+
spec.homepage = "https://github.com/entdec/mensa"
|
9
|
+
spec.summary = "Fast and awesome tables"
|
10
|
+
spec.description = "Fast and awesome tables, with pagination, sorting, filtering and custom views."
|
11
|
+
spec.license = "MIT"
|
12
|
+
|
13
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the "allowed_push_host"
|
14
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
15
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
16
|
+
|
17
|
+
spec.post_install_message = <<~MESSAGE
|
18
|
+
Mensa requires additional setup. Please run the following
|
19
|
+
command to install the necessary files:
|
20
|
+
|
21
|
+
bin/rails mensa:install:migrations
|
22
|
+
MESSAGE
|
23
|
+
|
24
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
25
|
+
spec.metadata["source_code_uri"] = "https://github.com/entdec/mensa"
|
26
|
+
spec.metadata["changelog_uri"] = "https://github.com/entdec/mensa/CHANGELOG"
|
27
|
+
|
28
|
+
spec.files = Dir.chdir(File.expand_path("..", __FILE__)) do
|
29
|
+
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
30
|
+
end
|
31
|
+
|
32
|
+
spec.add_dependency 'caxlsx_rails', '~> 0'
|
33
|
+
spec.add_dependency "rails", ">= 7.1"
|
34
|
+
spec.add_dependency 'pagy', '>=6'
|
35
|
+
spec.add_dependency 'textacular', '>=5'
|
36
|
+
|
37
|
+
spec.add_dependency 'slim'
|
38
|
+
spec.add_dependency 'tailwindcss-rails'
|
39
|
+
spec.add_dependency 'importmap-rails'
|
40
|
+
spec.add_dependency 'turbo-rails'
|
41
|
+
spec.add_dependency 'stimulus-rails'
|
42
|
+
end
|
data/package.json
ADDED
@@ -0,0 +1,2 @@
|
|
1
|
+
class FetchResponse{constructor(t){this.response=t}get statusCode(){return this.response.status}get redirected(){return this.response.redirected}get ok(){return this.response.ok}get unauthenticated(){return 401===this.statusCode}get unprocessableEntity(){return 422===this.statusCode}get authenticationURL(){return this.response.headers.get("WWW-Authenticate")}get contentType(){const t=this.response.headers.get("Content-Type")||"";return t.replace(/;.*$/,"")}get headers(){return this.response.headers}get html(){return this.contentType.match(/^(application|text)\/(html|xhtml\+xml)$/)?this.text:Promise.reject(new Error(`Expected an HTML response but got "${this.contentType}" instead`))}get json(){return this.contentType.match(/^application\/.*json$/)?this.responseJson||(this.responseJson=this.response.json()):Promise.reject(new Error(`Expected a JSON response but got "${this.contentType}" instead`))}get text(){return this.responseText||(this.responseText=this.response.text())}get isTurboStream(){return this.contentType.match(/^text\/vnd\.turbo-stream\.html/)}async renderTurboStream(){if(!this.isTurboStream)return Promise.reject(new Error(`Expected a Turbo Stream response but got "${this.contentType}" instead`));window.Turbo?await window.Turbo.renderStreamMessage(await this.text):console.warn("You must set `window.Turbo = Turbo` to automatically process Turbo Stream events with request.js")}}class RequestInterceptor{static register(t){this.interceptor=t}static get(){return this.interceptor}static reset(){this.interceptor=void 0}}function getCookie(t){const e=document.cookie?document.cookie.split("; "):[];const n=`${encodeURIComponent(t)}=`;const s=e.find((t=>t.startsWith(n)));if(s){const t=s.split("=").slice(1).join("=");if(t)return decodeURIComponent(t)}}function compact(t){const e={};for(const n in t){const s=t[n];void 0!==s&&(e[n]=s)}return e}function metaContent(t){const e=document.head.querySelector(`meta[name="${t}"]`);return e&&e.content}function stringEntriesFromFormData(t){return[...t].reduce(((t,[e,n])=>t.concat("string"===typeof n?[[e,n]]:[])),[])}function mergeEntries(t,e){for(const[n,s]of e)if(!(s instanceof window.File))if(t.has(n)&&!n.includes("[]")){t.delete(n);t.set(n,s)}else t.append(n,s)}class FetchRequest{constructor(t,e,n={}){this.method=t;this.options=n;this.originalUrl=e.toString()}async perform(){try{const t=RequestInterceptor.get();t&&await t(this)}catch(t){console.error(t)}const t=new FetchResponse(await window.fetch(this.url,this.fetchOptions));if(t.unauthenticated&&t.authenticationURL)return Promise.reject(window.location.href=t.authenticationURL);const e=t.ok||t.unprocessableEntity;e&&t.isTurboStream&&await t.renderTurboStream();return t}addHeader(t,e){const n=this.additionalHeaders;n[t]=e;this.options.headers=n}sameHostname(){if(!this.originalUrl.startsWith("http:"))return true;try{return new URL(this.originalUrl).hostname===window.location.hostname}catch(t){return true}}get fetchOptions(){return{method:this.method.toUpperCase(),headers:this.headers,body:this.formattedBody,signal:this.signal,credentials:this.credentials,redirect:this.redirect}}get headers(){const t={"X-Requested-With":"XMLHttpRequest","Content-Type":this.contentType,Accept:this.accept};this.sameHostname()&&(t["X-CSRF-Token"]=this.csrfToken);return compact(Object.assign(t,this.additionalHeaders))}get csrfToken(){return getCookie(metaContent("csrf-param"))||metaContent("csrf-token")}get contentType(){return this.options.contentType?this.options.contentType:null==this.body||this.body instanceof window.FormData?void 0:this.body instanceof window.File?this.body.type:"application/json"}get accept(){switch(this.responseKind){case"html":return"text/html, application/xhtml+xml";case"turbo-stream":return"text/vnd.turbo-stream.html, text/html, application/xhtml+xml";case"json":return"application/json, application/vnd.api+json";default:return"*/*"}}get body(){return this.options.body}get query(){const t=(this.originalUrl.split("?")[1]||"").split("#")[0];const e=new URLSearchParams(t);let n=this.options.query;n=n instanceof window.FormData?stringEntriesFromFormData(n):n instanceof window.URLSearchParams?n.entries():Object.entries(n||{});mergeEntries(e,n);const s=e.toString();return s.length>0?`?${s}`:""}get url(){return this.originalUrl.split("?")[0].split("#")[0]+this.query}get responseKind(){return this.options.responseKind||"html"}get signal(){return this.options.signal}get redirect(){return this.options.redirect||"follow"}get credentials(){return this.options.credentials||"same-origin"}get additionalHeaders(){return this.options.headers||{}}get formattedBody(){const t="[object String]"===Object.prototype.toString.call(this.body);const e="application/json"===this.headers["Content-Type"];return e&&!t?JSON.stringify(this.body):this.body}}async function get(t,e){const n=new FetchRequest("get",t,e);return n.perform()}async function post(t,e){const n=new FetchRequest("post",t,e);return n.perform()}async function put(t,e){const n=new FetchRequest("put",t,e);return n.perform()}async function patch(t,e){const n=new FetchRequest("patch",t,e);return n.perform()}async function destroy(t,e){const n=new FetchRequest("delete",t,e);return n.perform()}export{FetchRequest,FetchResponse,RequestInterceptor,destroy,get,patch,post,put};
|
2
|
+
|