maquina 0.5.2 → 0.7.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/.ruby-version +1 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +3 -35
- data/app/assets/javascripts/controllers/alert_controller.js +22 -0
- data/app/assets/stylesheets/maquina/application.tailwind.css +4 -101
- data/app/assets/stylesheets/maquina.css +114 -0
- data/app/controllers/concerns/maquina/authenticate.rb +29 -1
- data/app/controllers/concerns/maquina/index.rb +81 -2
- data/app/controllers/concerns/maquina/resourceful.rb +95 -9
- data/app/controllers/maquina/application_controller.rb +1 -1
- data/app/controllers/maquina/dashboard_controller.rb +10 -5
- data/app/controllers/maquina/invitations_controller.rb +0 -2
- data/app/controllers/maquina/plans_controller.rb +13 -23
- data/app/controllers/maquina/sessions_controller.rb +1 -1
- data/app/controllers/maquina/users_controller.rb +0 -2
- data/app/helpers/maquina/application_helper.rb +0 -8
- data/app/helpers/maquina/navbar_menu_helper.rb +1 -1
- data/app/models/concerns/maquina/blockeable.rb +64 -0
- data/app/models/concerns/maquina/organization_scoped.rb +26 -0
- data/app/models/concerns/maquina/retain_passwords.rb +44 -0
- data/app/models/concerns/maquina/sqlite_search.rb +92 -0
- data/app/models/concerns/maquina/user_scoped.rb +26 -0
- data/app/models/maquina/active_session.rb +40 -0
- data/app/models/maquina/current.rb +39 -2
- data/app/models/maquina/invitation.rb +28 -0
- data/app/models/maquina/membership.rb +23 -1
- data/app/models/maquina/organization.rb +19 -2
- data/app/models/maquina/plan.rb +26 -6
- data/app/models/maquina/used_password.rb +30 -0
- data/app/models/maquina/user.rb +50 -8
- data/app/policies/maquina/application_policy.rb +1 -1
- data/app/policies/maquina/dashboard_policy.rb +7 -0
- data/app/policies/maquina/navigation_policy.rb +2 -0
- data/app/views/layouts/maquina/application.html.erb +2 -2
- data/app/views/layouts/maquina/sessions.html.erb +1 -1
- data/app/views/maquina/application/_navbar.html.erb +8 -3
- data/app/views/maquina/application/components/checkbox_component.rb +3 -3
- data/app/views/maquina/application/components/component_base.rb +3 -2
- data/app/views/maquina/application/edit.html.erb +10 -7
- data/app/views/maquina/application/filters.rb +118 -0
- data/app/views/maquina/application/index.html.erb +6 -3
- data/app/views/maquina/application/index_header.rb +5 -2
- data/app/views/maquina/application/index_table.rb +71 -6
- data/app/views/maquina/application/index_tools.rb +17 -0
- data/app/views/maquina/application/new.html.erb +10 -7
- data/app/views/maquina/application/search.rb +42 -0
- data/app/views/maquina/application/sessions_header.rb +3 -9
- data/app/views/maquina/dashboard/index.html.erb +4 -0
- data/app/views/maquina/dashboard/stats.rb +35 -0
- data/app/views/maquina/dashboard/tasks.rb +124 -0
- data/app/views/maquina/first_runs/form.rb +0 -2
- data/app/views/maquina/first_runs/show.html.erb +4 -1
- data/app/views/maquina/navbar/title.rb +4 -2
- data/config/importmap.rb +1 -13
- data/config/locales/flash.en.yml +6 -0
- data/config/locales/flash.es.yml +6 -0
- data/config/locales/forms.en.yml +33 -4
- data/config/locales/forms.es.yml +22 -11
- data/config/locales/models.en.yml +10 -0
- data/config/locales/models.es.yml +10 -0
- data/config/locales/views.en.yml +33 -5
- data/config/locales/views.es.yml +28 -10
- data/config/routes.rb +1 -0
- data/db/migrate/20221109010726_create_maquina_plans.rb +1 -1
- data/db/migrate/20221113000409_create_maquina_users.rb +1 -1
- data/db/migrate/20221113020108_create_maquina_used_passwords.rb +1 -1
- data/db/migrate/20221115223414_create_maquina_active_sessions.rb +1 -3
- data/db/migrate/20230201203922_create_maquina_invitations.rb +1 -1
- data/db/migrate/20230829183530_create_maquina_organizations.rb +1 -1
- data/db/migrate/20230829192656_create_maquina_memberships.rb +2 -4
- data/db/migrate/20241109191405_add_counter_cache_to_plans.rb +5 -0
- data/lib/generators/maquina/install_generator.rb +67 -1
- data/lib/generators/maquina/tailwind_config/templates/lib/generators/tailwind_config/templates/config/tailwind.config.js.tt +9 -5
- data/lib/generators/maquina/tailwind_config/templates/lib/tasks/tailwind.rake.tt +2 -0
- data/lib/generators/maquina/templates/config/initializers/maquina.rb.tt +2 -1
- data/lib/maquina/engine.rb +6 -3
- data/lib/maquina/version.rb +1 -1
- data/lib/maquina.rb +2 -9
- metadata +20 -76
- data/app/assets/javascripts/maquina/application.js +0 -4
- data/app/assets/javascripts/maquina/controllers/alert_controller.js +0 -29
- data/app/assets/javascripts/maquina/controllers/application.js +0 -9
- data/app/assets/javascripts/maquina/controllers/index.js +0 -11
- data/app/models/concerns/maquina/authenticate_by.rb +0 -33
- data/app/views/maquina/navbar/search.rb +0 -40
- data/lib/generators/maquina/install_templates/install_templates_generator.rb +0 -31
- /data/app/assets/javascripts/{maquina/controllers → controllers}/backdrop_controller.js +0 -0
- /data/app/assets/javascripts/{maquina/controllers → controllers}/file_controller.js +0 -0
- /data/app/assets/javascripts/{maquina/controllers → controllers}/mobile_menu_controller.js +0 -0
- /data/app/assets/javascripts/{maquina/controllers → controllers}/modal_controller.js +0 -0
- /data/app/assets/javascripts/{maquina/controllers → controllers}/modal_open_controller.js +0 -0
- /data/app/assets/javascripts/{maquina/controllers → controllers}/popup_menu_controller.js +0 -0
- /data/app/assets/javascripts/{maquina/controllers → controllers}/submit_form_controller.js +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4b1650769946b608a9ed3993d2aeae3107961d2fdf57400f1db5a6a3b66cd10a
|
4
|
+
data.tar.gz: 8dada0a36f41e6c3d8c23c830c2456ff7eeac792221d8a0a6163bdd645865765
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b573303faa3ffa46a65ed9ac71c7ec8f80a034e49f50ff2fdb6c234289c705472e33118ee5523889fa8216b76db0a8c5034f1dd0b76719631d3b67d94dd0dc12
|
7
|
+
data.tar.gz: 1748332d65ea73bf86e696b6dd3b52b4534dbf9eb9a05ae12c66bd75d2e64387b73ab9f8347d05309053803740924cace533c4fb49e16bd68d7b78ab201f7b00
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.3.
|
1
|
+
3.3.5
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,18 +1,15 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
maquina (0.
|
4
|
+
maquina (0.7.2)
|
5
5
|
action_policy (>= 0.6.0)
|
6
6
|
bcrypt (>= 3.1.7)
|
7
|
-
importmap-rails (>= 2.0.0)
|
8
7
|
money-rails (>= 1.15.0)
|
9
8
|
pagy (>= 6.2)
|
10
9
|
phlex-rails (>= 1.1.0)
|
11
10
|
rails (>= 7.0.4)
|
12
11
|
rotp (>= 6.2.1)
|
13
|
-
stimulus-rails (>= 1.3.0)
|
14
12
|
tailwindcss-rails (>= 2.1.0)
|
15
|
-
turbo-rails (>= 2.0.0)
|
16
13
|
|
17
14
|
GEM
|
18
15
|
remote: https://rubygems.org/
|
@@ -92,10 +89,8 @@ GEM
|
|
92
89
|
addressable (2.8.7)
|
93
90
|
public_suffix (>= 2.0.2, < 7.0)
|
94
91
|
ast (2.4.2)
|
95
|
-
backport (1.2.0)
|
96
92
|
base64 (0.2.0)
|
97
93
|
bcrypt (3.1.20)
|
98
|
-
benchmark (0.3.0)
|
99
94
|
bigdecimal (3.1.8)
|
100
95
|
brakeman (6.2.1)
|
101
96
|
racc
|
@@ -114,9 +109,7 @@ GEM
|
|
114
109
|
debug (1.9.2)
|
115
110
|
irb (~> 1.10)
|
116
111
|
reline (>= 0.3.8)
|
117
|
-
diff-lcs (1.5.1)
|
118
112
|
drb (2.2.1)
|
119
|
-
e2mmap (0.1.0)
|
120
113
|
erubi (1.13.0)
|
121
114
|
globalid (1.2.1)
|
122
115
|
activesupport (>= 6.1)
|
@@ -130,12 +123,7 @@ GEM
|
|
130
123
|
irb (1.14.0)
|
131
124
|
rdoc (>= 4.0.0)
|
132
125
|
reline (>= 0.4.2)
|
133
|
-
jaro_winkler (1.6.0)
|
134
126
|
json (2.7.2)
|
135
|
-
kramdown (2.4.0)
|
136
|
-
rexml
|
137
|
-
kramdown-parser-gfm (1.1.0)
|
138
|
-
kramdown (~> 2.0)
|
139
127
|
language_server-protocol (3.17.0.3)
|
140
128
|
launchy (3.0.1)
|
141
129
|
addressable (~> 2.8)
|
@@ -239,14 +227,11 @@ GEM
|
|
239
227
|
zeitwerk (~> 2.6)
|
240
228
|
rainbow (3.1.1)
|
241
229
|
rake (13.2.1)
|
242
|
-
rbs (2.8.4)
|
243
230
|
rdoc (6.7.0)
|
244
231
|
psych (>= 4.0.0)
|
245
232
|
regexp_parser (2.9.2)
|
246
233
|
reline (0.5.10)
|
247
234
|
io-console (~> 0.5)
|
248
|
-
reverse_markdown (2.1.1)
|
249
|
-
nokogiri
|
250
235
|
rexml (3.3.7)
|
251
236
|
rotp (6.3.0)
|
252
237
|
rubocop (1.65.1)
|
@@ -273,22 +258,6 @@ GEM
|
|
273
258
|
ruby-next-core (1.0.3)
|
274
259
|
ruby-progressbar (1.13.0)
|
275
260
|
securerandom (0.3.1)
|
276
|
-
solargraph (0.50.0)
|
277
|
-
backport (~> 1.2)
|
278
|
-
benchmark
|
279
|
-
bundler (~> 2.0)
|
280
|
-
diff-lcs (~> 1.4)
|
281
|
-
e2mmap
|
282
|
-
jaro_winkler (~> 1.5)
|
283
|
-
kramdown (~> 2.3)
|
284
|
-
kramdown-parser-gfm (~> 1.1)
|
285
|
-
parser (~> 3.0)
|
286
|
-
rbs (~> 2.0)
|
287
|
-
reverse_markdown (~> 2.0)
|
288
|
-
rubocop (~> 1.38)
|
289
|
-
thor (~> 1.0)
|
290
|
-
tilt (~> 2.0)
|
291
|
-
yard (~> 0.9, >= 0.9.24)
|
292
261
|
standard (1.40.0)
|
293
262
|
language_server-protocol (~> 3.17.0.2)
|
294
263
|
lint_roller (~> 1.0)
|
@@ -310,7 +279,6 @@ GEM
|
|
310
279
|
tailwindcss-rails (2.7.3-arm64-darwin)
|
311
280
|
railties (>= 7.0.0)
|
312
281
|
thor (1.3.2)
|
313
|
-
tilt (2.4.0)
|
314
282
|
timeout (0.4.1)
|
315
283
|
turbo-rails (2.0.6)
|
316
284
|
actionpack (>= 6.0.0)
|
@@ -324,7 +292,6 @@ GEM
|
|
324
292
|
websocket-driver (0.7.6)
|
325
293
|
websocket-extensions (>= 0.1.0)
|
326
294
|
websocket-extensions (0.1.5)
|
327
|
-
yard (0.9.37)
|
328
295
|
zeitwerk (2.6.18)
|
329
296
|
|
330
297
|
PLATFORMS
|
@@ -335,6 +302,7 @@ DEPENDENCIES
|
|
335
302
|
brakeman
|
336
303
|
bundle-audit
|
337
304
|
debug (>= 1.0.0)
|
305
|
+
importmap-rails
|
338
306
|
irb
|
339
307
|
letter_opener
|
340
308
|
maquina!
|
@@ -342,9 +310,9 @@ DEPENDENCIES
|
|
342
310
|
pg_search
|
343
311
|
propshaft
|
344
312
|
puma
|
345
|
-
solargraph
|
346
313
|
standard
|
347
314
|
standard-rails
|
315
|
+
stimulus-rails
|
348
316
|
tailwindcss-rails
|
349
317
|
turbo-rails
|
350
318
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus"
|
2
|
+
import { enter, leave } from "el-transition"
|
3
|
+
|
4
|
+
/**
|
5
|
+
* Alert Controller
|
6
|
+
*
|
7
|
+
* Displays Rails flash messages with animation using el-transition.
|
8
|
+
* Auto-dismisses after 10 seconds or manual close.
|
9
|
+
*/
|
10
|
+
export default class extends Controller {
|
11
|
+
static targets = ["alert"];
|
12
|
+
|
13
|
+
connect() {
|
14
|
+
enter(this.alertTarget).then(() => {
|
15
|
+
setTimeout(this.close.bind(this), 10000)
|
16
|
+
})
|
17
|
+
}
|
18
|
+
|
19
|
+
close() {
|
20
|
+
leave(this.alertTarget)
|
21
|
+
}
|
22
|
+
}
|
@@ -1,101 +1,4 @@
|
|
1
|
-
@
|
2
|
-
@
|
3
|
-
@
|
4
|
-
|
5
|
-
/* @layer base { */
|
6
|
-
:root {
|
7
|
-
--color-base: 31 27 54;
|
8
|
-
--color-accented: 37 99 235;
|
9
|
-
--color-inverted: 255 255 255;
|
10
|
-
--color-accented-hover: 59 130 246;
|
11
|
-
--color-muted: 55 65 81;
|
12
|
-
--color-dimmed: 75 85 99;
|
13
|
-
--color-error: 220 38 38;
|
14
|
-
|
15
|
-
--color-border-base: 209 213 219;
|
16
|
-
--color-border-accented: 37 99 235;
|
17
|
-
}
|
18
|
-
|
19
|
-
.label {
|
20
|
-
@apply text-sm font-medium text-skin-muted;
|
21
|
-
}
|
22
|
-
|
23
|
-
.input {
|
24
|
-
@apply appearance-none rounded-md border border-skin-base px-3 py-2 placeholder-gray-400 shadow-sm focus:border-skin-accented focus:outline-none focus:ring-skin-accented sm:text-sm;
|
25
|
-
}
|
26
|
-
|
27
|
-
.link {
|
28
|
-
@apply font-medium text-skin-accented hover:text-skin-accented-hover;
|
29
|
-
}
|
30
|
-
|
31
|
-
.check {
|
32
|
-
@apply border-skin-base h-4 w-4 text-skin-accented focus:ring-skin-accented rounded;
|
33
|
-
}
|
34
|
-
|
35
|
-
.button {
|
36
|
-
@apply inline-flex justify-center py-2 px-4 border border-skin-base rounded-md shadow-sm text-sm font-medium text-skin-muted bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-skin-accented;
|
37
|
-
}
|
38
|
-
|
39
|
-
.control-error .label {
|
40
|
-
@apply text-skin-error;
|
41
|
-
}
|
42
|
-
|
43
|
-
.control-error .input {
|
44
|
-
@apply border-skin-error focus:border-skin-error focus:ring-skin-error;
|
45
|
-
}
|
46
|
-
|
47
|
-
.help {
|
48
|
-
@apply mt-2 text-sm text-skin-dimmed;
|
49
|
-
}
|
50
|
-
|
51
|
-
.help-error {
|
52
|
-
@apply text-skin-error;
|
53
|
-
}
|
54
|
-
|
55
|
-
.button[disabled] {
|
56
|
-
@apply bg-gray-50 text-skin-dimmed cursor-default;
|
57
|
-
}
|
58
|
-
|
59
|
-
.button-accented {
|
60
|
-
@apply rounded-md border border-transparent bg-skin-accented py-2 px-4 text-sm font-medium text-skin-inverted shadow-sm hover:bg-skin-accented-hover focus:outline-none focus:ring-2 focus:ring-skin-accented focus:ring-offset-2;
|
61
|
-
}
|
62
|
-
|
63
|
-
input[type="search"] {
|
64
|
-
@apply block w-full rounded-md border border-skin-base pl-10 leading-5 placeholder-gray-400 focus:placeholder-gray-300 focus:outline-none focus:ring-1 focus:ring-skin-accented focus:border-skin-accented sm:text-sm;
|
65
|
-
}
|
66
|
-
|
67
|
-
.desktop-menu {
|
68
|
-
@apply hidden lg:ml-6 lg:flex lg:space-x-8;
|
69
|
-
}
|
70
|
-
|
71
|
-
.desktop-menu-item {
|
72
|
-
@apply font-sans uppercase border-transparent text-skin-dimmed underline-offset-4 decoration-2 hover:underline hover:decoration-skin-accented hover:text-skin-muted inline-flex items-center px-1 pt-1 text-sm font-medium;
|
73
|
-
}
|
74
|
-
|
75
|
-
.desktop-menu-item__active {
|
76
|
-
@apply decoration-skin-accented underline text-skin-base;
|
77
|
-
}
|
78
|
-
|
79
|
-
.mobile-menu {
|
80
|
-
@apply pt-2 pb-3 space-y-1;
|
81
|
-
}
|
82
|
-
|
83
|
-
.mobile-menu-item {
|
84
|
-
@apply font-sans border-transparent text-skin-dimmed hover:bg-gray-200 hover:border-gray-300 hover:text-skin-muted block pl-3 pr-4 py-2 border-l-4 text-base font-medium;
|
85
|
-
}
|
86
|
-
|
87
|
-
.mobile-menu-item__active {
|
88
|
-
@apply bg-skin-accented-hover border-skin-accented text-skin-accented hover:text-skin-accented hover:bg-skin-accented-hover hover:border-skin-accented;
|
89
|
-
}
|
90
|
-
|
91
|
-
.desktop-profile-menu-item {
|
92
|
-
@apply block w-full text-left font-sans px-4 py-2 text-sm text-skin-dimmed hover:bg-gray-200 hover:text-skin-muted;
|
93
|
-
}
|
94
|
-
|
95
|
-
.mobile-profile-menu-item {
|
96
|
-
@apply block font-sans px-4 py-2 text-base font-medium text-skin-dimmed hover:text-skin-muted hover:bg-gray-200;
|
97
|
-
}
|
98
|
-
|
99
|
-
.mobile-button {
|
100
|
-
@apply inline-flex items-center justify-center p-2 rounded-md text-skin-dimmed hover:text-skin-muted hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-skin-accented;
|
101
|
-
}
|
1
|
+
@import "tailwindcss/base";
|
2
|
+
@import "../maquina.css";
|
3
|
+
@import "tailwindcss/components";
|
4
|
+
@import "tailwindcss/utilities";
|
@@ -0,0 +1,114 @@
|
|
1
|
+
/* Base maquina styles */
|
2
|
+
|
3
|
+
:root {
|
4
|
+
--color-base: 31 27 54;
|
5
|
+
--color-accented: 37 99 235;
|
6
|
+
--color-inverted: 255 255 255;
|
7
|
+
--color-accented-hover: 59 130 246;
|
8
|
+
--color-muted: 55 65 81;
|
9
|
+
--color-dimmed: 75 85 99;
|
10
|
+
--color-error: 220 38 38;
|
11
|
+
|
12
|
+
--color-alternate: 219 90 186;
|
13
|
+
--color-alternate-1: 198 218 191;
|
14
|
+
--color-alternate-2: 23 24 59;
|
15
|
+
|
16
|
+
--color-border-base: 209 213 219;
|
17
|
+
--color-border-accented: 37 99 235;
|
18
|
+
}
|
19
|
+
|
20
|
+
.label {
|
21
|
+
@apply text-sm font-medium text-skin-muted;
|
22
|
+
}
|
23
|
+
|
24
|
+
.input {
|
25
|
+
@apply appearance-none rounded-md border border-skin-base px-3 py-2 placeholder-gray-400 shadow-sm focus:border-skin-accented focus:outline-none focus:ring-skin-accented sm:text-sm;
|
26
|
+
}
|
27
|
+
|
28
|
+
.link {
|
29
|
+
@apply font-medium text-skin-accented hover:text-skin-accented-hover;
|
30
|
+
}
|
31
|
+
|
32
|
+
.check {
|
33
|
+
@apply border-skin-base h-4 w-4 text-skin-accented focus:ring-skin-accented rounded;
|
34
|
+
}
|
35
|
+
|
36
|
+
.button {
|
37
|
+
@apply inline-flex justify-center py-2 px-4 border border-skin-base rounded-md shadow-sm text-sm font-medium text-skin-muted bg-white hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-skin-accented;
|
38
|
+
}
|
39
|
+
|
40
|
+
.select {
|
41
|
+
@apply block w-full rounded-md border-0 py-2 pl-3 pr-10 text-skin-base ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-skin-accented sm:text-sm/6;
|
42
|
+
}
|
43
|
+
|
44
|
+
.control-error .label {
|
45
|
+
@apply text-skin-error;
|
46
|
+
}
|
47
|
+
|
48
|
+
.control-error .input {
|
49
|
+
@apply border-skin-error focus:border-skin-error focus:ring-skin-error;
|
50
|
+
}
|
51
|
+
|
52
|
+
.filter-option {
|
53
|
+
@apply mr-2 flex h-4 w-4 items-center justify-center rounded-sm border border-gray-400 opacity-50 text-white;
|
54
|
+
}
|
55
|
+
|
56
|
+
.filter-option[selected] {
|
57
|
+
@apply bg-skin-accented text-white border-0 opacity-100;
|
58
|
+
}
|
59
|
+
|
60
|
+
.help {
|
61
|
+
@apply mt-2 text-sm text-skin-dimmed;
|
62
|
+
}
|
63
|
+
|
64
|
+
.help-error {
|
65
|
+
@apply text-skin-error;
|
66
|
+
}
|
67
|
+
|
68
|
+
.button[disabled] {
|
69
|
+
@apply bg-gray-50 text-skin-dimmed cursor-default;
|
70
|
+
}
|
71
|
+
|
72
|
+
.button-accented {
|
73
|
+
@apply rounded-md border border-transparent bg-skin-accented py-2 px-4 text-sm font-medium text-skin-inverted shadow-sm hover:bg-skin-accented-hover focus:outline-none focus:ring-2 focus:ring-skin-accented focus:ring-offset-2;
|
74
|
+
}
|
75
|
+
|
76
|
+
input[type="search"] {
|
77
|
+
@apply block w-full rounded-md border border-skin-base pl-10 leading-5 placeholder-gray-400 focus:placeholder-gray-300 focus:outline-none focus:ring-1 focus:ring-skin-accented focus:border-skin-accented sm:text-sm;
|
78
|
+
}
|
79
|
+
|
80
|
+
.desktop-menu {
|
81
|
+
@apply hidden lg:ml-6 lg:flex lg:space-x-8;
|
82
|
+
}
|
83
|
+
|
84
|
+
.desktop-menu-item {
|
85
|
+
@apply font-sans uppercase border-transparent text-skin-dimmed underline-offset-4 decoration-2 hover:underline hover:decoration-skin-accented hover:text-skin-muted inline-flex items-center px-1 pt-1 text-sm font-medium;
|
86
|
+
}
|
87
|
+
|
88
|
+
.desktop-menu-item__active {
|
89
|
+
@apply decoration-skin-accented underline text-skin-base;
|
90
|
+
}
|
91
|
+
|
92
|
+
.mobile-menu {
|
93
|
+
@apply pt-2 pb-3 space-y-1;
|
94
|
+
}
|
95
|
+
|
96
|
+
.mobile-menu-item {
|
97
|
+
@apply font-sans border-transparent text-skin-dimmed hover:bg-gray-200 hover:border-gray-300 hover:text-skin-muted block pl-3 pr-4 py-2 border-l-4 text-base font-medium;
|
98
|
+
}
|
99
|
+
|
100
|
+
.mobile-menu-item__active {
|
101
|
+
@apply bg-skin-accented-hover border-skin-accented text-skin-accented hover:text-skin-accented hover:bg-skin-accented-hover hover:border-skin-accented;
|
102
|
+
}
|
103
|
+
|
104
|
+
.desktop-profile-menu-item {
|
105
|
+
@apply block w-full text-left font-sans px-4 py-2 text-sm text-skin-dimmed hover:bg-gray-200 hover:text-skin-muted;
|
106
|
+
}
|
107
|
+
|
108
|
+
.mobile-profile-menu-item {
|
109
|
+
@apply block font-sans px-4 py-2 text-base font-medium text-skin-dimmed hover:text-skin-muted hover:bg-gray-200;
|
110
|
+
}
|
111
|
+
|
112
|
+
.mobile-button {
|
113
|
+
@apply inline-flex items-center justify-center p-2 rounded-md text-skin-dimmed hover:text-skin-muted hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-skin-accented;
|
114
|
+
}
|
@@ -1,6 +1,17 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Maquina
|
4
|
+
##
|
5
|
+
# A Rails controller concern that handles user authentication.
|
6
|
+
# Provides methods for checking authentication status, managing sessions,
|
7
|
+
# and controlling access to actions.
|
8
|
+
#
|
9
|
+
# == Usage
|
10
|
+
#
|
11
|
+
# class ApplicationController < ActionController::Base
|
12
|
+
# include Maquina::Authenticate
|
13
|
+
# end
|
14
|
+
#
|
4
15
|
module Authenticate
|
5
16
|
extend ActiveSupport::Concern
|
6
17
|
|
@@ -10,24 +21,41 @@ module Maquina
|
|
10
21
|
end
|
11
22
|
|
12
23
|
class_methods do
|
24
|
+
##
|
25
|
+
# Skips authentication requirement for specified actions
|
13
26
|
def allow_unauthenticated_access(...)
|
14
27
|
skip_before_action(:require_authentication, ...)
|
15
28
|
end
|
16
29
|
end
|
17
30
|
|
31
|
+
##
|
32
|
+
# Returns whether there is a signed in user
|
33
|
+
#
|
34
|
+
# authenticated? # => true
|
18
35
|
def authenticated?
|
19
36
|
Maquina::Current.signed_in?
|
20
37
|
end
|
21
38
|
alias_method :signed_in?, :authenticated?
|
22
39
|
|
40
|
+
##
|
41
|
+
# Returns the currently signed in user or nil
|
42
|
+
#
|
43
|
+
# current_user # => #<User id: 1, email: "user@example.com">
|
23
44
|
def current_user
|
24
45
|
Maquina::Current.user
|
25
46
|
end
|
26
47
|
|
48
|
+
##
|
49
|
+
# Returns the URL to redirect to after successful authentication
|
50
|
+
#
|
51
|
+
# after_authentication_url # => "http://example.com/dashboard"
|
27
52
|
def after_authentication_url
|
28
53
|
session.delete(:return_to_after_authenticating) || root_url
|
29
54
|
end
|
30
55
|
|
56
|
+
##
|
57
|
+
# Ensures user is authenticated before proceeding.
|
58
|
+
# Redirects to login if no valid session exists.
|
31
59
|
def require_authentication
|
32
60
|
load_session || request_authentication
|
33
61
|
end
|
@@ -57,7 +85,7 @@ module Maquina
|
|
57
85
|
)
|
58
86
|
.find_by(id: active_session_id)
|
59
87
|
|
60
|
-
return if active_session.blank?
|
88
|
+
return if active_session.blank? || active_session.expired?
|
61
89
|
|
62
90
|
Maquina::Current.active_session = active_session
|
63
91
|
end
|
@@ -1,6 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Maquina
|
4
|
+
##
|
5
|
+
# The Index concern provides standardized index action functionality for Rails controllers.
|
6
|
+
# It includes pagination, authorization, searching, and sorting capabilities.
|
7
|
+
#
|
8
|
+
# === Features
|
9
|
+
# * Automatic pagination using Pagy
|
10
|
+
# * Policy-based authorization support
|
11
|
+
# * Full-text search integration (when model supports it)
|
12
|
+
# * Default sorting by updated_at
|
13
|
+
# * HTML and JSON response formats
|
14
|
+
# * Customizable scope through block parameter
|
15
|
+
#
|
16
|
+
# === Dependencies
|
17
|
+
# * {Pagy::Backend}[https://ddnexus.github.io/pagy/api/backend]
|
18
|
+
# * Policy class (optional)
|
19
|
+
# * Model must respond to +full_search+ if searching is used
|
20
|
+
#
|
21
|
+
# === Usage
|
22
|
+
# class UsersController < ApplicationController
|
23
|
+
# include Maquina::Index
|
24
|
+
#
|
25
|
+
# def index
|
26
|
+
# index! do |scope|
|
27
|
+
# scope.includes(:organization)
|
28
|
+
# end
|
29
|
+
# end
|
30
|
+
# end
|
31
|
+
#
|
4
32
|
module Index
|
5
33
|
extend ActiveSupport::Concern
|
6
34
|
include Pagy::Backend
|
@@ -10,11 +38,13 @@ module Maquina
|
|
10
38
|
authorize! with: policy_class if policy_class.present?
|
11
39
|
|
12
40
|
@collection ||= begin
|
13
|
-
scope = resource_class
|
41
|
+
scope = order_by(resource_class)
|
14
42
|
scope = authorized_scope(scope) if policy_class.present?
|
15
43
|
|
16
44
|
search_value = params[:q]&.strip
|
17
|
-
scope = scope.
|
45
|
+
scope = scope.full_search(search_value) if search_value.present? && resource_class.searchable?
|
46
|
+
|
47
|
+
scope = filter_by(scope) if filters.any?
|
18
48
|
|
19
49
|
scope = yield(scope) if block.present?
|
20
50
|
|
@@ -29,5 +59,54 @@ module Maquina
|
|
29
59
|
end
|
30
60
|
alias_method :index!, :index
|
31
61
|
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
##
|
66
|
+
# Applies query parameters as filters to the given scope
|
67
|
+
#
|
68
|
+
# scope:: The base ActiveRecord::Relation to filter
|
69
|
+
# Returns:: The filtered ActiveRecord::Relation
|
70
|
+
#
|
71
|
+
def filter_by(scope)
|
72
|
+
filters.each_pair do |field, options|
|
73
|
+
if params[field].present?
|
74
|
+
scope = scope.where(field => params[field])
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
scope
|
79
|
+
end
|
80
|
+
|
81
|
+
##
|
82
|
+
# Orders records based on order and direction parameters
|
83
|
+
#
|
84
|
+
# Returns scope ordered by updated_at desc if:
|
85
|
+
# * order parameter is blank
|
86
|
+
# * order attribute is not in sortable list
|
87
|
+
# * direction is not asc/desc
|
88
|
+
#
|
89
|
+
# scope:: The base ActiveRecord::Relation to order
|
90
|
+
# Returns:: The ordered ActiveRecord::Relation
|
91
|
+
#
|
92
|
+
def order_by(scope)
|
93
|
+
direction = ["asc", "desc"].include?(params[:dir]) ? params[:dir] : nil
|
94
|
+
attribute = params[:order]&.to_sym
|
95
|
+
|
96
|
+
return scope.order(updated_at: :desc) if attribute.blank? || !sortable.include?(attribute) || direction.blank?
|
97
|
+
|
98
|
+
attribute, direction = before_order_by(attribute, direction)
|
99
|
+
scope.order(attribute => direction)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Hook method called before applying sort order. Override in controller to customize ordering behavior.
|
103
|
+
#
|
104
|
+
# attribute:: The Symbol attribute to sort by
|
105
|
+
# direction:: The String sort direction ("asc" or "desc")
|
106
|
+
# Returns:: Array containing the modified attribute and direction
|
107
|
+
#
|
108
|
+
def before_order_by(attribute, direction)
|
109
|
+
[attribute, direction]
|
110
|
+
end
|
32
111
|
end
|
33
112
|
end
|