Compare commits
8 commits
a7809d13e8
...
8d5c35567c
Author | SHA1 | Date | |
---|---|---|---|
|
8d5c35567c | ||
|
effb1a7cfc | ||
|
6e0860b462 | ||
|
abc02aef8b | ||
|
4ad1339a60 | ||
|
21193a08ac | ||
|
9801cf8521 | ||
|
bfb0e2278e |
27 changed files with 863 additions and 71 deletions
4
Gemfile
4
Gemfile
|
@ -29,6 +29,10 @@ gem 'ssh_data'
|
||||||
|
|
||||||
gem 'anomaly_detection'
|
gem 'anomaly_detection'
|
||||||
|
|
||||||
|
gem 'bootstrap'
|
||||||
|
gem 'rails-i18n'
|
||||||
|
gem 'hamlit'
|
||||||
|
|
||||||
group :development, :test do
|
group :development, :test do
|
||||||
gem 'pry'
|
gem 'pry'
|
||||||
end
|
end
|
||||||
|
|
157
Gemfile.lock
157
Gemfile.lock
|
@ -1,60 +1,60 @@
|
||||||
GEM
|
GEM
|
||||||
remote: https://gems.sutty.nl/
|
remote: https://gems.sutty.nl/
|
||||||
specs:
|
specs:
|
||||||
actioncable (6.1.5)
|
actioncable (6.1.6)
|
||||||
actionpack (= 6.1.5)
|
actionpack (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
websocket-driver (>= 0.6.1)
|
websocket-driver (>= 0.6.1)
|
||||||
actionmailbox (6.1.5)
|
actionmailbox (6.1.6)
|
||||||
actionpack (= 6.1.5)
|
actionpack (= 6.1.6)
|
||||||
activejob (= 6.1.5)
|
activejob (= 6.1.6)
|
||||||
activerecord (= 6.1.5)
|
activerecord (= 6.1.6)
|
||||||
activestorage (= 6.1.5)
|
activestorage (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
mail (>= 2.7.1)
|
mail (>= 2.7.1)
|
||||||
actionmailer (6.1.5)
|
actionmailer (6.1.6)
|
||||||
actionpack (= 6.1.5)
|
actionpack (= 6.1.6)
|
||||||
actionview (= 6.1.5)
|
actionview (= 6.1.6)
|
||||||
activejob (= 6.1.5)
|
activejob (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
mail (~> 2.5, >= 2.5.4)
|
mail (~> 2.5, >= 2.5.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
actionpack (6.1.5)
|
actionpack (6.1.6)
|
||||||
actionview (= 6.1.5)
|
actionview (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
rack (~> 2.0, >= 2.0.9)
|
rack (~> 2.0, >= 2.0.9)
|
||||||
rack-test (>= 0.6.3)
|
rack-test (>= 0.6.3)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
rails-html-sanitizer (~> 1.0, >= 1.2.0)
|
||||||
actiontext (6.1.5)
|
actiontext (6.1.6)
|
||||||
actionpack (= 6.1.5)
|
actionpack (= 6.1.6)
|
||||||
activerecord (= 6.1.5)
|
activerecord (= 6.1.6)
|
||||||
activestorage (= 6.1.5)
|
activestorage (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
nokogiri (>= 1.8.5)
|
nokogiri (>= 1.8.5)
|
||||||
actionview (6.1.5)
|
actionview (6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
builder (~> 3.1)
|
builder (~> 3.1)
|
||||||
erubi (~> 1.4)
|
erubi (~> 1.4)
|
||||||
rails-dom-testing (~> 2.0)
|
rails-dom-testing (~> 2.0)
|
||||||
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
rails-html-sanitizer (~> 1.1, >= 1.2.0)
|
||||||
activejob (6.1.5)
|
activejob (6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
globalid (>= 0.3.6)
|
globalid (>= 0.3.6)
|
||||||
activemodel (6.1.5)
|
activemodel (6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
activerecord (6.1.5)
|
activerecord (6.1.6)
|
||||||
activemodel (= 6.1.5)
|
activemodel (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
activestorage (6.1.5)
|
activestorage (6.1.6)
|
||||||
actionpack (= 6.1.5)
|
actionpack (= 6.1.6)
|
||||||
activejob (= 6.1.5)
|
activejob (= 6.1.6)
|
||||||
activerecord (= 6.1.5)
|
activerecord (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
marcel (~> 1.0)
|
marcel (~> 1.0)
|
||||||
mini_mime (>= 1.1.0)
|
mini_mime (>= 1.1.0)
|
||||||
activesupport (6.1.5)
|
activesupport (6.1.6)
|
||||||
concurrent-ruby (~> 1.0, >= 1.0.2)
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
||||||
i18n (>= 1.6, < 2)
|
i18n (>= 1.6, < 2)
|
||||||
minitest (>= 5.1)
|
minitest (>= 5.1)
|
||||||
|
@ -63,20 +63,26 @@ GEM
|
||||||
anomaly_detection (0.1.4-x86_64-linux-musl)
|
anomaly_detection (0.1.4-x86_64-linux-musl)
|
||||||
rice (>= 4.0.2)
|
rice (>= 4.0.2)
|
||||||
ast (2.4.2)
|
ast (2.4.2)
|
||||||
|
autoprefixer-rails (10.4.2.0)
|
||||||
|
execjs (~> 2)
|
||||||
bcrypt (3.1.17-x86_64-linux-musl)
|
bcrypt (3.1.17-x86_64-linux-musl)
|
||||||
bindex (0.8.1-x86_64-linux-musl)
|
bindex (0.8.1-x86_64-linux-musl)
|
||||||
blazer (2.5.0)
|
blazer (2.6.3)
|
||||||
activerecord (>= 5)
|
activerecord (>= 5)
|
||||||
chartkick (>= 3.2)
|
chartkick (>= 3.2)
|
||||||
railties (>= 5)
|
railties (>= 5)
|
||||||
safely_block (>= 0.1.1)
|
safely_block (>= 0.1.1)
|
||||||
bootsnap (1.11.1-x86_64-linux-musl)
|
bootsnap (1.11.1-x86_64-linux-musl)
|
||||||
msgpack (~> 1.2)
|
msgpack (~> 1.2)
|
||||||
brakeman (5.2.1)
|
bootstrap (5.1.3)
|
||||||
|
autoprefixer-rails (>= 9.1.0)
|
||||||
|
popper_js (>= 2.9.3, < 3)
|
||||||
|
sassc-rails (>= 2.0.0)
|
||||||
|
brakeman (5.2.3)
|
||||||
builder (3.2.4)
|
builder (3.2.4)
|
||||||
chartkick (4.1.3)
|
chartkick (4.1.3)
|
||||||
coderay (1.1.3)
|
coderay (1.1.3)
|
||||||
concurrent-ruby (1.1.9)
|
concurrent-ruby (1.1.10)
|
||||||
crass (1.0.6)
|
crass (1.0.6)
|
||||||
database_cleaner (2.0.1)
|
database_cleaner (2.0.1)
|
||||||
database_cleaner-active_record (~> 2.0.0)
|
database_cleaner-active_record (~> 2.0.0)
|
||||||
|
@ -97,11 +103,16 @@ GEM
|
||||||
exception_notification (4.5.0)
|
exception_notification (4.5.0)
|
||||||
actionmailer (>= 5.2, < 8)
|
actionmailer (>= 5.2, < 8)
|
||||||
activesupport (>= 5.2, < 8)
|
activesupport (>= 5.2, < 8)
|
||||||
|
execjs (2.8.1)
|
||||||
factory_bot (6.2.1)
|
factory_bot (6.2.1)
|
||||||
activesupport (>= 5.0.0)
|
activesupport (>= 5.0.0)
|
||||||
ffi (1.15.5-x86_64-linux-musl)
|
ffi (1.15.5-x86_64-linux-musl)
|
||||||
globalid (1.0.0)
|
globalid (1.0.0)
|
||||||
activesupport (>= 5.0)
|
activesupport (>= 5.0)
|
||||||
|
hamlit (2.16.0-x86_64-linux-musl)
|
||||||
|
temple (>= 0.8.2)
|
||||||
|
thor
|
||||||
|
tilt
|
||||||
i18n (1.10.0)
|
i18n (1.10.0)
|
||||||
concurrent-ruby (~> 1.0)
|
concurrent-ruby (~> 1.0)
|
||||||
jbuilder (2.11.5)
|
jbuilder (2.11.5)
|
||||||
|
@ -110,12 +121,12 @@ GEM
|
||||||
listen (3.7.1)
|
listen (3.7.1)
|
||||||
rb-fsevent (~> 0.10, >= 0.10.3)
|
rb-fsevent (~> 0.10, >= 0.10.3)
|
||||||
rb-inotify (~> 0.9, >= 0.9.10)
|
rb-inotify (~> 0.9, >= 0.9.10)
|
||||||
lograge (0.11.2)
|
lograge (0.12.0)
|
||||||
actionpack (>= 4)
|
actionpack (>= 4)
|
||||||
activesupport (>= 4)
|
activesupport (>= 4)
|
||||||
railties (>= 4)
|
railties (>= 4)
|
||||||
request_store (~> 1.0)
|
request_store (~> 1.0)
|
||||||
loofah (2.15.0)
|
loofah (2.18.0)
|
||||||
crass (~> 1.0.2)
|
crass (~> 1.0.2)
|
||||||
nokogiri (>= 1.5.9)
|
nokogiri (>= 1.5.9)
|
||||||
mail (2.7.1)
|
mail (2.7.1)
|
||||||
|
@ -125,20 +136,21 @@ GEM
|
||||||
mini_mime (1.1.2)
|
mini_mime (1.1.2)
|
||||||
mini_portile2 (2.8.0)
|
mini_portile2 (2.8.0)
|
||||||
minitest (5.15.0)
|
minitest (5.15.0)
|
||||||
msgpack (1.4.5-x86_64-linux-musl)
|
msgpack (1.5.1-x86_64-linux-musl)
|
||||||
nio4r (2.5.8-x86_64-linux-musl)
|
nio4r (2.5.8-x86_64-linux-musl)
|
||||||
nokogiri (1.13.3-x86_64-linux-musl)
|
nokogiri (1.13.6-x86_64-linux-musl)
|
||||||
mini_portile2 (~> 2.8.0)
|
mini_portile2 (~> 2.8.0)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
orm_adapter (0.5.0)
|
orm_adapter (0.5.0)
|
||||||
parallel (1.21.0)
|
parallel (1.22.1)
|
||||||
parser (3.1.1.0)
|
parser (3.1.2.0)
|
||||||
ast (~> 2.4.1)
|
ast (~> 2.4.1)
|
||||||
pg (1.3.4-x86_64-linux-musl)
|
pg (1.3.5-x86_64-linux-musl)
|
||||||
|
popper_js (2.9.3)
|
||||||
pry (0.14.1)
|
pry (0.14.1)
|
||||||
coderay (~> 1.1)
|
coderay (~> 1.1)
|
||||||
method_source (~> 1.0)
|
method_source (~> 1.0)
|
||||||
puma (5.6.2-x86_64-linux-musl)
|
puma (5.6.4-x86_64-linux-musl)
|
||||||
nio4r (~> 2.0)
|
nio4r (~> 2.0)
|
||||||
racc (1.6.0-x86_64-linux-musl)
|
racc (1.6.0-x86_64-linux-musl)
|
||||||
rack (2.2.3)
|
rack (2.2.3)
|
||||||
|
@ -148,29 +160,32 @@ GEM
|
||||||
rack
|
rack
|
||||||
rack-test (1.1.0)
|
rack-test (1.1.0)
|
||||||
rack (>= 1.0, < 3)
|
rack (>= 1.0, < 3)
|
||||||
rails (6.1.5)
|
rails (6.1.6)
|
||||||
actioncable (= 6.1.5)
|
actioncable (= 6.1.6)
|
||||||
actionmailbox (= 6.1.5)
|
actionmailbox (= 6.1.6)
|
||||||
actionmailer (= 6.1.5)
|
actionmailer (= 6.1.6)
|
||||||
actionpack (= 6.1.5)
|
actionpack (= 6.1.6)
|
||||||
actiontext (= 6.1.5)
|
actiontext (= 6.1.6)
|
||||||
actionview (= 6.1.5)
|
actionview (= 6.1.6)
|
||||||
activejob (= 6.1.5)
|
activejob (= 6.1.6)
|
||||||
activemodel (= 6.1.5)
|
activemodel (= 6.1.6)
|
||||||
activerecord (= 6.1.5)
|
activerecord (= 6.1.6)
|
||||||
activestorage (= 6.1.5)
|
activestorage (= 6.1.6)
|
||||||
activesupport (= 6.1.5)
|
activesupport (= 6.1.6)
|
||||||
bundler (>= 1.15.0)
|
bundler (>= 1.15.0)
|
||||||
railties (= 6.1.5)
|
railties (= 6.1.6)
|
||||||
sprockets-rails (>= 2.0.0)
|
sprockets-rails (>= 2.0.0)
|
||||||
rails-dom-testing (2.0.3)
|
rails-dom-testing (2.0.3)
|
||||||
activesupport (>= 4.2.0)
|
activesupport (>= 4.2.0)
|
||||||
nokogiri (>= 1.6)
|
nokogiri (>= 1.6)
|
||||||
rails-html-sanitizer (1.4.2)
|
rails-html-sanitizer (1.4.2)
|
||||||
loofah (~> 2.3)
|
loofah (~> 2.3)
|
||||||
railties (6.1.5)
|
rails-i18n (7.0.3)
|
||||||
actionpack (= 6.1.5)
|
i18n (>= 0.7, < 2)
|
||||||
activesupport (= 6.1.5)
|
railties (>= 6.0.0, < 8)
|
||||||
|
railties (6.1.6)
|
||||||
|
actionpack (= 6.1.6)
|
||||||
|
activesupport (= 6.1.6)
|
||||||
method_source
|
method_source
|
||||||
rake (>= 12.2)
|
rake (>= 12.2)
|
||||||
thor (~> 1.0)
|
thor (~> 1.0)
|
||||||
|
@ -179,7 +194,7 @@ GEM
|
||||||
rb-fsevent (0.11.1)
|
rb-fsevent (0.11.1)
|
||||||
rb-inotify (0.10.1)
|
rb-inotify (0.10.1)
|
||||||
ffi (~> 1.0)
|
ffi (~> 1.0)
|
||||||
regexp_parser (2.2.1)
|
regexp_parser (2.4.0)
|
||||||
request_store (1.5.1)
|
request_store (1.5.1)
|
||||||
rack (>= 1.4)
|
rack (>= 1.4)
|
||||||
responders (3.0.1)
|
responders (3.0.1)
|
||||||
|
@ -187,16 +202,16 @@ GEM
|
||||||
railties (>= 5.0)
|
railties (>= 5.0)
|
||||||
rexml (3.2.5)
|
rexml (3.2.5)
|
||||||
rice (4.0.3)
|
rice (4.0.3)
|
||||||
rubocop (1.26.0)
|
rubocop (1.29.1)
|
||||||
parallel (~> 1.10)
|
parallel (~> 1.10)
|
||||||
parser (>= 3.1.0.0)
|
parser (>= 3.1.0.0)
|
||||||
rainbow (>= 2.2.2, < 4.0)
|
rainbow (>= 2.2.2, < 4.0)
|
||||||
regexp_parser (>= 1.8, < 3.0)
|
regexp_parser (>= 1.8, < 3.0)
|
||||||
rexml
|
rexml (>= 3.2.5, < 4.0)
|
||||||
rubocop-ast (>= 1.16.0, < 2.0)
|
rubocop-ast (>= 1.17.0, < 2.0)
|
||||||
ruby-progressbar (~> 1.7)
|
ruby-progressbar (~> 1.7)
|
||||||
unicode-display_width (>= 1.4.0, < 3.0)
|
unicode-display_width (>= 1.4.0, < 3.0)
|
||||||
rubocop-ast (1.16.0)
|
rubocop-ast (1.18.0)
|
||||||
parser (>= 3.1.1.0)
|
parser (>= 3.1.1.0)
|
||||||
ruby-progressbar (1.11.0)
|
ruby-progressbar (1.11.0)
|
||||||
safely_block (0.3.0)
|
safely_block (0.3.0)
|
||||||
|
@ -221,6 +236,7 @@ GEM
|
||||||
activesupport (>= 5.2)
|
activesupport (>= 5.2)
|
||||||
sprockets (>= 3.0.0)
|
sprockets (>= 3.0.0)
|
||||||
ssh_data (1.3.0)
|
ssh_data (1.3.0)
|
||||||
|
temple (0.8.2)
|
||||||
thor (1.2.1)
|
thor (1.2.1)
|
||||||
tilt (2.0.10)
|
tilt (2.0.10)
|
||||||
turbolinks (5.2.1)
|
turbolinks (5.2.1)
|
||||||
|
@ -254,12 +270,14 @@ DEPENDENCIES
|
||||||
anomaly_detection
|
anomaly_detection
|
||||||
blazer
|
blazer
|
||||||
bootsnap (>= 1.4.4)
|
bootsnap (>= 1.4.4)
|
||||||
|
bootstrap
|
||||||
brakeman
|
brakeman
|
||||||
database_cleaner
|
database_cleaner
|
||||||
devise
|
devise
|
||||||
devise-i18n
|
devise-i18n
|
||||||
exception_notification
|
exception_notification
|
||||||
factory_bot
|
factory_bot
|
||||||
|
hamlit
|
||||||
jbuilder (~> 2.7)
|
jbuilder (~> 2.7)
|
||||||
listen (~> 3.3)
|
listen (~> 3.3)
|
||||||
lograge
|
lograge
|
||||||
|
@ -268,6 +286,7 @@ DEPENDENCIES
|
||||||
puma (~> 5.0)
|
puma (~> 5.0)
|
||||||
rack-mini-profiler (~> 2.0)
|
rack-mini-profiler (~> 2.0)
|
||||||
rails (~> 6.1.4)
|
rails (~> 6.1.4)
|
||||||
|
rails-i18n
|
||||||
rubocop
|
rubocop
|
||||||
sass-rails (>= 6)
|
sass-rails (>= 6)
|
||||||
spring
|
spring
|
||||||
|
|
1
app/assets/stylesheets/main.scss
Normal file
1
app/assets/stylesheets/main.scss
Normal file
|
@ -0,0 +1 @@
|
||||||
|
@import "bootstrap";
|
30
app/controllers/sites_controller.rb
Normal file
30
app/controllers/sites_controller.rb
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Gestionar el sitio
|
||||||
|
class SitesController < ApplicationController
|
||||||
|
def show
|
||||||
|
site
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
site.update(site_params)
|
||||||
|
|
||||||
|
redirect_to site_path(site)
|
||||||
|
end
|
||||||
|
|
||||||
|
def update
|
||||||
|
site.update(site_params)
|
||||||
|
|
||||||
|
redirect_to site_path(site)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def site
|
||||||
|
@site ||= Site.first || Site.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def site_params
|
||||||
|
@site_params ||= params.require(:site).permit(:title, :logo)
|
||||||
|
end
|
||||||
|
end
|
31
app/controllers/users_controller.rb
Normal file
31
app/controllers/users_controller.rb
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UsersController < ApplicationController
|
||||||
|
def index
|
||||||
|
@users = User.all.order(created_at: :desc)
|
||||||
|
@user = User.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
user = User.create(password: SecureRandom.hex, created_by: current_user, **user_params)
|
||||||
|
|
||||||
|
user.send_reset_password_instructions if user.persisted?
|
||||||
|
|
||||||
|
redirect_to users_path
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
user = User.find(params[:id])
|
||||||
|
user.destroy
|
||||||
|
|
||||||
|
sign_out(current_user) if user == current_user
|
||||||
|
|
||||||
|
redirect_to users_path
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def user_params
|
||||||
|
@user_params ||= params.require(:user).permit(:email)
|
||||||
|
end
|
||||||
|
end
|
6
app/models/site.rb
Normal file
6
app/models/site.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class Site < ApplicationRecord
|
||||||
|
has_one_attached :logo
|
||||||
|
validates_presence_of :title
|
||||||
|
end
|
|
@ -3,4 +3,10 @@ class User < ApplicationRecord
|
||||||
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
||||||
devise :database_authenticatable,
|
devise :database_authenticatable,
|
||||||
:recoverable, :rememberable, :validatable, :lockable, :timeoutable
|
:recoverable, :rememberable, :validatable, :lockable, :timeoutable
|
||||||
|
|
||||||
|
# Trazabilidad
|
||||||
|
#
|
||||||
|
# @see {https://guides.rubyonrails.org/association_basics.html#self-joins}
|
||||||
|
belongs_to :created_by, class_name: 'User', optional: true
|
||||||
|
has_many :created, class_name: 'User', foreign_key: 'created_by_id'
|
||||||
end
|
end
|
||||||
|
|
250
app/views/blazer/queries/_form.html.erb
Normal file
250
app/views/blazer/queries/_form.html.erb
Normal file
|
@ -0,0 +1,250 @@
|
||||||
|
<% if @query.errors.any? %>
|
||||||
|
<div class="alert alert-danger"><%= @query.errors.full_messages.first %></div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div id="app" v-cloak>
|
||||||
|
<%= form_for @query, url: (@query.persisted? ? query_path(@query, params: variable_params(@query)) : queries_path(params: variable_params(@query))), html: {autocomplete: "off"} do |f| %>
|
||||||
|
<div class="row">
|
||||||
|
<div id="statement-box" class="col-xs-8">
|
||||||
|
<div class= "form-group">
|
||||||
|
<%= f.hidden_field :statement %>
|
||||||
|
<div id="editor-container">
|
||||||
|
<div id="editor" :style="{ height: editorHeight }"><%= @query.statement %></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group text-right" style="margin-bottom: 8px;">
|
||||||
|
<div class="pull-left" style="margin-top: 8px;">
|
||||||
|
<%= link_to t('.back'), :back %>
|
||||||
|
<a :href="docsPath" target="_blank" style="margin-left: 40px;"><%= t('.docs') %></a>
|
||||||
|
<a :href="schemaPath" target="_blank" style="margin-left: 40px;"><%= t('.schema') %></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<%= f.select :data_source, Blazer.data_sources.values.select { |ds| q = @query.dup; q.data_source = ds.id; q.editable?(blazer_user) }.map { |ds| [ds.name, ds.id] }, {}, class: ("hide" if Blazer.data_sources.size <= 1), style: "width: 140px;" %>
|
||||||
|
<div id="tables" style="display: inline-block; width: 250px; margin-right: 10px;">
|
||||||
|
<select id="table_names" style="width: 240px;" placeholder="<%= t('.preview_table') %>"></select>
|
||||||
|
</div>
|
||||||
|
<a v-on:click="run" v-if="!running" class="btn btn-info" style="vertical-align: top;"><%= t('.run') %></a>
|
||||||
|
<a v-on:click="cancel" v-if="running" class="btn btn-danger" style="vertical-align: top;"><%= t('.cancel') %></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-4">
|
||||||
|
<div class="form-group">
|
||||||
|
<%= f.label :name %>
|
||||||
|
<%= f.text_field :name, class: "form-control" %>
|
||||||
|
</div>
|
||||||
|
<div class="form-group">
|
||||||
|
<%= f.label :description %>
|
||||||
|
<%= f.text_area :description, placeholder: t('.optional'), style: "height: 80px;", class: "form-control" %>
|
||||||
|
</div>
|
||||||
|
<div class="form-group text-right">
|
||||||
|
<%= f.submit "For Enter Press", class: "hide" %>
|
||||||
|
<% if @query.persisted? %>
|
||||||
|
<%= link_to t('.delete'), query_path(@query), method: :delete, "data-confirm" => t('.are_you_sure'), class: "btn btn-danger" %>
|
||||||
|
<%= f.submit t('.fork'), class: "btn btn-info" %>
|
||||||
|
<% end %>
|
||||||
|
<%= f.submit @query.persisted? ? t('.update') : t('.create'), class: "btn btn-success" %>
|
||||||
|
</div>
|
||||||
|
<% if @query.persisted? %>
|
||||||
|
<% dashboards_count = @query.dashboards.count %>
|
||||||
|
<% checks_count = @query.checks.count %>
|
||||||
|
<% words = [] %>
|
||||||
|
<% words << pluralize(dashboards_count, "dashboard") if dashboards_count > 0 %>
|
||||||
|
<% words << pluralize(checks_count, "check") if checks_count > 0 %>
|
||||||
|
<% if words.any? %>
|
||||||
|
<div class="alert alert-info">
|
||||||
|
<%= t('.part_of', words: words.to_sentence) %>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div id="results">
|
||||||
|
<p class="text-muted" v-if="running"><%= t('.loading') %></p>
|
||||||
|
<div id="results-html" v-if="!running" :class="{ 'query-error': error }"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
<%= blazer_js_var "variableParams", variable_params(@query) %>
|
||||||
|
<%= blazer_js_var "previewStatement", Hash[Blazer.data_sources.map { |k, v| [k, (v.preview_statement rescue "")] }] %>
|
||||||
|
|
||||||
|
var app = new Vue({
|
||||||
|
el: "#app",
|
||||||
|
data: {
|
||||||
|
running: false,
|
||||||
|
results: "",
|
||||||
|
error: false,
|
||||||
|
dataSource: "",
|
||||||
|
selectize: null,
|
||||||
|
editorHeight: "180px"
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
schemaPath: function() {
|
||||||
|
return Routes.schema_queries_path({data_source: this.dataSource})
|
||||||
|
},
|
||||||
|
docsPath: function() {
|
||||||
|
return Routes.docs_queries_path({data_source: this.dataSource})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
run: function(e) {
|
||||||
|
this.running = true
|
||||||
|
this.results = ""
|
||||||
|
this.error = false
|
||||||
|
cancelAllQueries()
|
||||||
|
|
||||||
|
var data = {statement: this.getSQL(), data_source: $("#query_data_source").val(), variables: variableParams}
|
||||||
|
|
||||||
|
var _this = this
|
||||||
|
|
||||||
|
runQuery(data, function (data) {
|
||||||
|
_this.running = false
|
||||||
|
_this.showResults(data)
|
||||||
|
|
||||||
|
errorLine = _this.getErrorLine()
|
||||||
|
if (errorLine) {
|
||||||
|
editor.getSession().addGutterDecoration(errorLine - 1, "error")
|
||||||
|
editor.scrollToLine(errorLine, true, true, function () {})
|
||||||
|
editor.gotoLine(errorLine, 0, true)
|
||||||
|
editor.focus()
|
||||||
|
}
|
||||||
|
}, function (data) {
|
||||||
|
_this.running = false
|
||||||
|
_this.error = true
|
||||||
|
_this.showResults(data)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
cancel: function(e) {
|
||||||
|
this.running = false
|
||||||
|
cancelAllQueries()
|
||||||
|
},
|
||||||
|
updateDataSource: function(dataSource) {
|
||||||
|
this.dataSource = dataSource
|
||||||
|
var selectize = this.selectize
|
||||||
|
selectize.clearOptions()
|
||||||
|
|
||||||
|
if (this.tablesXhr) {
|
||||||
|
this.tablesXhr.abort()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tablesXhr = $.getJSON(Routes.tables_queries_path({data_source: this.dataSource}), function(data) {
|
||||||
|
var newOptions = []
|
||||||
|
for (var i = 0; i < data.length; i++) {
|
||||||
|
var table = data[i]
|
||||||
|
if (typeof table === "object") {
|
||||||
|
newOptions.push({text: table.table, value: table.value})
|
||||||
|
} else {
|
||||||
|
newOptions.push({text: table, value: table})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
selectize.clearOptions()
|
||||||
|
selectize.addOption(newOptions)
|
||||||
|
selectize.refreshOptions(false)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
showEditor: function() {
|
||||||
|
var _this = this
|
||||||
|
|
||||||
|
editor = ace.edit("editor")
|
||||||
|
editor.setTheme("ace/theme/twilight")
|
||||||
|
editor.getSession().setMode("ace/mode/sql")
|
||||||
|
editor.setOptions({
|
||||||
|
enableBasicAutocompletion: false,
|
||||||
|
enableSnippets: false,
|
||||||
|
enableLiveAutocompletion: false,
|
||||||
|
highlightActiveLine: false,
|
||||||
|
fontSize: 12,
|
||||||
|
minLines: 10
|
||||||
|
})
|
||||||
|
editor.renderer.setShowGutter(true)
|
||||||
|
editor.renderer.setPrintMarginColumn(false)
|
||||||
|
editor.renderer.setPadding(10)
|
||||||
|
editor.getSession().setUseWrapMode(true)
|
||||||
|
editor.commands.addCommand({
|
||||||
|
name: "run",
|
||||||
|
bindKey: {win: "Ctrl-Enter", mac: "Command-Enter"},
|
||||||
|
exec: function(editor) {
|
||||||
|
_this.run()
|
||||||
|
},
|
||||||
|
readOnly: false // false if this command should not apply in readOnly mode
|
||||||
|
})
|
||||||
|
// fix command+L
|
||||||
|
editor.commands.removeCommands(["gotoline", "find"])
|
||||||
|
|
||||||
|
this.editor = editor
|
||||||
|
|
||||||
|
editor.getSession().on("change", function () {
|
||||||
|
$("#query_statement").val(editor.getValue())
|
||||||
|
_this.adjustHeight()
|
||||||
|
})
|
||||||
|
this.adjustHeight()
|
||||||
|
editor.focus()
|
||||||
|
},
|
||||||
|
adjustHeight: function() {
|
||||||
|
// https://stackoverflow.com/questions/11584061/
|
||||||
|
var editor = this.editor
|
||||||
|
var lines = editor.getSession().getScreenLength()
|
||||||
|
if (lines < 9) {
|
||||||
|
lines = 9
|
||||||
|
}
|
||||||
|
|
||||||
|
this.editorHeight = ((lines + 1) * 16).toString() + "px"
|
||||||
|
|
||||||
|
Vue.nextTick(function () {
|
||||||
|
editor.resize()
|
||||||
|
})
|
||||||
|
},
|
||||||
|
getSQL: function() {
|
||||||
|
var selectedText = editor.getSelectedText()
|
||||||
|
var text = selectedText.length < 10 ? editor.getValue() : selectedText
|
||||||
|
return text.replace(/\n/g, "\r\n")
|
||||||
|
},
|
||||||
|
getErrorLine: function() {
|
||||||
|
var editor = this.editor
|
||||||
|
var errorLine = this.results.substring(0, 100).includes("alert-danger") && /LINE (\d+)/g.exec(this.results)
|
||||||
|
|
||||||
|
if (errorLine) {
|
||||||
|
errorLine = parseInt(errorLine[1], 10)
|
||||||
|
if (editor.getSelectedText().length >= 10) {
|
||||||
|
errorLine += editor.getSelectionRange().start.row
|
||||||
|
}
|
||||||
|
return errorLine
|
||||||
|
}
|
||||||
|
},
|
||||||
|
showResults(data) {
|
||||||
|
// can't do it the Vue way due to script tags in results
|
||||||
|
// this.results = data
|
||||||
|
|
||||||
|
Vue.nextTick(function () {
|
||||||
|
$("#results-html").html(data)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
var _this = this
|
||||||
|
|
||||||
|
var $select = $("#table_names").selectize({})
|
||||||
|
var selectize = $select[0].selectize
|
||||||
|
selectize.on("change", function(val) {
|
||||||
|
editor.setValue(previewStatement[_this.dataSource].replace("{table}", val), 1)
|
||||||
|
_this.run()
|
||||||
|
selectize.clear(true)
|
||||||
|
selectize.blur()
|
||||||
|
})
|
||||||
|
this.selectize = selectize
|
||||||
|
|
||||||
|
this.updateDataSource($("#query_data_source").val())
|
||||||
|
|
||||||
|
var $dsSelect = $("#query_data_source").selectize({})
|
||||||
|
var dsSelectize = $dsSelect[0].selectize
|
||||||
|
dsSelectize.on("change", function(val) {
|
||||||
|
_this.updateDataSource(val)
|
||||||
|
dsSelectize.blur()
|
||||||
|
})
|
||||||
|
|
||||||
|
this.showEditor()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
168
app/views/blazer/queries/home.html.erb
Normal file
168
app/views/blazer/queries/home.html.erb
Normal file
|
@ -0,0 +1,168 @@
|
||||||
|
<div id="queries">
|
||||||
|
<div id="header">
|
||||||
|
<div class="pull-right" style="line-height: 34px;">
|
||||||
|
<% if blazer_user %>
|
||||||
|
<%= link_to t('.all'), root_path, class: !params[:filter] ? "active" : nil, style: "margin-right: 40px;" %>
|
||||||
|
|
||||||
|
<% if Blazer.audit %>
|
||||||
|
<%= link_to t('.viewed'), root_path(filter: "viewed"), class: params[:filter] == "viewed" ? "active" : nil, style: "margin-right: 40px;" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<%= link_to t('.mine'), root_path(filter: "mine"), class: params[:filter] == "mine" ? "active" : nil, style: "margin-right: 40px;" %>
|
||||||
|
<% end %>
|
||||||
|
|
||||||
|
<div class="btn-group">
|
||||||
|
<%= link_to t('.new_query'), new_query_path, class: "btn btn-info" %>
|
||||||
|
<button type="button" class="btn btn-info dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
|
<span class="caret"></span>
|
||||||
|
<span class="sr-only"><%= t('.toggle_dropdown') %></span>
|
||||||
|
</button>
|
||||||
|
<ul class="dropdown-menu">
|
||||||
|
<li><%= link_to t('.checks'), checks_path %></li>
|
||||||
|
<% if Blazer.uploads? %>
|
||||||
|
<li><%= link_to t('.uploads'), uploads_path %></li>
|
||||||
|
<% end %>
|
||||||
|
<li role="separator" class="divider"></li>
|
||||||
|
<li><%= link_to t('.new_dashboard'), new_dashboard_path %></li>
|
||||||
|
<li><%= link_to t('.new_check'), new_check_path %></li>
|
||||||
|
<li><%= link_to t('.site'), Rails.application.routes.url_helpers.site_path(Site.first || Site.new) %></li>
|
||||||
|
<li><%= link_to t('.users'), Rails.application.routes.url_helpers.users_path %></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<input type="text" v-model="searchTerm" placeholder="<%= t('.placeholder') %>" style="width: 300px; display: inline-block;" v-focus class="search form-control" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table class="table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th><%= t('.name') %></th>
|
||||||
|
<% if Blazer.user_class %>
|
||||||
|
<th style="width: 20%; text-align: right;"><%= t('.mastermind') %></th>
|
||||||
|
<% end%>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody class="list" v-cloak>
|
||||||
|
<tr v-for="query in visibleItems">
|
||||||
|
<td>
|
||||||
|
<a :href="itemPath(query)" :class="{ dashboard: query.dashboard }">{{ query.name }}</a>
|
||||||
|
<span class="vars">{{ query.vars }}</span>
|
||||||
|
</td>
|
||||||
|
<% if Blazer.user_class %>
|
||||||
|
<td class="creator">{{ query.creator }}</td>
|
||||||
|
<% end %>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p v-if="more" class="text-muted"><%= t('.loading') %></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
<%= blazer_js_var "dashboards", @dashboards %>
|
||||||
|
<%= blazer_js_var "queries", @queries %>
|
||||||
|
<%= blazer_js_var "more", @more %>
|
||||||
|
|
||||||
|
var prepareSearch = function (list) {
|
||||||
|
var i, q, searchStr
|
||||||
|
for (i = 0; i < list.length; i++) {
|
||||||
|
q = list[i]
|
||||||
|
searchStr = q.name + q.creator
|
||||||
|
if (q.creator === "You") {
|
||||||
|
searchStr += "mine me"
|
||||||
|
}
|
||||||
|
q.searchStr = prepareQuery(searchStr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var prepareQuery = function (str) {
|
||||||
|
return str.toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
var app = new Vue({
|
||||||
|
el: "#queries",
|
||||||
|
data: {
|
||||||
|
searchTerm: "",
|
||||||
|
more: more,
|
||||||
|
updateCounter: 0
|
||||||
|
},
|
||||||
|
created: function() {
|
||||||
|
this.listItems = dashboards.concat(queries)
|
||||||
|
|
||||||
|
prepareSearch(this.listItems)
|
||||||
|
|
||||||
|
this.queryIds = {}
|
||||||
|
for (i = 0; i < queries.length; i++) {
|
||||||
|
this.queryIds[queries[i].id] = true
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.more) {
|
||||||
|
var _this = this
|
||||||
|
|
||||||
|
$.getJSON(Routes.queries_path(), function (data) {
|
||||||
|
var i, j, newValues, val, size = 500;
|
||||||
|
|
||||||
|
var newValues = []
|
||||||
|
for (j = 0; j < data.length; j++) {
|
||||||
|
val = data[j]
|
||||||
|
if (val && !_this.queryIds[val.id]) {
|
||||||
|
newValues.push(val)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prepareSearch(newValues)
|
||||||
|
|
||||||
|
_this.listItems = _this.listItems.concat(newValues)
|
||||||
|
_this.more = false
|
||||||
|
// hack to get to update
|
||||||
|
_this.updateCounter++
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
visibleItems: function () {
|
||||||
|
// hack to get to update
|
||||||
|
this.updateCounter
|
||||||
|
|
||||||
|
var pageSize = 200
|
||||||
|
var q, i
|
||||||
|
|
||||||
|
if (this.searchTerm.length > 0) {
|
||||||
|
var term = prepareQuery(this.searchTerm)
|
||||||
|
var items = []
|
||||||
|
var fuzzyItems = []
|
||||||
|
for (i = 0; i < this.listItems.length; i++) {
|
||||||
|
q = this.listItems[i]
|
||||||
|
if (q.searchStr.indexOf(term) !== -1) {
|
||||||
|
items.push(q)
|
||||||
|
if (items.length == pageSize) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
} else if (fuzzysearch(term, q.searchStr)) {
|
||||||
|
fuzzyItems.push(q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return items.concat(fuzzyItems).slice(0, pageSize)
|
||||||
|
} else {
|
||||||
|
return this.listItems.slice(0, pageSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
itemPath: function (item) {
|
||||||
|
if (item.dashboard) {
|
||||||
|
return Routes.dashboard_path(item.to_param)
|
||||||
|
} else {
|
||||||
|
return Routes.query_path(item.to_param)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
directives: {
|
||||||
|
focus: {
|
||||||
|
inserted: function (el) {
|
||||||
|
el.focus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
</script>
|
17
app/views/devise/confirmations/new.haml
Normal file
17
app/views/devise/confirmations/new.haml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
= render 'layouts/site'
|
||||||
|
|
||||||
|
%h2= t('.resend_confirmation_instructions')
|
||||||
|
|
||||||
|
= form_for(resource, as: resource_name, url: confirmation_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= render "devise/shared/error_messages", resource: resource
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :email, class: 'form-label'
|
||||||
|
= f.email_field :email, autofocus: true, autocomplete: 'email', value: (resource.pending_reconfirmation? ? resource.unconfirmed_email : resource.email), class: 'form-control', required: true
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.submit t('.resend_confirmation_instructions')
|
||||||
|
|
||||||
|
%div= render 'devise/shared/links'
|
24
app/views/devise/passwords/edit.haml
Normal file
24
app/views/devise/passwords/edit.haml
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
= render 'layouts/site'
|
||||||
|
|
||||||
|
%h2= t('.change_your_password')
|
||||||
|
|
||||||
|
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :put }) do |f|
|
||||||
|
= render 'devise/shared/error_messages', resource: resource
|
||||||
|
= f.hidden_field :reset_password_token
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :password, t('.new_password'), class: 'form-label'
|
||||||
|
= f.password_field :password, autofocus: true, autocomplete: 'new-password', required: true, class: 'form-control'
|
||||||
|
- if @minimum_password_length
|
||||||
|
.form-text= t('devise.shared.minimum_password_length', count: @minimum_password_length)
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :password_confirmation, t('.confirm_new_password'), class: 'form-label'
|
||||||
|
= f.password_field :password_confirmation, autocomplete: 'new-password', required: true, class: 'form-control'
|
||||||
|
|
||||||
|
.mb-4
|
||||||
|
= f.submit t('.change_my_password'), class: 'btn btn-success'
|
||||||
|
|
||||||
|
%div= render 'devise/shared/links'
|
17
app/views/devise/passwords/new.haml
Normal file
17
app/views/devise/passwords/new.haml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
= render 'layouts/site'
|
||||||
|
|
||||||
|
%h2= t('.forgot_your_password')
|
||||||
|
|
||||||
|
= form_for(resource, as: resource_name, url: password_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= render "devise/shared/error_messages", resource: resource
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :email, class: 'form-label'
|
||||||
|
= f.email_field :email, autofocus: true, autocomplete: 'email', required: true, class: 'form-control'
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.submit t('.send_me_reset_password_instructions'), class: 'btn btn-success'
|
||||||
|
|
||||||
|
%div= render "devise/shared/links"
|
19
app/views/devise/sessions/new.haml
Normal file
19
app/views/devise/sessions/new.haml
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
= render 'layouts/site'
|
||||||
|
|
||||||
|
%h2= t('.sign_in')
|
||||||
|
|
||||||
|
= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f|
|
||||||
|
.mb-3
|
||||||
|
= f.label :email, class: 'form-label'
|
||||||
|
= f.email_field :email, autofocus: true, required: true, autocomplete: 'email', class: 'form-control'
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :password, class: 'form-label'
|
||||||
|
= f.password_field :password, required: true, autocomplete: 'password', class: 'form-control'
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.submit t('.sign_in'), class: 'btn btn-success btn-block'
|
||||||
|
|
||||||
|
%div= render 'devise/shared/links'
|
8
app/views/devise/shared/_error_messages.haml
Normal file
8
app/views/devise/shared/_error_messages.haml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
- if resource.errors.any?
|
||||||
|
.alert.alert-primary
|
||||||
|
%h4.alert-heading
|
||||||
|
= I18n.t('errors.messages.not_saved', count: resource.errors.count, resource: resource.class.model_name.human.downcase)
|
||||||
|
|
||||||
|
%ul
|
||||||
|
- resource.errors.full_messages.each do |message|
|
||||||
|
%li= message
|
17
app/views/devise/unlocks/new.haml
Normal file
17
app/views/devise/unlocks/new.haml
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
= render 'layouts/site'
|
||||||
|
|
||||||
|
%h2= t('.resend_unlock_instructions')
|
||||||
|
|
||||||
|
= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f|
|
||||||
|
= render 'devise/shared/error_messages', resource: resource
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :email, class: 'form-label'
|
||||||
|
= f.email_field :email, autofocus: true, autocomplete: 'email', required: true, class: 'form-control'
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.submit t('.resend_unlock_instructions'), class: 'btn btn-success'
|
||||||
|
|
||||||
|
= render 'devise/shared/links'
|
5
app/views/layouts/_site.haml
Normal file
5
app/views/layouts/_site.haml
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
- if (site = Site.first)
|
||||||
|
- if site.logo
|
||||||
|
= image_tag url_for(site.logo)
|
||||||
|
|
||||||
|
%h1= site.title
|
15
app/views/sites/show.haml
Normal file
15
app/views/sites/show.haml
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
= render 'layouts/site'
|
||||||
|
|
||||||
|
= form_for @site do |f|
|
||||||
|
.mb-3
|
||||||
|
= f.label :title, class: 'form-label'
|
||||||
|
= f.text_field :title, class: 'form-control', required: true
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.label :logo, class: 'form-label'
|
||||||
|
= f.file_field :logo, class: 'form-control'
|
||||||
|
|
||||||
|
.mb-3
|
||||||
|
= f.submit class: 'btn btn-success'
|
27
app/views/users/index.haml
Normal file
27
app/views/users/index.haml
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
%section.w-100.min-vh-100.d-flex.align-items-center.justify-content-center
|
||||||
|
%div
|
||||||
|
%nav
|
||||||
|
= link_to t('.back'), root_path, class: 'btn btn-info mb-3'
|
||||||
|
|
||||||
|
%table.table
|
||||||
|
%thead
|
||||||
|
-# Esto no es HTML5 estándar pero al parecer funciona
|
||||||
|
= form_for @user do |f|
|
||||||
|
%tr
|
||||||
|
%td{ colspan: 3 }
|
||||||
|
= f.label :email, class: 'visually-hidden'
|
||||||
|
= f.email_field :email, class: 'form-control', placeholder: t('.email'), required: true
|
||||||
|
%td= f.submit t('.create'), class: 'btn btn-success'
|
||||||
|
%tr
|
||||||
|
%th= t('.email')
|
||||||
|
%th= t('.created_by')
|
||||||
|
%th= t('.created')
|
||||||
|
%th= t('.actions')
|
||||||
|
%tbody
|
||||||
|
|
||||||
|
- @users.each do |user|
|
||||||
|
%tr
|
||||||
|
%th= user.email
|
||||||
|
%td= user.created_by.try :email
|
||||||
|
%td.text-center= user.created.count
|
||||||
|
%td= link_to t('.destroy'), user_path(user), method: :delete, class: 'btn btn-danger', data: { confirm: t('.confirm') }
|
|
@ -5,7 +5,7 @@ require "rails"
|
||||||
require "active_model/railtie"
|
require "active_model/railtie"
|
||||||
require "active_job/railtie"
|
require "active_job/railtie"
|
||||||
require "active_record/railtie"
|
require "active_record/railtie"
|
||||||
# require "active_storage/engine"
|
require "active_storage/engine"
|
||||||
require "action_controller/railtie"
|
require "action_controller/railtie"
|
||||||
require "action_mailer/railtie"
|
require "action_mailer/railtie"
|
||||||
# require "action_mailbox/engine"
|
# require "action_mailbox/engine"
|
||||||
|
@ -31,5 +31,6 @@ module Ectomobile
|
||||||
#
|
#
|
||||||
# config.time_zone = "Central Time (US & Canada)"
|
# config.time_zone = "Central Time (US & Canada)"
|
||||||
# config.eager_load_paths << Rails.root.join("extras")
|
# config.eager_load_paths << Rails.root.join("extras")
|
||||||
|
config.active_storage.service = :local
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
6
config/initializers/locale.rb
Normal file
6
config/initializers/locale.rb
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
Rails.application.configure do
|
||||||
|
config.i18n.available_locales = %i[es en]
|
||||||
|
config.i18n.default_locale = :es
|
||||||
|
end
|
51
config/locales/es.yml
Normal file
51
config/locales/es.yml
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
es:
|
||||||
|
activerecord:
|
||||||
|
models:
|
||||||
|
query: Consulta
|
||||||
|
attributes:
|
||||||
|
query:
|
||||||
|
name: Nombre
|
||||||
|
description: Descripción
|
||||||
|
blazer:
|
||||||
|
queries:
|
||||||
|
home:
|
||||||
|
all: Todas
|
||||||
|
viewed: Vistas
|
||||||
|
mine: Mías
|
||||||
|
new_query: Crear consulta
|
||||||
|
toggle_dropdown: Desplegar opciones
|
||||||
|
checks: Alertas
|
||||||
|
uploads: Subida de archivos
|
||||||
|
new_dashboard: Crear resumen
|
||||||
|
new_check: Crear alerta
|
||||||
|
placeholder: Empieza a escribir para encontrar
|
||||||
|
name: Nombre
|
||||||
|
mastermind: Editorx
|
||||||
|
loading: Cargando...
|
||||||
|
new:
|
||||||
|
new_query: Crear consulta
|
||||||
|
form:
|
||||||
|
back: Volver
|
||||||
|
docs: Documentación
|
||||||
|
schema: Esquema
|
||||||
|
preview_table: Previsualizar la tabla
|
||||||
|
run: Resultados
|
||||||
|
cancel: Cancelar
|
||||||
|
optional: Opcional
|
||||||
|
delete: Eliminar
|
||||||
|
are_you_sure: ¿Confirmas que quieres eliminar esta consulta?
|
||||||
|
fork: Clonar
|
||||||
|
update: Guardar cambios
|
||||||
|
create: Guardar
|
||||||
|
part_of: Es parte de %{words}. Cualquier cambio puede afectarlas.
|
||||||
|
loading: Cargando...
|
||||||
|
users:
|
||||||
|
index:
|
||||||
|
email: Correo electrónico
|
||||||
|
create: Crear usuarix
|
||||||
|
destroy: Quitar acceso
|
||||||
|
confirm: ¿Confirmas?
|
||||||
|
back: Volver
|
||||||
|
actions: Acciones
|
||||||
|
created_by: Invitadx por
|
||||||
|
created: Invitadxs
|
|
@ -6,4 +6,5 @@ Rails.application.routes.draw do
|
||||||
mount Blazer::Engine, at: 'blazer'
|
mount Blazer::Engine, at: 'blazer'
|
||||||
|
|
||||||
resources :readings, only: %i[create]
|
resources :readings, only: %i[create]
|
||||||
|
resources :sites, only: %i[show create update]
|
||||||
end
|
end
|
||||||
|
|
4
config/storage.yml
Normal file
4
config/storage.yml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
local:
|
||||||
|
service: Disk
|
||||||
|
public: true
|
||||||
|
root: <%= Rails.root.join('storage') %>
|
11
db/migrate/20220514222253_create_site.rb
Normal file
11
db/migrate/20220514222253_create_site.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
# Configuración del sitio
|
||||||
|
class CreateSite < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
create_table :sites do |t|
|
||||||
|
t.timestamps
|
||||||
|
t.string :title, null: false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
# This migration comes from active_storage (originally 20170806125915)
|
||||||
|
class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
|
||||||
|
def change
|
||||||
|
create_table :active_storage_blobs do |t|
|
||||||
|
t.string :key, null: false
|
||||||
|
t.string :filename, null: false
|
||||||
|
t.string :content_type
|
||||||
|
t.text :metadata
|
||||||
|
t.string :service_name, null: false
|
||||||
|
t.bigint :byte_size, null: false
|
||||||
|
t.string :checksum, null: false
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
|
||||||
|
t.index [ :key ], unique: true
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :active_storage_attachments do |t|
|
||||||
|
t.string :name, null: false
|
||||||
|
t.references :record, null: false, polymorphic: true, index: false
|
||||||
|
t.references :blob, null: false
|
||||||
|
|
||||||
|
t.datetime :created_at, null: false
|
||||||
|
|
||||||
|
t.index [ :record_type, :record_id, :name, :blob_id ], name: "index_active_storage_attachments_uniqueness", unique: true
|
||||||
|
t.foreign_key :active_storage_blobs, column: :blob_id
|
||||||
|
end
|
||||||
|
|
||||||
|
create_table :active_storage_variant_records do |t|
|
||||||
|
t.belongs_to :blob, null: false, index: false
|
||||||
|
t.string :variation_digest, null: false
|
||||||
|
|
||||||
|
t.index %i[ blob_id variation_digest ], name: "index_active_storage_variant_records_uniqueness", unique: true
|
||||||
|
t.foreign_key :active_storage_blobs, column: :blob_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
11
db/migrate/20220608141004_change_value_to_decimal.rb
Normal file
11
db/migrate/20220608141004_change_value_to_decimal.rb
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class ChangeValueToDecimal < ActiveRecord::Migration[6.1]
|
||||||
|
def up
|
||||||
|
change_column :sensors, :value, :decimal, precision: 10
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
change_column :sensors, :value, :integer
|
||||||
|
end
|
||||||
|
end
|
7
db/migrate/20220611152100_add_created_by_to_users.rb
Normal file
7
db/migrate/20220611152100_add_created_by_to_users.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddCreatedByToUsers < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_belongs_to :users, :created_by, index: true
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue