maquina 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9a7e451e89b0cc87b356302a33dd2bf6e0ee95f3435f7f8161697e49cedac9bd
4
- data.tar.gz: 4f9502c3d4d0a5ff9bd41769c542e277ec255e217370fac3dd00fafdb8cf7bc6
3
+ metadata.gz: 040c1d643734bb33ae456b0bd092b87b250d0b4d56f03548d569594f3d6892f3
4
+ data.tar.gz: a17889606d8033a9e068cd212d5557f7cc77b60fd8f82d7f6f951974a526866f
5
5
  SHA512:
6
- metadata.gz: 0ecf0e0e1fead4ee3594ccb5d9991f7490ad6b8bad8cc6a76def65ccd4ad0ccea18f7b267d7d9dba11aaeb4ffa27463185cf57ade1fdd97e43f53261c55e5f71
7
- data.tar.gz: dfb73cdf21f2d9761c0ff263c12015a11a9be2fc0a1c19e48ceaf17372356de6a877df4aeafe7bb75d60306d053e71c570ee22c3959a9c64e695b0b156274e5a
6
+ metadata.gz: 4654d0514915f2fe7d7577ad73487a78d5b0036df114c82950a80e8f737a5b9d92bf7b163eeb316c2758428c80e0fe5dc52b13563cfeb9a2666323b62a4c773f
7
+ data.tar.gz: fe807c89c747bcf9b7fc95b7590edcd331b0ee6eab5e966ebe5576fb48e580bc445552d3e5d0fd4d773cf8b36054e8b2e9c90c0d9a1c29631c96312d0b0a670e
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- maquina (0.2.0)
4
+ maquina (0.2.2)
5
5
  action_policy (~> 0.6.3)
6
6
  bcrypt (~> 3.1.7)
7
7
  importmap-rails (~> 1.2.0)
@@ -0,0 +1,10 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+ import { useTransition } from "stimulus-use";
3
+
4
+ export default class extends Controller {
5
+ static targets = ["backdrop"]
6
+
7
+ connect() {
8
+ useTransition(this, { element: this.backdropTarget })
9
+ }
10
+ }
@@ -2,38 +2,92 @@ import { Controller } from "@hotwired/stimulus"
2
2
  import { useTransition } from "stimulus-use"
3
3
 
