admin_it 1.0.9 → 1.0.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 45f2f0b918cc7598db68bfa95c9531166582e32f
4
- data.tar.gz: 20beca7ce9441e4e9daf07193b683d2cce03fdbf
3
+ metadata.gz: 2b4af7fc6796fe6d148a1d91d62449d2cca40e44
4
+ data.tar.gz: dcd1542a809878391c15ed5604e74d26b1d7572d
5
5
  SHA512:
6
- metadata.gz: f3c96628072ee5f826f3363d3f46c0d35913af0f04d63f33cdcb38162c106c533535a32cf3705bfe2dd862086cfcd9ee03c4cc7cb704adf4e115c16e7f1af931
7
- data.tar.gz: bab6e0655d1a46847110bea8721ff19ad182e8f5cf516633de1b3edf83a635be1c6ad700c8cb4360f45f384492e5ed51cc8307b2dbd78aa181636262699cd78d
6
+ metadata.gz: 70d197f764d7b3126e564d7aeaf53cc47ef999f06d00a79db152defaad223725accbc64b7000cc07e92d55e964e2c856e48237c0176df300214081fec304cb62
7
+ data.tar.gz: b8886811264b9aaef4cbed1c6404eba4a93de24361785322cc86ed8ae7d65a9665136ff3d7cbc4359cf3b50ab872eed31dee8032c4f277d329582d239891240d
data/README.md CHANGED
@@ -38,6 +38,15 @@ bundle install
38
38
 
39
39
  # Changes
40
40
 
41
+ `1.0.10`
42
+
43
+ * added: sorting indicator in table column header
44
+ * added: sections
45
+
46
+ `1.0.9`
47
+
48
+ * added: filter button in table column header
49
+
41
50
  `1.0.8`
42
51
 
43
52
  * dsl code fully refactored
data/README_RU.md CHANGED
@@ -23,19 +23,98 @@ bundle install
23
23
 
24
24
  Конфигурация производится в файле `config/initializers/admin_it.rb`. На данный момент доступны следующие переменные:
25
25
 
26
+ `config.root`: папка, содержащая определения ресурсов и другие настройки. По умолчанию: `app/admin_it`.
27
+
28
+ `config.controller`: класс контроллера, от которого наследуются все контроллеры, используемые библиотекой `admin_it`. По умолчанию для Rails: `ActionController::Base`.
29
+
30
+ Пример файла конфигурации:
31
+
32
+ ```ruby
33
+ require 'admin_it'
34
+
35
+ AdminIt.config do |config|
36
+ config.root = 'admin_it'
37
+ end
38
+ ```
26
39
 
27
40
  # Использование
28
41
 
