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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.ruby-version +1 -1
  3. data/Gemfile +2 -0
  4. data/Gemfile.lock +3 -35
  5. data/app/assets/javascripts/controllers/alert_controller.js +22 -0
  6. data/app/assets/stylesheets/maquina/application.tailwind.css +4 -101
  7. data/app/assets/stylesheets/maquina.css +114 -0
  8. data/app/controllers/concerns/maquina/authenticate.rb +29 -1
  9. data/app/controllers/concerns/maquina/index.rb +81 -2
  10. data/app/controllers/concerns/maquina/resourceful.rb +95 -9
  11. data/app/controllers/maquina/application_controller.rb +1 -1
  12. data/app/controllers/maquina/dashboard_controller.rb +10 -5
  13. data/app/controllers/maquina/invitations_controller.rb +0 -2
  14. data/app/controllers/maquina/plans_controller.rb +13 -23
  15. data/app/controllers/maquina/sessions_controller.rb +1 -1
  16. data/app/controllers/maquina/users_controller.rb +0 -2
  17. data/app/helpers/maquina/application_helper.rb +0 -8
  18. data/app/helpers/maquina/navbar_menu_helper.rb +1 -1
  19. data/app/models/concerns/maquina/blockeable.rb +64 -0
  20. data/app/models/concerns/maquina/organization_scoped.rb +26 -0
  21. data/app/models/concerns/maquina/retain_passwords.rb +44 -0
  22. data/app/models/concerns/maquina/sqlite_search.rb +92 -0
  23. data/app/models/concerns/maquina/user_scoped.rb +26 -0
  24. data/app/models/maquina/active_session.rb +40 -0
  25. data/app/models/maquina/current.rb +39 -2
  26. data/app/models/maquina/invitation.rb +28 -0
  27. data/app/models/maquina/membership.rb +23 -1
  28. data/app/models/maquina/organization.rb +19 -2
  29. data/app/models/maquina/plan.rb +26 -6
  30. data/app/models/maquina/used_password.rb +30 -0
  31. data/app/models/maquina/user.rb +50 -8
  32. data/app/policies/maquina/application_policy.rb +1 -1
  33. data/app/policies/maquina/dashboard_policy.rb +7 -0
  34. data/app/policies/maquina/navigation_policy.rb +2 -0
  35. data/app/views/layouts/maquina/application.html.erb +2 -2
  36. data/app/views/layouts/maquina/sessions.html.erb +1 -1
  37. data/app/views/maquina/application/_navbar.html.erb +8 -3
  38. data/app/views/maquina/application/components/checkbox_component.rb +3 -3
  39. data/app/views/maquina/application/components/component_base.rb +3 -2
  40. data/app/views/maquina/application/edit.html.erb +10 -7
  41. data/app/views/maquina/application/filters.rb +118 -0
  42. data/app/views/maquina/application/index.html.erb +6 -3
  43. data/app/views/maquina/application/index_header.rb +5 -2
  44. data/app/views/maquina/application/index_table.rb +71 -6
  45. data/app/views/maquina/application/index_tools.rb +17 -0
  46. data/app/views/maquina/application/new.html.erb +10 -7
  47. data/app/views/maquina/application/search.rb +42 -0
  48. data/app/views/maquina/application/sessions_header.rb +3 -9
  49. data/app/views/maquina/dashboard/index.html.erb +4 -0
  50. data/app/views/maquina/dashboard/stats.rb +35 -0
  51. data/app/views/maquina/dashboard/tasks.rb +124 -0
  52. data/app/views/maquina/first_runs/form.rb +0 -2
  53. data/app/views/maquina/first_runs/show.html.erb +4 -1
  54. data/app/views/maquina/navbar/title.rb +4 -2
  55. data/config/importmap.rb +1 -13
  56. data/config/locales/flash.en.yml +6 -0
  57. data/config/locales/flash.es.yml +6 -0
  58. data/config/locales/forms.en.yml +33 -4
  59. data/config/locales/forms.es.yml +22 -11
  60. data/config/locales/models.en.yml +10 -0
  61. data/config/locales/models.es.yml +10 -0
  62. data/config/locales/views.en.yml +33 -5
  63. data/config/locales/views.es.yml +28 -10
  64. data/config/routes.rb +1 -0
  65. data/db/migrate/20221109010726_create_maquina_plans.rb +1 -1
  66. data/db/migrate/20221113000409_create_maquina_users.rb +1 -1
  67. data/db/migrate/20221113020108_create_maquina_used_passwords.rb +1 -1
  68. data/db/migrate/20221115223414_create_maquina_active_sessions.rb +1 -3
  69. data/db/migrate/20230201203922_create_maquina_invitations.rb +1 -1
  70. data/db/migrate/20230829183530_create_maquina_organizations.rb +1 -1
  71. data/db/migrate/20230829192656_create_maquina_memberships.rb +2 -4
  72. data/db/migrate/20241109191405_add_counter_cache_to_plans.rb +5 -0
  73. data/lib/generators/maquina/install_generator.rb +67 -1
  74. data/lib/generators/maquina/tailwind_config/templates/lib/generators/tailwind_config/templates/config/tailwind.config.js.tt +9 -5
  75. data/lib/generators/maquina/tailwind_config/templates/lib/tasks/tailwind.rake.tt +2 -0
  76. data/lib/generators/maquina/templates/config/initializers/maquina.rb.tt +2 -1
  77. data/lib/maquina/engine.rb +6 -3
  78. data/lib/maquina/version.rb +1 -1
  79. data/lib/maquina.rb +2 -9
  80. metadata +20 -76
  81. data/app/assets/javascripts/maquina/application.js +0 -4
  82. data/app/assets/javascripts/maquina/controllers/alert_controller.js +0 -29
  83. data/app/assets/javascripts/maquina/controllers/application.js +0 -9
  84. data/app/assets/javascripts/maquina/controllers/index.js +0 -11
  85. data/app/models/concerns/maquina/authenticate_by.rb +0 -33
  86. data/app/views/maquina/navbar/search.rb +0 -40
  87. data/lib/generators/maquina/install_templates/install_templates_generator.rb +0 -31
  88. /data/app/assets/javascripts/{maquina/controllers → controllers}/backdrop_controller.js +0 -0
  89. /data/app/assets/javascripts/{maquina/controllers → controllers}/file_controller.js +0 -0
  90. /data/app/assets/javascripts/{maquina/controllers → controllers}/mobile_menu_controller.js +0 -0
  91. /data/app/assets/javascripts/{maquina/controllers → controllers}/modal_controller.js +0 -0
  92. /data/app/assets/javascripts/{maquina/controllers → controllers}/modal_open_controller.js +0 -0
  93. /data/app/assets/javascripts/{maquina/controllers → controllers}/popup_menu_controller.js +0 -0
  94. /data/app/assets/javascripts/{maquina/controllers → controllers}/submit_form_controller.js +0 -0
