ditty 0.9.1 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.env.test +2 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +23 -4
- data/.travis.yml +2 -7
- data/Gemfile.ci +0 -15
- data/ditty.gemspec +19 -15
- data/lib/ditty.rb +2 -2
- data/lib/ditty/cli.rb +5 -0
- data/lib/ditty/components/ditty.rb +4 -7
- data/lib/ditty/controllers/application_controller.rb +6 -5
- data/lib/ditty/controllers/audit_logs_controller.rb +2 -0
- data/lib/ditty/controllers/auth_controller.rb +5 -2
- data/lib/ditty/controllers/component_controller.rb +3 -3
- data/lib/ditty/controllers/user_login_traits_controller.rb +28 -1
- data/lib/ditty/controllers/users_controller.rb +3 -2
- data/lib/ditty/db.rb +4 -3
- data/lib/ditty/emails/base.rb +32 -30
- data/lib/ditty/generators/crud_generator.rb +51 -41
- data/lib/ditty/generators/project_generator.rb +1 -0
- data/lib/ditty/helpers/pundit.rb +4 -4
- data/lib/ditty/helpers/response.rb +6 -11
- data/lib/ditty/helpers/views.rb +21 -3
- data/lib/ditty/listener.rb +1 -1
- data/lib/ditty/models/base.rb +5 -0
- data/lib/ditty/models/identity.rb +7 -7
- data/lib/ditty/models/user.rb +9 -1
- data/lib/ditty/policies/user_policy.rb +1 -1
- data/lib/ditty/services/authentication.rb +19 -9
- data/lib/ditty/services/email.rb +13 -13
- data/lib/ditty/services/logger.rb +26 -20
- data/lib/ditty/services/pagination_wrapper.rb +7 -5
- data/lib/ditty/services/settings.rb +7 -6
- data/lib/ditty/tasks/ditty.rake +2 -1
- data/lib/ditty/templates/application.rb +1 -1
- data/lib/ditty/templates/config.ru +2 -2
- data/lib/ditty/templates/controller.rb.erb +7 -1
- data/{public → lib/ditty/templates/public}/browserconfig.xml +0 -0
- data/{public → lib/ditty/templates/public}/css/styles.css +0 -0
- data/lib/ditty/templates/public/favicon.ico +0 -0
- data/{public → lib/ditty/templates/public}/images/apple-icon.png +0 -0
- data/{public → lib/ditty/templates/public}/images/favicon-16x16.png +0 -0
- data/{public → lib/ditty/templates/public}/images/favicon-32x32.png +0 -0
- data/{public → lib/ditty/templates/public}/images/launcher-icon-1x.png +0 -0
- data/{public → lib/ditty/templates/public}/images/launcher-icon-2x.png +0 -0
- data/{public → lib/ditty/templates/public}/images/launcher-icon-4x.png +0 -0
- data/{public → lib/ditty/templates/public}/images/mstile-150x150.png +0 -0
- data/{public → lib/ditty/templates/public}/images/safari-pinned-tab.svg +0 -0
- data/{public → lib/ditty/templates/public}/js/scripts.js +0 -0
- data/{public/manifest.json → lib/ditty/templates/public/manifest.json.erb} +2 -2
- data/lib/ditty/templates/settings.yml.erb +1 -0
- data/lib/ditty/templates/spec_helper.rb +1 -1
- data/lib/ditty/templates/views/display.haml.tt +1 -1
- data/lib/ditty/templates/views/edit.haml.tt +1 -1
- data/lib/ditty/templates/views/index.haml.tt +1 -1
- data/lib/ditty/templates/views/new.haml.tt +1 -1
- data/lib/ditty/version.rb +1 -1
- data/spec/ditty/api_spec.rb +1 -1
- data/spec/ditty/emails/base_spec.rb +3 -3
- data/spec/ditty/emails/forgot_password_spec.rb +3 -2
- data/spec/ditty/models/user_spec.rb +3 -3
- data/spec/ditty/services/logger_spec.rb +7 -6
- data/spec/ditty/services/settings_spec.rb +2 -2
- data/spec/factories.rb +4 -4
- data/spec/spec_helper.rb +5 -1
- data/views/403.haml +1 -1
- data/views/500.haml +11 -0
- data/views/audit_logs/index.haml +12 -11
- data/views/auth/forgot_password.haml +29 -24
- data/views/auth/ldap.haml +1 -1
- data/views/auth/login.haml +3 -2
- data/views/auth/register.haml +3 -2
- data/views/auth/reset_password.haml +36 -19
- data/views/blank.haml +1 -0
- data/views/embedded.haml +17 -11
- data/views/layout.haml +16 -8
- data/views/partials/actions.haml +15 -14
- data/views/partials/filter_control.haml +1 -1
- data/views/partials/footer.haml +10 -2
- data/views/partials/form_tag.haml +1 -1
- data/views/partials/navitems.haml +25 -27
- data/views/partials/pager.haml +44 -25
- data/views/partials/search.haml +14 -9
- data/views/partials/sidebar.haml +2 -2
- data/views/partials/sort_ui.haml +2 -0
- data/views/partials/timespan_selector.haml +64 -0
- data/views/partials/topbar.haml +0 -15
- data/views/partials/user_associations.haml +32 -0
- data/views/quick_start.haml +23 -0
- data/views/roles/display.haml +3 -3
- data/views/roles/edit.haml +1 -1
- data/views/roles/index.haml +2 -2
- data/views/roles/new.haml +1 -1
- data/views/user_login_traits/display.haml +1 -1
- data/views/user_login_traits/edit.haml +1 -1
- data/views/user_login_traits/index.haml +23 -25
- data/views/user_login_traits/new.haml +1 -1
- data/views/users/display.haml +5 -5
- data/views/users/edit.haml +1 -1
- data/views/users/index.haml +5 -5
- data/views/users/login_traits.haml +2 -2
- data/views/users/new.haml +1 -1
- data/views/users/profile.haml +4 -4
- data/views/users/user.haml +1 -1
- metadata +116 -54
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'dotenv'
|
4
|
+
Dotenv.load('.env.test')
|
5
|
+
Dotenv.overload('.env.test.local')
|
6
|
+
|
3
7
|
ENV['APP_ENV'] ||= 'test'
|
4
8
|
ENV['RACK_ENV'] ||= 'test'
|
5
9
|
require 'simplecov'
|
@@ -16,7 +20,7 @@ require 'database_cleaner'
|
|
16
20
|
require 'timecop'
|
17
21
|
|
18
22
|
if ENV['DATABASE_URL'] == 'sqlite::memory:'
|
19
|
-
folder = File.expand_path(File.dirname(__FILE__)
|
23
|
+
folder = File.expand_path("#{File.dirname(__FILE__)}/../migrate")
|
20
24
|
Sequel.extension :migration
|
21
25
|
Sequel::Migrator.apply(DB, folder)
|
22
26
|
|
data/views/403.haml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
|
-
%p.lead
|
1
|
+
%p.lead.text-center
|
2
2
|
Your user is not allowed access to the requested URL.
|
data/views/500.haml
ADDED
data/views/audit_logs/index.haml
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
= haml :'partials/search'
|
2
1
|
.row
|
3
|
-
.col-12
|
2
|
+
.col-md-12
|
3
|
+
= haml :'partials/search'
|
4
4
|
%table.table.table-striped.table-bordered.table-hover
|
5
5
|
%thead.thead-dark
|
6
6
|
%tr
|
7
|
-
%th User
|
8
|
-
%th Action
|
9
|
-
%th Details
|
10
|
-
%th IP Address
|
11
|
-
%th Browser
|
12
|
-
%th Device
|
13
|
-
%th Platform
|
14
|
-
%th Created
|
7
|
+
%th= "User #{sort_ui(:user)}"
|
8
|
+
%th= "Action #{sort_ui(:action)}"
|
9
|
+
%th= "Details #{sort_ui(:details)}"
|
10
|
+
%th= "IP Address #{sort_ui(:ip_address)}"
|
11
|
+
%th= "Browser #{sort_ui(:browser)}"
|
12
|
+
%th= "Device #{sort_ui(:device)}"
|
13
|
+
%th= "Platform #{sort_ui(:platform)}"
|
14
|
+
%th= "Created At #{sort_ui(:created_at)}"
|
15
15
|
%tbody
|
16
16
|
- if list.count > 0
|
17
17
|
- list.all.each do |entity|
|
@@ -32,4 +32,5 @@
|
|
32
32
|
%tr
|
33
33
|
%td.text-center{ colspan: 4 } No records
|
34
34
|
|
35
|
-
|
35
|
+
- if list.count > 0
|
36
|
+
= pagination(list, base_path)
|
@@ -1,27 +1,32 @@
|
|
1
1
|
.container
|
2
|
-
|
3
|
-
.card-body.p-0
|
4
|
-
/ Nested Row within Card Body
|
5
|
-
.row
|
6
|
-
.col-lg-6.d-none.d-lg-block.bg-password-image
|
7
|
-
.col-lg-6
|
8
|
-
.p-5
|
9
|
-
.text-center
|
10
|
-
%h1.h4.text-gray-900.mb-2
|
11
|
-
Forgot Your Password?
|
12
|
-
%p.mb-4
|
13
|
-
We get it, stuff happens. Just enter your email address below and we'll send you a link to reset your password!
|
14
|
-
= form_tag("#{settings.map_path}/auth/forgot-password", attributes: { class: 'user' }) do
|
15
|
-
.form-group
|
16
|
-
%input.form-control.form-control-user{ type: 'email', placeholder: 'Enter Email Address...' }
|
17
|
-
%button.btn.btn-primary.btn-user.btn-block{ type: 'submit' }
|
18
|
-
Reset Password
|
19
|
-
%hr
|
20
|
-
- if policy(::Ditty::User).register?
|
21
|
-
.text-center
|
22
|
-
%a.small{ href: "#{settings.map_path}/auth/register" } Create an Account!
|
23
|
-
.text-center
|
24
|
-
%a.small{ href: "#{settings.map_path}/auth/login" } Already have an account? Login!
|
25
|
-
|
2
|
+
/ Outer Row
|
26
3
|
.row.justify-content-center
|
27
4
|
.col-xl-10.col-lg-12.col-md-9
|
5
|
+
.card.card-default.o-hidden.border-0.shadow-lg.my-5
|
6
|
+
.card-body.p-0
|
7
|
+
/ Nested Row within Card Body
|
8
|
+
.row
|
9
|
+
.col-lg-6.d-none.d-lg-block.bg-password-image
|
10
|
+
.col-lg-6
|
11
|
+
.p-5
|
12
|
+
.text-center
|
13
|
+
%h1.h4.text-gray-900.mb-2
|
14
|
+
Forgot Your Password?
|
15
|
+
%p.mb-4
|
16
|
+
We get it, stuff happens. Just enter your email address below and we'll send you a link to reset your password!
|
17
|
+
.small
|
18
|
+
= haml :'partials/notifications'
|
19
|
+
= form_tag("#{settings.map_path}/auth/forgot-password", attributes: { class: 'user' }) do
|
20
|
+
.form-group
|
21
|
+
%input.form-control.form-control-user{ name: 'email', type: 'email', placeholder: 'Enter Email Address...' }
|
22
|
+
%button.btn.btn-primary.btn-user.btn-block{ type: 'submit' }
|
23
|
+
Reset Password
|
24
|
+
%hr
|
25
|
+
- if policy(::Ditty::User).register?
|
26
|
+
.text-center
|
27
|
+
%a.small{ href: "#{settings.map_path}/auth/register" } Create an Account!
|
28
|
+
.text-center
|
29
|
+
%a.small{ href: "#{settings.map_path}/auth/login" } Already have an account? Login!
|
30
|
+
|
31
|
+
.row.justify-content-center
|
32
|
+
.col-xl-10.col-lg-12.col-md-9
|
data/views/auth/ldap.haml
CHANGED
data/views/auth/login.haml
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
/ Outer Row
|
3
3
|
.row.justify-content-center
|
4
4
|
.col-xl-10.col-lg-12.col-md-9
|
5
|
-
.card.o-hidden.border-0.shadow-lg.my-5
|
5
|
+
.card.card-default.o-hidden.border-0.shadow-lg.my-5
|
6
6
|
.card-body.p-0
|
7
7
|
/ Nested Row within Card Body
|
8
8
|
.row
|
@@ -11,6 +11,8 @@
|
|
11
11
|
.p-5
|
12
12
|
.text-center
|
13
13
|
%h1.h4.text-gray-900.mb-4 Welcome Back!
|
14
|
+
.small
|
15
|
+
= haml :'partials/notifications'
|
14
16
|
- ::Ditty::Services::Authentication.providers.each do |name|
|
15
17
|
- provider = ::Ditty::Services::Authentication[name]
|
16
18
|
- next if provider[:login_prompt].nil?
|
@@ -18,6 +20,5 @@
|
|
18
20
|
%a.btn.btn-block.btn-secondary{ href: "#{settings.map_path}/auth/#{name}" }
|
19
21
|
%i.fab.fw{ class: "fa-#{provider[:icon] || 'key'}"}
|
20
22
|
= provider[:login_prompt]
|
21
|
-
= haml :'partials/notifications'
|
22
23
|
- if ::Ditty::Services::Authentication.provides? 'identity'
|
23
24
|
= haml :'auth/identity'
|
data/views/auth/register.haml
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
.container
|
2
|
-
.card.o-hidden.border-0.shadow-lg.my-5
|
2
|
+
.card.card-default.o-hidden.border-0.shadow-lg.my-5
|
3
3
|
.card-body.p-0
|
4
4
|
/ Nested Row within Card Body
|
5
5
|
.row
|
@@ -8,7 +8,8 @@
|
|
8
8
|
.p-5
|
9
9
|
.text-center
|
10
10
|
%h1.h4.text-gray-900.mb-4 Create an Account!
|
11
|
-
|
11
|
+
.small
|
12
|
+
= haml :'partials/notifications'
|
12
13
|
- ::Ditty::Services::Authentication.providers.each do |name|
|
13
14
|
- provider = ::Ditty::Services::Authentication[name]
|
14
15
|
- next if provider[:register_prompt].nil?
|
@@ -1,19 +1,36 @@
|
|
1
|
-
.
|
2
|
-
|
3
|
-
.
|
4
|
-
.
|
5
|
-
.card-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
.
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
1
|
+
.container
|
2
|
+
/ Outer Row
|
3
|
+
.row.justify-content-center
|
4
|
+
.col-xl-10.col-lg-12.col-md-9
|
5
|
+
.card.card-default.o-hidden.border-0.shadow-lg.my-5
|
6
|
+
.card-body.p-0
|
7
|
+
/ Nested Row within Card Body
|
8
|
+
.row
|
9
|
+
.col-lg-6.d-none.d-lg-block.bg-password-image
|
10
|
+
.col-lg-6
|
11
|
+
.p-5
|
12
|
+
.text-center
|
13
|
+
%h1.h4.text-gray-900.mb-2
|
14
|
+
Reset your Password
|
15
|
+
= edit_form_tag("#{settings.map_path}/auth/reset-password") do
|
16
|
+
%input{ name: 'token', value: params[:token], type: 'hidden' }
|
17
|
+
- if identity.errors[:password] && identity.errors[:password].include?('is not strong enough')
|
18
|
+
.alert.alert-warning
|
19
|
+
%p Make sure your password is at least 8 characters long, and including the following
|
20
|
+
%ul
|
21
|
+
%li Upper- and lowercase letters
|
22
|
+
%li Numbers
|
23
|
+
%li Special Characters
|
24
|
+
= form_control(:password, identity, type: 'password', placeholder: 'Your password', group: 'identity')
|
25
|
+
= form_control(:password_confirmation, identity, type: 'password', label: 'Confirm Password', placeholder: 'Confirm your password', group: 'identity')
|
26
|
+
%button.btn.btn-primary{ type: 'submit' }
|
27
|
+
Reset Password
|
28
|
+
%hr
|
29
|
+
- if policy(::Ditty::User).register?
|
30
|
+
.text-center
|
31
|
+
%a.small{ href: "#{settings.map_path}/auth/register" } Create an Account!
|
32
|
+
.text-center
|
33
|
+
%a.small{ href: "#{settings.map_path}/auth/login" } Already have an account? Login!
|
34
|
+
|
35
|
+
.row.justify-content-center
|
36
|
+
.col-xl-10.col-lg-12.col-md-9
|
data/views/blank.haml
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
%meta{ 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=edge,chrome=1' }
|
6
6
|
%meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
7
7
|
%meta{ name: 'theme-color', content: '#ffffff' }
|
8
|
+
= Rack::Csrf.csrf_metatag(env)
|
8
9
|
%link{ rel: 'manifest', href: '/manifest.json' }
|
9
10
|
%link{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '/images/favicon-32x32.png' }
|
10
11
|
%link{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '/images/favicon-16x16.png' }
|
data/views/embedded.haml
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
%meta{ 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=edge,chrome=1' }
|
6
6
|
%meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
7
7
|
%meta{ name: 'theme-color', content: '#ffffff' }
|
8
|
+
= Rack::Csrf.csrf_metatag(env)
|
8
9
|
%link{ rel: 'manifest', href: '/manifest.json' }
|
9
10
|
%link{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '#{request.base_url}/images/favicon-32x32.png' }
|
10
11
|
%link{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '#{request.base_url}/images/favicon-16x16.png' }
|
@@ -20,14 +21,9 @@
|
|
20
21
|
%meta{ name: 'author', content: '' }
|
21
22
|
|
22
23
|
/ Le styles
|
23
|
-
%link{ rel: 'stylesheet', href: '
|
24
|
-
%link{ rel: 'stylesheet', href: '
|
25
|
-
%link{ rel: 'stylesheet', href: 'https://
|
26
|
-
/[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
27
|
-
/[if lt IE 9] <script src="https://cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
|
28
|
-
|
29
|
-
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.0/jquery.min.js' }
|
30
|
-
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/startbootstrap-sb-admin-2/3.3.7+1/js/sb-admin-2.min.js' }
|
24
|
+
%link{ rel: 'stylesheet', href: '/css/sb-admin-2.min.css', media: 'screen' }
|
25
|
+
%link{ rel: 'stylesheet', href: '/css/styles.css', media: 'screen' }
|
26
|
+
%link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css', media: 'screen' }
|
31
27
|
%body
|
32
28
|
.container-fluid
|
33
29
|
.row
|
@@ -37,6 +33,16 @@
|
|
37
33
|
= yield
|
38
34
|
|
39
35
|
/ Placed at the end of the document so the pages load faster
|
40
|
-
%script{ type: 'text/javascript', src: 'https://
|
41
|
-
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/
|
42
|
-
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/
|
36
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js' }
|
37
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js' }
|
38
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js' }
|
39
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js' }
|
40
|
+
/ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js' }
|
41
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js' }
|
42
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/select2/4.0.7/js/select2.min.js' }
|
43
|
+
%script{ type: 'text/javascript', src: '/js/sb-admin-2.min.js' }
|
44
|
+
%script{ type: 'text/javascript', src: '/js/scripts.js' }
|
45
|
+
:javascript
|
46
|
+
$(function() {
|
47
|
+
$('.select2').select2();
|
48
|
+
});
|
data/views/layout.haml
CHANGED
@@ -5,6 +5,7 @@
|
|
5
5
|
%meta{ 'http-equiv' => 'X-UA-Compatible', 'content' => 'IE=edge,chrome=1' }
|
6
6
|
%meta{ name: 'viewport', content: 'width=device-width, initial-scale=1' }
|
7
7
|
%meta{ name: 'theme-color', content: '#ffffff' }
|
8
|
+
= Rack::Csrf.csrf_metatag(env)
|
8
9
|
%link{ rel: 'manifest', href: '/manifest.json' }
|
9
10
|
%link{ rel: 'icon', type: 'image/png', sizes: '32x32', href: '/images/favicon-32x32.png' }
|
10
11
|
%link{ rel: 'icon', type: 'image/png', sizes: '16x16', href: '/images/favicon-16x16.png' }
|
@@ -24,6 +25,20 @@
|
|
24
25
|
%link{ rel: 'stylesheet', href: '/css/styles.css', media: 'screen' }
|
25
26
|
%link{ rel: 'stylesheet', href: 'https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.8.2/css/all.min.css', media: 'screen' }
|
26
27
|
%body#page-top
|
28
|
+
/ Logout Modal
|
29
|
+
#logoutModal.modal.fade{ tabindex: -1, role: 'dialog', 'aria-hidden': 'true' }
|
30
|
+
.modal-dialog{ role: 'document' }
|
31
|
+
.modal-content
|
32
|
+
.modal-header
|
33
|
+
%h5.modal-title Ready to Leave?
|
34
|
+
%button.close{ type: 'button', 'data-dismiss': 'modal', 'aria-label': 'Close' }
|
35
|
+
%span{ 'aria-hidden': 'true' } ×
|
36
|
+
.modal-body
|
37
|
+
Select "Logout" below if you are ready to end your current session.
|
38
|
+
.modal-footer
|
39
|
+
%button.btn.btn-secondary{ type: 'button', 'data-dismiss': 'modal' } Cancel
|
40
|
+
= delete_form_tag("#{settings.map_path}/auth") do
|
41
|
+
%button.btn.btn-primary{ type: 'submit' } Logout
|
27
42
|
/ Page Wrapper
|
28
43
|
#wrapper
|
29
44
|
= haml :'partials/sidebar', locals: { title: (defined?(title) ? title : 'Ditty') }
|
@@ -36,14 +51,6 @@
|
|
36
51
|
/ .row
|
37
52
|
/ .col-md-12
|
38
53
|
= haml :'partials/notifications'
|
39
|
-
- if defined?(title) || defined?(actions)
|
40
|
-
.row
|
41
|
-
.col-md-9
|
42
|
-
%h1.text-dark.mb-2= defined?(title) ? title : ' '
|
43
|
-
.col-md-3.text-right.mt-1
|
44
|
-
= haml :'partials/actions', locals: { actions: defined?(actions) ? actions : {} }
|
45
|
-
- else
|
46
|
-
%div{ style: 'padding-top: 20px' }
|
47
54
|
|
48
55
|
= yield
|
49
56
|
|
@@ -56,6 +63,7 @@
|
|
56
63
|
/ Placed at the end of the document so the pages load faster
|
57
64
|
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery/3.4.1/jquery.min.js' }
|
58
65
|
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.3.1/js/bootstrap.min.js' }
|
66
|
+
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js' }
|
59
67
|
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js' }
|
60
68
|
/ %script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/react/16.8.6/umd/react.production.min.js' }
|
61
69
|
%script{ type: 'text/javascript', src: 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.8.0/Chart.min.js' }
|
data/views/partials/actions.haml
CHANGED
@@ -1,14 +1,15 @@
|
|
1
|
-
- if actions
|
2
|
-
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
%
|
7
|
-
|
8
|
-
|
9
|
-
-
|
10
|
-
|
11
|
-
%
|
12
|
-
|
13
|
-
-actions.
|
14
|
-
|
1
|
+
- if defined?(actions)
|
2
|
+
- if actions.count > 1
|
3
|
+
- link, text = actions.shift
|
4
|
+
.btn-group.text-right
|
5
|
+
%a.btn.btn-primary{ href: link }= text
|
6
|
+
%button.btn.btn-primary.dropdown-toggle{ type: 'button', id: 'actions-toggle', data: { toggle: 'dropdown' } }
|
7
|
+
%span.caret
|
8
|
+
%span.sr-only Toggle Dropdown
|
9
|
+
%ul.dropdown-menu{ 'aria-labelledby': 'actions-toggle' }
|
10
|
+
-actions.each do |k, v|
|
11
|
+
%li
|
12
|
+
%a{ href: k }= v
|
13
|
+
- elsif actions.count > 0
|
14
|
+
-actions.each do |k, v|
|
15
|
+
%a.btn.btn-primary{ href: k }= v
|
@@ -1,6 +1,6 @@
|
|
1
1
|
.form-group{ class: total_filters.to_i > 4 ? 'col-3' : 'col-md'}
|
2
2
|
%label{ for: "filter_#{name}" }= label
|
3
|
-
%select.form-control{ name: name, id: "filter_#{name}" }
|
3
|
+
%select.form-control.select2{ style: 'width: 100%', name: name, id: "filter_#{name}" }
|
4
4
|
%option{ value: '' } -- Select One --
|
5
5
|
- options.each do |k,v| k ||= v; v ||= k;
|
6
6
|
%option{ value: k, selected: (params[name].eql? k)}= v
|
data/views/partials/footer.haml
CHANGED
@@ -1,5 +1,13 @@
|
|
1
1
|
/ Footer
|
2
2
|
%footer.sticky-footer.bg-light
|
3
3
|
.container.my-auto
|
4
|
-
|
5
|
-
|
4
|
+
-if ENV['SKIP_BRANDING'].blank?
|
5
|
+
.copyright.text-center.my-auto.text-dark
|
6
|
+
%p
|
7
|
+
Copyright ©
|
8
|
+
%a{ href: 'https://hackerpla.net/requestd', target: '_blank' }
|
9
|
+
HackerPlanet
|
10
|
+
2020
|
11
|
+
%p.mb-0
|
12
|
+
%a{ href: 'https://hackerpla.net/requestd', target: '_blank' }
|
13
|
+
%img.rounded{ src: 'http://hackerpla.net/wp-content/uploads/2014/07/HP_1C_128x128.png', height: 60 }
|
@@ -1,5 +1,5 @@
|
|
1
1
|
%form{ { method: %i[get post].include?(form_verb.to_sym) ? form_verb : :post, action: url }.merge(attributes) }
|
2
|
-
= Rack::Csrf.csrf_tag(env) unless ENV['APP_ENV'] == 'test'
|
2
|
+
= Rack::Csrf.csrf_tag(env) unless form_verb.to_sym == :get || ENV['APP_ENV'] == 'test'
|
3
3
|
- if form_verb.to_sym == :get && layout
|
4
4
|
%input{ name: 'layout', value: layout, type: 'hidden' }
|
5
5
|
- if %i[get post].include?(form_verb.to_sym) == false
|
@@ -1,31 +1,29 @@
|
|
1
1
|
- if authenticated?
|
2
|
-
- Ditty::Components.
|
3
|
-
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
-
|
17
|
-
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
%span= item[:text]
|
28
|
-
%hr.sidebar-divider
|
2
|
+
- Ditty::Components.navigation(request).each do |item|
|
3
|
+
- if item[:type] == 'divider'
|
4
|
+
%hr.sidebar-divider.my-0
|
5
|
+
- elsif item[:target].nil? || policy(item[:target]).list?
|
6
|
+
- if item[:group]
|
7
|
+
%li.nav-item
|
8
|
+
%a.nav-link.collapsed{ href: '#', 'data-toggle': 'collapse', 'data-target': "##{item[:group].parameterize}", 'aria-expanded': 'true', 'aria-controls': item[:group].parameterize }
|
9
|
+
- if item[:icon]
|
10
|
+
%i.fas.fa-fw{ class: "fa-#{item[:icon]}" }
|
11
|
+
%span= item[:group]
|
12
|
+
.collapse{ id: item[:group].parameterize, 'data-parent': '#accordionSidebar' }
|
13
|
+
.bg-white.py-2.collapse-inner.rounded
|
14
|
+
- item[:items].each do |sub_item|
|
15
|
+
- next unless sub_item[:target] && policy(sub_item[:target]).list?
|
16
|
+
%a.collapse-item{ href: "#{settings.map_path}#{sub_item[:link]}" }
|
17
|
+
- if sub_item[:icon]
|
18
|
+
%i.fa.fa-fw{ class: "fa-#{sub_item[:icon]}" }
|
19
|
+
= sub_item[:text]
|
20
|
+
- else
|
21
|
+
%li.nav-item
|
22
|
+
%a.nav-link{ href: "#{settings.map_path}#{item[:link]}" }
|
23
|
+
- if item[:icon]
|
24
|
+
%i.fas.fa-fw{ class: "fa-#{item[:icon]}" }
|
25
|
+
%span= item[:text]
|
26
|
+
%hr.sidebar-divider.my-0
|
29
27
|
%li.nav-item
|
30
28
|
= delete_form_tag("#{settings.map_path}/auth", attributes: { id: 'logout-form' }) do
|
31
29
|
%a.nav-link{ type: 'submit', onClick: 'document.getElementById("logout-form").submit()' }
|