dashboard-rails 1.0.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 +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +198 -0
- data/Rakefile +34 -0
- data/app/assets/javascripts/dashboard-rails.js +119 -0
- data/app/assets/stylesheets/dashboard-rails.css +40 -0
- data/app/controllers/application_widget.rb +56 -0
- data/app/controllers/dashboard-rails/application_controller.rb +5 -0
- data/app/controllers/dashboard-rails/widgets_controller.rb +46 -0
- data/app/helpers/dashboard-rails/application_helper.rb +20 -0
- data/app/models/dashboard-rails/user.rb +9 -0
- data/app/views/dashboard-rails/widgets/_widgets_list.html.erb +24 -0
- data/app/views/dashboard-rails/widgets/index.html.erb +25 -0
- data/config/initializers/assets.rb +1 -0
- data/config/routes.rb +19 -0
- data/lib/dashboard-rails.rb +8 -0
- data/lib/dashboard-rails/engine.rb +6 -0
- data/lib/dashboard-rails/singleton_helper.rb +19 -0
- data/lib/dashboard-rails/version.rb +3 -0
- data/lib/dashboard-rails/widget.rb +23 -0
- data/lib/generators/dashboard-rails/install_generator.rb +26 -0
- data/lib/generators/dashboard-rails/view_generator.rb +11 -0
- data/lib/generators/dashboard-rails/widget_generator.rb +25 -0
- data/lib/generators/templates/create_taxweb_widgets_users.rb +18 -0
- data/lib/generators/templates/generic_widget.erb +12 -0
- data/lib/generators/templates/generic_widget.html.erb +2 -0
- metadata +89 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3a86427f3df1221fe3e57a76b2018089abc3264a47ab1f8ca71619cf547ae7cd
|
4
|
+
data.tar.gz: 56714713af95f13099f3721281b037a59c42a4e68dd2b55ae3c28adbc04a80d8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5c5c522b76dfa3d830dec7da01b35a7f67cd3331596fe34460a59c5f981fba735a5f077a9bf345cfef977f0058791ef21a2a8ac85b50f6edb5653060709797f2
|
7
|
+
data.tar.gz: 3129075c90183adc2ed987134bd164d87c2fb049878bfea9b7b9eef79d5074b32cd98a4cf76fd161e86e01a54bd1185e89016c47791cf273135df19b8cc6d613
|
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2015 Daniel de Carvalho Passarini
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,198 @@
|
|
1
|
+
# Dashboard Rails
|
2
|
+
|
3
|
+
This Gem was designed to help create a dashboard page where the user can configure the diplayed widgets.
|
4
|
+
|
5
|
+
The user selects the widgets that he would like to display and save this information to the database so next time he
|
6
|
+
loads the application the desired widgets will be displayed.
|
7
|
+
|
8
|
+
For the moment we require a model *User* and the method *current_user*
|
9
|
+
|
10
|
+
## TODO
|
11
|
+
|
12
|
+
- Configure page layout (number and size of columns)
|
13
|
+
- Define widgets position in the page using drag & drop
|
14
|
+
- Define the auto refrsesh interval (today fixed in 60 seconds)
|
15
|
+
|
16
|
+
### Installation
|
17
|
+
|
18
|
+
Add the gem to the Gemfile
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
gem 'dashboard-rails'
|
22
|
+
```
|
23
|
+
run bundle install
|
24
|
+
|
25
|
+
```sh
|
26
|
+
$ bundle install
|
27
|
+
```
|
28
|
+
|
29
|
+
Generate some required files using the provided install generator
|
30
|
+
```sh
|
31
|
+
$ rails g dashboard-rails:install
|
32
|
+
```
|
33
|
+
|
34
|
+
A migration will be created the table to keep the dashboard settings per user
|
35
|
+
|
36
|
+
```sh
|
37
|
+
$ rake db:migrate
|
38
|
+
```
|
39
|
+
|
40
|
+
Add the provide css to **application.css**
|
41
|
+
```js
|
42
|
+
*= require dashboard-rails
|
43
|
+
```
|
44
|
+
|
45
|
+
Add the provide js to **application.js**
|
46
|
+
```js
|
47
|
+
//= require dashboard-rails
|
48
|
+
```
|
49
|
+
|
50
|
+
### Dashboard Page
|
51
|
+
|
52
|
+
Create you dashboard page, just add the following helper to your page
|
53
|
+
|
54
|
+
```html
|
55
|
+
<%= dashboard_view %>
|
56
|
+
```
|
57
|
+
|
58
|
+
Or, you can generate the dashboard viwes in your project to customize it
|
59
|
+
|
60
|
+
```sh
|
61
|
+
rails g dashboard-rails:view
|
62
|
+
```
|
63
|
+
|
64
|
+
### the Dashboard Configuration Page
|
65
|
+
|
66
|
+
Create you confi dashboard page, just add the following helper to your page
|
67
|
+
|
68
|
+
```html
|
69
|
+
<%= config_dashboard_view %>
|
70
|
+
```
|
71
|
+
|
72
|
+
|
73
|
+
<%= config_dashboard_path %>
|
74
|
+
|
75
|
+
|
76
|
+
Or, you can generate the dashboard viwes in your project to customize it
|
77
|
+
|
78
|
+
```sh
|
79
|
+
rails g dashboard-rails:view
|
80
|
+
```
|
81
|
+
|
82
|
+
|
83
|
+
### Widget Generators
|
84
|
+
|
85
|
+
To create the widget skeleton use:
|
86
|
+
```sh
|
87
|
+
rails generate dashboard-rails:widget #{widget_name}
|
88
|
+
```
|
89
|
+
|
90
|
+
|
91
|
+
All widgets are create under the `app/widgets` folder
|
92
|
+
|
93
|
+
|
94
|
+
## How to create a Widget
|
95
|
+
|
96
|
+
For example:
|
97
|
+
|
98
|
+
```ruby
|
99
|
+
class ExemploWidget < ApplicationWidget
|
100
|
+
|
101
|
+
name! 'Widget Exemplo'
|
102
|
+
description! 'Esse Widget é apenas um exemplo'
|
103
|
+
|
104
|
+
description! :executar, 'Essa ação é um outro exemplo'
|
105
|
+
def executar
|
106
|
+
@ano = params[:ano] || Date.today.year
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
**Cada ação será uma visão diferente do widget. Exemplo: Calendário Mensal, Calendário Semanal, você terá o widget Calendários e as ações mensal e semanal.**
|
113
|
+
|
114
|
+
Parametros utilizados como documentação para exibir na lista de configuração de Widgets x Usuários.
|
115
|
+
|
116
|
+
- **name!** identifica o nome (título) do Widget.
|
117
|
+
- **description!** é a descrição (função) do Widget.
|
118
|
+
- **description! :acao** é a descrição (função) da ação daquele Widget.
|
119
|
+
|
120
|
+
O conteúdo visual do Widget (VIEW) seguirá o padrão do rails estando na pasta `app/views/widgets/nome_do_widget/nome_da_acao.html.erb`:
|
121
|
+
|
122
|
+
*app/widgets/exemplo/executar.html.erb*
|
123
|
+
```html
|
124
|
+
<div>
|
125
|
+
Meu widget de exemplo retornou o ano: <%= @ano %>
|
126
|
+
<%= link_to 'Próximo Ano e recarregar Widget', widget_path(ano: (@ano +1), widget_ajax: true %>
|
127
|
+
<%= link_to 'Ir para página externa normalmente', 'http://www.google.com.br/' %>
|
128
|
+
</div>
|
129
|
+
```
|
130
|
+
|
131
|
+
Para direcionar o usuário para configurar seus widgets, faça um link para `dashboard-rails_path`
|
132
|
+
```html
|
133
|
+
<%= link_to 'Gerenciar Widgets', dashboard-rails_path %>
|
134
|
+
|
135
|
+
<%= link_to 'Gerenciar Widgets', dashboard_settings_path %>
|
136
|
+
|
137
|
+
|
138
|
+
```
|
139
|
+
|
140
|
+
### Helpers
|
141
|
+
|
142
|
+
Para verificar a permissão de acesso ao Widget pelo usuário atual (current_user), utilize o helper `user_can_widget?(nome_widget, ação)`:
|
143
|
+
```html
|
144
|
+
<% if show_widget?(:calendarios, :mensal) %>
|
145
|
+
|
146
|
+
<% end %>
|
147
|
+
```
|
148
|
+
|
149
|
+
Para adicionar um widget use o helper `add_widget(nome_widget, ação)`:
|
150
|
+
```html
|
151
|
+
<%= add_widget(:calendarios, :mensal) %>
|
152
|
+
```
|
153
|
+
|
154
|
+
Para referenciar um path do widget de forma automática utilize `widget_path`. Esse helper espera que haja definido em params *widget_name* e *widget_name* :
|
155
|
+
```html
|
156
|
+
<!-- ESPERA QUE EXISTA params[:widget_name] e params[:widget_action] definidos -->
|
157
|
+
<%= widget_path(novo_atributo: 'novo valor') %>
|
158
|
+
```
|
159
|
+
|
160
|
+
Para criar um link que faça uma chamada ajax e retorne o resultado HTML no próprio widget (como mudar de página por exemplo):
|
161
|
+
```html
|
162
|
+
<%= link_to 'Link Remoto', widget_path({ano: @ano}), widget_ajax: true %>
|
163
|
+
```
|
164
|
+
|
165
|
+
Formulário para reescrever o plugin baseado em algum parametro:
|
166
|
+
```html
|
167
|
+
<%= form_tag widget_path, method: :get, widget_ajax: true do %>
|
168
|
+
|
169
|
+
<% end %>
|
170
|
+
```
|
171
|
+
|
172
|
+
### Atualização Manual do Widget
|
173
|
+
|
174
|
+
Para atualizar um widget de forma manual você precisa recuperar o elemento do widget com a classe `widget` e chamar o método `widget_load_from_ajax`:
|
175
|
+
```javascript
|
176
|
+
var elemento = $('.widget:first')
|
177
|
+
//Esse elemento precisa ser um elemento jQuery
|
178
|
+
widget_load_from_ajax(elemento);
|
179
|
+
```
|
180
|
+
|
181
|
+
### Recursos AJAX (automáticos)
|
182
|
+
|
183
|
+
Toda vez que um elemento com classe `widget-user-control` for alterado será disparado um evento AJAX que irá localizar as configuraçẽos do usuário na view de configuração e retornará um HTML com o conteúdo no elemento `.widgets_list .list`. Caso não seja informado esse item, o primeiro formulário com a classe `widget_config` será passado como elemento destino.
|
184
|
+
|
185
|
+
Todo formulário em widget que tenha a atributo `widget_ajax` terá seu evento "submit" enviado por AJAX, retornando o resultado no próprio container do widget, portanto é esperado um retorno HTML.
|
186
|
+
|
187
|
+
Todo elemento com atributo `data-url` tentará criar um contador com tempo igual ao atributo `data-tick` para atualização automática do widget.
|
188
|
+
|
189
|
+
|
190
|
+
|
191
|
+
# Developers
|
192
|
+
|
193
|
+
To publish this gem use:
|
194
|
+
|
195
|
+
```sh
|
196
|
+
gem push dashboard-rails-0.1.0.gem
|
197
|
+
|
198
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
begin
|
2
|
+
require 'bundler/setup'
|
3
|
+
rescue LoadError
|
4
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
5
|
+
end
|
6
|
+
|
7
|
+
# require 'rdoc/task'
|
8
|
+
# RDoc::Task.new(:rdoc) do |rdoc|
|
9
|
+
# rdoc.rdoc_dir = 'rdoc'
|
10
|
+
# rdoc.title = 'DashboardRails'
|
11
|
+
# rdoc.options << '--line-numbers'
|
12
|
+
# rdoc.rdoc_files.include('README.rdoc')
|
13
|
+
# rdoc.rdoc_files.include('lib/**/*.rb')
|
14
|
+
# end
|
15
|
+
|
16
|
+
APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__)
|
17
|
+
load 'rails/tasks/engine.rake'
|
18
|
+
|
19
|
+
|
20
|
+
load 'rails/tasks/statistics.rake'
|
21
|
+
|
22
|
+
Bundler::GemHelper.install_tasks
|
23
|
+
|
24
|
+
# require 'rake/testtask'
|
25
|
+
#
|
26
|
+
# Rake::TestTask.new(:test) do |t|
|
27
|
+
# t.libs << 'lib'
|
28
|
+
# t.libs << 'test'
|
29
|
+
# t.pattern = 'test/**/*_test.rb'
|
30
|
+
# t.verbose = false
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
#
|
34
|
+
# task default: :test
|
@@ -0,0 +1,119 @@
|
|
1
|
+
function hasParams(url) {
|
2
|
+
var regex = new RegExp(/\?\w+\=/);
|
3
|
+
regex.test(url);
|
4
|
+
}
|
5
|
+
|
6
|
+
function widget_load_from_ajax($el, new_url) {
|
7
|
+
if ($el!=undefined && $el!=null && $el instanceof jQuery) {
|
8
|
+
var dest_url = (new_url != undefined ? new_url : $el.attr('data-url'));
|
9
|
+
// var query_string = window.location.search.substring(1);
|
10
|
+
// if (query_string!=undefined && query_string!=null) {
|
11
|
+
// dest_url = dest_url + (hasParams(dest_url) ? '&' : '?') + query_string;
|
12
|
+
// }
|
13
|
+
$.ajax({
|
14
|
+
url: dest_url,
|
15
|
+
method: 'get',
|
16
|
+
dataType: 'html',
|
17
|
+
beforeSend: function (jqXHR, settings) {
|
18
|
+
widget_loading($el);
|
19
|
+
},
|
20
|
+
success: function (data, textStatus, jqXHR) {
|
21
|
+
//console.log('sucesso');
|
22
|
+
$el.html(data);
|
23
|
+
if (new_url != undefined) {
|
24
|
+
$el.attr('data-url', new_url);
|
25
|
+
}
|
26
|
+
},
|
27
|
+
error: function (jqXHR, textStatus, errorThrown) {
|
28
|
+
console.log('erro',jqXHR);
|
29
|
+
},
|
30
|
+
complete: function (jqXHR, textStatus) {
|
31
|
+
widget_loading($el, false);
|
32
|
+
}
|
33
|
+
});
|
34
|
+
} else {
|
35
|
+
alert('Erro! Objeto Widget Não encontrado!');
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
function widget_load_user_config(user_id, elDestBlock) {
|
40
|
+
var $elDestBlock = $('.widget_config');
|
41
|
+
var $elDestList = $elDestBlock.find('.widgets_list .list');
|
42
|
+
$.ajax({
|
43
|
+
url: '/dashboard-rails/widgets/user/'+user_id,
|
44
|
+
method: 'get',
|
45
|
+
dataType: 'html',
|
46
|
+
beforeSend: function (jqXHR, settings) {
|
47
|
+
widget_loading($elDestBlock);
|
48
|
+
},
|
49
|
+
success: function (data, textStatus, jqXHR) {
|
50
|
+
// console.log(data);
|
51
|
+
$elDestList.html(data);
|
52
|
+
},
|
53
|
+
error: function (jqXHR, textStatus, errorThrown) {
|
54
|
+
console.log('erro',jqXHR);
|
55
|
+
},
|
56
|
+
complete: function (jqXHR, textStatus) {
|
57
|
+
widget_loading($elDestBlock, false);
|
58
|
+
}
|
59
|
+
});
|
60
|
+
}
|
61
|
+
|
62
|
+
function widget_loading(element, state) {
|
63
|
+
var $el = $(element);
|
64
|
+
if (state==undefined) state=true;
|
65
|
+
|
66
|
+
if (state==true) {
|
67
|
+
$("<div class='widget_loading'><span>Carregando...</span></div>").appendTo($el);
|
68
|
+
} else {
|
69
|
+
$el.find('.widget_loading').fadeOut('fast', function(){
|
70
|
+
$(this).remove();
|
71
|
+
});
|
72
|
+
}
|
73
|
+
}
|
74
|
+
|
75
|
+
//FORMS
|
76
|
+
$(document).on('submit','form[widget_ajax]', function(ev) {
|
77
|
+
ev.preventDefault();
|
78
|
+
var widget_element = $(this).closest('.widget'),
|
79
|
+
atributos = $(this).serialize(),
|
80
|
+
form_url = $(this).attr('action');
|
81
|
+
if (atributos!=undefined && atributos!=null) {
|
82
|
+
form_url = form_url + (hasParams(form_url) ? '&' : '?') + atributos;
|
83
|
+
}
|
84
|
+
widget_load_from_ajax(widget_element, form_url);
|
85
|
+
});
|
86
|
+
|
87
|
+
//LINKS
|
88
|
+
$(document).on('click','a[widget_ajax]', function(ev) {
|
89
|
+
ev.preventDefault();
|
90
|
+
var widget_element = $(this).closest('.widget');
|
91
|
+
var new_url = $(this).attr('href');
|
92
|
+
widget_load_from_ajax(widget_element, new_url);
|
93
|
+
});
|
94
|
+
|
95
|
+
//USER CONTORL
|
96
|
+
$(document).on('change','.widget-user-control', function(ev) {
|
97
|
+
var $el = $(this);
|
98
|
+
widget_load_user_config($el.val());
|
99
|
+
});
|
100
|
+
|
101
|
+
$(document).on('ready',function(){
|
102
|
+
|
103
|
+
$('.widget[data-url]').each(function(i,el) {
|
104
|
+
var $el = $(el);
|
105
|
+
var delay_in_ms = $el.attr('data-tick') || 0;
|
106
|
+
widget_load_from_ajax($el);
|
107
|
+
if (delay_in_ms > 0) {
|
108
|
+
window.setInterval(function(){ widget_load_from_ajax($el); }, delay_in_ms);
|
109
|
+
}
|
110
|
+
});
|
111
|
+
|
112
|
+
//INIT
|
113
|
+
if ($('.widget-user-control').length > 0) {
|
114
|
+
$('.widget-user-control').trigger('change');
|
115
|
+
} else {
|
116
|
+
widget_load_user_config('');
|
117
|
+
}
|
118
|
+
|
119
|
+
});
|
@@ -0,0 +1,40 @@
|
|
1
|
+
.widget {
|
2
|
+
position: relative;
|
3
|
+
min-height: 50px;
|
4
|
+
}
|
5
|
+
|
6
|
+
.widgets_list ul {
|
7
|
+
padding-left: 0px;
|
8
|
+
}
|
9
|
+
|
10
|
+
.widgets_list ul li {
|
11
|
+
list-style: none;
|
12
|
+
}
|
13
|
+
|
14
|
+
.widget_loading {
|
15
|
+
position: absolute;
|
16
|
+
width: 100%;
|
17
|
+
height: 100%;
|
18
|
+
min-height: 50px;
|
19
|
+
top: 0;
|
20
|
+
left: 0;
|
21
|
+
background-color: #ccc;
|
22
|
+
opacity: 0.5;
|
23
|
+
border-radius: 5px;
|
24
|
+
cursor: not-allowed;
|
25
|
+
}
|
26
|
+
|
27
|
+
.widget_loading span {
|
28
|
+
background-color: #FFF;
|
29
|
+
font-size: 18px;
|
30
|
+
color: #000;
|
31
|
+
padding: 5px;
|
32
|
+
font-weight: bold;
|
33
|
+
margin: 0;
|
34
|
+
border-radius: 5px;
|
35
|
+
position: absolute;
|
36
|
+
top: 50%;
|
37
|
+
left: 50%;
|
38
|
+
margin-right: -50%;
|
39
|
+
transform: translate(-50%, -50%);
|
40
|
+
}
|
@@ -0,0 +1,56 @@
|
|
1
|
+
class ApplicationWidget < ::ApplicationController
|
2
|
+
include SingletonHelper
|
3
|
+
|
4
|
+
attr_singleton :refresh_interval, 0
|
5
|
+
|
6
|
+
def initialize(request)
|
7
|
+
self.request = request
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_template(view_file=nil, *args)
|
11
|
+
args << {template: view_file}
|
12
|
+
render_to_string *args
|
13
|
+
end
|
14
|
+
|
15
|
+
def view(view_file=nil, klass=nil)
|
16
|
+
class_caller = klass || (caller[0].match(/(\b\w+)\.rb/)[1] rescue '')
|
17
|
+
action_caller = view_file || (caller[0].match(/`(.*)'/)[1] rescue '')
|
18
|
+
view_file = "widgets/#{class_caller.to_s.sub('_widget','')}/#{action_caller}" unless lookup_context.find_all(view_file).any?
|
19
|
+
instance_variable_set(:@view_file, view_file)
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.name?
|
23
|
+
instance_variable_defined?(:@widget_name) ? instance_variable_get(:@widget_name) : ''
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.name!(value)
|
27
|
+
# define_singleton_method(:widget_name) {value}
|
28
|
+
instance_variable_set(:@widget_name, value)
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.description?(attr=nil)
|
32
|
+
attr='widget' if attr.nil?
|
33
|
+
instance_variable_defined?("@description_#{attr}") ? instance_variable_get("@description_#{attr}") : ''
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.description!(*args)
|
37
|
+
if args.size == 1
|
38
|
+
instance_variable_set(:@description_widget, args[0])
|
39
|
+
elsif args.size == 2
|
40
|
+
instance_variable_set("@description_#{args[0]}", args[1])
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.widgets
|
45
|
+
# ApplicationWidget.descendants.map do |klass| #Não estava carregando no primeiro load...
|
46
|
+
Dir["#{Rails.root}/app/widgets/*.rb"].map do |file_path|
|
47
|
+
file_name = File.basename(file_path, ".rb")
|
48
|
+
klass = Object.const_get file_name.classify
|
49
|
+
actions = klass.instance_methods(false).map do |action|
|
50
|
+
{name: action, description: klass.description?(action)}
|
51
|
+
end
|
52
|
+
{code: klass.to_s.tableize.sub('_widgets',''), name: klass.name?, description: klass.description?, actions: actions}
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require_dependency "dashboard-rails/application_controller"
|
2
|
+
|
3
|
+
module DashboardRails
|
4
|
+
class WidgetsController < ApplicationController
|
5
|
+
|
6
|
+
def load
|
7
|
+
widget = DashboardRails::Widget.new(params[:widget_name], self.request)
|
8
|
+
content = widget.html(params[:widget_action])
|
9
|
+
rescue Exception => e
|
10
|
+
content = e.message
|
11
|
+
ensure
|
12
|
+
render html: content, layout: false
|
13
|
+
end
|
14
|
+
|
15
|
+
def user
|
16
|
+
user_id = params[:id]
|
17
|
+
@widgets_code = DashboardRails::User.where(user_id: user_id).pluck(:widget, :action).map{|r| "#{r[0]}_#{r[1]}"}
|
18
|
+
render partial: 'widgets_list'
|
19
|
+
end
|
20
|
+
|
21
|
+
def index
|
22
|
+
@user_id = params[:user_id] || current_user.id
|
23
|
+
end
|
24
|
+
|
25
|
+
def save
|
26
|
+
user_id = params[:user_id]
|
27
|
+
widgets = params[:widgets]
|
28
|
+
widget_name_user = []
|
29
|
+
action_user = []
|
30
|
+
if user_id.present? && widgets.present?
|
31
|
+
widgets.each do |widget|
|
32
|
+
widget_name, action = widget.split('|')
|
33
|
+
if widget_name && action
|
34
|
+
widget_name_user << widget_name
|
35
|
+
action_user << action
|
36
|
+
DashboardRails::User.find_or_create_by(widget: widget_name, action: action, user_id: user_id)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
DashboardRails::User.where(user_id: user_id).where.not(widget: widget_name_user, action: action_user).destroy_all
|
41
|
+
flash[:success] = 'Alterações foram salvas com sucesso!'
|
42
|
+
redirect_to dashboard-rails_path(user_id: user_id)
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module DashboardRails
|
2
|
+
module ApplicationHelper
|
3
|
+
|
4
|
+
def add_widget(widget_name, widget_action)
|
5
|
+
widget = DashboardRails::Widget.new(widget_name, self.request)
|
6
|
+
content_tag(:div, '', id: "widget_#{widget_name}_#{widget_action}", class: 'widget', data: {tick: widget.param(:refresh_interval), url: dashboard-rails_load_path(widget_name: widget_name, widget_action: widget_action)})
|
7
|
+
end
|
8
|
+
|
9
|
+
def widget_path(args=nil)
|
10
|
+
my_params = {widget_name: params[:widget_name], widget_action: params[:widget_action]}
|
11
|
+
my_params.merge!(args) if args.present?
|
12
|
+
dashboard-rails_load_path(my_params)
|
13
|
+
end
|
14
|
+
|
15
|
+
def user_can_widget?(widget_name, widget_action)
|
16
|
+
DashboardRails::User.where(user_id: current_user.id, widget: widget_name, action: widget_action).count > 0
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
<% ApplicationWidget.widgets.each do |widget| %>
|
2
|
+
<ul>
|
3
|
+
<li>
|
4
|
+
<b><%= widget[:name] %></b>
|
5
|
+
<br><span class="help-block"><%= widget[:description] %></span>
|
6
|
+
<ul>
|
7
|
+
<% widget[:actions].each do |action| %>
|
8
|
+
<% widget_code = "#{widget[:code]}_#{action[:name]}" %>
|
9
|
+
<li>
|
10
|
+
<div class="checkbox">
|
11
|
+
<%= label_tag widget_code do %>
|
12
|
+
<%= check_box_tag 'widgets[]', "#{widget[:code]}|#{action[:name]}", @widgets_code.include?(widget_code), {id: widget_code} %>
|
13
|
+
<b><%= action[:name].to_s.humanize %></b>
|
14
|
+
<% if action[:description].present? %>
|
15
|
+
<br><span class="help-block"><%= action[:description] %></span>
|
16
|
+
<% end %>
|
17
|
+
<% end %>
|
18
|
+
</div>
|
19
|
+
</li>
|
20
|
+
<% end %>
|
21
|
+
</ul>
|
22
|
+
</li>
|
23
|
+
</ul>
|
24
|
+
<% end %>
|
@@ -0,0 +1,25 @@
|
|
1
|
+
<div class="row">
|
2
|
+
<div class="col-md-12">
|
3
|
+
<div class="panel panel-default">
|
4
|
+
<div class="panel-heading">
|
5
|
+
<div class="panel-title">Selecione os Widgets que deseja utilizar:</div>
|
6
|
+
</div>
|
7
|
+
<div class="panel-body">
|
8
|
+
<%= form_tag(dashboard-rails_save_path, method: :put, class: 'widget_config') do %>
|
9
|
+
|
10
|
+
<div class="form-group">
|
11
|
+
<label class="control-label">Usuário:</label>
|
12
|
+
<%= select_tag :user_id, options_from_collection_for_select(User.all, :id, :email, current_user.id), include_blank: false, class: 'form-control widget-user-control' %>
|
13
|
+
</div>
|
14
|
+
|
15
|
+
<fieldset class="widgets_list">
|
16
|
+
<legend>Widgets</legend>
|
17
|
+
<div class="list"></div>
|
18
|
+
</fieldset>
|
19
|
+
|
20
|
+
<%= submit_tag "Salvar", class: 'btn btn-success' %>
|
21
|
+
<% end %>
|
22
|
+
</div>
|
23
|
+
</div>
|
24
|
+
</div>
|
25
|
+
</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
Rails.application.config.assets.precompile += %w( dashboard-rails.js dashboard-rails.css )
|
data/config/routes.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Rails.application.routes.draw do
|
2
|
+
|
3
|
+
|
4
|
+
namespace :dashboard-rails do
|
5
|
+
|
6
|
+
get 'widgets/load/:widget_name/:widget_action', to: 'widgets#load', as: 'load'
|
7
|
+
get 'widgets/user(/:id)', to: 'widgets#user', as: 'user'
|
8
|
+
get 'widgets', to: 'widgets#index', as: ''
|
9
|
+
put 'widgets/save', to: 'widgets#save', as: 'save'
|
10
|
+
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module SingletonHelper
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def attr_singleton(attr, default=nil)
|
9
|
+
define_singleton_method attr do |value=nil|
|
10
|
+
if value.present?
|
11
|
+
instance_variable_set("@#{attr}", value)
|
12
|
+
else
|
13
|
+
instance_variable_get("@#{attr}") || default
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module DashboardRails
|
2
|
+
class Widget
|
3
|
+
|
4
|
+
attr_accessor :widget, :klass
|
5
|
+
|
6
|
+
def initialize(widget_name, request)
|
7
|
+
@klass_name = widget_name
|
8
|
+
@klass = Object.const_get "#{@klass_name}_widget".classify
|
9
|
+
@widget = @klass.new(request)
|
10
|
+
end
|
11
|
+
|
12
|
+
def param(param)
|
13
|
+
@klass.send(param)
|
14
|
+
end
|
15
|
+
|
16
|
+
def html(action)
|
17
|
+
content = @widget.send(action)
|
18
|
+
view_file = (@widget.instance_variables.include?(:@view_file) ? @widget.instance_variable_get(:@view_file) : @widget.view(action, @klass_name))
|
19
|
+
@widget.render_template(view_file) # rescue content
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
require 'rails/generators/migration'
|
3
|
+
|
4
|
+
module DashboardRails
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
source_root File.expand_path("../../templates", __FILE__)
|
7
|
+
include Rails::Generators::Migration
|
8
|
+
|
9
|
+
class_option :orm
|
10
|
+
desc 'Instalando Taxweb Widgets'
|
11
|
+
|
12
|
+
desc 'Criando Migrations'
|
13
|
+
def self.next_migration_number(path)
|
14
|
+
unless @prev_migration_nr
|
15
|
+
@prev_migration_nr = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
|
16
|
+
else
|
17
|
+
@prev_migration_nr += 1
|
18
|
+
end
|
19
|
+
@prev_migration_nr.to_s
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_migration_file
|
23
|
+
migration_template 'create_dashboard-rails_users.rb', 'db/migrate/create_dashboard-rails_users.rb'
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module DashboardRails
|
4
|
+
class ViewGenerator < Rails::Generators::Base
|
5
|
+
source_root File.expand_path("../../../../app/views/dashboard-rails", __FILE__)
|
6
|
+
|
7
|
+
def copy_views
|
8
|
+
directory 'widgets', 'app/views/dashboard-rails/widgets'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'rails/generators/base'
|
2
|
+
|
3
|
+
module DashboardRails
|
4
|
+
class WidgetGenerator < Rails::Generators::NamedBase
|
5
|
+
source_root File.expand_path("../../templates", __FILE__)
|
6
|
+
|
7
|
+
def generate_widget
|
8
|
+
@widget_name = file_name.classify
|
9
|
+
view_dir = "app/views/widgets/#{widget_name_file}"
|
10
|
+
|
11
|
+
template "generic_widget.erb", File.join('app/widgets', "#{widget_name_file}_widget.rb")
|
12
|
+
|
13
|
+
if self.behavior == :revoke && Dir.exists?(view_dir)
|
14
|
+
require 'fileutils'
|
15
|
+
FileUtils.rm_rf(view_dir)
|
16
|
+
elsif self.behavior == :invoke
|
17
|
+
copy_file "generic_widget.html.erb", File.join(view_dir, 'exemplo.html.erb')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def widget_name_file
|
22
|
+
file_name.underscore
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class CreateDashboardSettings < ActiveRecord::Migration
|
2
|
+
|
3
|
+
def up
|
4
|
+
unless table_exists?(:dashboard_settings)
|
5
|
+
create_table :dashboard_settings do |t|
|
6
|
+
t.references :user, index: true, foreign_key: false
|
7
|
+
t.string :widget
|
8
|
+
t.string :action
|
9
|
+
t.index [:widget, :action]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def down
|
15
|
+
drop_table :dashboard_settings if table_exists? :dashboard_settings
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
class <%= @widget_name %>Widget < ApplicationWidget
|
2
|
+
|
3
|
+
name! "<%= @widget_name %>"
|
4
|
+
description! "O Widget <%= @widget_name %> tem como função..."
|
5
|
+
#refresh_interval 60000 #60 segundos para refresh automático
|
6
|
+
|
7
|
+
description! :exemplo, 'Essa ação é um exemplo'
|
8
|
+
def exemplo
|
9
|
+
@data = Date.today
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dashboard-rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- TaxWeb
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rails
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '5'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '5'
|
33
|
+
description: Gerenciamento de Widgets para Dashboard
|
34
|
+
email:
|
35
|
+
- produto@taxweb.com.br
|
36
|
+
executables: []
|
37
|
+
extensions: []
|
38
|
+
extra_rdoc_files: []
|
39
|
+
files:
|
40
|
+
- MIT-LICENSE
|
41
|
+
- README.md
|
42
|
+
- Rakefile
|
43
|
+
- app/assets/javascripts/dashboard-rails.js
|
44
|
+
- app/assets/stylesheets/dashboard-rails.css
|
45
|
+
- app/controllers/application_widget.rb
|
46
|
+
- app/controllers/dashboard-rails/application_controller.rb
|
47
|
+
- app/controllers/dashboard-rails/widgets_controller.rb
|
48
|
+
- app/helpers/dashboard-rails/application_helper.rb
|
49
|
+
- app/models/dashboard-rails/user.rb
|
50
|
+
- app/views/dashboard-rails/widgets/_widgets_list.html.erb
|
51
|
+
- app/views/dashboard-rails/widgets/index.html.erb
|
52
|
+
- config/initializers/assets.rb
|
53
|
+
- config/routes.rb
|
54
|
+
- lib/dashboard-rails.rb
|
55
|
+
- lib/dashboard-rails/engine.rb
|
56
|
+
- lib/dashboard-rails/singleton_helper.rb
|
57
|
+
- lib/dashboard-rails/version.rb
|
58
|
+
- lib/dashboard-rails/widget.rb
|
59
|
+
- lib/generators/dashboard-rails/install_generator.rb
|
60
|
+
- lib/generators/dashboard-rails/view_generator.rb
|
61
|
+
- lib/generators/dashboard-rails/widget_generator.rb
|
62
|
+
- lib/generators/templates/create_taxweb_widgets_users.rb
|
63
|
+
- lib/generators/templates/generic_widget.erb
|
64
|
+
- lib/generators/templates/generic_widget.html.erb
|
65
|
+
homepage: http://www.taxweb.com.br
|
66
|
+
licenses:
|
67
|
+
- MIT
|
68
|
+
metadata: {}
|
69
|
+
post_install_message:
|
70
|
+
rdoc_options: []
|
71
|
+
require_paths:
|
72
|
+
- lib
|
73
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
requirements: []
|
84
|
+
rubyforge_project:
|
85
|
+
rubygems_version: 2.7.8
|
86
|
+
signing_key:
|
87
|
+
specification_version: 4
|
88
|
+
summary: Gerenciamento de Widgets para Dashboard
|
89
|
+
test_files: []
|