@@ -1,10 +1,13 @@
1
1
  <div class="px-4 sm:px-6 lg:px-8">
2
2
  <%= render Maquina::Application::IndexHeader.new(params[:q]) %>
3
3
 
4
+ <%= render Maquina::Application::IndexTools.new %>
5
+
4
6
  <%= render Maquina::Application::IndexTable.new(
5
- collection: collection,
6
- pagination: @pagination,
7
- list_attributes: list_attributes) %>
7
+ collection: collection,
8
+ pagination: @pagination,
9
+ list_attributes: list_attributes,
10
+ ) %>
8
11
  </div>
9
12
 
10
13
  <%= render Maquina::Application::IndexModal.new %>
@@ -13,9 +13,8 @@ module Maquina
13
13
  def view_template
14
14
  div(class: "sm:flex sm:items-center") do
15
15
  div(class: "sm:flex-auto") do
16
- h1(class: "text-xl font-semibold text-skin-base") { model_human_name(plural: true) }
16
+ h1(class: "text-xl font-semibold text-skin-base") { model_title }
17
17
  p(class: "mt-2 text-sm text-skin-muted") { description }
18
- p(class: "mt-4 text-skin-base") { unsafe_raw t("index.search", search: @filter) } if @filter.present?
19
18
  end
20
19
  add_new_template
21
20
  end
@@ -23,6 +22,10 @@ module Maquina
23
22
 
24
23
  private
25
24
 
25
+ def model_title
26
+ t("index.#{resource_class.model_name.i18n_key}.title", model: model_human_name(plural: true).downcase, default: model_human_name(plural: true))
27
+ end
28
+
26
29
  def add_new_template
27
30
  return if policy_class.blank? || !allowed_to?(:new?, with: policy_class)
28
31
 
@@ -4,8 +4,10 @@ module Maquina
4
4
  module Application
5
5
  class IndexTable < Phlex::HTML
6
6
  include ApplicationView
7
+ include Phlex::Rails::Helpers::LinkTo
7
8
 