42
+ Библиотека оперирует такими понятиями, как:
43
+
44
+ * **Ресурс (resource)** - набор данных, который можно просматривать или изменять. Как правило, ресурс соответствует таблице базы данных. Для каждого ресурса библиотека создаёт отдельный класс контроллера.
45
+ * **Контекст (context)** - представление данных, или форма отображения данных. Контекст может быть для отдельной записи (`единичный контекст`) или для набора данных (`множественный контекст`). На данный момент библиотека предоставляет следующие контексты:
46
+ - единичные:
47
+ + `show` - отображение или удаление записи
48
+ + `edit` - форма для редактирования записи
49
+ + `new` - форма для создания записи
50
+ - множественные:
51
+ + `table` - таблица данных
52
+ + `tiles` - набор плиток
53
+ + `list` - список (пока не работает)
54
+ * **Поле (field)** - представляет поле (колонку) данных. Имеет следующие атрибуты:
55
+ - readable
56
+ - writable
57
+ - visible
58
+ * **Фильтр (filter)** - фильтр данных. Пока не закончено.
59
+
60
+ Для создания интерфейса управления данными, необходимо определить ресурс. Делается это в файле с расширением `.rb` в папке, указанной в конфигурации, например:
61
+
62
+ ```ruby
63
+ AdminIt.resource :location do
64
+ icon 'globe'
65
+
66
+ use_contexts except: :list
67
+
68
+ collection do
69
+ use_fields except: %i(created_at updated_at geo_point geo_data okato
70
+ kladr_code lowcase_name short_name area_children
71
+ region_children region area)
72
+ use_filters :type_name_value, :level_value
73
+ end
74
+
75
+ context :tiles do
76
+ header :name
77
+ end
78
+
79
+ context :table do
80
+ use_fields :name, :level, :*
81
+ end
82
+ end
83
+ ```
84
+
85
+ В данном файле создается ресурс для данных класса `Location`. Ресурс использует для отображения иконку "глобус". (Все иконки можно найти [здесь](http://fortawesome.github.io/Font-Awesome/icons/) - имена необходимо указывать без суффикса `fa-`).
86
+
87
+ Далее указывается, что не нужно использовать (использовать все, кроме) контекст `:list`, посокльку его описание ещё не закончено.
88
+
89
+ Далее выполняется блок для всех множественных контекстов (поскольку `:list` исключён, то это `:table` и `:tiles`). Т.е. все множественные контексты будут использовать указанные в данном блоке настройки. В нашем случае это сокращенный список полей для удобства отображения и также, сокращённый список фильтров, имеющиё смысл в данном контексте.
90
+
91
+ Далее идет индивидуальная настройка каждого контекста (не указанные явно контексты принимают все значения по-умолчанию).
92
+
93
+ Для контекста `:tiles` указывается имя поля, служащее заголоком плитки
94
+
95
+ Для контекста `:table` указывается порядок следования полей: сначала `:name`, затем `:level`, затем все остальные в порядке по-умолчанию. Символ `:*` заменяется на все имеющиеся для данного контекста поля, не указанные в команде явно.
96
+
29
97
  # Планы
30
98
 
31
99
  * Поркытие тестами
32
100
  * Редактирование/создание записей
33
101
 
34
- ## Далёкие планы
102
+ # Изменения
35
103
 
36
- * Поддержка Sinatra
104
+ `1.0.10`
37
105
 
38
- # Изменения
106
+ * добавлен индикатор сортировки в заголовках таблиц
107
+ * добавлены вкладки для единичных контекстов
108
+
109
+ `1.0.9`
110
+
111
+ * добавлена кнопка фильтров в заголоки таблиц
112
+
113
+ `1.0.8`
114
+
115
+ * полностью переработан код DSL
116
+ * увеличено покрытие тестами
117
+ * добавлена возможность выбора набора фильтров для контекста
39
118
 
40
119
  `1.0.7`
41
120
 
@@ -23,3 +23,4 @@
23
23
  .tab-pane {
24
24
  margin-top: 10px;
25
25
  }
26
+
@@ -16,11 +16,32 @@
16
16
  - if for_context.confirm == :destroy
17
17
  p = t('admin_it.confirm.destroy.header')
18
18
 
19
- dl class="dl-horizontal"
20
- - for_context.fields.each do |f|
21
- - next if f.type == :relation
22
- dt = f.display_name
23
- = field f, tag: 'dl'
19
+ - if for_context.sections.size > 0
20
+ ul class="nav nav-tabs"
21
+ - for_context.sections.each do |section|
22
+ li class="#{section.name == for_context.section ? 'active' : ''}"
23
+ a href="##{section.name}" data-toggle="tab"
24
+ = section.display_name
25
+ div class="tab-content"
26
+ - for_context.sections.each do |section|
27
+ div class="tab-pane #{section.name == for_context.section ? 'active' : ''}" id==section.name
28
+ - if section.fields.size > 0
29
+ dl class="dl-horizontal"
30
+ - section.fields.each do |f_name|
31
+ - f = for_context.field(f_name)
32
+ - next if f.type == :relation
33
+ dt = f.display_name
34
+ - value = f.show(for_context.entity)
35
+ - value = value.nil? ? ' '.html_safe : value.to_s
36
+ = field value, tag: 'dd'
37
+ - else
38
+ dl class="dl-horizontal"
39
+ - for_context.fields.each do |f|
40
+ - next if f.type == :relation
41
+ dt = f.display_name
42
+ - value = f.show(for_context.entity)
43
+ - value = value.nil? ? ' '.html_safe : value.to_s
44
+ = field value, tag: 'dd'
24
45
  div class="clearfix"
25
46
 
26
47
  - if for_context.confirm?
@@ -10,9 +10,13 @@
10
10
  = _table.header do |header|
11
11
  - for_context.headers.each do |k, h|
12
12
  - opts = { :'data-toggle' => 'popup' }
13
- - opts[:class] = 'text-info' if for_context.sorting.any? { |s| s.index("#{k}:") == 0 }
13
+ - active_sorting = for_context.sorting.find { |s| s.index("#{k}:") == 0 }
14
+ - opts[:class] = 'text-info' unless active_sorting.nil?
14
15
  = header.cell opts do
15
16
  = h
17
+ - unless active_sorting.nil?
18
+ = ' '
19
+ i class="fa fa-caret-#{active_sorting.split(':').last == 'asc' ? 'down' : 'up'}"
16
20
  - filter_class = for_context.all_filters(scope: :value).find do |f|
17
21
  - f.field.field_name == k
18
22
  - unless filter_class.nil?
@@ -25,7 +25,7 @@ html
25
25
  div class="container"
26
26
  <!-- top-menu -->
27
27
 
28
- div class="container"
28
+ div class="container admin-it-#{context.name}"
29
29
  = render File.join(%w(admin_it shared toolbar))
30
30
  = render File.join(%w(admin_it shared filters))
31
31
  = yield
@@ -1,6 +1,6 @@
1
1
  div class="modal-header"
2
2
  h4.modal-title = yield :title
3
- div class="modal-body"
3
+ div class="modal-body admin-it-#{context.name}"
4
4
  = yield
5
5
  div class="modal-footer"
6
6
  button type="button" class="btn btn-default" data-dismiss="modal"
@@ -12,6 +12,7 @@ module AdminIt
12
12
  dsl do
13
13
  dsl_block :entities, variable: :entities_getter
14
14
  dsl_accessor :default_sorting
15
+ dsl_boolean :show_in_dialog
15
16
  end
16
17
 
17
18
  def self.before_configure
@@ -25,6 +26,10 @@ module AdminIt
25
26
  ]
26
27
  end
27
28
 
29
+ def self.show_in_dialog?
30
+ @show_in_dialog.nil? ? @show_in_dialog = true : @show_in_dialog == true
31
+ end
32
+
28
33
  def self.collection?
29
34
  true
30
35
  end
@@ -41,7 +46,7 @@ module AdminIt
41
46
  end
42
47
 
43
48
  attr_accessor :entity
44
- class_attr_reader :entities_getter, :path
49
+ class_attr_reader :entities_getter, :path, :show_in_dialog?
45
50
 
46
51
  before_load do |store: {}, params: {}|
47
52
  self.sorting = store[:sorting] || self.class.default_sorting
@@ -4,25 +4,39 @@ module AdminIt
4
4
  include ExtendIt::Dsl
5
5
  include Renderable
6
6
 
7
- attr_reader :name, :display_name
7
+ attr_reader :name, :display_name, :fields
8
8
 
9
9
  dsl do
10
10
  dsl_accessor :name, :display_name
11
11
  dsl_boolean :visible
12
+
13
+ def use_fields(*names, except: nil)
14
+ names = names.ensure_symbols
15
+ fields =
16
+ if names.nil? || names.empty?
17
+ dsl_get(:fields, default: [])
18
+ else
19
+ context = dsl_get(:context, default: nil)
20
+ names & context.fields.map(&:field_name)
21
+ end
22
+ fields -= except.ensure_symbols unless except.nil?
23
+ dsl_set(:fields, fields.uniq)
24
+ end
12
25
  end
13
26
 
14
27
  def visible?
15
28
  @visible.nil? ? @visible = true : @visible == true
16
29
  end
17
30
 
18
- def fields(*names)
19
- names.empty? ? @fields ||= [] : @fields = names
20
- end
21
-
22
- def initialize(name, *fields, display_name: nil)
31
+ def initialize(name, context, display_name: nil)
23
32
  @name = name
24
33
  @display_name = display_name || name
25
- @fields = fields
34
+ @context = context
35
+ @fields = context.fields.map(&:field_name)
36
+ context.sections.each do |section|
37
+ next if section.name == name
38
+ @fields -= section.fields
39
+ end
26
40
  end
27
41
  end
28
42
 
@@ -53,12 +67,12 @@ module AdminIt
53
67
  #general.display_name(I18n.t('admin_it.collection.no_data'))
54
68
  general = Section.new(
55
69
  :general,
56
- *fields.map(&:field_name),
70
+ self,
57
71
  display_name: 'Основные свойства'
58
72
  )
59
73
  @sections[:general] = general
60
74
  end
61
- Section.new(name)
75
+ name == :general ? @sections[:general] : Section.new(name, self)
62
76
  end
63
77
  end
64
78
 
@@ -3,6 +3,21 @@ module AdminIt
3
3
  module Resource
4
4
  protected
5
5
 
6
+ TYPE_MAPPING = {
7
+ primary_key: :integer,
8
+ string: :string,
9
+ text: :string,
10
+ integer: :integer,
11
+ float: :float,
12
+ decimal: :float,
13
+ datetime: :datetime,
14
+ timestamp: :datetime,
15
+ time: :time,
16
+ date: :date,
17
+ binary: :binary,
18
+ boolean: :boolean
19
+ }
20
+
6
21
  def default_display_name
7
22
  entity_class
8
23
  .model_name
@@ -24,7 +39,7 @@ module AdminIt
24
39
  entity_class.columns_hash.each do |name, c|
25
40
  next if exclude.include?(name)
26
41
  name = name.to_sym
27
- opts = { type: c.type }
42
+ opts = { type: TYPE_MAPPING[c.type] }
28
43
  if name == :id
29
44
  opts[:visible] = false
30
45
  opts[:writable] = false
@@ -50,7 +65,7 @@ module AdminIt
50
65
  module CollectionContext
51
66
  def entities=(value)
52
67
  super(value)
53
- @count = value.count
68
+ @count = @entities.nil? ? 0 : @entities.count
54
69
  end
55
70
 
56
71
  protected
@@ -70,7 +85,9 @@ module AdminIt
70
85
  name, order = _sort.split(':')
71
86
  sort[name.to_sym] = order.to_sym
72
87
  end
73
- collection = collection.order(sort) unless sort.empty?
88
+ unless collection.nil? || sort.empty?
89
+ collection = collection.order(sort)
90
+ end
74
91
  collection
75
92
  end
76
93
  end
@@ -15,7 +15,8 @@ module AdminIt
15
15
  extend DisplayableName
16
16
  include ExtendIt::Callbacks
17
17
 
18
- TYPES = %i(unknown integer float string date relation enum)
18
+ TYPES = %i(unknown integer float string date datetime time relation enum
19
+ binary)
19
20
 
20
21
  define_callbacks :initialize
21
22
 
@@ -29,16 +30,16 @@ module AdminIt
29
30
  dsl_block :read, :write, :render, :display
30
31
 
31
32
  def hide
32
- @visible = false
33
+ dsl_set(:visible, false)
33
34
  end
34
35
 
35
36
  def show
36
- @visible = true
37
+ dsl_set(:visible, true)
37
38
  end
38
39
  end
39
40
 
40
41
  class << self
41
- attr_reader :type, :read, :write, :render, :display
42
+ attr_reader :read, :write, :render, :display, :type
42
43
 
43
44
  protected
44
45
 
@@ -65,27 +66,29 @@ module AdminIt
65
66
 
66
67
  inherited_class_reader :field_name, :entity_class
67
68
 
68
- def self.create(name, _entity_class,
69
- type: :unknown,
70
- readable: true,
71
- writable: true,
72
- visible: true,
73
- sortable: true
74
- )
69
+ def self.create(name, _entity_class, **opts)
70
+ # type: :unknown,
71
+ # readable: true,
72
+ # writable: true,
73
+ # visible: true,
74
+ # sortable: true
75
+ # )
75
76
  base = self
77
+ # _type, _readable, _writable, _visible, _sortable =
78
+ # type, readable, writable, visible, sortable
76
79
  Class.new(base) do
77
80
  @field_name, @entity_class = name, _entity_class
78
81
  import_data_module(base)
79
- @readable = readable == true
80
- @writable = writable == true
81
- @visible = visible == true
82
- @sortable = sortable == true
83
- self.type = type
82
+ @readable = opts[:readable].nil? ? true : opts[:readable] == true
83
+ @writable = opts[:writable].nil? ? true : opts[:writable] == true
84
+ @visible = opts[:visible].nil? ? true : opts[:visible] == true
85
+ @sortable = opts[:sortable].nil? ? true : opts[:sortable] == true
86
+ self.type = opts[:type]
84
87
  end
85
88
  end
86
89
 
87
90
  def self.type=(value)
88
- TYPES.include?(value) ? value : TYPES[0]
91
+ @type = TYPES.include?(value) ? value : TYPES[0]
89
92
  end
90
93
 
91
94
  def self.placeholder
@@ -25,11 +25,18 @@ module AdminIt
25
25
  resource = parent.parent.resource
26
26
  single = resource.singles.select { |c| !(c <= NewContext) }
27
27
  buttons = single.map do |_context|
28
+ if _context <= ShowContext && context.show_in_dialog?
29
+ '<a class="btn btn-xs btn-info" ' +
30
+ %Q{data-toggle="modal" data-target="#confirm_modal" } +
31
+ %Q{href="#{_context.path(entity)}?layout=dialog">} +
32
+ %Q{<i class="fa fa-#{_context.icon}"></i></a>}
33
+ else
28
34
  cl = _context <= ShowContext ? 'info' : 'default'
29
35
  href = _context.path(entity)
30
36
  "<a class=\"btn btn-xs btn-#{cl}\" href=\"#{href}\">" \
31
37
  "<i class=\"fa fa-#{_context.icon}\"></i></a>"
32
38
  end
39
+ end
33
40
  if resource.destroyable?
34
41
  if context.confirm_destroy?
35
42
  confirm = single.find { |c| c.context_name == :confirm } ||
@@ -1,5 +1,5 @@
1
1
  #
2
2
  module AdminIt
3
3
  # Current gem version
4
- VERSION = '1.0.9'
4
+ VERSION = '1.0.10'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: admin_it
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.9
4
+ version: 1.0.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexey Ovchinnikov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-03-16 00:00:00.000000000 Z
11
+ date: 2014-03-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails