js_admin 0.0.1 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +17 -0
- data/README.md +179 -19
- data/app/assets/javascripts/js_admin/application.js +13 -0
- data/app/assets/javascripts/js_admin/controllers/flash_controller.js +23 -0
- data/app/assets/javascripts/js_admin/controllers/theme_controller.js +62 -0
- data/app/assets/tailwind/js_admin/engine.css +4 -0
- data/app/controllers/js_admin/application_controller.rb +28 -0
- data/app/controllers/js_admin/home_controller.rb +6 -0
- data/app/controllers/js_admin/resources_controller.rb +17 -4
- data/app/helpers/js_admin/application_helper.rb +286 -19
- data/app/views/js_admin/home/index.html.erb +5 -0
- data/app/views/js_admin/models/_index_content.html.erb +20 -0
- data/app/views/js_admin/models/index.html.erb +3 -20
- data/app/views/js_admin/resources/_edit_content.html.erb +11 -0
- data/app/views/js_admin/resources/_form.html.erb +20 -13
- data/app/views/js_admin/resources/_index_content.html.erb +74 -0
- data/app/views/js_admin/resources/_new_content.html.erb +10 -0
- data/app/views/js_admin/resources/_show_content.html.erb +26 -0
- data/app/views/js_admin/resources/destroy.turbo_stream.erb +7 -0
- data/app/views/js_admin/resources/edit.html.erb +3 -11
- data/app/views/js_admin/resources/index.html.erb +3 -52
- data/app/views/js_admin/resources/new.html.erb +3 -10
- data/app/views/js_admin/resources/show.html.erb +3 -26
- data/app/views/layouts/js_admin/_content_frame.html.erb +7 -0
- data/app/views/layouts/js_admin/_flash.html.erb +3 -0
- data/app/views/layouts/js_admin/_flash_messages.html.erb +9 -0
- data/app/views/layouts/js_admin/_sidebar.html.erb +36 -0
- data/app/views/layouts/js_admin/application.html.erb +19 -17
- data/config/routes.rb +2 -1
- data/lib/generators/js_admin/install/install_generator.rb +63 -5
- data/lib/js_admin/configuration.rb +16 -3
- data/lib/js_admin/field.rb +4 -4
- data/lib/js_admin/resource.rb +12 -4
- data/lib/js_admin/version.rb +1 -1
- data/lib/js_admin.rb +6 -0
- metadata +37 -2
|
@@ -1,54 +1,5 @@
|
|
|
1
1
|
<% content_for :title, @resource.label %>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<h1 class="text-2xl font-semibold text-slate-950"><%= @resource.label %></h1>
|
|
7
|
-
<p class="mt-1 text-sm text-slate-600"><%= number_with_delimiter(@total_count) %> records</p>
|
|
8
|
-
</div>
|
|
9
|
-
|
|
10
|
-
<%= link_to "New #{@resource.singular_label}", new_resource_path(@resource.model_id), class: "inline-flex items-center justify-center rounded-md bg-sky-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-sky-700" %>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<div class="overflow-x-auto rounded-lg border border-slate-200 bg-white shadow-sm">
|
|
14
|
-
<table class="min-w-full divide-y divide-slate-200">
|
|
15
|
-
<thead class="bg-slate-50">
|
|
16
|
-
<tr>
|
|
17
|
-
<% @resource.list_fields.each do |field| %>
|
|
18
|
-
<th scope="col" class="whitespace-nowrap px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500"><%= field.human_name %></th>
|
|
19
|
-
<% end %>
|
|
20
|
-
<th scope="col" class="w-24 px-4 py-3 text-right text-xs font-semibold uppercase tracking-wide text-slate-500">Actions</th>
|
|
21
|
-
</tr>
|
|
22
|
-
</thead>
|
|
23
|
-
<tbody class="divide-y divide-slate-200 bg-white">
|
|
24
|
-
<% @records.each do |record| %>
|
|
25
|
-
<tr class="hover:bg-slate-50">
|
|
26
|
-
<% @resource.list_fields.each do |field| %>
|
|
27
|
-
<td class="whitespace-nowrap px-4 py-3 text-sm"><%= js_admin_table_value(field, record) %></td>
|
|
28
|
-
<% end %>
|
|
29
|
-
<td class="whitespace-nowrap px-4 py-3 text-right text-sm">
|
|
30
|
-
<%= link_to "Open", resource_path(@resource.model_id, record), class: "font-medium text-sky-700 hover:text-sky-900" %>
|
|
31
|
-
</td>
|
|
32
|
-
</tr>
|
|
33
|
-
<% end %>
|
|
34
|
-
|
|
35
|
-
<% if @records.empty? %>
|
|
36
|
-
<tr>
|
|
37
|
-
<td colspan="<%= @resource.list_fields.size + 1 %>" class="px-4 py-10 text-center text-sm text-slate-500">No records</td>
|
|
38
|
-
</tr>
|
|
39
|
-
<% end %>
|
|
40
|
-
</tbody>
|
|
41
|
-
</table>
|
|
42
|
-
</div>
|
|
43
|
-
|
|
44
|
-
<div class="mt-4 flex items-center justify-between">
|
|
45
|
-
<div class="text-sm text-slate-500">Page <%= @page %></div>
|
|
46
|
-
<div class="flex gap-2">
|
|
47
|
-
<% if @resource.previous_page?(@page) %>
|
|
48
|
-
<%= link_to "Previous", resources_path(@resource.model_id, page: @page - 1), class: "rounded-md border border-slate-300 bg-white px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50" %>
|
|
49
|
-
<% end %>
|
|
50
|
-
<% if @resource.next_page?(@page) %>
|
|
51
|
-
<%= link_to "Next", resources_path(@resource.model_id, page: @page + 1), class: "rounded-md border border-slate-300 bg-white px-3 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50" %>
|
|
52
|
-
<% end %>
|
|
53
|
-
</div>
|
|
54
|
-
</div>
|
|
3
|
+
<%= render layout: "layouts/js_admin/content_frame" do %>
|
|
4
|
+
<%= render "index_content" %>
|
|
5
|
+
<% end %>
|
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
<% content_for :title, "New #{@resource.singular_label}" %>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<%= link_to @resource.label, resources_path(@resource.model_id), class: "hover:text-slate-950" %> /
|
|
7
|
-
New
|
|
8
|
-
</div>
|
|
9
|
-
<h1 class="text-2xl font-semibold text-slate-950">New <%= @resource.singular_label %></h1>
|
|
10
|
-
</div>
|
|
11
|
-
|
|
12
|
-
<%= render "form", record: @record, resource: @resource, url: resources_path(@resource.model_id) %>
|
|
3
|
+
<%= render layout: "layouts/js_admin/content_frame" do %>
|
|
4
|
+
<%= render "new_content" %>
|
|
5
|
+
<% end %>
|
|
@@ -1,28 +1,5 @@
|
|
|
1
1
|
<% content_for :title, @resource.display_name(@record) %>
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
<%= link_to "Models", root_path, class: "hover:text-slate-950" %> /
|
|
7
|
-
<%= link_to @resource.label, resources_path(@resource.model_id), class: "hover:text-slate-950" %> /
|
|
8
|
-
<%= @resource.display_name(@record) %>
|
|
9
|
-
</div>
|
|
10
|
-
<h1 class="text-2xl font-semibold text-slate-950"><%= @resource.display_name(@record) %></h1>
|
|
11
|
-
</div>
|
|
12
|
-
|
|
13
|
-
<div class="flex gap-2">
|
|
14
|
-
<%= link_to "Edit", edit_resource_path(@resource.model_id, @record), class: "inline-flex items-center justify-center rounded-md border border-slate-300 bg-white px-4 py-2 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50" %>
|
|
15
|
-
<%= button_to "Delete", resource_path(@resource.model_id, @record), method: :delete, form: { data: { turbo_confirm: "Delete this record?" } }, class: "inline-flex items-center justify-center rounded-md bg-rose-600 px-4 py-2 text-sm font-medium text-white shadow-sm hover:bg-rose-700" %>
|
|
16
|
-
</div>
|
|
17
|
-
</div>
|
|
18
|
-
|
|
19
|
-
<div class="overflow-hidden rounded-lg border border-slate-200 bg-white shadow-sm">
|
|
20
|
-
<dl class="divide-y divide-slate-200">
|
|
21
|
-
<% @resource.fields.each do |field| %>
|
|
22
|
-
<div class="grid gap-2 px-4 py-4 sm:grid-cols-3">
|
|
23
|
-
<dt class="text-sm font-medium text-slate-600"><%= field.human_name %></dt>
|
|
24
|
-
<dd class="text-sm text-slate-950 sm:col-span-2"><%= js_admin_table_value(field, @record) %></dd>
|
|
25
|
-
</div>
|
|
26
|
-
<% end %>
|
|
27
|
-
</dl>
|
|
28
|
-
</div>
|
|
3
|
+
<%= render layout: "layouts/js_admin/content_frame" do %>
|
|
4
|
+
<%= render "show_content" %>
|
|
5
|
+
<% end %>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="w-full max-w-sm space-y-3">
|
|
2
|
+
<% if notice.present? %>
|
|
3
|
+
<div data-controller="js-admin-flash" data-js-admin-flash-timeout-value="4000" class="<%= js_admin_flash_classes(:notice) %>" role="status"><%= notice %></div>
|
|
4
|
+
<% end %>
|
|
5
|
+
|
|
6
|
+
<% if alert.present? %>
|
|
7
|
+
<div data-controller="js-admin-flash" data-js-admin-flash-timeout-value="4000" class="<%= js_admin_flash_classes(:alert) %>" role="alert"><%= alert %></div>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
<aside class="flex shrink-0 flex-col border-b border-slate-200 bg-white/80 dark:border-slate-800 dark:bg-slate-900/70 lg:sticky lg:top-16 lg:h-[calc(100vh-4rem)] lg:w-64 lg:self-start lg:overflow-hidden lg:border-b-0 lg:border-r">
|
|
2
|
+
<nav class="min-h-0 flex-1 space-y-6 overflow-y-auto px-5 py-6 sm:px-8 lg:px-5">
|
|
3
|
+
<section>
|
|
4
|
+
<div class="space-y-1">
|
|
5
|
+
<% js_admin_sidebar_top_level_resources.each do |resource| %>
|
|
6
|
+
<%= link_to js_admin_sidebar_resource_label(resource), resources_path(resource.model_id), class: js_admin_sidebar_link_classes(resource), data: js_admin_content_link_data.merge(js_admin_sidebar_link: resource.model_id) %>
|
|
7
|
+
<% end %>
|
|
8
|
+
|
|
9
|
+
<% js_admin_sidebar_namespace_groups.each do |namespace, resources| %>
|
|
10
|
+
<details class="group" <%= "open" if js_admin_sidebar_namespace_open?(resources) %>>
|
|
11
|
+
<summary class="flex cursor-pointer items-center justify-between rounded-md px-3 py-2 text-xs font-semibold uppercase tracking-wide text-slate-500 hover:bg-slate-100 hover:text-slate-950 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-100">
|
|
12
|
+
<span><%= js_admin_sidebar_namespace_label(namespace) %></span>
|
|
13
|
+
<span class="transition-transform group-open:rotate-90">></span>
|
|
14
|
+
</summary>
|
|
15
|
+
|
|
16
|
+
<div class="mt-1 space-y-1 pl-3">
|
|
17
|
+
<% resources.each do |resource| %>
|
|
18
|
+
<%= link_to js_admin_sidebar_resource_label(resource), resources_path(resource.model_id), class: js_admin_sidebar_link_classes(resource), data: js_admin_content_link_data.merge(js_admin_sidebar_link: resource.model_id) %>
|
|
19
|
+
<% end %>
|
|
20
|
+
</div>
|
|
21
|
+
</details>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
24
|
+
</section>
|
|
25
|
+
</nav>
|
|
26
|
+
|
|
27
|
+
<div class="shrink-0 border-t border-slate-200 px-5 py-4 dark:border-slate-800 sm:px-8 lg:px-5">
|
|
28
|
+
<button type="button" data-js-admin-theme-target="toggle" data-action="js-admin-theme#toggle" class="inline-flex h-9 w-full items-center justify-between rounded-md border border-slate-300 bg-white px-3 text-sm font-medium text-slate-700 shadow-sm hover:bg-slate-50 dark:border-slate-700 dark:bg-slate-900 dark:text-slate-200 dark:hover:bg-slate-800" aria-label="Toggle dark mode" aria-pressed="false">
|
|
29
|
+
<span class="flex items-center gap-2">
|
|
30
|
+
<span class="h-2.5 w-2.5 rounded-full bg-slate-500 dark:bg-amber-300"></span>
|
|
31
|
+
<span>Theme</span>
|
|
32
|
+
</span>
|
|
33
|
+
<span class="text-xs text-slate-400 dark:text-slate-500">Toggle</span>
|
|
34
|
+
</button>
|
|
35
|
+
</div>
|
|
36
|
+
</aside>
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
|
-
<html>
|
|
2
|
+
<html class="<%= js_admin_html_classes %>">
|
|
3
3
|
<head>
|
|
4
4
|
<title><%= content_for(:title) || "JSAdmin" %></title>
|
|
5
5
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<meta name="color-scheme" content="light dark">
|
|
6
7
|
<%= csrf_meta_tags %>
|
|
7
8
|
<%= csp_meta_tag %>
|
|
8
9
|
|
|
@@ -10,28 +11,29 @@
|
|
|
10
11
|
|
|
11
12
|
<%= js_admin_stylesheet_link_tag "tailwind" %>
|
|
12
13
|
<%= stylesheet_link_tag "js_admin/application", media: "all", "data-turbo-track": "reload" %>
|
|
13
|
-
<%=
|
|
14
|
+
<%= js_admin_javascript_tags %>
|
|
14
15
|
</head>
|
|
15
|
-
<body class="min-h-screen bg-slate-50 text-slate-950">
|
|
16
|
+
<body class="min-h-screen bg-slate-50 text-slate-950 antialiased dark:bg-slate-950 dark:text-slate-100" data-controller="js-admin-theme">
|
|
16
17
|
<div class="min-h-screen">
|
|
17
|
-
<header class="border-b border-slate-200 bg-white">
|
|
18
|
-
<div class="
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
<header class="fixed inset-x-0 top-0 z-40 border-b border-slate-200 bg-white/95 dark:border-slate-800 dark:bg-slate-900/95">
|
|
19
|
+
<div class="flex min-h-16 w-full items-center">
|
|
20
|
+
<div class="flex min-h-16 shrink-0 items-center px-5 sm:px-8 lg:w-64 lg:border-r lg:border-slate-200 lg:px-5 lg:dark:border-slate-800">
|
|
21
|
+
<%= link_to "JSAdmin", root_path, class: "text-base font-semibold text-slate-950 dark:text-slate-100", data: js_admin_content_link_data %>
|
|
22
|
+
</div>
|
|
23
|
+
|
|
24
|
+
<div class="min-h-16 min-w-0 flex-1"></div>
|
|
21
25
|
</div>
|
|
22
26
|
</header>
|
|
23
27
|
|
|
24
|
-
<
|
|
25
|
-
|
|
26
|
-
<div class="mb-4 rounded-md border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800"><%= notice %></div>
|
|
27
|
-
<% end %>
|
|
28
|
-
|
|
29
|
-
<% if alert.present? %>
|
|
30
|
-
<div class="mb-4 rounded-md border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-800"><%= alert %></div>
|
|
31
|
-
<% end %>
|
|
28
|
+
<div class="flex w-full flex-col pt-16 lg:flex-row">
|
|
29
|
+
<%= render "layouts/js_admin/sidebar" %>
|
|
32
30
|
|
|
33
|
-
|
|
34
|
-
|
|
31
|
+
<main class="min-w-0 flex-1 px-5 py-8 sm:px-8 sm:py-10 lg:px-10">
|
|
32
|
+
<div class="mx-auto max-w-screen-2xl">
|
|
33
|
+
<%= yield %>
|
|
34
|
+
</div>
|
|
35
|
+
</main>
|
|
36
|
+
</div>
|
|
35
37
|
</div>
|
|
36
38
|
</body>
|
|
37
39
|
</html>
|
data/config/routes.rb
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
JSAdmin::Engine.routes.draw do
|
|
2
|
-
root to: "
|
|
2
|
+
root to: "home#index"
|
|
3
3
|
|
|
4
|
+
get "/models", to: "models#index", as: :models
|
|
4
5
|
get "/:model_id", to: "resources#index", as: :resources
|
|
5
6
|
get "/:model_id/new", to: "resources#new", as: :new_resource
|
|
6
7
|
post "/:model_id", to: "resources#create"
|
|
@@ -3,22 +3,80 @@ require "rails/generators"
|
|
|
3
3
|
module JSAdmin
|
|
4
4
|
module Generators
|
|
5
5
|
class InstallGenerator < Rails::Generators::Base
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
IMPORTMAP_PINS = {
|
|
7
|
+
"@hotwired/turbo-rails" => 'pin "@hotwired/turbo-rails", to: "turbo.min.js"',
|
|
8
|
+
"@hotwired/stimulus" => 'pin "@hotwired/stimulus", to: "stimulus.min.js"',
|
|
9
|
+
"js_admin" => 'pin "js_admin", to: "js_admin/application.js", preload: true',
|
|
10
|
+
"js_admin/controllers/theme_controller" => 'pin "js_admin/controllers/theme_controller", to: "js_admin/controllers/theme_controller.js", preload: true',
|
|
11
|
+
"js_admin/controllers/flash_controller" => 'pin "js_admin/controllers/flash_controller", to: "js_admin/controllers/flash_controller.js", preload: true'
|
|
12
|
+
}.freeze
|
|
13
|
+
|
|
14
|
+
namespace "js_admin:install"
|
|
15
|
+
|
|
16
|
+
class_option :path,
|
|
17
|
+
type: :string,
|
|
18
|
+
default: "/admin",
|
|
19
|
+
desc: "Mount path for JSAdmin"
|
|
8
20
|
|
|
9
21
|
def mount_engine
|
|
10
22
|
route %(mount JSAdmin::Engine => "#{options[:path]}")
|
|
11
23
|
end
|
|
12
24
|
|
|
25
|
+
def create_initializer
|
|
26
|
+
create_file "config/initializers/js_admin.rb", <<~RUBY
|
|
27
|
+
JSAdmin.configure do |config|
|
|
28
|
+
# Limit visible models. When empty, JSAdmin exposes every concrete Active Record model.
|
|
29
|
+
# config.include_models User, Post
|
|
30
|
+
# config.exclude_models AuditLog
|
|
31
|
+
|
|
32
|
+
# UI pagination and association select limits.
|
|
33
|
+
# config.records_per_page = 10
|
|
34
|
+
# config.association_limit = 100
|
|
35
|
+
|
|
36
|
+
# Methods tried in order when displaying records in labels and associations.
|
|
37
|
+
# config.display_name_methods = %i[name title email username id]
|
|
38
|
+
|
|
39
|
+
# Basic Auth is disabled unless both username and password are present.
|
|
40
|
+
# config.basic_auth_username = ENV["JS_ADMIN_BASIC_AUTH_USERNAME"]
|
|
41
|
+
# config.basic_auth_password = ENV["JS_ADMIN_BASIC_AUTH_PASSWORD"]
|
|
42
|
+
# config.basic_auth_realm = "JSAdmin"
|
|
43
|
+
end
|
|
44
|
+
RUBY
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def pin_importmap_modules
|
|
48
|
+
importmap_path = application_path("config/importmap.rb")
|
|
49
|
+
|
|
50
|
+
unless File.exist?(importmap_path)
|
|
51
|
+
say_status :warning, "config/importmap.rb was not found. Run bin/rails importmap:install, then rerun js_admin:install.", :yellow
|
|
52
|
+
return
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
importmap = File.read(importmap_path)
|
|
56
|
+
missing_pins = IMPORTMAP_PINS.filter_map do |name, line|
|
|
57
|
+
line unless importmap.match?(/^\s*pin\s+["']#{Regexp.escape(name)}["']/)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
return if missing_pins.empty?
|
|
61
|
+
|
|
62
|
+
append_to_file importmap_path, "\n#{missing_pins.join("\n")}\n"
|
|
63
|
+
end
|
|
64
|
+
|
|
13
65
|
def import_tailwind_engine_styles
|
|
14
|
-
tailwind_entrypoint =
|
|
15
|
-
return unless
|
|
66
|
+
tailwind_entrypoint = application_path("app/assets/tailwind/application.css")
|
|
67
|
+
return unless File.exist?(tailwind_entrypoint)
|
|
16
68
|
|
|
17
69
|
import_line = '@import "../builds/tailwind/js_admin";'
|
|
18
|
-
return if
|
|
70
|
+
return if File.read(tailwind_entrypoint).include?(import_line)
|
|
19
71
|
|
|
20
72
|
append_to_file tailwind_entrypoint, "\n#{import_line}\n"
|
|
21
73
|
end
|
|
74
|
+
|
|
75
|
+
private
|
|
76
|
+
|
|
77
|
+
def application_path(relative_path)
|
|
78
|
+
File.join(destination_root, relative_path)
|
|
79
|
+
end
|
|
22
80
|
end
|
|
23
81
|
end
|
|
24
82
|
end
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
module JSAdmin
|
|
2
2
|
class Configuration
|
|
3
|
-
attr_accessor :included_models,
|
|
4
|
-
|
|
3
|
+
attr_accessor :included_models,
|
|
4
|
+
:excluded_models,
|
|
5
|
+
:records_per_page,
|
|
6
|
+
:association_limit,
|
|
7
|
+
:display_name_methods,
|
|
8
|
+
:basic_auth_username,
|
|
9
|
+
:basic_auth_password,
|
|
10
|
+
:basic_auth_realm
|
|
5
11
|
|
|
6
12
|
def initialize
|
|
7
13
|
@included_models = []
|
|
8
14
|
@excluded_models = []
|
|
9
|
-
@records_per_page =
|
|
15
|
+
@records_per_page = 10
|
|
10
16
|
@association_limit = 100
|
|
11
17
|
@display_name_methods = %i[name title email username id]
|
|
18
|
+
@basic_auth_username = nil
|
|
19
|
+
@basic_auth_password = nil
|
|
20
|
+
@basic_auth_realm = "JSAdmin"
|
|
12
21
|
end
|
|
13
22
|
|
|
14
23
|
def include_models(*models)
|
|
@@ -19,6 +28,10 @@ module JSAdmin
|
|
|
19
28
|
excluded_models.concat(normalize_model_names(models))
|
|
20
29
|
end
|
|
21
30
|
|
|
31
|
+
def basic_auth_enabled?
|
|
32
|
+
basic_auth_username.to_s != "" && basic_auth_password.to_s != ""
|
|
33
|
+
end
|
|
34
|
+
|
|
22
35
|
private
|
|
23
36
|
|
|
24
37
|
def normalize_model_names(models)
|
data/lib/js_admin/field.rb
CHANGED
|
@@ -67,8 +67,8 @@ module JSAdmin
|
|
|
67
67
|
|
|
68
68
|
def belongs_to_association
|
|
69
69
|
@belongs_to_association ||= resource.model_class
|
|
70
|
-
|
|
71
|
-
|
|
70
|
+
.reflect_on_all_associations(:belongs_to)
|
|
71
|
+
.find { |association| association.foreign_key.to_s == name }
|
|
72
72
|
rescue NameError
|
|
73
73
|
nil
|
|
74
74
|
end
|
|
@@ -79,8 +79,8 @@ module JSAdmin
|
|
|
79
79
|
|
|
80
80
|
association_resource = Resource.new(association.klass)
|
|
81
81
|
association.klass
|
|
82
|
-
|
|
83
|
-
|
|
82
|
+
.limit(JSAdmin.configuration.association_limit)
|
|
83
|
+
.map { |record| [ association_resource.display_name(record), record.id ] }
|
|
84
84
|
rescue ActiveRecord::ActiveRecordError, NameError
|
|
85
85
|
[]
|
|
86
86
|
end
|
data/lib/js_admin/resource.rb
CHANGED
|
@@ -7,7 +7,7 @@ module JSAdmin
|
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
def model_id
|
|
10
|
-
model_class.name.underscore.
|
|
10
|
+
model_class.name.underscore.gsub("/", "--")
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def label
|
|
@@ -42,14 +42,18 @@ module JSAdmin
|
|
|
42
42
|
page_number = [ page.to_i, 1 ].max
|
|
43
43
|
model_class.all
|
|
44
44
|
.then { |scope| ordered_scope(scope) }
|
|
45
|
-
.limit(
|
|
46
|
-
.offset((page_number - 1) *
|
|
45
|
+
.limit(records_per_page)
|
|
46
|
+
.offset((page_number - 1) * records_per_page)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
def count
|
|
50
50
|
model_class.count
|
|
51
51
|
end
|
|
52
52
|
|
|
53
|
+
def total_pages(total_count: count)
|
|
54
|
+
[ (total_count.to_f / records_per_page).ceil, 1 ].max
|
|
55
|
+
end
|
|
56
|
+
|
|
53
57
|
def find(record_id)
|
|
54
58
|
model_class.find(record_id)
|
|
55
59
|
end
|
|
@@ -69,7 +73,7 @@ module JSAdmin
|
|
|
69
73
|
end
|
|
70
74
|
|
|
71
75
|
def next_page?(page)
|
|
72
|
-
|
|
76
|
+
page.to_i < total_pages
|
|
73
77
|
end
|
|
74
78
|
|
|
75
79
|
def previous_page?(page)
|
|
@@ -84,5 +88,9 @@ module JSAdmin
|
|
|
84
88
|
|
|
85
89
|
scope.order(primary_key => :desc)
|
|
86
90
|
end
|
|
91
|
+
|
|
92
|
+
def records_per_page
|
|
93
|
+
[ JSAdmin.configuration.records_per_page.to_i, 1 ].max
|
|
94
|
+
end
|
|
87
95
|
end
|
|
88
96
|
end
|
data/lib/js_admin/version.rb
CHANGED
data/lib/js_admin.rb
CHANGED
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: js_admin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- JoungSik
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date: 2026-07-
|
|
10
|
+
date: 2026-07-17 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: rails
|
|
@@ -29,6 +29,26 @@ dependencies:
|
|
|
29
29
|
- - "<"
|
|
30
30
|
- !ruby/object:Gem::Version
|
|
31
31
|
version: '9.0'
|
|
32
|
+
- !ruby/object:Gem::Dependency
|
|
33
|
+
name: importmap-rails
|
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
|
35
|
+
requirements:
|
|
36
|
+
- - ">="
|
|
37
|
+
- !ruby/object:Gem::Version
|
|
38
|
+
version: '2.0'
|
|
39
|
+
- - "<"
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '3.0'
|
|
42
|
+
type: :runtime
|
|
43
|
+
prerelease: false
|
|
44
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '2.0'
|
|
49
|
+
- - "<"
|
|
50
|
+
- !ruby/object:Gem::Version
|
|
51
|
+
version: '3.0'
|
|
32
52
|
- !ruby/object:Gem::Dependency
|
|
33
53
|
name: stimulus-rails
|
|
34
54
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -101,19 +121,34 @@ files:
|
|
|
101
121
|
- MIT-LICENSE
|
|
102
122
|
- README.md
|
|
103
123
|
- Rakefile
|
|
124
|
+
- app/assets/javascripts/js_admin/application.js
|
|
125
|
+
- app/assets/javascripts/js_admin/controllers/flash_controller.js
|
|
126
|
+
- app/assets/javascripts/js_admin/controllers/theme_controller.js
|
|
104
127
|
- app/assets/stylesheets/js_admin/application.css
|
|
105
128
|
- app/assets/tailwind/js_admin/engine.css
|
|
106
129
|
- app/controllers/js_admin/application_controller.rb
|
|
130
|
+
- app/controllers/js_admin/home_controller.rb
|
|
107
131
|
- app/controllers/js_admin/models_controller.rb
|
|
108
132
|
- app/controllers/js_admin/resources_controller.rb
|
|
109
133
|
- app/helpers/js_admin/application_helper.rb
|
|
110
134
|
- app/models/js_admin/application_record.rb
|
|
135
|
+
- app/views/js_admin/home/index.html.erb
|
|
136
|
+
- app/views/js_admin/models/_index_content.html.erb
|
|
111
137
|
- app/views/js_admin/models/index.html.erb
|
|
138
|
+
- app/views/js_admin/resources/_edit_content.html.erb
|
|
112
139
|
- app/views/js_admin/resources/_form.html.erb
|
|
140
|
+
- app/views/js_admin/resources/_index_content.html.erb
|
|
141
|
+
- app/views/js_admin/resources/_new_content.html.erb
|
|
142
|
+
- app/views/js_admin/resources/_show_content.html.erb
|
|
143
|
+
- app/views/js_admin/resources/destroy.turbo_stream.erb
|
|
113
144
|
- app/views/js_admin/resources/edit.html.erb
|
|
114
145
|
- app/views/js_admin/resources/index.html.erb
|
|
115
146
|
- app/views/js_admin/resources/new.html.erb
|
|
116
147
|
- app/views/js_admin/resources/show.html.erb
|
|
148
|
+
- app/views/layouts/js_admin/_content_frame.html.erb
|
|
149
|
+
- app/views/layouts/js_admin/_flash.html.erb
|
|
150
|
+
- app/views/layouts/js_admin/_flash_messages.html.erb
|
|
151
|
+
- app/views/layouts/js_admin/_sidebar.html.erb
|
|
117
152
|
- app/views/layouts/js_admin/application.html.erb
|
|
118
153
|
- config/routes.rb
|
|
119
154
|
- lib/generators/js_admin/install/install_generator.rb
|