4
4
  export default class extends Controller {
5
- static targets = ["content", "container", "frame"]
5
+ static targets = ["modal", "container", "frame", "form", "submit"]
6
+ static outlets = ["backdrop"]
6
7
 
7
8
  connect() {
8
- useTransition(this, { element: this.contentTarget })
9
+ this.timeouts = []
10
+ this.root = document.querySelector("html")
9
11
 
10
- this.resultCallback = this.modalResult.bind(this)
11
- addEventListener("turbo:submit-end", this.resultCallback)
12
+ useTransition(this, { element: this.modalTarget })
13
+
14
+ if (this.hasFormTarget) addEventListener("turbo:submit-end", this.submitResult.bind(this))
12
15
  }
13
16
 
14
17
  disconnect() {
15
- removeEventListener("turbo:submit-end", this.resultCallback)
18
+ this.timeouts.forEach(t => clearTimeout(t))
19
+
20
+ if (this.hasFormTarget) removeEventListener("turbo:submit-end", this.submitResult.bind(this))
16
21
  }
17
22
 
18
- modalResult(event) {
19
- if (event.detail.fetchResponse.response.status == 202) {
20
- this.toggleModal(event)
23
+ submitResult(event) {
24
+ if (this.hasFormTarget) this.submitTarget.removeAttribute("disabled")
25
+
26
+ const status = event.detail.fetchResponse.response.status
27
+ if (status == 201 || status == 202) {
28
+ this.close(event)
21
29
  }
22
30
  }
23
31
 
24
- toggleModal(event) {
32
+ submit(event) {
25
33
  event.preventDefault()
26
34
 
27
- if (this.hasFrameTarget && this.contentTarget.classList.contains("hidden")) {
28
- let url = event["detail"]["src"] || this.element.dataset["frameSrc"]
29
- this.frameTarget.setAttribute("src", url)
30
- } else if (!this.contentTarget.classList.contains("hidden")) {
31
- this.frameTarget.setAttribute("src", "")
32
- this.frameTarget.innerText = ""
35
+ if (!this.hasFormTarget) {
36
+ return
33
37
  }
34
38
 
35
- document.documentElement.classList.toggle("overflow-hidden")
36
- this.containerTarget.classList.toggle("hidden")
39
+ this.submitTarget.setAttribute("disabled", "true")
40
+ this.formTarget.requestSubmit()
41
+ }
42
+
43
+ open(event) {
44
+ event.preventDefault()
45
+
46
+ this.configureModal(event.target)
47
+ this.root.classList.toggle("overflow-hidden")
48
+
49
+ this.toggleBackdrop()
50
+ this.toggleTransition()
51
+ }
52
+
53
+ close(event) {
54
+ event.preventDefault()
55
+
56
+ this.timeouts.forEach(t => clearTimeout(t))
57
+
58
+ this.root.classList.toggle("overflow-hidden")
37
59
  this.toggleTransition()
60
+ this.toggleBackdrop()
61
+
62
+
63
+ this.timeouts.push(
64
+ setTimeout(() => this.restoreModal(), 500)
65
+ )
66
+ }
67
+
68
+ configureModal(target) {
69
+ if (this.hasSubmitTarget) {
70
+ const label = target.dataset["submit-label"]
71
+ this.submitTarget.innerText = label
72
+ }
73
+
74
+ const url = target.getAttribute("href")
75
+ this.frameTarget.setAttribute("src", url)
76
+
77
+ this.containerTarget.classList.toggle("hidden")
78
+ }
79
+
80
+ restoreModal() {
81
+ this.containerTarget.classList.toggle("hidden")
82
+
83
+ if (this.hasSubmitTarget) {
84
+ this.submitTarget.innerText = ""
85
+ this.submitTarget.removeAttribute("disabled")
86
+ }
87
+ this.frameTarget.setAttribute("src", "")
88
+ }
89
+
90
+ toggleBackdrop() {
91
+ this.backdropOutlets.forEach(backdrop => backdrop.toggleTransition())
38
92
  }
39
93
  }
@@ -1,15 +1,10 @@
1
1
  import { Controller } from "@hotwired/stimulus";
2
- import { useDispatch } from "stimulus-use";
3
2
 
4
3
  export default class extends Controller {
5
- static targets = [];
6
-
7
- connect() {
8
- useDispatch(this)
9
- }
4
+ static outlets = ["modal"];
10
5
 
11
6
  open(event) {
12
- event.preventDefault();
13
- this.dispatch("toggle", {src: event.target.getAttribute("href")});
7
+ event.preventDefault()
8
+ this.modalOutlets.forEach(modal => modal.open(event))
14
9
  }
15
10
  }
@@ -35,6 +35,9 @@ module Maquina
35
35
  active_session = ActiveSession.eager_load(user: {memberships: :organization})
36
36
  .where(maquina_memberships: {blocked_at: nil})
37
37
  .where(maquina_organizations: {active: true})
38
+ .or(
39
+ ActiveSession.where(maquina_users: {management: true})
40
+ )
38
41
  .find_by(id: active_session_id)
39
42
 
40
43
  return if active_session.blank?
@@ -11,13 +11,13 @@ module Maquina
11
11
  end
12
12
 
13
13
  class_methods do
14
- def search_scope(fields: [], options: {})
14
+ def search_scope(fields: [], options: {}, associated_against: {})
15
15
  return if fields.empty?
16
16
 
17
17
  default_options = {tsearch: {prefix: true, any_word: true}}
18
18
  search_options = options.deep_merge(default_options)
19
19
 
20
- pg_search_scope :search_full, against: fields, using: search_options # , ignoring: :accents
20
+ pg_search_scope :search_full, against: fields, using: search_options, associated_against: associated_against # , ignoring: :accents
21
21
  end
22
22
  end
23
23
  end
@@ -1,11 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "pg_search"
4
-
5
3
  module Maquina
6
4
  class ApplicationRecord < ActiveRecord::Base
7
5
  self.abstract_class = true
8
6
 
9
- include PgSearch::Model
7
+ def self.searchable?
8
+ false
9
+ end
10
10
  end
11
11
  end
@@ -25,8 +25,6 @@ module Maquina
25
25
  # attributes and use the provided methods and scopes for querying and manipulating plan data.
26
26
 
27
27
  class Plan < ApplicationRecord
28
- include Searchable
29
-
30
28
  has_many :organizations, class_name: "Maquina::Organization", foreign_key: :maquina_plan_id, dependent: :nullify
31
29
 
32
30
  monetize :price_cents
@@ -34,7 +32,5 @@ module Maquina
34
32
  validates :price, numericality: {greater_than_or_equal_to: 0}, if: ->(plan) { plan.free? }
35
33
  validates :price, numericality: {greater_than: 0}, if: ->(plan) { !plan.free? }
36
34
  validates :name, presence: true, uniqueness: true
37
-
38
- search_scope(fields: [:name])
39
35
  end
40
36
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Maquina
4
4
  class User < ApplicationRecord
5
- include Maquina::Searchable
6
5
  include Maquina::RetainPasswords
7
6
  include Maquina::AuthenticateBy
8
7
  include Maquina::Blockeable
@@ -18,8 +17,6 @@ module Maquina
18
17
 
19
18
  before_save :downcase_email
20
19
 
21
- search_scope(fields: [:email])
22
-
23
20
  def expired_password?
24
21
  return false if password_expires_at.blank?
25
22
 
@@ -3,11 +3,11 @@
3
3
  module Maquina
4
4
  class InvitationPolicy < ApplicationPolicy
5
5
  def new?
6
- management?
6
+ management? || admin?
7
7
  end
8
8
 
9
9
  def create?
10
- new?
10
+ new? || admin?
11
11
  end
12
12
  end
13
13
  end
@@ -6,7 +6,7 @@
6
6
  <%= render Maquina::Navbar::Menu.new %>
7
7
  </div>
8
8
 
9
- <%= render Maquina::Navbar::Search.new(query: params[:q], url: collection_path) if action_name == "index" && respond_to?(:collection_path) && collection_path.present? %>
9
+ <%= render Maquina::Navbar::Search.new(query: params[:q], url: collection_path) if action_name == "index" && respond_to?(:collection_path) && collection_path.present? && respond_to?(:resource_class) && resource_class.searchable? %>
10
10
 
11
11
  <%= render Maquina::Navbar::MobileButton.new %>
12
12
 
@@ -30,7 +30,7 @@ module Maquina
30
30
 
31
31
  div(class: "pt-5") do
32
32
  div(class: "flex justify-end") do
33
- link_to t("helpers.cancel"), collection_path, class: "button", data: @modal ? {action: "modal#toggleModal"} : {turbo_frame: :_top}
33
+ link_to t("helpers.cancel"), collection_path, class: "button", data: @modal ? {action: "modal#close"} : {turbo_frame: :_top}
34
34
  form.submit class: "ml-3 button button-accented"
35
35
  end
36
36
  end
@@ -27,7 +27,7 @@ module Maquina
27
27
  return if policy_class.blank? || !allowed_to?(:new?, with: policy_class)
28
28
 
29
29
  options = {}
30
- options[:data] = {controller: "modal-open", action: "modal-open#open"} if policy_class.present? && allowed_to?(:new_modal?, with: policy_class)
30
+ options[:data] = {controller: "modal-open", modal_open_modal_outlet: ".modal", action: "modal-open#open"} if policy_class.present? && allowed_to?(:new_modal?, with: policy_class)
31
31
 
32
32
  div(class: "mt-4 sm:mt-0 sm:ml-16 sm:flex-none") do
33
33
  a(href: new_resource_path, class: "inline-flex items-center justify-center button button-accented", **options) { add_new }
@@ -7,13 +7,13 @@ module Maquina
7
7
  register_element :turbo_frame
8
8
 
9
9
  def template
10
- div(data_controller: "modal",
11
- data_action: " modal-open:toggle@window->modal#toggleModal close-frame-modal:toggle@window->modal#toggleModal",
12
- data_frame_src: "") do
13
- div(class: "fixed inset-0 z-30 hidden overflow-y-auto", aria_labelledby: "modal-title", role: "dialog",
10
+ div(data_controller: "modal", class: "modal", data_modal_backdrop_outlet: ".modal-backdrop") do
11
+ div(class: "hidden fixed inset-0 z-30 overflow-y-auto", aria_labelledby: "modal-title", role: "dialog",
14
12
  aria_modal: "true", data_modal_target: "container") do
15
13
  div(class: "flex items-end justify-center min-h-screen px-4 pt-4 pb-20 text-center sm:block sm:p-0") do
16
- div(class: "fixed inset-0 transition-opacity",
14
+ div(class: "hidden fixed inset-0 transition-opacity modal-backdrop",
15
+ data_controller: "backdrop",
16
+ data_backdrop_target: "backdrop",
17
17
  data_transition_enter: "ease-out duration-300",
18
18
  data_transition_enter_active: "opacity-0",
19
19
  data_transition_enter_to: "opacity-100",
@@ -24,8 +24,8 @@ module Maquina
24
24
  div(class: "fixed inset-0 bg-gray-500 bg-opacity-75 transition-opacity", aria_hidden: "true")
25
25
  end
26
26
  span(class: "hidden sm:inline-block sm:align-middle sm:h-screen", aria_hidden: "true") { "​" }
27
- div(class: "inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6",
28
- data_modal_target: "content",
27
+ div(class: "hidden inline-block align-bottom bg-white rounded-lg px-4 pt-5 pb-4 text-left overflow-hidden shadow-xl transform transition-all sm:my-8 sm:align-middle sm:max-w-lg sm:w-full sm:p-6",
28
+ data_modal_target: "modal",
29
29
  data_transition_enter: "ease-out duration-300",
30
30
  data_transition_enter_active: "opacity-0 translate-y-4 sm:translate-y-0 sm:scale-95",
31
31
  data_transition_enter_to: "opacity-100 translate-y-0 sm:scale-100",
@@ -47,8 +47,8 @@ module Maquina
47
47
  def field_attributes(field_name, scope = nil)
48
48
  scope ||= "sessions"
49
49
  {
50
- maxlength: t("maxlength.#{scope}.#{field_name}", default: t("maxlength.default")),
51
- placeholder: t("placeholder.#{scope}.#{field_name}", default: "")
50
+ maxlength: t("helpers.maxlength.#{scope}.#{field_name}", default: t("helpers.maxlength.default")),
51
+ placeholder: t("helpers.placeholder.#{scope}.#{field_name}", default: "")
52
52
  }
53
53
  end
54
54
  end
@@ -3,7 +3,8 @@ en:
3
3
  maquina/plan:
4
4
  title: Configure a plan for your customers
5
5
  maquina/invitation:
6
- title: User will receive an invitation to join this application in the provided email.
6
+ title: Invite user to collaborate
7
+ description: User will receive an invitation to join this application in the provided email.
7
8
 
8
9
  form:
9
10
  sessions:
@@ -26,18 +27,6 @@ en:
26
27
  maquina/invitation:
27
28
  email: Enter user's email
28
29
 
29
- maxlength:
30
- default: 30
31
-
32
- maquina/plan:
33
- name: 60
34
- trial: 3
35
- price: 9
36
-
37
- sessions:
38
- email: 60
39
- password: 60
40
-
41
30
  help:
42
31
  maquina/plan:
43
32
  name: Descriptive plan name
@@ -56,3 +45,14 @@ en:
56
45
  maquina/invitation:
57
46
  create: Send invitation
58
47
 
48
+ maxlength:
49
+ default: 30
50
+
51
+ maquina/plan:
52
+ name: 60
53
+ trial: 3
54
+ price: 9
55
+
56
+ sessions:
57
+ email: 60
58
+ password: 60
@@ -24,9 +24,5 @@ module Maquina
24
24
  def copy_migrations
25
25
  rake "maquina:install:migrations"
26
26
  end
27
-
28
- def build_tailwind
29
- rake "maquina:tailwindcss:build"
30
- end
31
27
  end
32
28
  end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ Maquina.configure do |config|
4
+ # Configure membership roles.
5
+ config.membership_roles = Maquina.postgresql? ? {admin: "admin", member: "member"} : {admin: 0, member: 1}
6
+ end
@@ -1,3 +1,3 @@
1
1
  module Maquina
2
- VERSION = "0.2.0"
2
+ VERSION = "0.2.2"
3
3
  end
data/lib/maquina.rb CHANGED
@@ -11,6 +11,10 @@ require "pagy"
11
11
  module Maquina
12
12
  class << self
13
13
  attr_accessor :configuration
14
+
15
+ def postgresql?
16
+ ActiveRecord::Base.connection_db_config.configuration_hash[:adapter].downcase == "postgresql"
17
+ end
14
18
  end
15
19
 
16
20
  class Configuration
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: maquina
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mario Alberto Chávez
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-08-30 00:00:00.000000000 Z
11
+ date: 2023-09-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -307,6 +307,7 @@ files:
307
307
  - app/assets/javascripts/maquina/application.js
308
308
  - app/assets/javascripts/maquina/controllers/alert_controller.js
309
309
  - app/assets/javascripts/maquina/controllers/application.js
310
+ - app/assets/javascripts/maquina/controllers/backdrop_controller.js
310
311
  - app/assets/javascripts/maquina/controllers/file_controller.js
311
312
  - app/assets/javascripts/maquina/controllers/index.js
312
313
  - app/assets/javascripts/maquina/controllers/mobile_menu_controller.js
@@ -434,7 +435,7 @@ files:
434
435
  - lib/generators/maquina/tailwind_config/templates/lib/generators/tailwind_config/tailwind_config_generator.rb.tt
435
436
  - lib/generators/maquina/tailwind_config/templates/lib/generators/tailwind_config/templates/config/tailwind.config.js.tt
436
437
  - lib/generators/maquina/tailwind_config/templates/lib/tasks/tailwind.rake.tt
437
- - lib/generators/maquina/templates/config/initializers/maquina.rb
438
+ - lib/generators/maquina/templates/config/initializers/maquina.rb.tt
438
439
  - lib/maquina.rb
439
440
  - lib/maquina/engine.rb
440
441
  - lib/maquina/version.rb
@@ -1,3 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # TODO: Have and initializer