8
- delegate :humanized_money_with_symbol, :edit_resource_path, :resource_path, to: :helpers
9
+ delegate :humanized_money_with_symbol, :edit_resource_path, :resource_path, :collection_path, :params, :sortable,
10
+ to: :helpers
9
11
 
10
12
  def initialize(collection: nil, pagination: nil, list_attributes: nil)
11
13
  @collection = collection
@@ -39,8 +41,8 @@ module Maquina
39
41
  end
40
42
 
41
43
  def table_headers_template
42
- base_css = "px-3 py-3.5 text-left text-sm font-semibold text-skin-base"
43
- first_css = "py-3.5 pl-4 pr-3 text-left text-sm font-semibold text-skin-base sm:pl-6"
44
+ base_css = "px-1 py-3 text-left text-sm font-medium text-skin-base"
45
+ first_css = "py-1 py-3 text-left text-sm font-medium text-skin-base sm:pl-6"
44
46
 
45
47
  @list_attributes.each_with_index do |attribute, index|
46
48
  current_css = if index == 0
@@ -49,7 +51,21 @@ module Maquina
49
51
  base_css
50
52
  end
51
53
 
52
- th(scope: :col, class: current_css) { attribute_human_name(attribute) }
54
+ th(scope: :col, class: current_css) do
55
+ if sortable.include?(attribute)
56
+ link_to(collection_path(sort_link_params(attribute)), class: "inline-flex items-center justify-center gap-2 whitespace-nowrap hover:bg-gray-100 hover:cursor-pointer p-2 rounded-sm") do
57
+ span { attribute_human_name(attribute) }
58
+ unsafe_raw case sort_status(attribute)
59
+ when :asc then asc_sort_icon
60
+ when :desc then desc_sort_icon
61
+ else
62
+ no_sort_icon
63
+ end
64
+ end
65
+ else
66
+ span { attribute_human_name(attribute) }
67
+ end
68
+ end
53
69
  end
54
70
  end
55
71
 
@@ -58,7 +74,7 @@ module Maquina
58
74
 
59
75
  tr do
60
76
  th(scope: "col", colspan: col_span, class: "whitespace-nowrap px-3 py-4 text-sm text-skin-dimmed") do
61
- t("index.no_items", model: model_human_name(plural: true))
77
+ t("index.no_items", model: model_human_name(plural: true).downcase)
62
78
  end
63
79
  end
64
80
  end
@@ -67,7 +83,7 @@ module Maquina
67
83
  base_css = "whitespace-nowrap px-3 py-4 text-sm text-skin-muted"
68
84
  first_css = "whitespace-nowrap py-4 pl-4 pr-3 text-sm font-medium text-skin-base sm:pl-6"
69
85
 
70
- tr do
86
+ tr(class: "hover:bg-gray-50") do
71
87
  @list_attributes.each_with_index do |attribute, index|
72
88
  td(class: (index == 0) ? first_css : base_css, scope: "col") { attribute_to_link(item, attribute, attribute_value(item, attribute)) }
73
89
  end
@@ -122,6 +138,55 @@ module Maquina
122
138
 
123
139
  link_to(value, resource_path(item), class: "link", data: {"turbo-frame": "_top"})
124
140
  end
141
+
142
+ def sort_link_params(attribute)
143
+ current_params = params.dup.to_unsafe_h.except(:controller, :action)
144
+ current_order = current_params[:order]
145
+ current_dir = current_params[:dir]
146
+
147
+ if current_order != attribute.to_s
148
+ current_params[:order] = attribute
149
+ current_params[:dir] = :desc
150
+ elsif current_dir == "desc"
151
+ current_params[:dir] = :asc
152
+ elsif current_dir == "asc"
153
+ current_params.except!(:order, :dir)
154
+ else
155
+ current_params[:order] = attribute
156
+ current_params[:dir] = :desc
157
+ end
158
+
159
+ current_params
160
+ end
161
+
162
+ def sort_status(attribute)
163
+ return nil unless params[:order] == attribute.to_s
164
+ (params[:dir] == "asc") ? :asc : :desc
165
+ end
166
+
167
+ def no_sort_icon
168
+ <<~SVG
169
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-auto text-skin-dimmed">
170
+ <path d="m7 15 5 5 5-5"></path><path d="m7 9 5-5 5 5"></path>
171
+ </svg>
172
+ SVG
173
+ end
174
+
175
+ def desc_sort_icon
176
+ <<~SVG
177
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-auto text-skin-dimmed">
178
+ <path d="M12 5v14"></path><path d="m19 12-7 7-7-7"></path>
179
+ </svg>
180
+ SVG
181
+ end
182
+
183
+ def asc_sort_icon
184
+ <<~SVG
185
+ <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="h-4 w-auto text-skin-dimmed">
186
+ <path d="m5 12 7-7 7 7"></path><path d="M12 19V5"></path>
187
+ </svg>
188
+ SVG
189
+ end
125
190
  end
