lesli_admin 1.0.2 → 1.1.2
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/Rakefile +6 -1
- data/app/assets/stylesheets/lesli_admin/application.css +648 -584
- data/app/controllers/lesli_admin/account/currencies_controller.rb +2 -2
- data/app/controllers/lesli_admin/account/details_controller.rb +13 -6
- data/app/controllers/lesli_admin/account/locations_controller.rb +10 -6
- data/app/controllers/lesli_admin/account/settings_controller.rb +2 -2
- data/app/controllers/lesli_admin/accounts_controller.rb +41 -27
- data/app/controllers/lesli_admin/dashboards_controller.rb +21 -0
- data/app/models/lesli_admin/account/currency.rb +4 -2
- data/app/models/lesli_admin/account/detail.rb +3 -0
- data/app/models/lesli_admin/account/location.rb +12 -2
- data/app/models/lesli_admin/account/setting.rb +4 -2
- data/app/models/lesli_admin/account.rb +18 -1
- data/app/models/lesli_admin/dashboard.rb +8 -1
- data/app/services/lesli_admin/account_service.rb +43 -16
- data/app/views/lesli_admin/accounts/show.html.erb +104 -7
- data/app/views/lesli_admin/dashboards/_component-account-metadata.html.erb +44 -0
- data/app/views/lesli_admin/dashboards/_component-installed-engines.html.erb +1 -8
- data/app/views/lesli_admin/dashboards/_component-roles.html.erb +1 -0
- data/app/views/lesli_admin/dashboards/_component-users.html.erb +1 -0
- data/app/views/lesli_admin/settings/_configuration_value.html.erb +52 -0
- data/app/views/lesli_admin/settings/_defaults.html.erb +153 -56
- data/app/views/lesli_admin/settings/_modules.html.erb +28 -32
- data/db/migrate/v1/0101000210_create_lesli_admin_account_details.rb +7 -1
- data/db/migrate/v1/0101000410_create_lesli_admin_account_locations.rb +6 -1
- data/db/seeds.rb +1 -1
- data/lib/lesli_admin/engine.rb +0 -4
- data/lib/lesli_admin/version.rb +2 -2
- data/readme.md +123 -49
- metadata +12 -7
- data/app/assets/config/lesli_admin_manifest.js +0 -38
- data/lib/scss/application.scss +0 -4
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
<%
|
|
2
|
+
sensitive_key = setting_key.to_s.match?(/password|secret|token|api[_-]?key|private[_-]?key|credential|encryption|salt/i)
|
|
3
|
+
%>
|
|
4
|
+
|
|
5
|
+
<% if sensitive_key %>
|
|
6
|
+
<span class="inline-flex items-center gap-1.5 rounded-full bg-slate-200 px-2.5 py-1 text-xs font-semibold text-slate-600">
|
|
7
|
+
<span class="material-symbols-outlined text-sm" aria-hidden="true">lock</span>
|
|
8
|
+
Filtered
|
|
9
|
+
</span>
|
|
10
|
+
<% elsif value.is_a?(Hash) %>
|
|
11
|
+
<dl class="space-y-2">
|
|
12
|
+
<% value.each do |nested_key, nested_value| %>
|
|
13
|
+
<div class="rounded-lg border border-slate-200 bg-white p-3">
|
|
14
|
+
<dt class="text-xs font-medium text-slate-500"><%= nested_key.to_s.humanize %></dt>
|
|
15
|
+
<dd class="mt-1.5">
|
|
16
|
+
<%= render("configuration_value", setting_key: nested_key, value: nested_value) %>
|
|
17
|
+
</dd>
|
|
18
|
+
</div>
|
|
19
|
+
<% end %>
|
|
20
|
+
</dl>
|
|
21
|
+
<% elsif value.is_a?(Array) %>
|
|
22
|
+
<% if value.empty? %>
|
|
23
|
+
<span class="text-slate-400">Empty list</span>
|
|
24
|
+
<% else %>
|
|
25
|
+
<ul class="flex flex-wrap gap-2">
|
|
26
|
+
<% value.each do |item| %>
|
|
27
|
+
<li class="rounded-lg border border-slate-200 bg-white px-2.5 py-1 text-xs text-slate-700">
|
|
28
|
+
<%= render("configuration_value", setting_key: :item, value: item) %>
|
|
29
|
+
</li>
|
|
30
|
+
<% end %>
|
|
31
|
+
</ul>
|
|
32
|
+
<% end %>
|
|
33
|
+
<% elsif value == true %>
|
|
34
|
+
<span class="inline-flex items-center gap-1.5 rounded-full bg-emerald-100 px-2.5 py-1 text-xs font-semibold text-emerald-700">
|
|
35
|
+
<span class="h-1.5 w-1.5 rounded-full bg-emerald-500" aria-hidden="true"></span>
|
|
36
|
+
Enabled
|
|
37
|
+
</span>
|
|
38
|
+
<% elsif value == false %>
|
|
39
|
+
<span class="inline-flex items-center gap-1.5 rounded-full bg-red-100 px-2.5 py-1 text-xs font-semibold text-red-700">
|
|
40
|
+
<span class="h-1.5 w-1.5 rounded-full bg-red-500" aria-hidden="true"></span>
|
|
41
|
+
Disabled
|
|
42
|
+
</span>
|
|
43
|
+
<% elsif value.nil? %>
|
|
44
|
+
<span class="italic text-slate-400">Not configured</span>
|
|
45
|
+
<% elsif value.to_s.match?(/\A#[0-9a-f]{3,8}\z/i) %>
|
|
46
|
+
<span class="inline-flex items-center gap-2">
|
|
47
|
+
<span class="h-5 w-5 rounded-md border border-slate-300 shadow-sm" style="background-color: <%= value %>" aria-hidden="true"></span>
|
|
48
|
+
<code class="break-all rounded-md bg-slate-200 px-2 py-1 text-xs text-slate-700"><%= value %></code>
|
|
49
|
+
</span>
|
|
50
|
+
<% else %>
|
|
51
|
+
<code class="break-all rounded-md bg-slate-200 px-2 py-1 text-xs leading-5 text-slate-700"><%= value %></code>
|
|
52
|
+
<% end %>
|
|
@@ -1,61 +1,158 @@
|
|
|
1
|
-
<%
|
|
2
|
-
sections =
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
<%
|
|
2
|
+
sections = [
|
|
3
|
+
{
|
|
4
|
+
title: "Instance",
|
|
5
|
+
icon: "dns",
|
|
6
|
+
description: "Runtime identity and operating mode for this installation.",
|
|
7
|
+
config: {
|
|
8
|
+
demo: Lesli.config.demo,
|
|
9
|
+
instance: Lesli.config.instance
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
title: "Company",
|
|
14
|
+
icon: "apartment",
|
|
15
|
+
description: "Organization details displayed throughout the platform.",
|
|
16
|
+
config: Lesli.config.company
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
title: "Locales",
|
|
20
|
+
icon: "translate",
|
|
21
|
+
description: "Languages currently available to users.",
|
|
22
|
+
config: Lesli.config.babel&.fetch(:locales, {})
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
title: "Date and time",
|
|
26
|
+
icon: "schedule",
|
|
27
|
+
description: "Time zone, week boundaries, and display formats.",
|
|
28
|
+
config: Lesli.config.datetime
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
title: "Security",
|
|
32
|
+
icon: "shield_lock",
|
|
33
|
+
description: "Authentication and account-access behavior.",
|
|
34
|
+
config: Lesli.config.security
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
title: "Theme",
|
|
38
|
+
icon: "palette",
|
|
39
|
+
description: "Colors used by the shared Lesli interface.",
|
|
40
|
+
config: Lesli.config.theme
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
title: "Layout",
|
|
44
|
+
icon: "dashboard_customize",
|
|
45
|
+
description: "Global interface features and visibility controls.",
|
|
46
|
+
config: Lesli.config.layout
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
title: "Mailer",
|
|
50
|
+
icon: "mail",
|
|
51
|
+
description: "Email delivery and template configuration.",
|
|
52
|
+
config: Lesli.config.mailer
|
|
53
|
+
},
|
|
54
|
+
{
|
|
55
|
+
title: "Paths",
|
|
56
|
+
icon: "route",
|
|
57
|
+
description: "Application destinations used by navigation and authentication.",
|
|
58
|
+
config: {
|
|
59
|
+
path_after_login: Lesli.config.shield&.fetch(:path_after_login, nil)
|
|
60
|
+
}
|
|
16
61
|
}
|
|
17
|
-
}
|
|
62
|
+
].map { |section| section.merge(config: section[:config] || {}) }
|
|
63
|
+
|
|
64
|
+
leaf_count = lambda do |value|
|
|
65
|
+
case value
|
|
66
|
+
when Hash
|
|
67
|
+
value.values.sum { |nested_value| leaf_count.call(nested_value) }
|
|
68
|
+
when Array
|
|
69
|
+
value.sum { |nested_value| leaf_count.call(nested_value) }
|
|
70
|
+
else
|
|
71
|
+
1
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
total_settings = sections.sum { |section| leaf_count.call(section[:config]) }
|
|
18
76
|
%>
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
<div class="
|
|
24
|
-
<
|
|
25
|
-
<div
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
%>
|
|
34
|
-
<% config.each do |key, value| %>
|
|
35
|
-
<div class="column <%= grid %>">
|
|
36
|
-
<p class="has-text-weight-semibold"><%= key.to_s.humanize %></p>
|
|
37
|
-
<div>
|
|
38
|
-
<% if value.is_a?(Hash) %>
|
|
39
|
-
<ul class="pl-4">
|
|
40
|
-
<% value.each do |key, value| %>
|
|
41
|
-
<li>
|
|
42
|
-
<strong><%= key.to_s.humanize %>:</strong>
|
|
43
|
-
<code><%= value %></code>
|
|
44
|
-
</li>
|
|
45
|
-
<% end %>
|
|
46
|
-
</ul>
|
|
47
|
-
|
|
48
|
-
<% elsif value == true %>
|
|
49
|
-
<span class="tag is-success has-text-white">Enabled</span>
|
|
50
|
-
<% elsif value == false %>
|
|
51
|
-
<span class="tag is-danger has-text-white">Disabled</span>
|
|
52
|
-
<% else %>
|
|
53
|
-
<code class="is-size-7"><%= value.to_s %></code>
|
|
54
|
-
<% end %>
|
|
55
|
-
</div>
|
|
56
|
-
</div>
|
|
57
|
-
<% end %>
|
|
77
|
+
|
|
78
|
+
<section aria-labelledby="lesli-configuration-title">
|
|
79
|
+
|
|
80
|
+
<div class="rounded-2xl border border-slate-200 bg-white p-5 shadow-sm sm:p-6">
|
|
81
|
+
<div class="flex items-center gap-3">
|
|
82
|
+
<span class="material-symbols-outlined rounded-xl bg-sky-50 p-2.5 text-2xl text-sky-700" aria-hidden="true">settings</span>
|
|
83
|
+
<div>
|
|
84
|
+
<h2 id="lesli-configuration-title" class="text-xl font-semibold tracking-tight text-slate-900">
|
|
85
|
+
Lesli configuration
|
|
86
|
+
</h2>
|
|
87
|
+
<p class="mt-1 text-sm leading-6 text-slate-500">
|
|
88
|
+
Effective read-only values loaded by this application instance.
|
|
89
|
+
</p>
|
|
58
90
|
</div>
|
|
59
91
|
</div>
|
|
60
|
-
|
|
92
|
+
|
|
93
|
+
<dl class="mt-6 grid grid-cols-2 gap-3 lg:grid-cols-4">
|
|
94
|
+
<div class="rounded-xl bg-slate-50 px-4 py-3">
|
|
95
|
+
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Environment</dt>
|
|
96
|
+
<dd class="mt-1 text-sm font-semibold text-slate-900"><%= Rails.env.to_s.humanize %></dd>
|
|
97
|
+
</div>
|
|
98
|
+
<div class="rounded-xl bg-slate-50 px-4 py-3">
|
|
99
|
+
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Sections</dt>
|
|
100
|
+
<dd class="mt-1 text-sm font-semibold text-slate-900"><%= sections.size %></dd>
|
|
101
|
+
</div>
|
|
102
|
+
<div class="rounded-xl bg-slate-50 px-4 py-3">
|
|
103
|
+
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Values</dt>
|
|
104
|
+
<dd class="mt-1 text-sm font-semibold text-slate-900"><%= total_settings %></dd>
|
|
105
|
+
</div>
|
|
106
|
+
<div class="rounded-xl bg-slate-50 px-4 py-3">
|
|
107
|
+
<dt class="text-xs font-medium uppercase tracking-wide text-slate-500">Demo mode</dt>
|
|
108
|
+
<dd class="mt-1">
|
|
109
|
+
<span class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-semibold <%= Lesli.config.demo ? "bg-amber-100 text-amber-700" : "bg-emerald-100 text-emerald-700" %>">
|
|
110
|
+
<%= Lesli.config.demo ? "Enabled" : "Disabled" %>
|
|
111
|
+
</span>
|
|
112
|
+
</dd>
|
|
113
|
+
</div>
|
|
114
|
+
</dl>
|
|
115
|
+
</div>
|
|
116
|
+
|
|
117
|
+
<div class="mt-5 space-y-4">
|
|
118
|
+
<% sections.each_with_index do |section, index| %>
|
|
119
|
+
<details
|
|
120
|
+
class="group rounded-2xl border border-slate-200 bg-white shadow-sm"
|
|
121
|
+
<%= "open" if index < 2 %>>
|
|
122
|
+
<summary class="flex cursor-pointer list-none items-center gap-4 px-5 py-4 marker:hidden sm:px-6">
|
|
123
|
+
<span class="material-symbols-outlined rounded-xl bg-slate-100 p-2.5 text-2xl text-slate-600" aria-hidden="true"><%= section[:icon] %></span>
|
|
124
|
+
<span class="min-w-0 flex-1">
|
|
125
|
+
<span class="block text-base font-semibold text-slate-900"><%= section[:title] %></span>
|
|
126
|
+
<span class="mt-0.5 block text-sm leading-5 text-slate-500"><%= section[:description] %></span>
|
|
127
|
+
</span>
|
|
128
|
+
<span class="hidden rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-600 sm:inline-flex">
|
|
129
|
+
<%= pluralize(section[:config].size, "group") %>
|
|
130
|
+
</span>
|
|
131
|
+
<span class="material-symbols-outlined text-slate-400 transition-transform group-open:rotate-180" aria-hidden="true">expand_more</span>
|
|
132
|
+
</summary>
|
|
133
|
+
|
|
134
|
+
<div class="border-t border-slate-100 px-5 py-5 sm:px-6">
|
|
135
|
+
<% if section[:config].empty? %>
|
|
136
|
+
<p class="text-sm text-slate-500">No values are configured for this section.</p>
|
|
137
|
+
<% else %>
|
|
138
|
+
<dl class="grid grid-cols-1 gap-4 lg:grid-cols-2">
|
|
139
|
+
<% section[:config].each do |key, value| %>
|
|
140
|
+
<div class="min-w-0 rounded-xl border border-slate-100 bg-slate-50/60 p-4">
|
|
141
|
+
<dt class="text-xs font-semibold uppercase tracking-wide text-slate-500"><%= key.to_s.humanize %></dt>
|
|
142
|
+
<dd class="mt-2 text-sm text-slate-900">
|
|
143
|
+
<%= render("configuration_value", setting_key: key, value: value) %>
|
|
144
|
+
</dd>
|
|
145
|
+
</div>
|
|
146
|
+
<% end %>
|
|
147
|
+
</dl>
|
|
148
|
+
<% end %>
|
|
149
|
+
</div>
|
|
150
|
+
</details>
|
|
151
|
+
<% end %>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<p class="mt-5 flex items-start gap-2 text-xs leading-5 text-slate-500">
|
|
155
|
+
<span class="material-symbols-outlined text-base" aria-hidden="true">lock</span>
|
|
156
|
+
Sensitive values are filtered on the server and are never included in this page.
|
|
157
|
+
</p>
|
|
61
158
|
</section>
|
|
@@ -20,42 +20,38 @@
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
</script>
|
|
23
|
-
|
|
24
|
-
.fixed-grid .partial-engine-spec ul {
|
|
25
|
-
display: flex;
|
|
26
|
-
}
|
|
27
|
-
.fixed-grid .partial-engine-spec ul li {
|
|
28
|
-
margin: 0 1rem 0 0;
|
|
29
|
-
font-size: 13px;
|
|
30
|
-
}
|
|
31
|
-
.fixed-grid .partial-engine-spec ul li:last-child {
|
|
32
|
-
display: none;
|
|
33
|
-
}
|
|
34
|
-
.fixed-grid .partial-engine-spec .material-symbols {
|
|
35
|
-
font-size: 0px;
|
|
36
|
-
}
|
|
37
|
-
</style>
|
|
23
|
+
|
|
38
24
|
<%
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
lesli_engines = LesliSystem.engines.values.map do |engine_info|
|
|
26
|
+
summary = engine_info[:summary]
|
|
27
|
+
&.sub("for the Lesli Framework", "")
|
|
28
|
+
&.sub("for The Lesli Framework", "")
|
|
29
|
+
|
|
30
|
+
engine_info.merge(summary: summary)
|
|
31
|
+
end
|
|
43
32
|
%>
|
|
44
33
|
|
|
45
|
-
<
|
|
46
|
-
|
|
47
|
-
|
|
34
|
+
<section
|
|
35
|
+
class="grid grid-cols-1 gap-5 xl:grid-cols-2"
|
|
36
|
+
aria-label="Modules"
|
|
37
|
+
x-data="engineManager()">
|
|
38
|
+
<% lesli_engines.each do |engine| %>
|
|
48
39
|
<% next if engine[:name] == "Root" %>
|
|
49
|
-
|
|
50
|
-
|
|
40
|
+
|
|
41
|
+
<% engine_key = engine[:path].delete("/") %>
|
|
42
|
+
|
|
43
|
+
<article class="module-engine-card flex min-w-0 flex-col rounded-2xl border border-slate-200 bg-white p-5 shadow-sm sm:p-6">
|
|
44
|
+
<div class="min-w-0 flex-1">
|
|
51
45
|
<%= render(LesliView::Partials::EngineSpec.new(engine)) %>
|
|
52
|
-
<button
|
|
53
|
-
@click="toggleEngine('<%= engine[:path].gsub("/","") %>')"
|
|
54
|
-
:class="data.engines.includes('<%= engine[:path].gsub("/","") %>') ? 'button is-small is-info' : 'button is-small is-danger has-text-white'"
|
|
55
|
-
x-text="data.engines.includes('<%= engine[:path].gsub("/","") %>') ? 'Activar módulo' : 'Desactivar módulo'">
|
|
56
|
-
</button>
|
|
57
46
|
</div>
|
|
58
|
-
|
|
47
|
+
|
|
48
|
+
<button
|
|
49
|
+
type="button"
|
|
50
|
+
class="mt-5 inline-flex w-fit items-center justify-center rounded-lg px-3 py-2 text-sm font-semibold text-white shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2"
|
|
51
|
+
@click="toggleEngine(<%= engine_key.to_json %>)"
|
|
52
|
+
:class="data.engines.includes(<%= engine_key.to_json %>) ? 'bg-emerald-600 hover:bg-emerald-700 focus-visible:ring-emerald-500/30' : 'bg-red-600 hover:bg-red-700 focus-visible:ring-red-500/30'"
|
|
53
|
+
x-text="data.engines.includes(<%= engine_key.to_json %>) ? 'Activar módulo' : 'Desactivar módulo'">
|
|
54
|
+
</button>
|
|
55
|
+
</article>
|
|
59
56
|
<% end %>
|
|
60
|
-
</
|
|
61
|
-
</div>
|
|
57
|
+
</section>
|
|
@@ -65,6 +65,12 @@ class CreateLesliAdminAccountDetails < ActiveRecord::Migration[6.0]
|
|
|
65
65
|
t.datetime :deleted_at, index: true
|
|
66
66
|
t.timestamps
|
|
67
67
|
end
|
|
68
|
-
add_reference(
|
|
68
|
+
add_reference(
|
|
69
|
+
:lesli_admin_account_details,
|
|
70
|
+
:account,
|
|
71
|
+
null: false,
|
|
72
|
+
index: { unique: true },
|
|
73
|
+
foreign_key: { to_table: :lesli_admin_accounts }
|
|
74
|
+
)
|
|
69
75
|
end
|
|
70
76
|
end
|
|
@@ -57,7 +57,12 @@ class CreateLesliAdminAccountLocations < ActiveRecord::Migration[6.0]
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
add_reference(:lesli_admin_account_locations, :parent, foreign_key: { to_table: :lesli_admin_account_locations })
|
|
60
|
-
add_reference(
|
|
60
|
+
add_reference(
|
|
61
|
+
:lesli_admin_account_locations,
|
|
62
|
+
:account,
|
|
63
|
+
null: false,
|
|
64
|
+
foreign_key: { to_table: :lesli_admin_accounts }
|
|
65
|
+
)
|
|
61
66
|
add_index(:lesli_admin_account_locations, %i[account_id name level parent_id], unique: true, name: "location_uniqueness_index")
|
|
62
67
|
end
|
|
63
68
|
end
|
data/db/seeds.rb
CHANGED
|
@@ -31,7 +31,7 @@ Building a better future, one line of code at a time.
|
|
|
31
31
|
=end
|
|
32
32
|
|
|
33
33
|
|
|
34
|
-
|
|
34
|
+
Termline.info("Loading seeds for: LesliAdmin #{LesliAdmin::VERSION} (#{LesliAdmin::BUILD})")
|
|
35
35
|
|
|
36
36
|
if Rails.env.development? || Lesli.config.demo
|
|
37
37
|
#load(LesliAdmin::Engine.root.join("db", "seed", "#{ Rails.env.downcase }.rb"))
|
data/lib/lesli_admin/engine.rb
CHANGED
|
@@ -35,10 +35,6 @@ module LesliAdmin
|
|
|
35
35
|
isolate_namespace LesliAdmin
|
|
36
36
|
|
|
37
37
|
initializer :lesli_admin do |app|
|
|
38
|
-
|
|
39
|
-
# register assets manifest
|
|
40
|
-
config.assets.precompile += %w[lesli_admin_manifest.js]
|
|
41
|
-
|
|
42
38
|
# register engine migrations path
|
|
43
39
|
unless app.root.to_s.match root.to_s
|
|
44
40
|
config.paths["db/migrate"].expanded.each do |expanded_path|
|
data/lib/lesli_admin/version.rb
CHANGED
data/readme.md
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
<div align="center">
|
|
2
|
-
<
|
|
3
|
-
|
|
2
|
+
<h1 align="center">
|
|
3
|
+
<img width="100" alt="LesliAdmin" src="./app/assets/images/lesli_admin/admin-logo.svg" />
|
|
4
|
+
</h1>
|
|
5
|
+
<h3 align="center">Account and application administration for the Lesli Framework.</h3>
|
|
4
6
|
</div>
|
|
5
7
|
|
|
6
8
|
<br />
|
|
7
|
-
<hr/>
|
|
8
9
|
|
|
9
10
|
<div align="center">
|
|
10
|
-
<a target="_blank" href="https://github.com/LesliTech/LesliAdmin/actions">
|
|
11
|
-
<img alt="
|
|
11
|
+
<a target="_blank" href="https://github.com/LesliTech/LesliAdmin/actions/workflows/lesli-ci-engine.yaml">
|
|
12
|
+
<img alt="LesliAdmin test status" src="https://img.shields.io/github/actions/workflow/status/LesliTech/LesliAdmin/lesli-ci-engine.yaml?branch=master&style=for-the-badge&logo=github&label=tests">
|
|
12
13
|
</a>
|
|
13
14
|
<a target="_blank" href="https://rubygems.org/gems/lesli_admin">
|
|
14
15
|
<img alt="Gem Version" src="https://img.shields.io/gem/v/lesli_admin?style=for-the-badge&logo=ruby">
|
|
@@ -16,83 +17,159 @@
|
|
|
16
17
|
<a target="_blank" href="https://codecov.io/github/LesliTech/LesliAdmin">
|
|
17
18
|
<img alt="Codecov" src="https://img.shields.io/codecov/c/github/LesliTech/LesliAdmin?style=for-the-badge&logo=codecov">
|
|
18
19
|
</a>
|
|
20
|
+
<a target="_blank" href="https://sonarcloud.io/project/overview?id=LesliTech_LesliAdmin">
|
|
21
|
+
<img alt="Sonar Quality Gate" src="https://img.shields.io/sonar/quality_gate/LesliTech_LesliAdmin?server=https%3A%2F%2Fsonarcloud.io&style=for-the-badge&logo=sonarqubecloud&label=Quality">
|
|
22
|
+
</a>
|
|
19
23
|
</div>
|
|
20
24
|
|
|
21
|
-
<hr/>
|
|
22
25
|
<br />
|
|
23
26
|
|
|
24
27
|
<div align="center">
|
|
25
28
|
<img
|
|
26
29
|
style="width:100%;max-width:800px;border-radius:6px;"
|
|
27
|
-
alt="
|
|
30
|
+
alt="LesliAdmin account administration"
|
|
31
|
+
src="./docs/images/screenshot.png" />
|
|
28
32
|
</div>
|
|
29
33
|
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
<br />
|
|
37
|
+
|
|
38
|
+
## Introduction
|
|
39
|
+
|
|
40
|
+
LesliAdmin is the official account and application administration engine for the [Lesli Framework](https://github.com/LesliTech/Lesli).
|
|
41
|
+
|
|
42
|
+
It gives account owners and administrators a central interface for maintaining the core account identity, inspecting application configuration, and understanding the engines installed in a Lesli application.
|
|
43
|
+
|
|
30
44
|
<br />
|
|
31
|
-
|
|
45
|
+
|
|
46
|
+
## Features
|
|
47
|
+
|
|
48
|
+
- Core account identity, status, and data-region management
|
|
49
|
+
- Company profile, contact, address, and social-link management
|
|
50
|
+
- Read-only framework configuration viewer with server-side secret filtering
|
|
51
|
+
- Account dashboard with user, role, installed-engine, and lifecycle metrics
|
|
52
|
+
- Installed-engine inventory and metadata
|
|
53
|
+
- Account-scoped data structures for details, locations, settings, and currencies
|
|
54
|
+
- Optional dashboard components through LesliDashboard
|
|
55
|
+
|
|
56
|
+
<br />
|
|
57
|
+
|
|
58
|
+
## Try LesliAdmin
|
|
59
|
+
|
|
60
|
+
- [Try the online demo](https://demo.lesli.dev/)
|
|
61
|
+
- [Run the Docker demo](https://github.com/LesliTech/lesli-docker-demo)
|
|
62
|
+
|
|
32
63
|
<br />
|
|
33
64
|
|
|
34
|
-
|
|
65
|
+
## Quick Start
|
|
66
|
+
|
|
67
|
+
### Requirements
|
|
68
|
+
|
|
69
|
+
- A Rails application with [Lesli 5.1](https://rubygems.org/gems/lesli)
|
|
70
|
+
- SQLite by default, or PostgreSQL when preferred by the host application
|
|
71
|
+
|
|
72
|
+
### Install LesliAdmin
|
|
73
|
+
|
|
74
|
+
Add the engine to the host Rails application and prepare its database:
|
|
35
75
|
|
|
36
76
|
```shell
|
|
37
|
-
# Add LesliAdmin engine gem
|
|
38
77
|
bundle add lesli_admin
|
|
78
|
+
bin/rails lesli:db:prepare
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Mount the engine
|
|
39
82
|
|
|
40
|
-
|
|
41
|
-
|
|
83
|
+
Applications using Lesli's standard router mount LesliAdmin automatically at `/admin`:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
# config/routes.rb
|
|
87
|
+
Rails.application.routes.draw do
|
|
88
|
+
Lesli::Router.mount(self)
|
|
89
|
+
end
|
|
42
90
|
```
|
|
43
91
|
|
|
92
|
+
If the application does not use the standard Lesli router, mount the engine directly:
|
|
93
|
+
|
|
44
94
|
```ruby
|
|
45
|
-
#
|
|
95
|
+
# config/routes.rb
|
|
46
96
|
Rails.application.routes.draw do
|
|
47
97
|
mount LesliAdmin::Engine => "/admin"
|
|
48
98
|
end
|
|
49
99
|
```
|
|
50
100
|
|
|
101
|
+
Start Rails and visit [http://127.0.0.1:3000/admin](http://127.0.0.1:3000/admin):
|
|
102
|
+
|
|
103
|
+
```shell
|
|
104
|
+
bin/rails routes -g admin
|
|
105
|
+
bin/rails server
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Install [LesliDashboard](https://rubygems.org/gems/lesli_dashboard) when the application should persist and render LesliAdmin's account metrics and metadata components.
|
|
109
|
+
|
|
51
110
|
<br />
|
|
52
|
-
<hr/>
|
|
53
|
-
<br />
|
|
54
111
|
|
|
55
|
-
|
|
112
|
+
## Development
|
|
113
|
+
|
|
114
|
+
Clone LesliAdmin into the host application's `engines` directory:
|
|
56
115
|
|
|
57
116
|
```shell
|
|
58
|
-
|
|
59
|
-
|
|
117
|
+
cd RailsApp
|
|
118
|
+
mkdir -p engines
|
|
119
|
+
git clone https://github.com/LesliTech/LesliAdmin.git engines/LesliAdmin
|
|
120
|
+
```
|
|
60
121
|
|
|
61
|
-
|
|
62
|
-
gem "lesli", path: "engines/LesliAdmin"
|
|
122
|
+
Reference the local engine from the host application's `Gemfile`:
|
|
63
123
|
|
|
64
|
-
|
|
124
|
+
```ruby
|
|
125
|
+
gem "lesli_admin", path: "engines/LesliAdmin"
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Install dependencies, prepare the host database, and start Rails:
|
|
129
|
+
|
|
130
|
+
```shell
|
|
65
131
|
bundle install
|
|
132
|
+
bin/rails lesli:db:prepare
|
|
133
|
+
bin/rails server
|
|
134
|
+
```
|
|
66
135
|
|
|
67
|
-
|
|
68
|
-
rake lesli:db:setup
|
|
136
|
+
### Tests
|
|
69
137
|
|
|
138
|
+
From a complete Lesli development workspace, run the engine test suite from the LesliAdmin directory:
|
|
139
|
+
|
|
140
|
+
```shell
|
|
141
|
+
cd engines/LesliAdmin
|
|
142
|
+
bin/rails test
|
|
70
143
|
```
|
|
71
144
|
|
|
72
145
|
<br />
|
|
73
|
-
<hr/>
|
|
74
|
-
<br />
|
|
75
|
-
|
|
76
|
-
### Demo
|
|
77
146
|
|
|
78
|
-
|
|
79
|
-
* [docker demo](https://github.com/LesliTech/lesli-docker-demo)
|
|
147
|
+
## Documentation
|
|
80
148
|
|
|
149
|
+
- [Lesli website](https://www.lesli.dev/)
|
|
150
|
+
- [Documentation](https://www.lesli.dev/engines/admin)
|
|
151
|
+
- [Installation guide](https://www.lesli.dev/engines/admin/about/installation)
|
|
152
|
+
- [Account management](https://www.lesli.dev/engines/admin/account/)
|
|
153
|
+
- [Dashboard components](https://www.lesli.dev/engines/admin/about/dashboards)
|
|
154
|
+
- [Settings and configuration](https://www.lesli.dev/engines/admin/about/settings)
|
|
155
|
+
- [Translations](https://www.lesli.dev/engines/admin/about/translations)
|
|
156
|
+
- [Database](https://www.lesli.dev/engines/admin/about/database)
|
|
157
|
+
- [Release notes](https://github.com/LesliTech/LesliAdmin/releases)
|
|
158
|
+
- [Issue tracker](https://github.com/LesliTech/LesliAdmin/issues)
|
|
159
|
+
- [Source code](https://github.com/LesliTech/LesliAdmin)
|
|
81
160
|
|
|
82
|
-
|
|
83
|
-
* [website](https://www.lesli.dev/)
|
|
84
|
-
* [documentation](https://www.lesli.dev/engines/admin)
|
|
161
|
+
<br />
|
|
85
162
|
|
|
163
|
+
## Community
|
|
86
164
|
|
|
87
|
-
|
|
165
|
+
- [X: @LesliTech](https://x.com/LesliTech)
|
|
166
|
+
- [hello@lesli.tech](mailto:hello@lesli.tech)
|
|
167
|
+
- [https://www.lesli.tech](https://www.lesli.tech)
|
|
88
168
|
|
|
89
|
-
|
|
90
|
-
* [Email: hello@lesli.tech](hello@lesli.tech)
|
|
91
|
-
* [Website: https://www.lesli.tech](https://www.lesli.tech)
|
|
169
|
+
<br />
|
|
92
170
|
|
|
171
|
+
## License
|
|
93
172
|
|
|
94
|
-
### License
|
|
95
|
-
-------
|
|
96
173
|
Copyright (c) 2026, Lesli Technologies, S. A.
|
|
97
174
|
|
|
98
175
|
This program is free software: you can redistribute it and/or modify
|
|
@@ -106,19 +183,16 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
106
183
|
GNU General Public License for more details.
|
|
107
184
|
|
|
108
185
|
You should have received a copy of the GNU General Public License
|
|
109
|
-
along with this program. If not, see
|
|
186
|
+
along with this program. If not, see [https://www.gnu.org/licenses/](https://www.gnu.org/licenses/).
|
|
110
187
|
|
|
111
|
-
|
|
112
|
-
<hr />
|
|
113
|
-
<br />
|
|
114
|
-
<br />
|
|
188
|
+
The complete license text is available in the [license file](./license).
|
|
115
189
|
|
|
116
|
-
|
|
117
|
-
<img width="200" alt="Lesli logo" src="https://cdn.lesli.tech/lesli/brand/app-logo.svg" />
|
|
118
|
-
<h3 align="center" class="mt-0">
|
|
119
|
-
The Open-Source SaaS Development Framework for Ruby on Rails.
|
|
120
|
-
</h3>
|
|
121
|
-
</div>
|
|
190
|
+
---
|
|
122
191
|
|
|
123
192
|
<br />
|
|
124
193
|
<br />
|
|
194
|
+
|
|
195
|
+
<div align="center">
|
|
196
|
+
<img width="80" alt="Lesli icon" src="https://cdn.lesli.tech/lesli/brand/app-icon.svg" />
|
|
197
|
+
<h3 align="center">The Open-Source SaaS Development Framework for Ruby on Rails.</h3>
|
|
198
|
+
</div>
|