katalyst-tables 3.4.6 → 3.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/builds/katalyst/tables.esm.js +15 -3
- data/app/assets/builds/katalyst/tables.js +15 -3
- data/app/assets/builds/katalyst/tables.min.js +1 -1
- data/app/assets/builds/katalyst/tables.min.js.map +1 -1
- data/app/assets/stylesheets/katalyst/tables/_query.scss +20 -20
- data/app/components/katalyst/tables/query/input_component.html.erb +7 -6
- data/app/components/katalyst/tables/query/input_component.rb +23 -7
- data/app/components/katalyst/tables/query/modal_component.html.erb +7 -17
- data/app/components/katalyst/tables/query/modal_component.rb +7 -62
- data/app/components/katalyst/tables/query/suggestion_component.html.erb +3 -0
- data/app/components/katalyst/tables/query/suggestion_component.rb +35 -0
- data/app/components/katalyst/tables/query_component.rb +0 -1
- data/app/javascript/tables/query_controller.js +10 -3
- data/app/javascript/tables/query_input_controller.js +5 -0
- data/app/models/concerns/katalyst/tables/collection/query/array_value_parser.rb +19 -1
- data/app/models/concerns/katalyst/tables/collection/query/parser.rb +12 -11
- data/app/models/concerns/katalyst/tables/collection/query/single_value_parser.rb +10 -0
- data/app/models/concerns/katalyst/tables/collection/query/untagged_literal.rb +36 -0
- data/app/models/concerns/katalyst/tables/collection/query/value_parser.rb +11 -2
- data/app/models/concerns/katalyst/tables/collection/query.rb +11 -26
- data/app/models/concerns/katalyst/tables/collection/suggestions.rb +120 -0
- data/app/models/katalyst/tables/suggestions/attribute.rb +13 -0
- data/app/models/katalyst/tables/suggestions/base.rb +31 -0
- data/app/models/katalyst/tables/suggestions/constant_value.rb +28 -0
- data/app/models/katalyst/tables/suggestions/custom_value.rb +26 -0
- data/app/models/katalyst/tables/suggestions/database_value.rb +36 -0
- data/app/models/katalyst/tables/suggestions/search_value.rb +13 -0
- data/config/locales/tables.en.yml +9 -1
- data/lib/katalyst/tables/collection/type/boolean.rb +10 -2
- data/lib/katalyst/tables/collection/type/date.rb +7 -5
- data/lib/katalyst/tables/collection/type/enum.rb +4 -4
- data/lib/katalyst/tables/collection/type/helpers/extensions.rb +1 -11
- data/lib/katalyst/tables/collection/type/value.rb +14 -12
- metadata +12 -3
- data/lib/katalyst/tables/collection/type/example.rb +0 -30
@@ -8,6 +8,7 @@ module Katalyst
|
|
8
8
|
include Katalyst::Tables::Frontend
|
9
9
|
|
10
10
|
renders_one :footer
|
11
|
+
renders_many :suggestions, SuggestionComponent
|
11
12
|
|
12
13
|
attr_reader :collection, :url
|
13
14
|
|
@@ -17,6 +18,12 @@ module Katalyst
|
|
17
18
|
@collection = collection
|
18
19
|
end
|
19
20
|
|
21
|
+
def before_render
|
22
|
+
collection.suggestions.each do |suggestion|
|
23
|
+
with_suggestion(suggestion:)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
20
27
|
private
|
21
28
|
|
22
29
|
def default_html_attributes
|
@@ -28,68 +35,6 @@ module Katalyst
|
|
28
35
|
},
|
29
36
|
}
|
30
37
|
end
|
31
|
-
|
32
|
-
using Collection::Type::Helpers::Extensions
|
33
|
-
|
34
|
-
def show_examples?
|
35
|
-
current_key && attributes[current_key]
|
36
|
-
end
|
37
|
-
|
38
|
-
def current_key
|
39
|
-
unless instance_variable_defined?(:@current_key)
|
40
|
-
attributes.each_key do |key|
|
41
|
-
@current_key = key if collection.query_active?(key)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
@current_key ||= nil
|
46
|
-
end
|
47
|
-
|
48
|
-
def attributes
|
49
|
-
collection.class.attribute_types
|
50
|
-
.select { |_, a| a.filterable? && a.type != :search }
|
51
|
-
.to_h
|
52
|
-
end
|
53
|
-
|
54
|
-
def available_filters
|
55
|
-
keys = attributes.keys
|
56
|
-
|
57
|
-
if current_token.present?
|
58
|
-
keys = keys.select { |k| k.include?(current_token) }
|
59
|
-
end
|
60
|
-
|
61
|
-
keys.map do |key|
|
62
|
-
[key, collection.model.human_attribute_name(key)]
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def examples_for(key)
|
67
|
-
collection.examples_for(key).filter_map do |example|
|
68
|
-
case example
|
69
|
-
when Collection::Type::Example
|
70
|
-
example if example.value.to_s.present?
|
71
|
-
else
|
72
|
-
raise ArgumentError, "Invalid example #{example.inspect} for #{collection.model_name}.#{key}"
|
73
|
-
end
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def format_value(value)
|
78
|
-
if /\A[\w.-]*\z/.match?(value.to_s)
|
79
|
-
value.to_s
|
80
|
-
else
|
81
|
-
%("#{value}")
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def current_token
|
86
|
-
return nil unless collection.position&.in?(0..collection.query.length)
|
87
|
-
|
88
|
-
prefix = collection.query[...collection.position].match(/\w*\z/)
|
89
|
-
suffix = collection.query[collection.position..].match(/\A\w*/)
|
90
|
-
|
91
|
-
"#{prefix}#{suffix}"
|
92
|
-
end
|
93
38
|
end
|
94
39
|
end
|
95
40
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Query
|
6
|
+
class SuggestionComponent < ViewComponent::Base
|
7
|
+
include Katalyst::HtmlAttributes
|
8
|
+
|
9
|
+
delegate :type, :value, to: :@suggestion
|
10
|
+
|
11
|
+
def initialize(suggestion:, **)
|
12
|
+
super(**)
|
13
|
+
|
14
|
+
@suggestion = suggestion
|
15
|
+
end
|
16
|
+
|
17
|
+
def default_html_attributes
|
18
|
+
{
|
19
|
+
class: ["suggestion", type.to_s],
|
20
|
+
}
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def format_value(value)
|
26
|
+
if /\A[\w.-]*\z/.match?(value.to_s)
|
27
|
+
value.to_s
|
28
|
+
else
|
29
|
+
%("#{value}")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -37,11 +37,18 @@ export default class QueryController extends Controller {
|
|
37
37
|
document.addEventListener("selectionchange", this.selection);
|
38
38
|
}
|
39
39
|
|
40
|
+
/**
|
41
|
+
* If the user presses escape once, clear the input.
|
42
|
+
* If the user presses escape again, get them out of here.
|
43
|
+
*/
|
40
44
|
clear() {
|
41
45
|
if (this.query.value === "") {
|
42
|
-
// if the user presses escape once, browser clears the input
|
43
|
-
// if the user presses escape again, get them out of here
|
44
46
|
this.closeModal();
|
47
|
+
} else {
|
48
|
+
this.query.value = "";
|
49
|
+
this.query.dispatchEvent(new Event("input"));
|
50
|
+
this.query.dispatchEvent(new Event("change"));
|
51
|
+
this.update();
|
45
52
|
}
|
46
53
|
}
|
47
54
|
|
@@ -95,7 +102,7 @@ export default class QueryController extends Controller {
|
|
95
102
|
}
|
96
103
|
|
97
104
|
get query() {
|
98
|
-
return this.element.querySelector("
|
105
|
+
return this.element.querySelector("[role=searchbox]");
|
99
106
|
}
|
100
107
|
|
101
108
|
get position() {
|
@@ -18,6 +18,7 @@ module Katalyst
|
|
18
18
|
query.scan(/#{'\['}\s*/)
|
19
19
|
|
20
20
|
until query.eos?
|
21
|
+
@value_start = query.charpos
|
21
22
|
break unless take_quoted_value || take_unquoted_value
|
22
23
|
break unless take_delimiter
|
23
24
|
end
|
@@ -33,8 +34,25 @@ module Katalyst
|
|
33
34
|
query.scan(/\s*#{','}\s*/)
|
34
35
|
end
|
35
36
|
|
37
|
+
def value
|
38
|
+
@value.map(&:value)
|
39
|
+
end
|
40
|
+
|
36
41
|
def value=(value)
|
37
|
-
@value << value
|
42
|
+
@value << Value.new(value, @value_start, @query.charpos)
|
43
|
+
end
|
44
|
+
|
45
|
+
def value_at(position)
|
46
|
+
@value.detect { |v| v.range.cover?(position) }&.value
|
47
|
+
end
|
48
|
+
|
49
|
+
class Value
|
50
|
+
attr_accessor :range, :value
|
51
|
+
|
52
|
+
def initialize(value, start, fin)
|
53
|
+
@value = value
|
54
|
+
@range = (start..fin)
|
55
|
+
end
|
38
56
|
end
|
39
57
|
end
|
40
58
|
end
|
@@ -29,6 +29,11 @@ module Katalyst
|
|
29
29
|
self
|
30
30
|
end
|
31
31
|
|
32
|
+
def token_at_position(position:)
|
33
|
+
tagged.values.detect { |v| v.range.cover?(position) } ||
|
34
|
+
untagged.detect { |v| v.range.cover?(position) }
|
35
|
+
end
|
36
|
+
|
32
37
|
private
|
33
38
|
|
34
39
|
def skip_whitespace
|
@@ -43,31 +48,27 @@ module Katalyst
|
|
43
48
|
key, = query.values_at(1)
|
44
49
|
skip_whitespace
|
45
50
|
|
46
|
-
tagged[key] = value_parser(start).parse(query)
|
51
|
+
tagged[key] = value_parser(key, start).parse(query)
|
47
52
|
end
|
48
53
|
|
49
54
|
def take_untagged
|
55
|
+
start = query.charpos
|
56
|
+
|
50
57
|
return unless query.scan(/\S+/)
|
51
58
|
|
52
|
-
untagged << query.matched
|
59
|
+
untagged << UntaggedLiteral.new(value: query.matched, start:)
|
53
60
|
|
54
61
|
untagged
|
55
62
|
end
|
56
63
|
|
57
64
|
using Type::Helpers::Extensions
|
58
65
|
|
59
|
-
def value_parser(start)
|
66
|
+
def value_parser(key, start)
|
60
67
|
if query.check(/#{'\['}\s*/)
|
61
|
-
ArrayValueParser.new(start:)
|
68
|
+
ArrayValueParser.new(key:, start:)
|
62
69
|
else
|
63
|
-
SingleValueParser.new(start:)
|
70
|
+
SingleValueParser.new(key:, start:)
|
64
71
|
end
|
65
|
-
|
66
|
-
# if attribute.type.multiple? || attribute.value.is_a?(::Array)
|
67
|
-
# ArrayValueParser.new(attribute:, pos:)
|
68
|
-
# else
|
69
|
-
# SingleValueParser.new(attribute:, pos:)
|
70
|
-
# end
|
71
72
|
end
|
72
73
|
end
|
73
74
|
end
|
@@ -15,6 +15,8 @@ module Katalyst
|
|
15
15
|
def parse(query)
|
16
16
|
@query = query
|
17
17
|
|
18
|
+
@value_start = query.charpos
|
19
|
+
|
18
20
|
take_quoted_value || take_unquoted_value
|
19
21
|
|
20
22
|
@end = query.charpos
|
@@ -22,9 +24,17 @@ module Katalyst
|
|
22
24
|
self
|
23
25
|
end
|
24
26
|
|
27
|
+
def value
|
28
|
+
@value
|
29
|
+
end
|
30
|
+
|
25
31
|
def value=(value)
|
26
32
|
@value = value
|
27
33
|
end
|
34
|
+
|
35
|
+
def value_at(position)
|
36
|
+
@value if (@value_start..@end).cover?(position)
|
37
|
+
end
|
28
38
|
end
|
29
39
|
end
|
30
40
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Collection
|
6
|
+
module Query
|
7
|
+
class UntaggedLiteral
|
8
|
+
attr_accessor :query, :value
|
9
|
+
|
10
|
+
def initialize(value:, start:)
|
11
|
+
@value = value
|
12
|
+
@start = start
|
13
|
+
@end = start + value.length
|
14
|
+
end
|
15
|
+
|
16
|
+
def literal?
|
17
|
+
true
|
18
|
+
end
|
19
|
+
|
20
|
+
def tagged?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def range
|
25
|
+
@start..@end
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_str
|
29
|
+
@value
|
30
|
+
end
|
31
|
+
alias to_s to_str
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -5,12 +5,21 @@ module Katalyst
|
|
5
5
|
module Collection
|
6
6
|
module Query
|
7
7
|
class ValueParser
|
8
|
-
attr_accessor :query, :
|
8
|
+
attr_accessor :query, :key
|
9
9
|
|
10
|
-
def initialize(start:)
|
10
|
+
def initialize(key:, start:)
|
11
|
+
@key = key
|
11
12
|
@start = start
|
12
13
|
end
|
13
14
|
|
15
|
+
def literal?
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
def tagged?
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
14
23
|
def range
|
15
24
|
@start..@end
|
16
25
|
end
|
@@ -7,6 +7,7 @@ module Katalyst
|
|
7
7
|
extend ActiveSupport::Concern
|
8
8
|
|
9
9
|
include Filtering
|
10
|
+
include Suggestions
|
10
11
|
|
11
12
|
class_methods do
|
12
13
|
def search_attribute
|
@@ -21,26 +22,13 @@ module Katalyst
|
|
21
22
|
included do
|
22
23
|
attribute :q, :query, default: ""
|
23
24
|
alias_attribute :query, :q
|
24
|
-
|
25
|
-
attribute :p, :integer, filter: false
|
26
|
-
alias_attribute :position, :p
|
27
25
|
end
|
28
26
|
|
29
|
-
|
30
|
-
|
31
|
-
def examples_for(key)
|
32
|
-
key = key.to_s
|
33
|
-
examples_method = "#{key.parameterize.underscore}_examples"
|
34
|
-
if respond_to?(examples_method)
|
35
|
-
public_send(examples_method)&.map { |e| e.is_a?(Example) ? e : Example.new(example) }
|
36
|
-
elsif @attributes.key?(key)
|
37
|
-
@attributes[key].type.examples_for(unscoped_items, @attributes[key])
|
38
|
-
end
|
27
|
+
def searchable?
|
28
|
+
self.class.search_attribute.present?
|
39
29
|
end
|
40
30
|
|
41
|
-
|
42
|
-
@attributes[attribute].query_range&.cover?(position)
|
43
|
-
end
|
31
|
+
using Type::Helpers::Extensions
|
44
32
|
|
45
33
|
private
|
46
34
|
|
@@ -48,19 +36,16 @@ module Katalyst
|
|
48
36
|
result = super
|
49
37
|
|
50
38
|
if query_changed?
|
51
|
-
|
39
|
+
@query_parser = Parser.new(self).parse(query)
|
40
|
+
|
41
|
+
@query_parser.tagged.each do |k, p|
|
42
|
+
next unless @attributes.key?(k)
|
52
43
|
|
53
|
-
|
54
|
-
if @attributes.key?(k)
|
55
|
-
_assign_attribute(k, p.value)
|
56
|
-
@attributes[k].query_range = p.range
|
57
|
-
else
|
58
|
-
errors.add(k, :unknown)
|
59
|
-
end
|
44
|
+
_assign_attribute(k, p.value)
|
60
45
|
end
|
61
46
|
|
62
|
-
if
|
63
|
-
_assign_attribute(search,
|
47
|
+
if @query_parser.untagged.any? && (search = self.class.search_attribute)
|
48
|
+
_assign_attribute(search, @query_parser.untagged.map(&:value).join(" "))
|
64
49
|
end
|
65
50
|
end
|
66
51
|
|
@@ -0,0 +1,120 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Collection
|
6
|
+
module Suggestions # :nodoc:
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
attribute :p, :integer, filter: false
|
11
|
+
alias_attribute :position, :p
|
12
|
+
end
|
13
|
+
|
14
|
+
using Type::Helpers::Extensions
|
15
|
+
|
16
|
+
def suggestions(position: self.position)
|
17
|
+
query_token = token_at_position(position:)
|
18
|
+
|
19
|
+
attribute = attribute_for_token(query_token:)
|
20
|
+
method = suggestions_method(attribute) if attribute.present?
|
21
|
+
|
22
|
+
# build a suggestions list
|
23
|
+
suggestions = if method && respond_to?(method)
|
24
|
+
user_suggestions(attribute:, method:)
|
25
|
+
elsif attribute
|
26
|
+
value_suggestions(attribute:)
|
27
|
+
else
|
28
|
+
attribute_suggestions(query_token:)
|
29
|
+
end
|
30
|
+
|
31
|
+
add_context_suggestions(suggestions:, query_token:, attribute:) if query_token
|
32
|
+
|
33
|
+
suggestions
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def attribute_for_token(query_token:)
|
39
|
+
return unless query_token&.tagged?
|
40
|
+
|
41
|
+
attribute = suggestable_attributes[query_token.key]
|
42
|
+
|
43
|
+
return unless attribute
|
44
|
+
|
45
|
+
# construct an attribute from the input token, so we can focus on what the user is currently typing instead
|
46
|
+
# of searching for the whole input for this attribute (e.g. if we're constructing an array filter)
|
47
|
+
ActiveModel::Attribute.from_user(attribute.name, query_token.value_at(position),
|
48
|
+
attribute.type, attribute)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Augments suggestions to ensure the user always has some feedback on their input.
|
52
|
+
def add_context_suggestions(suggestions:, query_token:, attribute:)
|
53
|
+
if query_token.tagged?
|
54
|
+
if !attribute
|
55
|
+
# user has entered a `:` but we don't know the attribute
|
56
|
+
errors.add(:query, :unknown_key, input: query_token.key)
|
57
|
+
elsif suggestions.none?
|
58
|
+
# the user might know more than us about what values are valid
|
59
|
+
suggestions << Tables::Suggestions::SearchValue.new(query_token.value_at(position))
|
60
|
+
end
|
61
|
+
elsif searchable?
|
62
|
+
# user is typing an untagged search term, indicate they can continue
|
63
|
+
suggestions << Tables::Suggestions::SearchValue.new(query_token.value)
|
64
|
+
else
|
65
|
+
errors.add(:query, :no_untagged_search, input: query_token.value)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def attribute_suggestions(query_token:)
|
70
|
+
attributes = suggestable_attributes.values
|
71
|
+
|
72
|
+
if query_token&.literal?
|
73
|
+
attributes = attributes.select { |a| a.name.include?(query_token.value) }
|
74
|
+
end
|
75
|
+
|
76
|
+
attributes.map { |a| Tables::Suggestions::Attribute.new(a.name) }
|
77
|
+
end
|
78
|
+
|
79
|
+
def user_suggestions(attribute:, method:)
|
80
|
+
suggestions = public_send(method, attribute)
|
81
|
+
|
82
|
+
raise TypeError, "Suggestions must be an array" unless suggestions.is_a?(Enumerable)
|
83
|
+
|
84
|
+
suggestions.map do |suggestion|
|
85
|
+
case suggestion
|
86
|
+
when Tables::Suggestions::Base
|
87
|
+
suggestion
|
88
|
+
else
|
89
|
+
Tables::Suggestions::CustomValue.new(suggestion, name: attribute.name, type: attribute.type)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def value_suggestions(attribute:)
|
95
|
+
attribute.type.suggestions(unscoped_items, attribute)
|
96
|
+
end
|
97
|
+
|
98
|
+
def suggestions_method(attribute)
|
99
|
+
:"#{attribute.name.parameterize.underscore}_suggestions" if attribute.present?
|
100
|
+
end
|
101
|
+
|
102
|
+
def suggestable_attributes
|
103
|
+
@attributes.keys.filter_map do |name|
|
104
|
+
attribute = @attributes[name]
|
105
|
+
|
106
|
+
# skip if the attribute can't generate useful suggestions
|
107
|
+
next unless attribute.type.filterable?
|
108
|
+
next if attribute.type.type == :search
|
109
|
+
|
110
|
+
[name, attribute]
|
111
|
+
end.to_h
|
112
|
+
end
|
113
|
+
|
114
|
+
def token_at_position(position: self.position)
|
115
|
+
@query_parser&.token_at_position(position:)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Suggestions
|
6
|
+
class Base
|
7
|
+
attr_reader :value
|
8
|
+
|
9
|
+
def initialize(value)
|
10
|
+
@value = value
|
11
|
+
end
|
12
|
+
|
13
|
+
def type
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
|
17
|
+
def hash
|
18
|
+
[self.class, value].hash
|
19
|
+
end
|
20
|
+
|
21
|
+
def eql?(other)
|
22
|
+
other.class.eql?(self.class) && other.value.eql?(value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
"#<#{self.class.name} value: #{value.inspect}>"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Suggestions
|
6
|
+
class ConstantValue < Base
|
7
|
+
delegate :to_param, to: :@attribute_type
|
8
|
+
|
9
|
+
def initialize(name:, type:, model:, column:, value:)
|
10
|
+
super(value)
|
11
|
+
|
12
|
+
@attribute_type = type
|
13
|
+
@model = model
|
14
|
+
@column = column
|
15
|
+
@name = name
|
16
|
+
end
|
17
|
+
|
18
|
+
def type
|
19
|
+
:constant_value
|
20
|
+
end
|
21
|
+
|
22
|
+
def value
|
23
|
+
to_param(@value)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Suggestions
|
6
|
+
class CustomValue < Base
|
7
|
+
delegate :to_param, to: :@attribute_type
|
8
|
+
|
9
|
+
def initialize(value, name:, type:)
|
10
|
+
super(value)
|
11
|
+
|
12
|
+
@name = name
|
13
|
+
@attribute_type = type
|
14
|
+
end
|
15
|
+
|
16
|
+
def type
|
17
|
+
:custom_value
|
18
|
+
end
|
19
|
+
|
20
|
+
def value
|
21
|
+
to_param(@value)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Katalyst
|
4
|
+
module Tables
|
5
|
+
module Suggestions
|
6
|
+
class DatabaseValue < Base
|
7
|
+
attr_reader :model, :column
|
8
|
+
|
9
|
+
delegate :to_param, to: :@attribute_type
|
10
|
+
|
11
|
+
def initialize(name:, type:, model:, column:, value:)
|
12
|
+
super(value)
|
13
|
+
|
14
|
+
@attribute_type = type
|
15
|
+
@model = model
|
16
|
+
@column = column
|
17
|
+
@name = name
|
18
|
+
end
|
19
|
+
|
20
|
+
def type
|
21
|
+
:database_value
|
22
|
+
end
|
23
|
+
|
24
|
+
using Tables::Collection::Type::Helpers::Extensions
|
25
|
+
|
26
|
+
def value
|
27
|
+
if @attribute_type.multiple? && @value.is_a?(Array) && @value.length == 1
|
28
|
+
to_param(@value.first)
|
29
|
+
else
|
30
|
+
to_param(@value)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|