126
191
  end
127
192
  end
@@ -0,0 +1,17 @@
1
+ module Maquina
2
+ module Application
3
+ class IndexTools < Phlex::HTML
4
+ include ApplicationView
5
+ delegate :resource_class, :filters, to: :helpers
6
+
7
+ def view_template
8
+ div(class: "flex items-center justify-between mt-8") do
9
+ div(class: "flex flex-1 items-center space-x-2") do
10
+ render Maquina::Application::Search.new if resource_class.searchable?
11
+ render Maquina::Application::Filters.new if filters.any?
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,9 +1,12 @@
1
- <div class="bg-white">
2
- <div class="mx-auto max-w-7xl py-12 px-4 sm:px-6 lg:px-8">
3
- <div class="mx-auto max-w-3xl">
4
- <%= turbo_frame_tag class_to_form_frame(resource_class) do %>
5
- <%= render Maquina::Application::New.new(resource: resource) %>
6
- <% end %>
7
- </div>
1
+ <div
2
+ class="
3
+ bg-white mx-auto max-w-4xl py-12 px-4 sm:px-6 lg:px-8 border border-gray-200
4
+ rounded-lg shadow-sm
5
+ "
6
+ >
7
+ <div class="mx-auto max-w-3xl">
8
+ <%= turbo_frame_tag class_to_form_frame(resource_class) do %>
9
+ <%= render Maquina::Application::New.new(resource: resource) %>
10
+ <% end %>
8
11
  </div>
9
12
  </div>
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Maquina
4
+ module Application
5
+ class Search < Phlex::HTML
6
+ include ApplicationView
7
+ include Phlex::Rails::Helpers::FormWith
8
+
9
+ delegate :t, :request, :collection_path, :params, to: :helpers
10
+
11
+ def view_template
12
+ current_params = request.params.except(:q, :page, :controller, :action)
13
+ current_params.reject! { |key, value| value.blank? }
14
+ query = params[:q]
15
+
16
+ form_with(url: @url, method: :get, data: {controller: "submit-form"}, class: "pr-3") do |form|
17
+ current_params.each do |key, value|
18
+ form.hidden_field key, value: value
19
+ end
20
+ form.label :search, t("search.search"), class: "sr-only"
21
+
22
+ div class: "relative" do
23
+ div class: "absolute inset-y-0 left-0 pl-3 flex items-center pointer-events-none" do
24
+ unsafe_raw search_icon
25
+ end
26
+ form.text_field :q, value: query, placeholder: t("search.search"), class: "block w-full font-sans", maxlength: 15, type: :search, data: {action: "input->submit-form#clear"}
27
+ end
28
+ end
29
+ end
30
+
31
+ private
32
+
33
+ def search_icon
34
+ <<~SVG
35
+ <svg class="h-5 w-5 text-skin-dimmed" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20" aria-hidden="true">
36
+ <path d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"></path>
37
+ </svg>
38
+ SVG
39
+ end
40
+ end
41
+ end
42
+ end
@@ -7,7 +7,7 @@ module Maquina
7
7
  include Phlex::DeferredRender
8
8
  include Phlex::Rails::Helpers::Translate
9
9
 
10
- def initialize(brand_icon:, translation_key: "maquina.application.sessions_header")
10
+ def initialize(brand_icon:, translation_key: "maquina.sessions.new")
11
11
  @brand_icon = brand_icon
12
12
  @translation_key = translation_key
13
13
  end
@@ -17,17 +17,11 @@ module Maquina
17
17
  image_tag(@brand_icon, class: "mx-auto h-12 w-auto", alt: t("application_name"))
18
18
  h2(class: "mt-6 text-center text-3xl font-bold tracking-tight text-skin-base") { t("#{@translation_key}.title") }
19
19
 
20
- if @description.present?
21
- p(class: "mt-2 text-center text-sm text-skin-dimmed") do
22
- yield_content(&@description)
23
- end
20
+ p(class: "mt-2 text-center text-sm text-skin-dimmed") do
21
+ t("#{@translation_key}.subtitle", default: "")
24
22
  end
