card 1.93.5 → 1.93.6

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.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -1
  3. data/db/migrate_core_cards/data/1.12_stylesheets/classic_cards.scss +1 -1
  4. data/db/migrate_core_cards/data/1.12_stylesheets/traditional.scss +2 -1
  5. data/lib/card/format/nest.rb +4 -1
  6. data/lib/card/format/nest/mode.rb +11 -3
  7. data/lib/card/query.rb +6 -2
  8. data/lib/card/query/sorting.rb +21 -12
  9. data/lib/card/query/sql_statement.rb +1 -2
  10. data/lib/card/view/options.rb +17 -12
  11. data/mod/Modfile +1 -0
  12. data/mod/core/layout/simple_modal.html +3 -0
  13. data/mod/core/set/all/fetch_helper.rb +42 -30
  14. data/mod/core/spec/format/html_format_spec.rb +10 -17
  15. data/mod/core/spec/set/all/fetch_helper_spec.rb +48 -0
  16. data/mod/machines/file/all_script_machine_output/file.js +132 -18
  17. data/mod/machines/lib/javascript/decko.js.coffee +11 -2
  18. data/mod/machines/lib/javascript/decko_filter.js.coffee +116 -9
  19. data/mod/machines/lib/stylesheets/style_cards.scss +24 -3
  20. data/mod/pointer/lib/javascript/script_pointer_config.js.coffee +16 -6
  21. data/mod/pointer/set/abstract/00_paging_params.rb +17 -4
  22. data/mod/pointer/set/abstract/02_pointer/filtered.rb +48 -0
  23. data/mod/pointer/set/self/input_options.rb +1 -0
  24. data/mod/pointer/spec/set/self/input_options_spec.rb +1 -1
  25. data/mod/pointer/template/abstract/02_pointer/filtered/filter_items.haml +34 -0
  26. data/mod/pointer/template/abstract/02_pointer/filtered/filtered_list_input.haml +30 -0
  27. data/mod/search/lib/card/filter_query.rb +81 -0
  28. data/mod/search/set/abstract/00_filter_helper.rb +51 -0
  29. data/mod/search/set/abstract/01_filter_form_helper.rb +77 -0
  30. data/mod/search/set/abstract/01_search_params.rb +3 -11
  31. data/mod/search/set/abstract/02_filter_formgroups.rb +134 -0
  32. data/mod/search/set/abstract/03_filter.rb +117 -0
  33. data/mod/search/set/abstract/04_right_filter_form.rb +23 -0
  34. data/mod/search/set/abstract/search.rb +44 -10
  35. data/mod/search/set/abstract/wql_search.rb +22 -18
  36. data/mod/search/spec/set/{all → abstract}/filter_spec.rb +6 -5
  37. data/mod/search/template/{all/filter → abstract/03_filter}/_filter_input.haml +0 -0
  38. data/mod/search/template/{all/filter → abstract/03_filter}/filter_form.haml +9 -7
  39. data/mod/search/template/abstract/search/checkbox_item.haml +7 -0
  40. data/mod/search/template/abstract/search/select_item.haml +14 -0
  41. data/mod/standard/set/all/rich_html/editing.rb +4 -4
  42. data/mod/standard/set/all/rich_html/form_elements.rb +11 -2
  43. data/mod/standard/set/all/rich_html/modal.rb +26 -19
  44. data/mod/standard/set/all/rich_html/new.rb +8 -2
  45. data/mod/standard/set/all/rich_html/wrapper.rb +22 -18
  46. data/mod/standard/set/type/cardtype.rb +2 -2
  47. data/mod/standard/spec/set/all/rich_html/editing_spec.rb +0 -1
  48. data/mod/utility/set/abstract/utility.rb +13 -0
  49. data/mod/utility/spec/set/abstract/utility_spec.rb +16 -0
  50. metadata +21 -7
  51. data/mod/search/set/all/filter.rb +0 -9
