kadim 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +13 -1
- data/app/assets/javascripts/kadim/application.js +1 -1
- data/app/assets/javascripts/kadim/bulma/application.js +22 -0
- data/app/assets/javascripts/kadim/bulma/direct_upload.js +36 -0
- data/app/assets/javascripts/kadim/bulma/resumable_upload.js +36 -0
- data/app/assets/stylesheets/kadim/application.css +1 -1
- data/app/assets/stylesheets/kadim/bulma/application.scss +151 -0
- data/app/assets/stylesheets/kadim/bulma/direct_upload.css +19 -0
- data/app/assets/stylesheets/kadim/bulma/resumable_upload.css +19 -0
- data/app/controllers/kadim/application_controller.rb +5 -0
- data/app/helpers/kadim/application_helper.rb +15 -3
- data/app/views/kadim/application/_notice.html.erb +6 -0
- data/app/views/layouts/kadim/bulma/application.html.erb +67 -0
- data/lib/generators/kadim/scaffold_controller/scaffold_controller_generator.rb +2 -0
- data/lib/generators/kadim/scaffold_controller/templates/bulma/_form.html.erb.tt +112 -0
- data/lib/generators/kadim/scaffold_controller/templates/bulma/edit.html.erb.tt +5 -0
- data/lib/generators/kadim/scaffold_controller/templates/bulma/index.html.erb.tt +49 -0
- data/lib/generators/kadim/scaffold_controller/templates/bulma/new.html.erb.tt +5 -0
- data/lib/generators/kadim/scaffold_controller/templates/bulma/show.html.erb.tt +32 -0
- data/lib/kadim.rb +17 -6
- data/lib/kadim/engine.rb +5 -0
- data/lib/kadim/version.rb +1 -1
- metadata +87 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 969b2f040793f3267751ee1fcb3a66ca7fa7378858a21259a1ac882b68fec8c8
|
4
|
+
data.tar.gz: 05e6d286c7780728b386de66614001b4f530be45a3b83e808637262d43091f63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7be33523c6f406d972622515396d83145f45287afa7acb5c3d0e74e48517d167ae44594f667216956c934af0d86fcbe60c1c2a2f45bb75f54b6cbfdabf407a11
|
7
|
+
data.tar.gz: f30402ebcd1bf3f1cfb43ed37da84ae4080972450eb29d81bf6e9ed484bf117de2c3453012d758523a05d418033899f835d87b0f1e28e5851576e07575a0c987
|
data/README.md
CHANGED
@@ -17,6 +17,18 @@ allows you to run kadim in environments with ephemeral file systems, like [herok
|
|
17
17
|
|
18
18
|
Just follow the [Installation](#installation) section and access http://localhost:3000/kadim
|
19
19
|
|
20
|
+
### [bulma.io](https://bulma.io) layout
|
21
|
+
If you want a more beautiful view, add the following to your configuration file:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
# config/initializers/kadim.rb
|
25
|
+
Kadim.configure do |config|
|
26
|
+
config.layout = :bulma
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+

|
31
|
+
|
20
32
|
### ActiveStorage support
|
21
33
|
If we detect that you have S3, GCS or Azure Storage configured we will use
|
22
34
|
[Direct Uploads](https://edgeguides.rubyonrails.org/active_storage_overview.html#direct-uploads) by default. If you are
|
@@ -95,7 +107,7 @@ And access http://localhost:3000/kadim
|
|
95
107
|
- [x] Tasks to copy files form kadim to the hosted application
|
96
108
|
- [x] Add support to ActiveStorage attachments
|
97
109
|
- [ ] Add support to belongs_to relationships
|
98
|
-
- [
|
110
|
+
- [x] Add a beautiful look and feel
|
99
111
|
|
100
112
|
## License
|
101
113
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -0,0 +1,22 @@
|
|
1
|
+
//= require rails-ujs
|
2
|
+
//= require activestorage
|
3
|
+
//= require activestorage-resumable
|
4
|
+
//= require_tree .
|
5
|
+
|
6
|
+
document.addEventListener('DOMContentLoaded', () => {
|
7
|
+
(document.querySelectorAll('.notification .delete') || []).forEach(($delete) => {
|
8
|
+
const $notification = $delete.parentNode
|
9
|
+
$delete.addEventListener('click', () => {
|
10
|
+
$notification.parentNode.removeChild($notification)
|
11
|
+
})
|
12
|
+
})
|
13
|
+
});
|
14
|
+
|
15
|
+
(function () {
|
16
|
+
var burger = document.querySelector('.burger')
|
17
|
+
var menu = document.querySelector('#' + burger.dataset.target)
|
18
|
+
burger.addEventListener('click', function () {
|
19
|
+
burger.classList.toggle('is-active')
|
20
|
+
menu.classList.toggle('is-active')
|
21
|
+
})
|
22
|
+
})()
|
@@ -0,0 +1,36 @@
|
|
1
|
+
addEventListener('direct-upload:initialize', event => {
|
2
|
+
const { target, detail } = event
|
3
|
+
const { id, file } = detail
|
4
|
+
target.insertAdjacentHTML('beforebegin', `
|
5
|
+
<div id="direct-upload-${id}" class="direct-upload direct-upload--pending">
|
6
|
+
<span>${file.name}</span>
|
7
|
+
<progress id="direct-upload-progress-${id}" class="progress" value="0" max="100"></progress>
|
8
|
+
</div>
|
9
|
+
`)
|
10
|
+
})
|
11
|
+
|
12
|
+
addEventListener('direct-upload:start', event => {
|
13
|
+
const { id } = event.detail
|
14
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
15
|
+
element.classList.remove('direct-upload--pending')
|
16
|
+
})
|
17
|
+
|
18
|
+
addEventListener('direct-upload:progress', event => {
|
19
|
+
const { id, progress } = event.detail
|
20
|
+
const progressElement = document.getElementById(`direct-upload-progress-${id}`)
|
21
|
+
progressElement.value = Math.round(progress)
|
22
|
+
})
|
23
|
+
|
24
|
+
addEventListener('direct-upload:error', event => {
|
25
|
+
event.preventDefault()
|
26
|
+
const { id, error } = event.detail
|
27
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
28
|
+
element.classList.add('direct-upload--error')
|
29
|
+
element.setAttribute('title', error)
|
30
|
+
})
|
31
|
+
|
32
|
+
addEventListener('direct-upload:end', event => {
|
33
|
+
const { id } = event.detail
|
34
|
+
const element = document.getElementById(`direct-upload-${id}`)
|
35
|
+
element.classList.add('direct-upload--complete')
|
36
|
+
})
|
@@ -0,0 +1,36 @@
|
|
1
|
+
addEventListener('resumable-upload:initialize', event => {
|
2
|
+
const { target, detail } = event
|
3
|
+
const { id, file } = detail
|
4
|
+
target.parentNode.parentNode.insertAdjacentHTML('beforebegin', `
|
5
|
+
<div id="resumable-upload-${id}" class="resumable-upload resumable-upload--pending">
|
6
|
+
<span>${file.name}</span>
|
7
|
+
<progress id="resumable-upload-progress-${id}" class="progress" value="0" max="100"></progress>
|
8
|
+
</div>
|
9
|
+
`)
|
10
|
+
})
|
11
|
+
|
12
|
+
addEventListener('resumable-upload:start', event => {
|
13
|
+
const { id } = event.detail
|
14
|
+
const element = document.getElementById(`resumable-upload-${id}`)
|
15
|
+
element.classList.remove('resumable-upload--pending')
|
16
|
+
})
|
17
|
+
|
18
|
+
addEventListener('resumable-upload:progress', event => {
|
19
|
+
const { id, progress } = event.detail
|
20
|
+
const progressElement = document.getElementById(`resumable-upload-progress-${id}`)
|
21
|
+
progressElement.value = Math.round(progress)
|
22
|
+
})
|
23
|
+
|
24
|
+
addEventListener('resumable-upload:error', event => {
|
25
|
+
event.preventDefault()
|
26
|
+
const { id, error } = event.detail
|
27
|
+
const element = document.getElementById(`resumable-upload-${id}`)
|
28
|
+
element.classList.add('resumable-upload--error')
|
29
|
+
element.setAttribute('title', error)
|
30
|
+
})
|
31
|
+
|
32
|
+
addEventListener('resumable-upload:end', event => {
|
33
|
+
const { id } = event.detail
|
34
|
+
const element = document.getElementById(`resumable-upload-${id}`)
|
35
|
+
element.classList.add('resumable-upload--complete')
|
36
|
+
})
|
@@ -0,0 +1,151 @@
|
|
1
|
+
$primary: hsl(217, 71%, 53%);
|
2
|
+
$menu-item-color: #adb5bd;
|
3
|
+
$menu-item-hover-color: #adb5bd;
|
4
|
+
$menu-item-hover-background-color: #495057;
|
5
|
+
$menu-item-active-background-color: #495057;
|
6
|
+
@import "bulma";
|
7
|
+
@import "font-awesome-sprockets";
|
8
|
+
@import "font-awesome";
|
9
|
+
|
10
|
+
@import "direct_upload";
|
11
|
+
@import "resumable_upload";
|
12
|
+
|
13
|
+
.brand-text {
|
14
|
+
font-family: 'Muli', sans-serif;
|
15
|
+
}
|
16
|
+
|
17
|
+
.menu-container {
|
18
|
+
min-height: 100vh;
|
19
|
+
flex-direction: column;
|
20
|
+
|
21
|
+
.brand-container {
|
22
|
+
border-bottom: 1px solid grey;
|
23
|
+
}
|
24
|
+
|
25
|
+
.models-container {
|
26
|
+
flex-grow: 1;
|
27
|
+
overflow: auto;
|
28
|
+
|
29
|
+
.models-container--column {
|
30
|
+
overflow: auto
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
34
|
+
|
35
|
+
table.table td.action {
|
36
|
+
background-clip: padding-box;
|
37
|
+
background-color: $white;
|
38
|
+
position: sticky;
|
39
|
+
right: 0;
|
40
|
+
white-space: nowrap;
|
41
|
+
width: 1px;
|
42
|
+
|
43
|
+
a {
|
44
|
+
padding: 0 0.375em;
|
45
|
+
&:first-child {
|
46
|
+
padding-left: 0;
|
47
|
+
}
|
48
|
+
&:last-child {
|
49
|
+
padding-right: 0;
|
50
|
+
}
|
51
|
+
}
|
52
|
+
}
|
53
|
+
|
54
|
+
.table.is-striped tbody tr:not(.is-selected):nth-child(2n) {
|
55
|
+
td.action {
|
56
|
+
background-color: $white-bis;
|
57
|
+
}
|
58
|
+
}
|
59
|
+
|
60
|
+
@media screen and (min-width: 1024px) {
|
61
|
+
aside.aside.is-expanded {
|
62
|
+
width: 14rem; }
|
63
|
+
aside.aside.is-expanded .menu-list .icon {
|
64
|
+
width: 3rem; }
|
65
|
+
aside.aside.is-expanded .menu-list .icon.has-update-mark:after {
|
66
|
+
right: 0.65rem; }
|
67
|
+
aside.aside.is-expanded .menu-list span.menu-item-label {
|
68
|
+
display: inline-block; }
|
69
|
+
aside.aside.is-expanded .menu-list li.is-active ul {
|
70
|
+
display: block; } }
|
71
|
+
|
72
|
+
aside.aside {
|
73
|
+
display: none;
|
74
|
+
position: fixed;
|
75
|
+
top: 0;
|
76
|
+
left: 0;
|
77
|
+
z-index: 40;
|
78
|
+
height: 100vh;
|
79
|
+
padding: 0;
|
80
|
+
box-shadow: none;
|
81
|
+
background: #2e323a; }
|
82
|
+
aside.aside .aside-tools {
|
83
|
+
display: flex;
|
84
|
+
flex-direction: row;
|
85
|
+
width: 100%;
|
86
|
+
background-color: #17191e;
|
87
|
+
color: white;
|
88
|
+
line-height: 3.25rem;
|
89
|
+
height: 3.25rem;
|
90
|
+
padding-left: 0.75rem;
|
91
|
+
flex: 1; }
|
92
|
+
aside.aside .aside-tools .icon {
|
93
|
+
margin-right: 0.75rem; }
|
94
|
+
aside.aside .menu-list li a.has-dropdown-icon {
|
95
|
+
position: relative;
|
96
|
+
padding-right: 3rem; }
|
97
|
+
aside.aside .menu-list li a.has-dropdown-icon .dropdown-icon {
|
98
|
+
position: absolute;
|
99
|
+
top: 0.5rem;
|
100
|
+
right: 0; }
|
101
|
+
aside.aside .menu-list li ul {
|
102
|
+
display: none;
|
103
|
+
border-left: 0;
|
104
|
+
background-color: #282c33;
|
105
|
+
padding-left: 0;
|
106
|
+
margin: 0 0 0.75rem; }
|
107
|
+
aside.aside .menu-list li ul li a {
|
108
|
+
padding: 0.75rem 0 0.75rem 0.75rem;
|
109
|
+
font-size: 0.95rem; }
|
110
|
+
aside.aside .menu-list li ul li a.has-icon {
|
111
|
+
padding-left: 0; }
|
112
|
+
aside.aside .menu-list li ul li a.is-active:not(:hover) {
|
113
|
+
background: transparent; }
|
114
|
+
aside.aside .menu-label {
|
115
|
+
padding: 0 0.75rem;
|
116
|
+
margin-top: 0.75rem;
|
117
|
+
margin-bottom: 0.75rem; }
|
118
|
+
|
119
|
+
@media screen and (max-width: 1023px) {
|
120
|
+
aside.aside {
|
121
|
+
transition: left 250ms ease-in-out 50ms; }
|
122
|
+
html.has-aside-mobile-transition body {
|
123
|
+
overflow-x: hidden; }
|
124
|
+
html.has-aside-mobile-transition body, html.has-aside-mobile-transition #app, html.has-aside-mobile-transition nav.navbar {
|
125
|
+
width: 100vw; }
|
126
|
+
html.has-aside-mobile-transition aside.aside {
|
127
|
+
width: 15rem;
|
128
|
+
display: block;
|
129
|
+
left: -15rem; }
|
130
|
+
html.has-aside-mobile-transition aside.aside .image img {
|
131
|
+
max-width: 4.95rem; }
|
132
|
+
html.has-aside-mobile-transition aside.aside .menu-list li.is-active ul {
|
133
|
+
display: block; }
|
134
|
+
html.has-aside-mobile-transition aside.aside .menu-list a .icon {
|
135
|
+
width: 3rem; }
|
136
|
+
html.has-aside-mobile-transition aside.aside .menu-list a .icon.has-update-mark:after {
|
137
|
+
right: 0.65rem; }
|
138
|
+
html.has-aside-mobile-transition aside.aside .menu-list a span.menu-item-label {
|
139
|
+
display: inline-block; }
|
140
|
+
html.has-aside-mobile-expanded #app, html.has-aside-mobile-expanded nav.navbar {
|
141
|
+
margin-left: 15rem; }
|
142
|
+
html.has-aside-mobile-expanded aside.aside {
|
143
|
+
left: 0; } }
|
144
|
+
|
145
|
+
aside.aside .menu-list li a.has-icon {
|
146
|
+
display: flex; }
|
147
|
+
aside.aside .menu-list li a.has-icon .icon i {
|
148
|
+
height: auto; }
|
149
|
+
aside.aside .menu-list li a.has-icon .menu-item-label {
|
150
|
+
line-height: 1.5rem;
|
151
|
+
height: 1.5rem; }
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.direct-upload {
|
2
|
+
margin-bottom: 0.75em;
|
3
|
+
}
|
4
|
+
|
5
|
+
.direct-upload--pending {
|
6
|
+
opacity: 0.6;
|
7
|
+
}
|
8
|
+
|
9
|
+
.direct-upload--complete .direct-upload__progress {
|
10
|
+
opacity: 0.4;
|
11
|
+
}
|
12
|
+
|
13
|
+
.direct-upload--error {
|
14
|
+
border-color: red;
|
15
|
+
}
|
16
|
+
|
17
|
+
input[type=file][data-direct-upload-url][disabled] {
|
18
|
+
display: none;
|
19
|
+
}
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.resumable-upload {
|
2
|
+
margin-bottom: 0.75em;
|
3
|
+
}
|
4
|
+
|
5
|
+
.resumable-upload--pending {
|
6
|
+
opacity: 0.6;
|
7
|
+
}
|
8
|
+
|
9
|
+
.resumable-upload--complete .resumable-upload__progress {
|
10
|
+
opacity: 0.4;
|
11
|
+
}
|
12
|
+
|
13
|
+
.resumable-upload--error {
|
14
|
+
border-color: red;
|
15
|
+
}
|
16
|
+
|
17
|
+
input[type=file][data-resumable-upload-url][disabled] {
|
18
|
+
display: none;
|
19
|
+
}
|
@@ -5,10 +5,15 @@ module Kadim
|
|
5
5
|
protect_from_forgery with: :exception
|
6
6
|
before_action :import_main_app_polymorphic_mappings
|
7
7
|
append_view_path Kadim::MemoryResolver.instance
|
8
|
+
layout :kadim_layout
|
8
9
|
|
9
10
|
private
|
10
11
|
def import_main_app_polymorphic_mappings
|
11
12
|
Kadim::Engine.routes.polymorphic_mappings.merge! Rails.application.routes.polymorphic_mappings
|
12
13
|
end
|
14
|
+
|
15
|
+
def kadim_layout
|
16
|
+
Kadim.layout ? "kadim/#{Kadim.layout}/application" : "kadim/application"
|
17
|
+
end
|
13
18
|
end
|
14
19
|
end
|
@@ -4,12 +4,16 @@ module Kadim
|
|
4
4
|
module ApplicationHelper
|
5
5
|
def menu_links
|
6
6
|
kadim_link = link_to("Kadim", kadim.root_path)
|
7
|
-
links =
|
8
|
-
link_to model_klass.model_name.human(count: :many), model_klass
|
9
|
-
end
|
7
|
+
links = raw_menu_links
|
10
8
|
safe_join([kadim_link] + links, " | ")
|
11
9
|
end
|
12
10
|
|
11
|
+
def raw_menu_links(options = {})
|
12
|
+
Kadim.app_model_paths.map(&:camelize).map(&:constantize).map do |model_klass|
|
13
|
+
active_link_to model_klass.model_name.human(count: :many), model_klass, **options
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
13
17
|
def upload_type
|
14
18
|
case Kadim.upload_type
|
15
19
|
when :direct then { direct_upload: true }
|
@@ -18,6 +22,14 @@ module Kadim
|
|
18
22
|
end
|
19
23
|
end
|
20
24
|
|
25
|
+
def invalid_attribute_class(model, attribute)
|
26
|
+
attribute_invalid?(model, attribute) ? "is-danger" : ""
|
27
|
+
end
|
28
|
+
|
29
|
+
def attribute_invalid?(model, attribute)
|
30
|
+
model.errors.key?(attribute)
|
31
|
+
end
|
32
|
+
|
21
33
|
def method_missing(method, *args, &block)
|
22
34
|
if method.to_s.end_with?("_path", "_url")
|
23
35
|
if main_app.respond_to?(method)
|
@@ -0,0 +1,67 @@
|
|
1
|
+
<!DOCTYPE html>
|
2
|
+
<html>
|
3
|
+
<head>
|
4
|
+
<meta charset="utf-8">
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
7
|
+
<title>Kadim</title>
|
8
|
+
<%= csrf_meta_tags %>
|
9
|
+
<%= csp_meta_tag %>
|
10
|
+
|
11
|
+
<%= stylesheet_link_tag 'kadim/bulma/application', media: 'all', 'data-turbolinks-track': 'reload' %>
|
12
|
+
<%= javascript_include_tag 'kadim/bulma/application', 'data-turbolinks-track': 'reload', defer: true %>
|
13
|
+
<link href="https://fonts.googleapis.com/css?family=Muli&display=swap" rel="stylesheet">
|
14
|
+
</head>
|
15
|
+
<body>
|
16
|
+
<nav class="navbar is-hidden-desktop">
|
17
|
+
<div class="container">
|
18
|
+
<div class="navbar-brand">
|
19
|
+
<a class="navbar-item brand-text" href="../index.html">kadim</a>
|
20
|
+
<div class="navbar-burger burger" data-target="kadim-menu">
|
21
|
+
<span></span>
|
22
|
+
<span></span>
|
23
|
+
<span></span>
|
24
|
+
</div>
|
25
|
+
|
26
|
+
</div>
|
27
|
+
<div id="kadim-menu" class="navbar-menu is-hidden-desktop">
|
28
|
+
<div class="navbar-start">
|
29
|
+
<% raw_menu_links(class: "navbar-item").each do |link| %>
|
30
|
+
<%= link %>
|
31
|
+
<% end %>
|
32
|
+
</div>
|
33
|
+
</div>
|
34
|
+
</div>
|
35
|
+
</nav>
|
36
|
+
|
37
|
+
<div class="columns is-marginless">
|
38
|
+
<div class="column is-2 is-flex menu-container">
|
39
|
+
<div class="columns brand-container">
|
40
|
+
<div class="column is-12 has-background-dark has-text-centered">
|
41
|
+
<%= link_to 'kadim', root_path, class: "has-text-danger is-size-4 is-block is-fullwidth brand-text" %>
|
42
|
+
</div>
|
43
|
+
</div>
|
44
|
+
<div class="columns models-container">
|
45
|
+
<div class="column is-12 has-background-dark is-hidden-mobile models-container--column">
|
46
|
+
<aside class="menu">
|
47
|
+
<p class="menu-label">
|
48
|
+
Models
|
49
|
+
</p>
|
50
|
+
<ul class="menu-list">
|
51
|
+
<% raw_menu_links(class_active: "is-active").each do |link| %>
|
52
|
+
<li><%= link %></li>
|
53
|
+
<% end %>
|
54
|
+
</ul>
|
55
|
+
</aside>
|
56
|
+
</div>
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
<div class="column is-10">
|
61
|
+
<div class="content">
|
62
|
+
<%= yield %>
|
63
|
+
</div>
|
64
|
+
</div>
|
65
|
+
</div>
|
66
|
+
</body>
|
67
|
+
</html>
|
@@ -18,6 +18,8 @@ module Kadim
|
|
18
18
|
end
|
19
19
|
|
20
20
|
@initial_args += Kadim.scaffold_attributes(model_path.camelize.constantize) if @initial_args.one?
|
21
|
+
@initial_options.reject! { |option| option.starts_with?("-e") || option.starts_with?("--template-engine") }
|
22
|
+
@initial_options << "--template-engine=erb"
|
21
23
|
|
22
24
|
Kadim.scaffold_controller(@initial_args, @initial_options, @initial_config)
|
23
25
|
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
<%%= form_with(model: <%= model_resource_name %>, local: true) do |form| %>
|
2
|
+
<%% if <%= singular_table_name %>.errors.any? %>
|
3
|
+
<article id="error_explanation" class="message is-danger">
|
4
|
+
<div class="message-body">
|
5
|
+
<p><%%= pluralize(<%= singular_table_name %>.errors.count, "error") %> prohibited this <%= singular_table_name %> from being saved:</p>
|
6
|
+
<ul>
|
7
|
+
<%% <%= singular_table_name %>.errors.full_messages.each do |message| %>
|
8
|
+
<li><%%= message %></li>
|
9
|
+
<%% end %>
|
10
|
+
</ul>
|
11
|
+
</div>
|
12
|
+
</article>
|
13
|
+
<%% end %>
|
14
|
+
|
15
|
+
<% attributes.each do |attribute| -%>
|
16
|
+
<div class="field is-horizontal">
|
17
|
+
<% if attribute.password_digest? -%>
|
18
|
+
<div class="field-label is-normal">
|
19
|
+
<%%= form.label :password, class: "label" %>
|
20
|
+
</div>
|
21
|
+
<div class="field-body">
|
22
|
+
<div class="field">
|
23
|
+
<div class="control">
|
24
|
+
<%%= form.password_field :password, class: "input" %>
|
25
|
+
</div>
|
26
|
+
</div>
|
27
|
+
</div>
|
28
|
+
</div>
|
29
|
+
|
30
|
+
<div class="field is-horizontal">
|
31
|
+
<div class="field-label is-normal">
|
32
|
+
<%%= form.label :password_confirmation, class: "label" %>
|
33
|
+
</div>
|
34
|
+
<div class="field-body">
|
35
|
+
<div class="field">
|
36
|
+
<div class="control">
|
37
|
+
<%%= form.password_field :password_confirmation, class: "input" %>
|
38
|
+
</div>
|
39
|
+
</div>
|
40
|
+
</div>
|
41
|
+
<% elsif attribute.attachment? -%>
|
42
|
+
<div class="field-label is-normal">
|
43
|
+
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
44
|
+
</div>
|
45
|
+
<div class="field-body">
|
46
|
+
<div class="field">
|
47
|
+
<div class="control">
|
48
|
+
<div class="file">
|
49
|
+
<label class="file-label">
|
50
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, **upload_type, class: "file-input" %>
|
51
|
+
<span class="file-cta">
|
52
|
+
<span class="file-icon">
|
53
|
+
<i class="fas fa-upload"></i>
|
54
|
+
</span>
|
55
|
+
<span class="file-label">Choose a file...</span>
|
56
|
+
</span>
|
57
|
+
</label>
|
58
|
+
</div>
|
59
|
+
</div>
|
60
|
+
</div>
|
61
|
+
</div>
|
62
|
+
<% elsif attribute.attachments? -%>
|
63
|
+
<div class="field-label is-normal">
|
64
|
+
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
65
|
+
</div>
|
66
|
+
<div class="field-body">
|
67
|
+
<div class="field">
|
68
|
+
<div class="control">
|
69
|
+
<div class="file">
|
70
|
+
<label class="file-label">
|
71
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, **upload_type, multiple: true, class: "file-input" %>
|
72
|
+
<span class="file-cta">
|
73
|
+
<span class="file-icon">
|
74
|
+
<i class="fas fa-upload"></i>
|
75
|
+
</span>
|
76
|
+
<span class="file-label">Choose files...</span>
|
77
|
+
</span>
|
78
|
+
</label>
|
79
|
+
</div>
|
80
|
+
</div>
|
81
|
+
</div>
|
82
|
+
</div>
|
83
|
+
<% else -%>
|
84
|
+
<div class="field-label is-normal">
|
85
|
+
<%%= form.label :<%= attribute.column_name %>, class: "label" %>
|
86
|
+
</div>
|
87
|
+
<div class="field-body">
|
88
|
+
<div class="field">
|
89
|
+
<div class="control">
|
90
|
+
<%%= form.<%= attribute.field_type %> :<%= attribute.column_name %>, class: "input #{invalid_attribute_class(<%= singular_table_name %>, :<%= attribute.column_name %>)}" %>
|
91
|
+
<%% if attribute_invalid?(<%= singular_table_name %>, :<%= attribute.column_name %>) %>
|
92
|
+
<p class="help is-danger"><%%= <%= singular_table_name %>.errors[:<%= attribute.column_name %>].to_sentence %></p>
|
93
|
+
<%% end %>
|
94
|
+
</div>
|
95
|
+
</div>
|
96
|
+
</div>
|
97
|
+
<% end -%>
|
98
|
+
</div>
|
99
|
+
|
100
|
+
<% end -%>
|
101
|
+
<section class="box has-background-light is-shadowless">
|
102
|
+
<div class="columns">
|
103
|
+
<div class="column is-11 is-offset-1">
|
104
|
+
<%%= form.submit class: "button is-primary" %>
|
105
|
+
<%% if action_name == "edit" %>
|
106
|
+
<%%= link_to 'Show', @<%= singular_table_name %>, class: "button" %>
|
107
|
+
<%% end %>
|
108
|
+
<%%= link_to 'Back', <%= index_helper %>_path, class: "button" %>
|
109
|
+
</div>
|
110
|
+
</div>
|
111
|
+
</section>
|
112
|
+
<%% end %>
|
@@ -0,0 +1,49 @@
|
|
1
|
+
<%%= render 'notice' %>
|
2
|
+
|
3
|
+
<h1><%= plural_table_name.titleize %></h1>
|
4
|
+
|
5
|
+
<%% if @<%= plural_table_name %>.any? %>
|
6
|
+
<div class="table-container">
|
7
|
+
<table class="table is-striped">
|
8
|
+
<thead>
|
9
|
+
<tr>
|
10
|
+
<th>#</th>
|
11
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
12
|
+
<th><%= attribute.human_name %></th>
|
13
|
+
<% end -%>
|
14
|
+
<th colspan="3"></th>
|
15
|
+
</tr>
|
16
|
+
</thead>
|
17
|
+
|
18
|
+
<tbody>
|
19
|
+
<%% @<%= plural_table_name %>.each do |<%= singular_table_name %>| %>
|
20
|
+
<tr>
|
21
|
+
<td><%%= <%= singular_table_name %>.id %></td>
|
22
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
23
|
+
<td><%%= <%= singular_table_name %>.<%= attribute.column_name %> %></td>
|
24
|
+
<% end -%>
|
25
|
+
<td class="action">
|
26
|
+
<%%= link_to icon("far", "eye"), <%= model_resource_name %>, title: "Show" %>
|
27
|
+
<%%= link_to icon("far", "edit"), edit_<%= singular_route_name %>_path(<%= singular_table_name %>), title: "Edit" %>
|
28
|
+
<%%= link_to icon("far", "trash-alt"), <%= model_resource_name %>, title: "Destroy", method: :delete, data: { confirm: 'Are you sure?' } %>
|
29
|
+
</td>
|
30
|
+
</tr>
|
31
|
+
<%% end %>
|
32
|
+
</tbody>
|
33
|
+
</table>
|
34
|
+
</div>
|
35
|
+
<%% else %>
|
36
|
+
<div class="box is-shadowless has-background-light has-text-centered">
|
37
|
+
<%%= icon("fas", "cloud-sun", class: "fa-5x", style: "padding-bottom: 15px") %>
|
38
|
+
<br />
|
39
|
+
Let's input some data?
|
40
|
+
</div>
|
41
|
+
<%% end %>
|
42
|
+
|
43
|
+
<section class="box has-background-light is-shadowless">
|
44
|
+
<div class="columns">
|
45
|
+
<div class="column is-11 is-offset-1">
|
46
|
+
<%%= link_to 'New <%= singular_table_name.titleize %>', new_<%= singular_route_name %>_path, class: "button is-link" %>
|
47
|
+
</div>
|
48
|
+
</div>
|
49
|
+
</section>
|
@@ -0,0 +1,32 @@
|
|
1
|
+
<%%= render 'notice' %>
|
2
|
+
|
3
|
+
<h1><%= singular_table_name.titleize %> #<%%= @<%= singular_table_name %>.id %> - <%%= @<%= singular_table_name %>.to_s %></h1>
|
4
|
+
|
5
|
+
<% attributes.reject(&:password_digest?).each do |attribute| -%>
|
6
|
+
<div class="columns">
|
7
|
+
<div class="column is-3 has-text-right">
|
8
|
+
<strong><%= attribute.human_name %>:</strong>
|
9
|
+
</div>
|
10
|
+
<div class="column">
|
11
|
+
<% if attribute.attachment? -%>
|
12
|
+
<%%= link_to @<%= singular_table_name %>.<%= attribute.column_name %>.filename, @<%= singular_table_name %>.<%= attribute.column_name %> if @<%= singular_table_name %>.<%= attribute.column_name %>.attached? %>
|
13
|
+
<% elsif attribute.attachments? -%>
|
14
|
+
<%% @<%= singular_table_name %>.<%= attribute.column_name %>.each do |<%= attribute.singular_name %>| %>
|
15
|
+
<div><%%= link_to <%= attribute.singular_name %>.filename, <%= attribute.singular_name %> %></div>
|
16
|
+
<%% end %>
|
17
|
+
<% else -%>
|
18
|
+
<%%= @<%= singular_table_name %>.<%= attribute.column_name %> %>
|
19
|
+
<% end -%>
|
20
|
+
</div>
|
21
|
+
</div>
|
22
|
+
|
23
|
+
<% end -%>
|
24
|
+
|
25
|
+
<section class="box has-background-light is-shadowless">
|
26
|
+
<div class="columns">
|
27
|
+
<div class="column is-11 is-offset-1">
|
28
|
+
<%%= link_to 'Edit', edit_<%= singular_table_name %>_path(@<%= singular_table_name %>), class: "button is-primary" %>
|
29
|
+
<%%= link_to 'Back', <%= index_helper %>_path, class: "button" %>
|
30
|
+
</div>
|
31
|
+
</div>
|
32
|
+
</section>
|
data/lib/kadim.rb
CHANGED
@@ -8,13 +8,21 @@ module Kadim
|
|
8
8
|
# @return [Symbol] current upload type used to scaffold file input fields
|
9
9
|
# @overload upload_type=(value)
|
10
10
|
# You can use the following symbols to set the upload type:
|
11
|
-
# *
|
12
|
-
# *
|
13
|
-
# *
|
11
|
+
# * :local - Uses ActiveStorage {https://guides.rubyonrails.org/active_storage_overview.html#disk-service Disk Service}
|
12
|
+
# * :direct - Uses ActiveStorage {https://guides.rubyonrails.org/active_storage_overview.html#direct-uploads Direct Upload}
|
13
|
+
# * :resumable - Uses {https://rubygems.org/gems/activestorage-resumable activestorage-resumable gem} to implement {https://cloud.google.com/storage/docs/performing-resumable-uploads Resumable Uploads} (supports only GCS)
|
14
14
|
# @param value [Symbol]
|
15
15
|
# @return [Symbol]
|
16
16
|
mattr_accessor :upload_type
|
17
17
|
|
18
|
+
# @overload layout
|
19
|
+
# @return [Symbol, nil] current layout or nil for the default Rails layout for scaffold_controller
|
20
|
+
# @overload layout=(value)
|
21
|
+
# The following layouts are available:
|
22
|
+
# * nil - No layout, will use Rails generators template.
|
23
|
+
# * :bulma - A layout using the {https://bulma.io bulma} CSS framework.
|
24
|
+
mattr_accessor :layout
|
25
|
+
|
18
26
|
def self.init
|
19
27
|
@@upload_type ||= if [:amazon, :google, :microsoft].include?(Rails.configuration.active_storage.service)
|
20
28
|
:direct
|
@@ -50,9 +58,12 @@ module Kadim
|
|
50
58
|
Rails::Generators.namespace = Kadim
|
51
59
|
|
52
60
|
require "rails/generators/erb/scaffold/scaffold_generator"
|
53
|
-
|
54
|
-
|
55
|
-
|
61
|
+
templates_path = if Kadim.layout == :bulma
|
62
|
+
"generators/kadim/scaffold_controller/templates/bulma"
|
63
|
+
else
|
64
|
+
"generators/kadim/scaffold_controller/templates"
|
65
|
+
end
|
66
|
+
Erb::Generators::ScaffoldGenerator.source_paths.prepend(File.expand_path(templates_path, __dir__))
|
56
67
|
|
57
68
|
generator = Rails::Generators::ScaffoldControllerGenerator.new(args, options, config)
|
58
69
|
source_path_idx = generator.class.source_paths.index { |source_path| source_path.include?("jbuilder") }
|
data/lib/kadim/engine.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "active_link_to"
|
3
4
|
require "activestorage/resumable"
|
5
|
+
require "bulma-rails"
|
6
|
+
require "font-awesome-sass"
|
4
7
|
|
5
8
|
module Kadim
|
6
9
|
class Engine < ::Rails::Engine
|
@@ -10,6 +13,8 @@ module Kadim
|
|
10
13
|
config.assets.precompile += %w[
|
11
14
|
kadim/application.css
|
12
15
|
kadim/application.js
|
16
|
+
kadim/bulma/application.css
|
17
|
+
kadim/bulma/application.js
|
13
18
|
]
|
14
19
|
end
|
15
20
|
|
data/lib/kadim/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kadim
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kadu Diógenes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-01-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: active_link_to
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 1.0.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 1.0.0
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: activestorage-resumable
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -24,6 +38,34 @@ dependencies:
|
|
24
38
|
- - "~>"
|
25
39
|
- !ruby/object:Gem::Version
|
26
40
|
version: 1.0.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bulma-rails
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 0.8.0
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 0.8.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: font-awesome-sass
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.9.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 5.9.0
|
27
69
|
- !ruby/object:Gem::Dependency
|
28
70
|
name: google-cloud-storage
|
29
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -204,14 +246,28 @@ dependencies:
|
|
204
246
|
requirements:
|
205
247
|
- - "~>"
|
206
248
|
- !ruby/object:Gem::Version
|
207
|
-
version:
|
249
|
+
version: 4.0.0.beta3
|
250
|
+
type: :development
|
251
|
+
prerelease: false
|
252
|
+
version_requirements: !ruby/object:Gem::Requirement
|
253
|
+
requirements:
|
254
|
+
- - "~>"
|
255
|
+
- !ruby/object:Gem::Version
|
256
|
+
version: 4.0.0.beta3
|
257
|
+
- !ruby/object:Gem::Dependency
|
258
|
+
name: rails-controller-testing
|
259
|
+
requirement: !ruby/object:Gem::Requirement
|
260
|
+
requirements:
|
261
|
+
- - "~>"
|
262
|
+
- !ruby/object:Gem::Version
|
263
|
+
version: 1.0.4
|
208
264
|
type: :development
|
209
265
|
prerelease: false
|
210
266
|
version_requirements: !ruby/object:Gem::Requirement
|
211
267
|
requirements:
|
212
268
|
- - "~>"
|
213
269
|
- !ruby/object:Gem::Version
|
214
|
-
version:
|
270
|
+
version: 1.0.4
|
215
271
|
- !ruby/object:Gem::Dependency
|
216
272
|
name: rubocop-performance
|
217
273
|
requirement: !ruby/object:Gem::Requirement
|
@@ -282,6 +338,20 @@ dependencies:
|
|
282
338
|
- - "~>"
|
283
339
|
- !ruby/object:Gem::Version
|
284
340
|
version: 3.142.0
|
341
|
+
- !ruby/object:Gem::Dependency
|
342
|
+
name: shoulda-matchers
|
343
|
+
requirement: !ruby/object:Gem::Requirement
|
344
|
+
requirements:
|
345
|
+
- - "~>"
|
346
|
+
- !ruby/object:Gem::Version
|
347
|
+
version: 4.1.2
|
348
|
+
type: :development
|
349
|
+
prerelease: false
|
350
|
+
version_requirements: !ruby/object:Gem::Requirement
|
351
|
+
requirements:
|
352
|
+
- - "~>"
|
353
|
+
- !ruby/object:Gem::Version
|
354
|
+
version: 4.1.2
|
285
355
|
- !ruby/object:Gem::Dependency
|
286
356
|
name: sqlite3
|
287
357
|
requirement: !ruby/object:Gem::Requirement
|
@@ -322,23 +392,36 @@ files:
|
|
322
392
|
- Rakefile
|
323
393
|
- app/assets/config/kadim_manifest.js
|
324
394
|
- app/assets/javascripts/kadim/application.js
|
395
|
+
- app/assets/javascripts/kadim/bulma/application.js
|
396
|
+
- app/assets/javascripts/kadim/bulma/direct_upload.js
|
397
|
+
- app/assets/javascripts/kadim/bulma/resumable_upload.js
|
325
398
|
- app/assets/javascripts/kadim/direct_upload.js
|
326
399
|
- app/assets/javascripts/kadim/resumable_upload.js
|
327
400
|
- app/assets/stylesheets/kadim/application.css
|
401
|
+
- app/assets/stylesheets/kadim/bulma/application.scss
|
402
|
+
- app/assets/stylesheets/kadim/bulma/direct_upload.css
|
403
|
+
- app/assets/stylesheets/kadim/bulma/resumable_upload.css
|
328
404
|
- app/assets/stylesheets/kadim/direct_upload.css
|
329
405
|
- app/assets/stylesheets/kadim/resumable_upload.css
|
330
406
|
- app/controllers/kadim/application_controller.rb
|
331
407
|
- app/helpers/kadim/application_helper.rb
|
332
408
|
- app/jobs/kadim/application_job.rb
|
333
409
|
- app/mailers/kadim/application_mailer.rb
|
410
|
+
- app/views/kadim/application/_notice.html.erb
|
334
411
|
- app/views/kadim/application/index.html.erb
|
335
412
|
- app/views/layouts/kadim/application.html.erb
|
413
|
+
- app/views/layouts/kadim/bulma/application.html.erb
|
336
414
|
- config/routes.rb
|
337
415
|
- lib/generators/kadim/host/USAGE
|
338
416
|
- lib/generators/kadim/host/host_generator.rb
|
339
417
|
- lib/generators/kadim/scaffold_controller/USAGE
|
340
418
|
- lib/generators/kadim/scaffold_controller/scaffold_controller_generator.rb
|
341
419
|
- lib/generators/kadim/scaffold_controller/templates/_form.html.erb.tt
|
420
|
+
- lib/generators/kadim/scaffold_controller/templates/bulma/_form.html.erb.tt
|
421
|
+
- lib/generators/kadim/scaffold_controller/templates/bulma/edit.html.erb.tt
|
422
|
+
- lib/generators/kadim/scaffold_controller/templates/bulma/index.html.erb.tt
|
423
|
+
- lib/generators/kadim/scaffold_controller/templates/bulma/new.html.erb.tt
|
424
|
+
- lib/generators/kadim/scaffold_controller/templates/bulma/show.html.erb.tt
|
342
425
|
- lib/kadim.rb
|
343
426
|
- lib/kadim/engine.rb
|
344
427
|
- lib/kadim/template/memory_resolver.rb
|