25
23
  end
26
24
  end
27
-
28
- def description(&block)
29
- @description = block
30
- end
31
25
  end
32
26
  end
33
27
  end
@@ -0,0 +1,4 @@
1
+ <% if allowed_to? :management_stats?, with: policy_class %>
2
+ <%= render Maquina::Dashboard::Stats.new(stats: @stats) %>
3
+ <%= render Maquina::Dashboard::Tasks.new %>
4
+ <% end %>
@@ -0,0 +1,35 @@
1
+ module Maquina
2
+ module Dashboard
3
+ class Stats < Phlex::HTML
4
+ include Phlex::Rails::Helpers::Translate
5
+
6
+ def initialize(stats:)
7
+ @stats = stats
8
+ end
9
+
10
+ def view_template
11
+ div(class: "mx-auto max-w-lg") do
12
+ h3(class: "text-base font-semibold text-skin-base") { t("maquina.dashboard.index.stats.title") }
13
+
14
+ dl(class: "mt-5 grid grid-cols-2 gap-5 sm:grid-cols-#{@stats.length}") do
15
+ @stats.each do |stat|
16
+ stats_card(
17
+ label: stat[:label],
18
+ value: stat[:value]
19
+ )
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def stats_card(label:, value:)
28
+ div(class: "overflow-hidden rounded-lg bg-white px-4 py-5 shadow sm:p-6") do
29
+ dt(class: "truncate text-sm font-medium text-skin-dimmed") { label }
30
+ dd(class: "mt-1 text-3xl font-semibold tracking-tight text-skin-base") { value }
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,124 @@
1
+ module Maquina
2
+ module Dashboard
3
+ class Tasks < Phlex::HTML
4
+ include Maquina::ApplicationView
5
+
6
+ def initialize(translation_key: "maquina.dashboard.index.tasks")
7
+ @translation_key = translation_key
8
+ end
9
+
10
+ def view_template
11
+ div(class: "mx-auto max-w-lg mt-12") do
12
+ h2(class: "text-base font-semibold text-skin-base") do
13
+ t("#{@translation_key}.title")
14
+ end
15
+
16
+ p(class: "mt-1 text-sm text-skin-dimmed") do
17
+ t("#{@translation_key}.subtitle")
18
+ end
19
+
20
+ ul(
21
+ role: "list",
22
+ class: "mt-6 divide-y divide-gray-200 border-b border-t border-gray-200"
23
+ ) do
24
+ # Create Plan Task
25
+ task_item(
26
+ title: t("#{@translation_key}.create_plan.title"),
27
+ description: t("#{@translation_key}.create_plan.description"),
28
+ color: "bg-skin-accented",
29
+ path: plans_path,
30
+ icon: create_plan_icon
31
+ )
32
+
33
+ # Manage Users Task
34
+ task_item(
35
+ title: t("#{@translation_key}.manage_users.title"),
36
+ description: t("#{@translation_key}.manage_users.description"),
37
+ color: "bg-skin-alternate",
38
+ path: users_path,
39
+ icon: manage_users_icon
40
+ )
41
+
42
+ # Organization Settings Task
43
+ task_item(
44
+ title: t("#{@translation_key}.organization_settings.title"),
45
+ description: t("#{@translation_key}.organization_settings.description"),
46
+ color: "bg-skin-alternate-2",
47
+ path: "#",
48
+ icon: organization_settings_icon
49
+ )
50
+ end
51
+
52
+ # TODO: Uncomment or remove this code later
53
+ # div(class: "mt-6 flex") do
54
+ # a(href: "#", class: "text-sm font-medium text-indigo-600 hover:text-indigo-500") do
55
+ # t("#{@translation_key}.view_all")
56
+ # span(aria_hidden: "true") { " →" }
57
+ # end
58
+ # end
59
+ end
60
+ end
61
+
62
+ private
63
+
64
+ def task_item(title:, description:, color:, path:, icon:)
65
+ li do
66
+ div(class: "group relative flex items-start space-x-3 py-4 hover:bg-white/75") do
67
+ div(class: "shrink-0") do
68
+ span(class: "inline-flex h-10 w-10 items-center justify-center rounded-lg #{color}") do
69
+ unsafe_raw icon
70
+ end
71
+ end
72
+
73
+ div(class: "min-w-0 flex-1") do
74
+ div(class: "text-sm font-medium text-skin-base") do
75
+ a(href: path) do
76
+ span(class: "absolute inset-0", aria_hidden: "true")
77
+ span { title }
78
+ end
79
+ end
80
+ p(class: "text-sm text-skin-dimmed") { description }
81
+ end
82
+
83
+ div(class: "shrink-0 self-center") do
84
+ unsafe_raw chevron_icon
85
+ end
86
+ end
87
+ end
88
+ end
89
+
90
+ def create_plan_icon
91
+ <<~SVG
92
+ <svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor" class="size-6 text-white">
93
+ <path stroke-linecap="round" stroke-linejoin="round" d="M13.5 16.875h3.375m0 0h3.375m-3.375 0V13.5m0 3.375v3.375M6 10.5h2.25a2.25 2.25 0 0 0 2.25-2.25V6a2.25 2.25 0 0 0-2.25-2.25H6A2.25 2.25 0 0 0 3.75 6v2.25A2.25 2.25 0 0 0 6 10.5Zm0 9.75h2.25A2.25 2.25 0 0 0 10.5 18v-2.25a2.25 2.25 0 0 0-2.25-2.25H6a2.25 2.25 0 0 0-2.25 2.25V18A2.25 2.25 0 0 0 6 20.25Zm9.75-9.75H18a2.25 2.25 0 0 0 2.25-2.25V6A2.25 2.25 0 0 0 18 3.75h-2.25A2.25 2.25 0 0 0 13.5 6v2.25a2.25 2.25 0 0 0 2.25 2.25Z" />
94
+ </svg>
95
+ SVG
96
+ end
97
+
98
+ def manage_users_icon
99
+ <<~SVG
100
+ <svg class="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
101
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15 19.128a9.38 9.38 0 002.625.372 9.337 9.337 0 004.121-.952 4.125 4.125 0 00-7.533-2.493M15 19.128v-.003c0-1.113-.285-2.16-.786-3.07M15 19.128v.106A12.318 12.318 0 018.624 21c-2.331 0-4.512-.645-6.374-1.766l-.001-.109a6.375 6.375 0 0111.964-3.07M12 6.375a3.375 3.375 0 11-6.75 0 3.375 3.375 0 016.75 0zm8.25 2.25a2.625 2.625 0 11-5.25 0 2.625 2.625 0 015.25 0z" />
102
+ </svg>
103
+ SVG
104
+ end
105
+
106
+ def organization_settings_icon
107
+ <<~SVG
108
+ <svg class="h-6 w-6 text-white" fill="none" viewBox="0 0 24 24" stroke-width="1.5" stroke="currentColor">
109
+ <path stroke-linecap="round" stroke-linejoin="round" d="M9.594 3.94c.09-.542.56-.94 1.11-.94h2.593c.55 0 1.02.398 1.11.94l.213 1.281c.063.374.313.686.645.87.074.04.147.083.22.127.324.196.72.257 1.075.124l1.217-.456a1.125 1.125 0 011.37.49l1.296 2.247a1.125 1.125 0 01-.26 1.431l-1.003.827c-.293.24-.438.613-.431.992a6.759 6.759 0 010 .255c-.007.378.138.75.43.99l1.005.828c.424.35.534.954.26 1.43l-1.298 2.247a1.125 1.125 0 01-1.369.491l-1.217-.456c-.355-.133-.75-.072-1.076.124a6.57 6.57 0 01-.22.128c-.331.183-.581.495-.644.869l-.213 1.28c-.09.543-.56.941-1.11.941h-2.594c-.55 0-1.02-.398-1.11-.94l-.213-1.281c-.062-.374-.312-.686-.644-.87a6.52 6.52 0 01-.22-.127c-.325-.196-.72-.257-1.076-.124l-1.217.456a1.125 1.125 0 01-1.369-.49l-1.297-2.247a1.125 1.125 0 01.26-1.431l1.004-.827c.292-.24.437-.613.43-.992a6.932 6.932 0 010-.255c.007-.378-.138-.75-.43-.99l-1.004-.828a1.125 1.125 0 01-.26-1.43l1.297-2.247a1.125 1.125 0 011.37-.491l1.216.456c.356.133.751.072 1.076-.124.072-.044.146-.087.22-.128.332-.183.582-.495.644-.869l.214-1.281z" />
110
+ <path stroke-linecap="round" stroke-linejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
111
+ </svg>
112
+ SVG
113
+ end
114
+
115
+ def chevron_icon
116
+ <<~SVG
117
+ <svg class="h-5 w-5 text-gray-400 group-hover:text-skin-dimmed" viewBox="0 0 20 20" fill="currentColor">
118
+ <path fill-rule="evenodd" d="M8.22 5.22a.75.75 0 0 1 1.06 0l4.25 4.25a.75.75 0 0 1 0 1.06l-4.25 4.25a.75.75 0 0 1-1.06-1.06L11.94 10 8.22 6.28a.75.75 0 0 1 0-1.06Z" clip-rule="evenodd" />
119
+ </svg>
120
+ SVG
121
+ end
122
+ end
123
+ end
124
+ end
@@ -6,13 +6,11 @@ module Maquina
6
6
 