@@ -0,0 +1,134 @@
1
+ include_set Abstract::FilterFormHelper
2
+
3
+ # FIXME: the vast majority of these need to be moved back to wikirate
4
+ format :html do
5
+ view :filter_name_formgroup, cache: :never do
6
+ text_filter :name
7
+ end
8
+
9
+ view :filter_project_formgroup, cache: :never do
10
+ select_filter_type_based :project
11
+ end
12
+
13
+ view :filter_year_formgroup, cache: :never do
14
+ select_filter :year, "Year", "most recent"
15
+ end
16
+
17
+ view :filter_wikirate_topic_formgroup, cache: :never do
18
+ # select_filter_type_based :wikirate_topic
19
+ autocomplete_filter :wikirate_topic
20
+ end
21
+
22
+ view :filter_metric_formgroup, cache: :never do
23
+ # select_filter_type_based :metric
24
+ autocomplete_filter :metric
25
+ end
26
+
27
+ view :filter_wikirate_company_formgroup, cache: :never do
28
+ # select_filter_type_based :wikirate_company
29
+ autocomplete_filter :wikirate_company
30
+ end
31
+
32
+ view :filter_research_policy_formgroup, cache: :never do
33
+ multiselect_filter :research_policy, "Research Policy"
34
+ end
35
+
36
+ def research_policy_select
37
+ select_filter_type_based :research_policy
38
+ end
39
+
40
+ view :filter_metric_type_formgroup, cache: :never do
41
+ multiselect_filter :metric_type, "Metric Type"
42
+ end
43
+
44
+ def metric_type_select
45
+ select_filter :metric_type, "Metric Type"
46
+ end
47
+
48
+ view :filter_metric_value_formgroup, cache: :never do
49
+ select_filter :metric_value, "Value", "exists"
50
+ end
51
+
52
+ view :filter_designer_formgroup, cache: :never do
53
+ select_filter :designer, "Designer"
54
+ end
55
+
56
+ view :filter_importance_formgroup, cache: :never do
57
+ multiselect_filter :importance, "My Vote", %w[upvotes novotes]
58
+ end
59
+
60
+ view :filter_industry_formgroup, cache: :never do
61
+ select_filter :industry, "Industry"
62
+ end
63
+
64
+ def sort_options
65
+ {}
66
+ end
67
+
68
+ def default_year_option
69
+ { "Most Recent" => "latest" }
70
+ end
71
+
72
+ def year_options
73
+ type_options(:year, "desc").each_with_object(default_year_option) do |v, h|
74
+ h[v] = v
75
+ end
76
+ end
77
+
78
+ def metric_value_options
79
+ opts = {
80
+ "All" => "all",
81
+ "Researched" => "exists",
82
+ "Known" => "known",
83
+ "Unknown" => "unknown",
84
+ "Not Researched" => "none",
85
+ "Edited today" => "today",
86
+ "Edited this week" => "week",
87
+ "Edited this month" => "month",
88
+ "Outliers" => "outliers"
89
+ }
90
+ return opts unless filter_param(:range)
91
+ opts.each_with_object({}) do |(k, v), h|
92
+ h[add_range(k, v)] = v
93
+ end
94
+ end
95
+
96
+ def add_range key, _value
97
+ key # unless selected_value?(value)
98
+ # range = filter_param :range
99
+ # "#{range[:from]} <= #{key} < #{range[:to]}"
100
+ end
101
+
102
+ def selected_value? value
103
+ (filter_param(:metric_value) && value == filter_param(:metric_value)) ||
104
+ value == "exists"
105
+ end
106
+
107
+ def metric_type_options
108
+ %i[researched formula wiki_rating].map { |n| Card.quick_fetch(n).name }
109
+ end
110
+
111
+ def research_policy_options
112
+ type_options :research_policy
113
+ end
114
+
115
+ def importance_options
116
+ { "I voted FOR" => :upvotes,
117
+ "I voted AGAINST" => :downvotes,
118
+ "I did NOT vote" => :novotes }
119
+ end
120
+
121
+ def industry_options
122
+ card_name = CompanyFilterQuery::INDUSTRY_METRIC_NAME
123
+ Card[card_name].value_options
124
+ end
125
+
126
+ def designer_options
127
+ metrics = Card.search type_id: MetricID, return: :name
128
+ metrics.map do |m|
129
+ names = m.to_name.parts
130
+ # score metric?
131
+ names.length == 3 ? names[2] : names[0]
132
+ end.uniq!(&:downcase).sort_by!(&:downcase)
133
+ end
134
+ end
@@ -0,0 +1,117 @@
1
+ include_set Abstract::FilterFormgroups
2
+ include_set Abstract::Utility
3
+
4
+ def filter_class
5
+ Card::FilterQuery
6
+ end
7
+
8
+ def filter_and_sort_wql
9
+ sort? ? filter_wql.merge(sort_wql) : filter_wql
10
+ end
11
+
12
+ def filter_wql
13
+ return {} if filter_hash.empty?
14
+ filter_wql_from_params
15
+ end
16
+
17
+ # separate method is needed for tests
18
+ def filter_wql_from_params
19
+ filter_class.new(filter_keys_with_values, blocked_id_wql).to_wql
20
+ end
21
+
22
+ def sort_wql
23
+ return {} if !sort? || sort_param.blank?
24
+ sort_hash
25
+ end
26
+
27
+ def sort?
28
+ true
29
+ end
30
+
31
+ def current_sort
32
+ sort_param || default_sort_option
33
+ end
34
+
35
+ def blocked_id_wql
36
+ not_ids = filter_param :not_ids
37
+ not_ids.present? ? { id: ["not in", not_ids.split(",")] } : {}
38
+ end
39
+
40
+ def advanced_filter_keys
41
+ []
42
+ end
43
+
44
+ # all filter keys in the order they were selected
45
+ def all_filter_keys
46
+ @all_filter_keys ||= filter_keys_from_params | filter_keys | advanced_filter_keys
47
+ end
48
+
49
+ def filter_keys
50
+ [:name]
51
+ end
52
+
53
+ def filter_keys_from_params
54
+ filter_hash.keys.map(&:to_sym) - [:not_ids]
55
+ end
56
+
57
+ format :html do
58
+ delegate :filter_hash, to: :card
59
+
60
+ def filter_fields slot_selector: nil, sort_field: nil
61
+ form_args = { action: filter_action_path, class: "slotter" }
62
+ form_args["data-slot-selector"] = slot_selector if slot_selector
63
+ filter_form filter_form_data, sort_field, form_args
64
+ end
65
+
66
+ def filter_form_data
67
+ all_filter_keys.each_with_object({}) do |cat, h|
68
+ h[cat] = { label: filter_label(cat),
69
+ input_field: _render("filter_#{cat}_formgroup"),
70
+ active: show_filter_field?(cat) }
71
+ end
72
+ end
73
+
74
+ def show_filter_field? field
75
+ filter_hash.present? ? filter_hash[field] : card.default_filter_option[field]
76
+ end
77
+
78
+ def filter_label field
79
+ return "Keyword" if field.to_sym == :name
80
+ Card.fetch_name(field) { field.to_s.capitalize }
81
+ end
82
+
83
+ def filter_action_path
84
+ path
85
+ end
86
+
87
+ view :filter_form, cache: :never do
88
+ filter_fields slot_selector: "._filter-result-slot",
89
+ sort_field: _render(:sort_formgroup)
90
+ end
91
+
92
+ # @param data [Hash] the filter categories. The hash needs for every category
93
+ # a hash with a label and a input_field entry.
94
+ def filter_form data={}, sort_input_field=nil, form_args={}
95
+ haml :filter_form, categories: data,
96
+ sort_input_field: sort_input_field,
97
+ form_args: form_args
98
+ end
99
+
100
+ def sort_options
101
+ {
102
+ "Alphabetical": :name,
103
+ "Recently Updated": :updated_at
104
+ }
105
+ end
106
+
107
+ view :sort_formgroup, cache: :never do
108
+ select_tag "sort",
109
+ options_for_select(sort_options, card.current_sort),
110
+ class: "pointer-select _filter-sort",
111
+ "data-minimum-results-for-search": "Infinity"
112
+ end
113
+ end
114
+
115
+ def default_sort_option
116
+ wql_from_content[:sort]
117
+ end
@@ -0,0 +1,23 @@
1
+ # To be included in a field card to get a filter for the parent.
2
+ # The core view renders a filter for the left card.
3
+
4
+ include_set Set::Abstract::Filter
5
+
6
+ def virtual?
7
+ true
8
+ end
9
+
10
+ format :html do
11
+ def filter_action_path
12
+ path mark: card.name.left, view: filter_view
13
+ end
14
+
15
+ # FIXME: wikirate-specific reference in selector
16
+ view :core, cache: :never do
17
+ filter_fields slot_selector: ".RIGHT-all_metric_value.filter_result-view"
18
+ end
19
+
20
+ def filter_view
21
+ :filter_result
22
+ end
23
+ end
@@ -1,5 +1,6 @@
1
1
  include_set Abstract::SearchParams
