administratum 0.2.4
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 +7 -0
- data/DESIGN.md +68 -0
- data/MIT-LICENSE +20 -0
- data/README.md +431 -0
- data/Rakefile +6 -0
- data/app/admin/administratum/user_admin.rb +39 -0
- data/app/assets/builds/administratum.css +2 -0
- data/app/assets/javascripts/administratum.js +250 -0
- data/app/assets/tailwind/administratum/components.css +199 -0
- data/app/assets/tailwind/administratum/index.css +8 -0
- data/app/assets/tailwind/administratum/theme.css +62 -0
- data/app/controllers/administratum/application_controller.rb +31 -0
- data/app/controllers/administratum/dashboard_controller.rb +7 -0
- data/app/controllers/administratum/page.rb +51 -0
- data/app/controllers/administratum/password_resets_controller.rb +42 -0
- data/app/controllers/administratum/resource.rb +224 -0
- data/app/controllers/administratum/sessions_controller.rb +33 -0
- data/app/helpers/administratum/application_helper.rb +11 -0
- data/app/helpers/administratum/form_helper.rb +115 -0
- data/app/helpers/administratum/island_helper.rb +16 -0
- data/app/helpers/administratum/layout_helper.rb +81 -0
- data/app/helpers/administratum/resource_helper.rb +199 -0
- data/app/mailers/administratum/application_mailer.rb +8 -0
- data/app/mailers/administratum/user_mailer.rb +11 -0
- data/app/models/administratum/application_record.rb +7 -0
- data/app/models/administratum/user.rb +13 -0
- data/app/views/administratum/dashboard/index.html.erb +16 -0
- data/app/views/administratum/fields/_belongs_to.html.erb +1 -0
- data/app/views/administratum/fields/_boolean.html.erb +1 -0
- data/app/views/administratum/fields/_date.html.erb +1 -0
- data/app/views/administratum/fields/_datetime.html.erb +1 -0
- data/app/views/administratum/fields/_email.html.erb +1 -0
- data/app/views/administratum/fields/_has_many_ids.html.erb +1 -0
- data/app/views/administratum/fields/_hidden.html.erb +1 -0
- data/app/views/administratum/fields/_island.html.erb +4 -0
- data/app/views/administratum/fields/_json.html.erb +1 -0
- data/app/views/administratum/fields/_multi_select.html.erb +1 -0
- data/app/views/administratum/fields/_number.html.erb +1 -0
- data/app/views/administratum/fields/_password.html.erb +1 -0
- data/app/views/administratum/fields/_select.html.erb +1 -0
- data/app/views/administratum/fields/_string.html.erb +1 -0
- data/app/views/administratum/fields/_textarea.html.erb +1 -0
- data/app/views/administratum/fields/_wrapper.html.erb +11 -0
- data/app/views/administratum/pages/index.html.erb +7 -0
- data/app/views/administratum/password_resets/edit.html.erb +17 -0
- data/app/views/administratum/password_resets/new.html.erb +11 -0
- data/app/views/administratum/resources/_attributes.html.erb +11 -0
- data/app/views/administratum/resources/_form.html.erb +14 -0
- data/app/views/administratum/resources/_table.html.erb +42 -0
- data/app/views/administratum/resources/edit.html.erb +7 -0
- data/app/views/administratum/resources/index.html.erb +17 -0
- data/app/views/administratum/resources/new.html.erb +7 -0
- data/app/views/administratum/resources/show.html.erb +7 -0
- data/app/views/administratum/sessions/new.html.erb +18 -0
- data/app/views/administratum/shared/_card.html.erb +9 -0
- data/app/views/administratum/shared/_filters.html.erb +43 -0
- data/app/views/administratum/shared/_flash.html.erb +9 -0
- data/app/views/administratum/shared/_form_errors.html.erb +10 -0
- data/app/views/administratum/shared/_nav.html.erb +10 -0
- data/app/views/administratum/shared/_page_header.html.erb +17 -0
- data/app/views/administratum/shared/_panel.html.erb +24 -0
- data/app/views/administratum/shared/_topbar.html.erb +29 -0
- data/app/views/administratum/user_mailer/reset_password.html.erb +4 -0
- data/app/views/administratum/user_mailer/reset_password.text.erb +7 -0
- data/app/views/layouts/administratum/application.html.erb +25 -0
- data/app/views/layouts/administratum/authentication.html.erb +32 -0
- data/config/locales/en.yml +65 -0
- data/config/routes.rb +16 -0
- data/db/migrate/20261016000000_create_administratum_users.rb +17 -0
- data/lib/administratum/configuration.rb +66 -0
- data/lib/administratum/definition.rb +283 -0
- data/lib/administratum/dsl.rb +195 -0
- data/lib/administratum/engine.rb +31 -0
- data/lib/administratum/field_types.rb +77 -0
- data/lib/administratum/page_dsl.rb +48 -0
- data/lib/administratum/paths.rb +85 -0
- data/lib/administratum/ransackable.rb +41 -0
- data/lib/administratum/registry.rb +95 -0
- data/lib/administratum/routing.rb +57 -0
- data/lib/administratum/tailwind.rb +34 -0
- data/lib/administratum/version.rb +5 -0
- data/lib/administratum.rb +43 -0
- data/lib/generators/administratum/install/install_generator.rb +42 -0
- data/lib/generators/administratum/install/templates/administratum.rb +41 -0
- data/lib/generators/administratum/resource/resource_generator.rb +30 -0
- data/lib/generators/administratum/resource/templates/resource.rb.tt +20 -0
- data/lib/tasks/administratum.rake +32 -0
- metadata +209 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Administratum
|
|
4
|
+
class UserMailer < ApplicationMailer
|
|
5
|
+
def reset_password
|
|
6
|
+
@user = params[:user]
|
|
7
|
+
@url = administratum.edit_password_reset_url(token: params[:token])
|
|
8
|
+
mail to: @user.email, subject: t("administratum.password_resets.subject", app: Administratum.config.app_name)
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<%= page_header title: t("administratum.dashboard"), breadcrumbs: [] %>
|
|
2
|
+
|
|
3
|
+
<div class="adm-container adm-page-body">
|
|
4
|
+
<% if administratum_config.dashboard %>
|
|
5
|
+
<%= render administratum_config.dashboard %>
|
|
6
|
+
<% else %>
|
|
7
|
+
<div class="adm-grid">
|
|
8
|
+
<% Administratum.registry.menu_items.each do |resource| %>
|
|
9
|
+
<%= link_to Administratum::Paths.new(resource, self).index, class: "adm-card adm-tile" do %>
|
|
10
|
+
<span class="adm-tile-label"><%= resource.menu_label %></span>
|
|
11
|
+
<span class="adm-tile-value"><%= number_with_delimiter(resource.definition.model.count) %></span>
|
|
12
|
+
<% end %>
|
|
13
|
+
<% end %>
|
|
14
|
+
</div>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.select field.name, field_collection(field, resource), { include_blank: field.options[:placeholder] || field.options.fetch(:include_blank, true) }, **input_options(field, form:, class: "adm-input") %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.checkbox field.name, **input_options(field, form:, class: "adm-checkbox") %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= adm_date_field form, field.name, value:, **input_options(field, form:) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= adm_datetime_field form, field.name, value:, **input_options(field, form:) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.email_field field.name, **input_options(field, form:, class: "adm-input", autocomplete: "off") %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.select field.name, field_collection(field, resource), {}, **input_options(field, form:, class: "adm-input", multiple: true, size: field.options.fetch(:size, 6)) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.hidden_field field.name, **input_options(field) %>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<%# A field rendered by a JS island. The island receives the input name and current value and must render its own input(s). %>
|
|
2
|
+
<% extra = field.options[:props] %>
|
|
3
|
+
<% extra = extra.arity.zero? ? instance_exec(&extra) : instance_exec(resource, &extra) if extra.respond_to?(:call) %>
|
|
4
|
+
<%= island field.options.fetch(:island), props: { name: form.field_name(field.name), id: form.field_id(field.name), value: value }.merge(extra || {}) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.text_area field.name, **input_options(field, form:, class: "adm-input adm-code", rows: field.options.fetch(:rows, 8), value: value.is_a?(String) || value.nil? ? value : JSON.pretty_generate(value)) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.select field.name, field_collection(field, resource), {}, **input_options(field, form:, class: "adm-input", multiple: true, size: field.options.fetch(:size, 6)) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.number_field field.name, **input_options(field, form:, class: "adm-input", step: field.options.fetch(:step, "any"), min: field.options[:min], max: field.options[:max]) %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.password_field field.name, **input_options(field, form:, class: "adm-input", autocomplete: "new-password") %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.select field.name, field_collection(field, resource), { include_blank: field.options[:placeholder] || field.options.fetch(:include_blank, false) }, **input_options(field, form:, class: "adm-input") %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.text_field field.name, **input_options(field, form:, class: "adm-input") %>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<%= form.text_area field.name, **input_options(field, form:, class: "adm-input", rows: field.options.fetch(:rows, 4)) %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% errors = field_errors(form, field) %>
|
|
2
|
+
<div class="<%= class_names("adm-field adm-field-horizontal", "adm-field-invalid" => errors.any?) %>">
|
|
3
|
+
<div class="adm-field-label">
|
|
4
|
+
<%= form.label field.name, class: "adm-label" do %><%= field_label(form, field) %><% if field_required?(form, field) %><span class="adm-required" aria-hidden="true">*</span><% end %><% end %>
|
|
5
|
+
</div>
|
|
6
|
+
<div class="adm-field-control">
|
|
7
|
+
<%= input %>
|
|
8
|
+
<% if field.hint %><p class="adm-hint" id="<%= form.field_id(field.name, :hint) %>"><%= field.hint %></p><% end %>
|
|
9
|
+
<% errors.each do |message| %><p class="adm-error"><%= message %></p><% end %>
|
|
10
|
+
</div>
|
|
11
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<% content_for :title, t("administratum.password_resets.new_password") %>
|
|
2
|
+
<h1 class="adm-auth-title"><%= t("administratum.password_resets.new_password") %></h1>
|
|
3
|
+
<% if @errors.present? %>
|
|
4
|
+
<div class="adm-alert" role="alert"><ul><% @errors.each do |message| %><li><%= message %></li><% end %></ul></div>
|
|
5
|
+
<% end %>
|
|
6
|
+
<%= form_with url: administratum.password_reset_path, method: :patch, class: "adm-form" do |f| %>
|
|
7
|
+
<%= f.hidden_field :token, value: @token %>
|
|
8
|
+
<div class="adm-field">
|
|
9
|
+
<%= f.label :password, t("administratum.sessions.password"), class: "adm-label" %>
|
|
10
|
+
<%= f.password_field :password, class: "adm-input", required: true, autofocus: true, autocomplete: "new-password" %>
|
|
11
|
+
</div>
|
|
12
|
+
<div class="adm-field">
|
|
13
|
+
<%= f.label :password_confirmation, t("administratum.password_resets.confirmation"), class: "adm-label" %>
|
|
14
|
+
<%= f.password_field :password_confirmation, class: "adm-input", required: true, autocomplete: "new-password" %>
|
|
15
|
+
</div>
|
|
16
|
+
<%= f.submit t("administratum.password_resets.save"), class: "adm-btn adm-btn-primary adm-btn-block" %>
|
|
17
|
+
<% end %>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<% content_for :title, t("administratum.password_resets.title") %>
|
|
2
|
+
<h1 class="adm-auth-title"><%= t("administratum.password_resets.title") %></h1>
|
|
3
|
+
<p class="adm-muted adm-auth-lead"><%= t("administratum.password_resets.lead") %></p>
|
|
4
|
+
<%= form_with url: administratum.password_reset_path, class: "adm-form" do |f| %>
|
|
5
|
+
<div class="adm-field">
|
|
6
|
+
<%= f.label :email, t("administratum.sessions.email"), class: "adm-label" %>
|
|
7
|
+
<%= f.email_field :email, class: "adm-input", required: true, autofocus: true, autocomplete: "username" %>
|
|
8
|
+
</div>
|
|
9
|
+
<%= f.submit t("administratum.password_resets.submit"), class: "adm-btn adm-btn-primary adm-btn-block" %>
|
|
10
|
+
<% end %>
|
|
11
|
+
<p class="adm-auth-footer"><%= link_to t("administratum.password_resets.back"), administratum.sign_in_path, class: "adm-link" %></p>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
<section class="adm-card">
|
|
2
|
+
<dl class="adm-attributes">
|
|
3
|
+
<% definition.resolved_show_attributes.each do |attribute| %>
|
|
4
|
+
<% next unless condition_met?(attribute.condition, @resource) %>
|
|
5
|
+
<div class="adm-attribute">
|
|
6
|
+
<dt><%= column_label(attribute) %></dt>
|
|
7
|
+
<dd><%= column_value(@resource, attribute) %></dd>
|
|
8
|
+
</div>
|
|
9
|
+
<% end %>
|
|
10
|
+
</dl>
|
|
11
|
+
</section>
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
<section class="adm-card">
|
|
2
|
+
<%= administratum_form(class: "adm-form-flush") do |form| %>
|
|
3
|
+
<% if form.object.errors.any? %>
|
|
4
|
+
<div class="adm-form-errors"><%= render "administratum/shared/form_errors", record: form.object %></div>
|
|
5
|
+
<% end %>
|
|
6
|
+
<div class="adm-form-body">
|
|
7
|
+
<%= render_fields(form) %>
|
|
8
|
+
</div>
|
|
9
|
+
<footer class="adm-form-actions">
|
|
10
|
+
<%= form.submit class: "adm-btn adm-btn-primary" %>
|
|
11
|
+
<%= link_to t("administratum.cancel"), (@resource.persisted? && definition.action_enabled?(:show) ? resource_path : (definition.action_enabled?(:index) ? collection_path : (parent_path || administratum.root_path))), class: "adm-btn adm-btn-secondary" %>
|
|
12
|
+
</footer>
|
|
13
|
+
<% end %>
|
|
14
|
+
</section>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
<section class="adm-card">
|
|
2
|
+
<div class="adm-table-wrap">
|
|
3
|
+
<table class="adm-table">
|
|
4
|
+
<thead>
|
|
5
|
+
<tr>
|
|
6
|
+
<% definition.index_columns.each do |column| %>
|
|
7
|
+
<th scope="col"><%= column.sortable ? sort_link(@search, column.name, column_label(column)) : column_label(column) %></th>
|
|
8
|
+
<% end %>
|
|
9
|
+
<th scope="col" class="adm-table-actions"><span class="adm-sr-only"><%= t("administratum.actions.title") %></span></th>
|
|
10
|
+
</tr>
|
|
11
|
+
</thead>
|
|
12
|
+
<tbody>
|
|
13
|
+
<% @resources.each do |record| %>
|
|
14
|
+
<tr>
|
|
15
|
+
<% definition.index_columns.each_with_index do |column, index| %>
|
|
16
|
+
<td>
|
|
17
|
+
<% if index.zero? && !column.block && definition.action_enabled?(:show) %>
|
|
18
|
+
<%= link_to column_value(record, column), resource_path(record), class: "adm-link" %>
|
|
19
|
+
<% else %>
|
|
20
|
+
<%= column_value(record, column) %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</td>
|
|
23
|
+
<% end %>
|
|
24
|
+
<td class="adm-table-actions"><div class="adm-btn-group"><%= buttons_for(:row, record) %></div></td>
|
|
25
|
+
</tr>
|
|
26
|
+
<% end %>
|
|
27
|
+
<% if @resources.empty? %>
|
|
28
|
+
<tr><td colspan="<%= definition.index_columns.size + 1 %>" class="adm-empty"><%= t("administratum.empty", resources: resource_class.plural_label.downcase) %></td></tr>
|
|
29
|
+
<% end %>
|
|
30
|
+
</tbody>
|
|
31
|
+
</table>
|
|
32
|
+
</div>
|
|
33
|
+
<footer class="adm-card-footer adm-table-footer">
|
|
34
|
+
<div class="adm-muted">
|
|
35
|
+
<%== pagy_info(@pagy) %>
|
|
36
|
+
<% if definition.csv %>
|
|
37
|
+
· <%= link_to t("administratum.download_csv"), url_for(format: :csv, q: request.query_parameters[:q], scope: current_index_scope&.name), class: "adm-link" %>
|
|
38
|
+
<% end %>
|
|
39
|
+
</div>
|
|
40
|
+
<div class="adm-pagy"><%== pagy_nav(@pagy) if @pagy.pages > 1 %></div>
|
|
41
|
+
</footer>
|
|
42
|
+
</section>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<%= page_header title: resource_class.plural_label do %>
|
|
2
|
+
<% if filters? %>
|
|
3
|
+
<button type="button" class="adm-btn adm-btn-secondary" data-adm-offcanvas-open="adm-filters"><%= t("administratum.filters.title") %></button>
|
|
4
|
+
<% end %>
|
|
5
|
+
<%= buttons_for(:index, nil) %>
|
|
6
|
+
<% end %>
|
|
7
|
+
|
|
8
|
+
<div class="adm-container adm-page-body">
|
|
9
|
+
<%= index_scope_tabs %>
|
|
10
|
+
<%= render "table" %>
|
|
11
|
+
</div>
|
|
12
|
+
|
|
13
|
+
<% if filters? %>
|
|
14
|
+
<% content_for :panels do %>
|
|
15
|
+
<%= render "administratum/shared/filters" %>
|
|
16
|
+
<% end %>
|
|
17
|
+
<% end %>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<% content_for :title, t("administratum.sessions.title") %>
|
|
2
|
+
<h1 class="adm-auth-title"><%= t("administratum.sessions.title") %></h1>
|
|
3
|
+
<%= form_with url: administratum.sign_in_path, class: "adm-form" do |f| %>
|
|
4
|
+
<div class="adm-field">
|
|
5
|
+
<%= f.label :email, t("administratum.sessions.email"), class: "adm-label" %>
|
|
6
|
+
<%= f.email_field :email, value: params[:email], class: "adm-input", required: true, autofocus: true, autocomplete: "username" %>
|
|
7
|
+
</div>
|
|
8
|
+
<div class="adm-field">
|
|
9
|
+
<%= f.label :password, t("administratum.sessions.password"), class: "adm-label" %>
|
|
10
|
+
<%= f.password_field :password, class: "adm-input", required: true, autocomplete: "current-password" %>
|
|
11
|
+
</div>
|
|
12
|
+
<label class="adm-check">
|
|
13
|
+
<%= f.checkbox :remember_me, class: "adm-checkbox" %>
|
|
14
|
+
<span><%= t("administratum.sessions.remember_me") %></span>
|
|
15
|
+
</label>
|
|
16
|
+
<%= f.submit t("administratum.sessions.submit"), class: "adm-btn adm-btn-primary adm-btn-block" %>
|
|
17
|
+
<% end %>
|
|
18
|
+
<p class="adm-auth-footer"><%= link_to t("administratum.password_resets.link"), administratum.new_password_reset_path, class: "adm-link" %></p>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<section class="adm-card">
|
|
2
|
+
<% if title %>
|
|
3
|
+
<header class="adm-card-header"><h2 class="adm-card-title"><%= title %></h2></header>
|
|
4
|
+
<% end %>
|
|
5
|
+
<div class="<%= flush ? "adm-card-flush" : "adm-card-body" %>"><%= body %></div>
|
|
6
|
+
<% if footer %>
|
|
7
|
+
<footer class="adm-card-footer"><%= footer %></footer>
|
|
8
|
+
<% end %>
|
|
9
|
+
</section>
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
<div class="adm-offcanvas" data-adm-offcanvas="adm-filters" hidden>
|
|
2
|
+
<div class="adm-offcanvas-backdrop" data-adm-offcanvas-close></div>
|
|
3
|
+
<aside class="adm-offcanvas-panel" role="dialog" aria-modal="true" aria-labelledby="adm-filters-title">
|
|
4
|
+
<header class="adm-offcanvas-header">
|
|
5
|
+
<h2 id="adm-filters-title" class="adm-card-title"><%= t("administratum.filters.title") %></h2>
|
|
6
|
+
<button type="button" class="adm-icon-btn" data-adm-offcanvas-close aria-label="<%= t("administratum.close") %>">×</button>
|
|
7
|
+
</header>
|
|
8
|
+
<div class="adm-offcanvas-body">
|
|
9
|
+
<%= search_form_for @search, url: collection_path, method: :get, html: { class: "adm-form" } do |f| %>
|
|
10
|
+
<%= hidden_field_tag :scope, current_index_scope.name, id: nil if current_index_scope %>
|
|
11
|
+
<% definition.filters.each do |filter| %>
|
|
12
|
+
<div class="adm-field">
|
|
13
|
+
<% label = filter.label || definition.model.human_attribute_name(filter.name) %>
|
|
14
|
+
<% case filter.type %>
|
|
15
|
+
<% when :select %>
|
|
16
|
+
<%= f.label filter.keys.first, label, class: "adm-label" %>
|
|
17
|
+
<%= f.select filter.keys.first, filter_collection(filter), { include_blank: t("administratum.filters.any") }, class: "adm-input" %>
|
|
18
|
+
<% when :boolean %>
|
|
19
|
+
<%= f.label filter.keys.first, label, class: "adm-label" %>
|
|
20
|
+
<%= f.select filter.keys.first, [[t("administratum.yes"), true], [t("administratum.no"), false]], { include_blank: t("administratum.filters.any") }, class: "adm-input" %>
|
|
21
|
+
<% when :date_range %>
|
|
22
|
+
<span class="adm-label"><%= label %></span>
|
|
23
|
+
<div class="adm-field-row">
|
|
24
|
+
<%= adm_date_field f, filter.keys.first, "aria-label": t("administratum.filters.from", field: label) %>
|
|
25
|
+
<%= adm_date_field f, filter.keys.last, "aria-label": t("administratum.filters.to", field: label) %>
|
|
26
|
+
</div>
|
|
27
|
+
<% when :number %>
|
|
28
|
+
<%= f.label filter.keys.first, label, class: "adm-label" %>
|
|
29
|
+
<%= f.number_field filter.keys.first, class: "adm-input" %>
|
|
30
|
+
<% else %>
|
|
31
|
+
<%= f.label filter.keys.first, label, class: "adm-label" %>
|
|
32
|
+
<%= f.search_field filter.keys.first, class: "adm-input" %>
|
|
33
|
+
<% end %>
|
|
34
|
+
</div>
|
|
35
|
+
<% end %>
|
|
36
|
+
<div class="adm-form-footer">
|
|
37
|
+
<%= f.submit t("administratum.filters.apply"), class: "adm-btn adm-btn-primary", name: nil %>
|
|
38
|
+
<%= link_to t("administratum.filters.clear"), collection_path(scope: current_index_scope&.name), class: "adm-btn adm-btn-secondary" %>
|
|
39
|
+
</div>
|
|
40
|
+
<% end %>
|
|
41
|
+
</div>
|
|
42
|
+
</aside>
|
|
43
|
+
</div>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
<div class="adm-flash-stack" aria-live="polite">
|
|
2
|
+
<% flash.each do |type, message| %>
|
|
3
|
+
<% next unless message.is_a?(String) %>
|
|
4
|
+
<div class="adm-flash <%= type.to_s == "alert" ? "adm-flash-alert" : "adm-flash-notice" %>" data-adm-flash role="status">
|
|
5
|
+
<span><%= message %></span>
|
|
6
|
+
<button type="button" class="adm-flash-close" data-adm-dismiss aria-label="<%= t("administratum.close") %>">×</button>
|
|
7
|
+
</div>
|
|
8
|
+
<% end %>
|
|
9
|
+
</div>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<% if record.errors.any? %>
|
|
2
|
+
<div class="adm-alert" role="alert">
|
|
3
|
+
<p class="adm-alert-title"><%= t("administratum.errors.title", count: record.errors.count) %></p>
|
|
4
|
+
<ul>
|
|
5
|
+
<% record.errors.full_messages.each do |message| %>
|
|
6
|
+
<li><%= message %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
<% end %>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
<nav id="adm-nav" class="adm-nav" aria-label="<%= t("administratum.menu") %>">
|
|
2
|
+
<div class="adm-container">
|
|
3
|
+
<ul class="adm-nav-list">
|
|
4
|
+
<li><%= link_to t("administratum.dashboard"), administratum.root_path, class: class_names("adm-nav-link", "adm-nav-link-active" => controller_name == "dashboard") %></li>
|
|
5
|
+
<% administratum_nav_items.each do |item| %>
|
|
6
|
+
<li><%= link_to item[:label], item[:path], class: class_names("adm-nav-link", "adm-nav-link-active" => item[:active]), "aria-current": (item[:active] ? "page" : nil) %></li>
|
|
7
|
+
<% end %>
|
|
8
|
+
</ul>
|
|
9
|
+
</div>
|
|
10
|
+
</nav>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<div class="adm-page-header">
|
|
2
|
+
<div class="adm-container adm-page-header-inner">
|
|
3
|
+
<div class="adm-page-heading">
|
|
4
|
+
<% if breadcrumbs.any? %>
|
|
5
|
+
<ol class="adm-breadcrumb">
|
|
6
|
+
<% breadcrumbs.each do |label, path| %>
|
|
7
|
+
<li class="adm-breadcrumb-item"><%= path ? link_to(label, path) : label %></li>
|
|
8
|
+
<% end %>
|
|
9
|
+
</ol>
|
|
10
|
+
<% end %>
|
|
11
|
+
<h1 class="adm-page-title"><%= title %></h1>
|
|
12
|
+
</div>
|
|
13
|
+
<% if actions.present? %>
|
|
14
|
+
<div class="adm-page-actions"><%= actions %></div>
|
|
15
|
+
<% end %>
|
|
16
|
+
</div>
|
|
17
|
+
</div>
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<div class="adm-offcanvas" data-adm-offcanvas="<%= id %>" hidden>
|
|
2
|
+
<div class="adm-offcanvas-backdrop" data-adm-offcanvas-close></div>
|
|
3
|
+
<aside class="adm-offcanvas-panel" role="dialog" aria-modal="true" aria-labelledby="<%= id %>-title">
|
|
4
|
+
<header class="adm-offcanvas-header">
|
|
5
|
+
<h2 id="<%= id %>-title" class="adm-card-title"><%= title %></h2>
|
|
6
|
+
<button type="button" class="adm-icon-btn" data-adm-offcanvas-close aria-label="<%= t("administratum.close") %>">×</button>
|
|
7
|
+
</header>
|
|
8
|
+
<div class="adm-offcanvas-body">
|
|
9
|
+
<% if button.panel %>
|
|
10
|
+
<%= render button.panel, resource: record, button: button %>
|
|
11
|
+
<% else %>
|
|
12
|
+
<%= form_with url: target, method: :post, multipart: true, class: "adm-form" do |f| %>
|
|
13
|
+
<div class="adm-field">
|
|
14
|
+
<%= f.label :file, t("administratum.upload.file"), class: "adm-label" %>
|
|
15
|
+
<%= f.file_field :file, class: "adm-input", required: true, accept: (button.upload.is_a?(String) ? button.upload : nil) %>
|
|
16
|
+
</div>
|
|
17
|
+
<div class="adm-form-footer">
|
|
18
|
+
<%= f.submit t("administratum.upload.submit"), class: "adm-btn adm-btn-primary" %>
|
|
19
|
+
</div>
|
|
20
|
+
<% end %>
|
|
21
|
+
<% end %>
|
|
22
|
+
</div>
|
|
23
|
+
</aside>
|
|
24
|
+
</div>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
<header class="adm-topbar">
|
|
2
|
+
<div class="adm-container adm-topbar-inner">
|
|
3
|
+
<button type="button" class="adm-icon-btn md:hidden" data-adm-toggle="adm-nav" aria-controls="adm-nav" aria-expanded="false" aria-label="<%= t("administratum.menu") %>">
|
|
4
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="adm-icon" aria-hidden="true"><path d="M4 6h16M4 12h16M4 18h16"/></svg>
|
|
5
|
+
</button>
|
|
6
|
+
<%= link_to administratum.root_path, class: "adm-brand" do %>
|
|
7
|
+
<% if administratum_config.logo %>
|
|
8
|
+
<%= image_tag administratum_config.logo, alt: administratum_config.app_name, class: "adm-logo" %>
|
|
9
|
+
<% else %>
|
|
10
|
+
<span class="adm-brand-name"><%= administratum_config.app_name %></span>
|
|
11
|
+
<% end %>
|
|
12
|
+
<% end %>
|
|
13
|
+
<div class="adm-topbar-actions">
|
|
14
|
+
<button type="button" class="adm-icon-btn" data-adm-theme-toggle aria-label="<%= t("administratum.toggle_theme") %>">
|
|
15
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" class="adm-icon" aria-hidden="true"><path d="M21 12.8A9 9 0 1 1 11.2 3a7 7 0 0 0 9.8 9.8z"/></svg>
|
|
16
|
+
</button>
|
|
17
|
+
<% if current_admin %>
|
|
18
|
+
<div class="adm-dropdown" data-adm-dropdown>
|
|
19
|
+
<button type="button" class="adm-btn adm-btn-ghost" data-adm-dropdown-toggle aria-haspopup="true" aria-expanded="false">
|
|
20
|
+
<%= current_admin.email %>
|
|
21
|
+
</button>
|
|
22
|
+
<div class="adm-dropdown-menu" data-adm-dropdown-menu hidden>
|
|
23
|
+
<%= button_to t("administratum.sessions.sign_out"), administratum.sign_out_path, method: :delete, class: "adm-dropdown-item" %>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
<% end %>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</header>
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<p><%= t("administratum.password_resets.email.greeting", email: @user.email) %></p>
|
|
2
|
+
<p><%= t("administratum.password_resets.email.body", app: Administratum.config.app_name) %></p>
|
|
3
|
+
<p><%= link_to t("administratum.password_resets.email.link"), @url %></p>
|
|
4
|
+
<p><%= t("administratum.password_resets.email.ignore") %></p>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="<%= I18n.locale %>">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title><%= administratum_title %></title>
|
|
7
|
+
<%= csrf_meta_tags %>
|
|
8
|
+
<%= csp_meta_tag %>
|
|
9
|
+
<%= administratum_color_scheme_script %>
|
|
10
|
+
<%= administratum_stylesheet_tag %>
|
|
11
|
+
<%= administratum_theme_style %>
|
|
12
|
+
<%= javascript_include_tag "administratum", type: "module" %>
|
|
13
|
+
<%= administratum_head %>
|
|
14
|
+
<%= yield :head %>
|
|
15
|
+
</head>
|
|
16
|
+
<body class="adm-body">
|
|
17
|
+
<%= render "administratum/shared/topbar" %>
|
|
18
|
+
<%= render "administratum/shared/nav" %>
|
|
19
|
+
<main class="adm-main">
|
|
20
|
+
<%= yield %>
|
|
21
|
+
</main>
|
|
22
|
+
<%= yield :panels %>
|
|
23
|
+
<%= render "administratum/shared/flash" %>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="<%= I18n.locale %>">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
6
|
+
<title><%= administratum_title %></title>
|
|
7
|
+
<%= csrf_meta_tags %>
|
|
8
|
+
<%= csp_meta_tag %>
|
|
9
|
+
<%= administratum_color_scheme_script %>
|
|
10
|
+
<%= administratum_stylesheet_tag %>
|
|
11
|
+
<%= administratum_theme_style %>
|
|
12
|
+
<%= javascript_include_tag "administratum", type: "module" %>
|
|
13
|
+
<%= administratum_head %>
|
|
14
|
+
</head>
|
|
15
|
+
<body class="adm-body adm-auth">
|
|
16
|
+
<div class="adm-auth-panel">
|
|
17
|
+
<div class="adm-auth-brand">
|
|
18
|
+
<% if administratum_config.logo %>
|
|
19
|
+
<%= image_tag administratum_config.logo, alt: administratum_config.app_name, class: "adm-logo" %>
|
|
20
|
+
<% else %>
|
|
21
|
+
<span class="adm-brand-name"><%= administratum_config.app_name %></span>
|
|
22
|
+
<% end %>
|
|
23
|
+
</div>
|
|
24
|
+
<div class="adm-card">
|
|
25
|
+
<div class="adm-card-body">
|
|
26
|
+
<%= yield %>
|
|
27
|
+
</div>
|
|
28
|
+
</div>
|
|
29
|
+
</div>
|
|
30
|
+
<%= render "administratum/shared/flash" %>
|
|
31
|
+
</body>
|
|
32
|
+
</html>
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
en:
|
|
2
|
+
administratum:
|
|
3
|
+
"yes": "Yes"
|
|
4
|
+
"no": "No"
|
|
5
|
+
dashboard: Dashboard
|
|
6
|
+
menu: Menu
|
|
7
|
+
close: Close
|
|
8
|
+
cancel: Cancel
|
|
9
|
+
confirm: Are you sure?
|
|
10
|
+
toggle_theme: Toggle dark mode
|
|
11
|
+
empty: No %{resources} yet.
|
|
12
|
+
download_csv: Download CSV
|
|
13
|
+
actions:
|
|
14
|
+
title: Actions
|
|
15
|
+
new: New %{resource}
|
|
16
|
+
edit: Edit
|
|
17
|
+
edit_resource: Edit %{title}
|
|
18
|
+
view: View
|
|
19
|
+
destroy: Delete
|
|
20
|
+
flash:
|
|
21
|
+
created: "%{resource} was created."
|
|
22
|
+
updated: "%{resource} was updated."
|
|
23
|
+
destroyed: "%{resource} was deleted."
|
|
24
|
+
errors:
|
|
25
|
+
title:
|
|
26
|
+
one: 1 error prevented saving
|
|
27
|
+
other: "%{count} errors prevented saving"
|
|
28
|
+
scope_tabs: Views
|
|
29
|
+
filters:
|
|
30
|
+
title: Filters
|
|
31
|
+
apply: Apply
|
|
32
|
+
clear: Clear
|
|
33
|
+
any: Any
|
|
34
|
+
from: "%{field} from"
|
|
35
|
+
to: "%{field} to"
|
|
36
|
+
upload:
|
|
37
|
+
file: File
|
|
38
|
+
submit: Upload
|
|
39
|
+
sessions:
|
|
40
|
+
title: Sign in
|
|
41
|
+
email: Email
|
|
42
|
+
password: Password
|
|
43
|
+
remember_me: Remember me
|
|
44
|
+
submit: Sign in
|
|
45
|
+
sign_out: Sign out
|
|
46
|
+
invalid: Invalid email or password.
|
|
47
|
+
unauthenticated: Please sign in to continue.
|
|
48
|
+
signed_out: You have been signed out.
|
|
49
|
+
password_resets:
|
|
50
|
+
link: Forgot your password?
|
|
51
|
+
title: Reset password
|
|
52
|
+
lead: Enter your email and we'll send you a link to choose a new password.
|
|
53
|
+
submit: Send reset link
|
|
54
|
+
back: Back to sign in
|
|
55
|
+
sent: If that email belongs to an admin, a reset link is on its way.
|
|
56
|
+
new_password: Choose a new password
|
|
57
|
+
confirmation: Confirm password
|
|
58
|
+
save: Save password
|
|
59
|
+
updated: Your password was changed. Please sign in.
|
|
60
|
+
subject: Reset your %{app} admin password
|
|
61
|
+
email:
|
|
62
|
+
greeting: Hello %{email},
|
|
63
|
+
body: Someone asked to reset your %{app} admin password. Use the link below to choose a new one.
|
|
64
|
+
link: Choose a new password
|
|
65
|
+
ignore: If you didn't ask for this, you can ignore this email.
|