7
7
  def initialize(resource)
8
8
  @resource = resource
9
- @scope = "first_runs"
10
9
  end
11
10
 
12
11
  def view_template
13
12
  div(class: "mt-8 sm:mx-auto sm:w-full sm:max-w-md") do
14
13
  div(class: "bg-white py-8 px-4 shadow sm:rounded-lg sm:px-10") do
15
- p(class: "text-center text-skin-muted") { t("maquina.application.first_runs_header.description") }
16
14
  form_with(model: @resource, url: first_run_path, method: :post, class: "space-y-6") do |form|
17
15
  text_field(form, field_name: :email, required: true)
18
16
  password_field(form, field_name: :password, required: true)
@@ -1,5 +1,8 @@
1
1
  <div class="flex min-h-full flex-col justify-center py-12 sm:px-6 lg:px-8">
2
2
 
3
- <%= render Maquina::Application::SessionsHeader.new(brand_icon: brand_icon, translation_key: "maquina.application.first_runs_header") %>
3
+ <%= render Maquina::Application::SessionsHeader.new(
4
+ brand_icon: brand_icon,
5
+ translation_key: "maquina.first_runs.show",
6
+ ) %>
4
7
  <%= render Maquina::FirstRuns::Form.new(@user) %>
5
8
  </div>