2
2
  include_set Abstract::Paging
3
+ include_set Abstract::Filter
3
4
 
4
5
  def search _args={}
5
6
  raise Error, "search not overridden"
@@ -106,26 +107,59 @@ format :csv do
106
107
  end
107
108
 
108
109
  format :html do
109
- view :card_list do
110
+ def with_results
110
111
  return render_no_search_results if search_with_params.empty?
111
- search_result_list do
112
- search_with_params.map do |item_card|
113
- nest_item item_card, size: voo.size do |rendered, item_view|
114
- klass = "search-result-item item-#{item_view}"
115
- %(<div class="#{klass}">#{rendered}</div>)
116
- end
112
+ yield
113
+ end
114
+
115
+ view :card_list do
116
+ with_results do
117
+ search_result_list "search-result-list" do |item_card|
118
+ card_list_item item_card
117
119
  end
118
120
  end
119
121
  end
120
122
 
121
- def search_result_list
123
+ def card_list_item item_card
124
+ nest_item item_card, size: voo.size do |rendered, item_view|
125
+ %(<div class="search-result-item item-#{item_view}">#{rendered}</div>)
126
+ end
127
+ end
128
+
129
+ def search_result_list klass
122
130
  with_paging do
123
- wrap_with :div, class: "search-result-list" do
124
- yield
131
+ wrap_with :div, class: klass do
132
+ search_with_params.map do |item_card|
133
+ yield item_card
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ view :select_item, cache: :never do
140
+ wrap do
141
+ haml :select_item
142
+ end
143
+ end
144
+
145
+ def default_select_item_args _args
146
+ class_up "card-slot", "_filter-result-slot"
147
+ end
148
+
149
+ view :checkbox_list, cache: :never do
150
+ with_results do
151
+ search_result_list "_search-checkbox-list" do |item_card|
152
+ checkbox_item item_card
125
153
  end
126
154
  end
127
155
  end
128
156
 
157
+ def checkbox_item item_card
158
+ subformat(item_card).wrap do
159
+ haml :checkbox_item, unique_id: unique_id, item_card: item_card
160
+ end
161
+ end
162
+
129
163
  def closed_limit
130
164
  [search_params[:limit].to_i, Card.config.closed_search_limit].min
131
165
  end
@@ -8,34 +8,38 @@ def search args={}
8
8
  query.run
9
9
  end
10
10
 
11
- # override this to define search
12
- def wql_hash
13
- @wql_hash ||= begin
14
- query = content
15
- query = query.is_a?(Hash) ? query : parse_json_query(query)
16
- query.symbolize_keys
17
- end
18
- end
19
-
20
- def query_args args={}
21
- wql_hash.merge args
11
+ def fetch_query args={}
12
+ @query ||= {}
13
+ @query[args.to_s] ||= query(args.clone) # cache query
22
14
  end
23
15
 
24
16
  def query args={}
25
17
  Query.new standardized_query_args(args), name
26
18
  end
27
19
 
28
- def fetch_query args={}
29
- @query ||= {}
30
- @query[args.to_s] ||= query(args.clone) # cache query
31
- end
32
-
33
20
  def standardized_query_args args
34
21
  args = query_args(args).symbolize_keys
35
22
  args[:context] ||= name
36
23
  args
37
24
  end
38
25
 
26
+ # override this to define search
27
+ def wql_hash
28
+ @wql_hash ||= wql_from_content.merge filter_and_sort_wql
29
+ end
30
+
31
+ def wql_from_content
32
+ @wql_from_content ||= begin
33
+ query = content
34
+ query = query.is_a?(Hash) ? query : parse_json_query(query)
35
+ query.symbolize_keys
36
+ end
37
+ end
38
+
39
+ def query_args args={}
40
+ wql_hash.merge args
41
+ end
42
+
39
43
  def parse_json_query query
40
44
  empty_query_error! if query.empty?
41
45
  JSON.parse query
@@ -49,8 +53,8 @@ def empty_query_error!
49
53
  end
50
54
 
51
55
  format do
52
- def default_search_params
53
- @default_search_params ||= { limit: (card_content_limit || default_limit) }
56
+ def default_limit
57
+ card_content_limit || super
54
58
  end
55
59
 
56
60
  def card_content_limit
@@ -1,9 +1,10 @@
1
- describe Card::Set::All::Filter do
1
+ describe Card::Set::Abstract::Filter do
2
2
  subject do
3
- Card["A"].format.filter_form a: { input_field: "<input id='a'/>", label: "A" },
4
- b: { input_field: "<select id='b'/>", label: "B" },
5
- c: { input_field: "<select id='c'/>", label: "C",
6
- active: true }
3
+ search_card = Card.new type: "Search"
4
+ search_card.format.filter_form a: { input_field: "<input id='a'/>", label: "A" },
5
+ b: { input_field: "<select id='b'/>", label: "B" },
6
+ c: { input_field: "<select id='c'/>", label: "C",
7
+ active: true }
7
8
  end
8
9
 
9
10
  specify "#filter_form" do
@@ -8,9 +8,11 @@
8
8
  - unless category[:active]
9
9
  = haml_partial :filter_input, key: key, category: category
10
10
 
11
- %form._filter-form{form_args, "accept-charset" => "UTF-8",
12
- "data-remote" => "true",
13
- :method => "get"}
11
+ %form._filter-form{form_args, "accept-charset": "UTF-8",
12
+ "data-remote": "true",
13
+ method: "get"}
14
+ - not_ids = params.dig :filter, :not_ids
15
+ %input{ type: :hidden, name: "filter[not_ids]", class: "_not-ids", value: not_ids }
14
16
  .d-flex.flex-row
15
17
  - if sort_input_field
16
18
  %i.material-icons.text-muted.md-24.p-2 sort
@@ -25,10 +27,10 @@
25
27
  = haml_partial :filter_input, key: key, category: category
26
28
 
27
29
  .dropdown._add-filter-dropdown
28
- %button.btn.btn-secondary.dropdown-toggle{"aria-expanded" => "false",
29
- "aria-haspopup" => "true",
30
- "data-toggle" => "dropdown",
31
- :type => "button"}
30
+ %button.btn.btn-secondary.dropdown-toggle{"aria-expanded": "false",
31
+ "aria-haspopup": "true",
32
+ "data-toggle": "dropdown",
33
+ type: "button" }
32
34
  Add filter
33
35
  .dropdown-menu
34
36
  - categories.each do |key, category|