@@ -12,8 +12,10 @@ module Maquina
12
12
  def view_template
13
13
  div class: "flex-shrink-0 flex items-center" do
14
14
  if @brand_icon.present?
15
- img(src: @brand_icon, class: "hidden lg:block mx-auto h-8 w-auto")
16
- img(src: @brand_icon, class: "block lg:hidden mx-auto h-8 w-auto")
15
+ a(href: root_path) do
16
+ img(src: @brand_icon, class: "hidden lg:block mx-auto h-8 w-auto")
17
+ img(src: @brand_icon, class: "block lg:hidden mx-auto h-8 w-auto")
18
+ end
17
19
  end
18
20
  end
19
21
  end
data/config/importmap.rb CHANGED
@@ -1,13 +1 @@
1
- # frozen_string_literal: true
2
-
3
- pin "application" # , to: "maquina/application.js", preload: true
4
-
5
- # Stimulus & Turbo
6
- pin "@hotwired/turbo-rails", to: "turbo.min.js"
7
- pin "@hotwired/stimulus", to: "@hotwired--stimulus.js" # @3.2.2
8
- pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
9
- pin "stimulus-use" # , to: "https://ga.jspm.io/npm:stimulus-use@0.52.2/dist/index.js"
10
-
11
- # Maquina entrypoint
12
-
13
- pin_all_from Maquina::Engine.root.join("app/assets/javascripts/maquina/controllers"), under: "controllers" # , to: "maquina/controllers"
1
+ pin_all_from File.expand_path("../app/assets/javascripts/controllers", __dir__), under: "controllers", preload: false
@@ -30,6 +30,12 @@ en:
30
30
  title: Invitation sent
31
31
  description: Invitation for %{email} expires in 3 days
32
32
 
33
+ first_runs:
34
+ create:
35
+ notice:
36
+ title: Admin account created
37
+ description: Welcome to maquina!
38
+
33
39
  sessions:
34
40
  create:
35
41
  notice:
@@ -30,6 +30,12 @@ es:
30
30
  title: Invitación enviada
31
31
  description: La inivitación para %{email} expira en 3 días
32
32
 
33
+ first_runs:
34
+ create:
35
+ notice:
36
+ title: Cuenta de administrador creada
37
+ description: Bienvenido a maquina!
38
+
33
39
  sessions:
34
40
  create:
35
41
  notice:
@@ -1,11 +1,21 @@
1
1
  en:
2
2
  new:
3
+ title: New %{model}
4
+ description: Complete the form to create a new %{model}
3
5
  maquina/plan:
4
- title: Configure a plan for your customers
6
+ title: Create subscription plan
7
+ description: Set up a new subscription plan with pricing and features
5
8
  maquina/invitation:
6
9
  title: Invite user to collaborate
7
10
  description: User will receive an invitation to join this application in the provided email.
8
11
 
12
+ edit:
13
+ title: Edit %{model}
14
+ description: Modify the %{model} details
15
+ maquina/plan:
16
+ title: Edit subscription plan
17
+ description: Modify existing subscription plan details and configurations
18
+
9
19
  form:
10
20
  sessions:
11
21
  email: Email address
@@ -21,12 +31,12 @@ en:
21
31
  email: user@mail.com
22
32
  password: Current password
23
33
 
24
- maquina/plan:
25
- name: Basic plan
26
-
27
34
  maquina/invitation:
28
35
  email: Enter user's email
29
36
 
37
+ first_runs:
38
+ email: admin@maquina.app
39
+
30
40
  help:
31
41
  maquina/plan:
32
42
  name: Descriptive plan name
@@ -34,6 +44,8 @@ en:
34
44
  price: Price for not free plans
35
45
  free: Check if plan is free of cost
36
46
  active: Active plans are available for customers
47
+ first_runs:
48
+ passwords: Use a strong password. The password must contain at least 8 characters, including uppercase and lowercase letters, numbers and special characters.
37
49
 
38
50
  helpers:
39
51
  cancel: Cancel
@@ -45,6 +57,9 @@ en:
45
57
  maquina/invitation:
46
58
  create: Send invitation
47
59
 
60
+ first_runs:
61
+ create: Create admin account
62
+
48
63
  maxlength:
49
64
  default: 30
50
65
 
@@ -53,6 +68,20 @@ en:
53
68
  trial: 3
54
69
  price: 9
55
70
 
71
+ first_runs:
72
+ email: 60
73
+ password: 30
74
+
56
75
  sessions:
57
76
  email: 60
58
77
  password: 60
78
+
79
+ placeholder:
80
+
81
+ help:
82
+ maquina/plan:
83
+ name: Descriptive and unique plan name
84
+ trial: Number of days on trial
85
+ price: Price for not free plans
86
+ free: Check if plan is free of cost
87
+ active: Active plans are available for customers
@@ -1,11 +1,21 @@
1
1
  es:
2
2
  new:
3
+ title: Nuevo %{model}
4
+ description: Complete el formulario para crear un nuevo %{model}
3
5
  maquina/plan:
4
- title: Configura el plan para los clientes
6
+ title: Crear plan de suscripción
7
+ description: Configura un nuevo plan de suscripción con precios y características
5
8
  maquina/invitation:
6
9
  title: Invitar a un usuario a colaborar
7
10
  description: El usuario va a recibir la invitación para unirse a colaborar vía correo electrónico.
8
11
 
12
+ edit:
13
+ title: Editar %{model}
14
+ description: Modificar los detalles de %{model}
15
+ maquina/plan:
16
+ title: Editar plan de suscripción
17
+ description: Modifica los detalles y configuraciones del plan de suscripción
18
+
9
19
  form:
10
20
  sessions:
11
21
  email: Correo electrónico
@@ -21,22 +31,13 @@ es:
21
31
  email: user@mail.com
22
32
  password: Contraseña actual
23
33
 
24
- maquina/plan:
25
- name: Plan básico
26
-
27
34
  maquina/invitation:
28
35
  email: Correo electrónico del usuario
29
36
 
30
37
  first_runs:
31
- email: admin@aoorora.com
38
+ email: admin@maquina.app
32
39
 
33
40
  help:
34
- maquina/plan:
35
- name: Nombre del plan
36
- trial: Número de días de prueba
37
- price: Precio del plan
38
- free: Indica si el plan es gratuito
39
- active: Activar plan para clientes
40
41
  first_runs:
41
42
  password: Utilize una contraseña robusta. La contraseña debe contener al menos 8 caracteres, incluyendo letras mayúsculas y minúsculas, números y caracteres especiales.
42
43
 
@@ -68,3 +69,13 @@ es:
68
69
  sessions:
69
70
  email: 60
70
71
  password: 60
72
+
73
+ placeholder:
74
+
75
+ help:
76
+ maquina/plan:
77
+ name: Nombre del plan
78
+ trial: Número de días de prueba
79
+ price: Precio del plan
80
+ free: Indica si el plan es gratuito
81
+ active: Activar plan para clientes