aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZog2018-01-15 10:34:30 +0100
committerZog2018-01-25 17:17:57 +0100
commit8c9ce8f5c143d1e9d3f2c038e447a01ee59c91d3 (patch)
treeed94d90b5ae6e6ad77973bd0e8dddcf335a0d995
parent5ecadfdead964381304fcf56a2564e2045988ef7 (diff)
downloadchouette-core-8c9ce8f5c143d1e9d3f2c038e447a01ee59c91d3.tar.bz2
Refs #5586 @4h; First `action_links` refactor
- Implement new API - Migrate the LineDecorator - ensure no change on the "lines/index" view
-rw-r--r--Gemfile1
-rw-r--r--Gemfile.lock7
-rw-r--r--app/decorators/line_decorator.rb111
-rw-r--r--app/helpers/table_builder_helper.rb2
-rw-r--r--app/views/lines/index.html.slim1
-rw-r--r--config/locales/lines.en.yml1
-rw-r--r--config/locales/lines.fr.yml1
-rw-r--r--lib/af83/decorator.rb124
-rw-r--r--spec/lib/af83/decorator/decorator_spec.rb423
-rw-r--r--spec/spec_helper.rb1
-rw-r--r--spec/views/lines/__snapshots__/lines/index.snap1
-rw-r--r--spec/views/lines/index.html.slim_spec.rb4
12 files changed, 614 insertions, 63 deletions
diff --git a/Gemfile b/Gemfile
index c378820b3..f22b718c3 100644
--- a/Gemfile
+++ b/Gemfile
@@ -174,6 +174,7 @@ group :test do
gem 'simplecov-rcov', :require => false
gem 'htmlbeautifier'
gem 'timecop'
+ gem 'rspec-snapshot'
end
group :test, :development, :dev do
diff --git a/Gemfile.lock b/Gemfile.lock
index ba1a90a5a..09ef00f94 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -442,6 +442,10 @@ GEM
roo (2.7.1)
nokogiri (~> 1)
rubyzip (~> 1.1, < 2.0.0)
+ rspec (3.5.0)
+ rspec-core (~> 3.5.0)
+ rspec-expectations (~> 3.5.0)
+ rspec-mocks (~> 3.5.0)
rspec-core (3.5.4)
rspec-support (~> 3.5.0)
rspec-expectations (3.5.0)
@@ -458,6 +462,8 @@ GEM
rspec-expectations (~> 3.5.0)
rspec-mocks (~> 3.5.0)
rspec-support (~> 3.5.0)
+ rspec-snapshot (0.1.1)
+ rspec (> 3.0.0)
rspec-support (3.5.0)
ruby-graphviz (1.2.3)
rubycas-client (2.3.9)
@@ -674,6 +680,7 @@ DEPENDENCIES
rgeo (~> 0.5.2)
roo
rspec-rails (~> 3.5.0)
+ rspec-snapshot
rubyzip
sass-rails (~> 4.0.3)
sawyer (~> 0.6.0)
diff --git a/app/decorators/line_decorator.rb b/app/decorators/line_decorator.rb
index 9c0cf7292..8e8e3bbc5 100644
--- a/app/decorators/line_decorator.rb
+++ b/app/decorators/line_decorator.rb
@@ -1,76 +1,67 @@
-class LineDecorator < Draper::Decorator
+class LineDecorator < AF83::Decorator
decorates Chouette::Line
delegate_all
- # Requires:
- # context: {
- # line_referential: ,
- # current_organisation:
- # }
- def action_links
- links = []
+ ### primary (and secondary) can be
+ ### - a single action
+ ### - an array of actions
+ ### - a boolean
- links << Link.new(
- content: h.t('lines.actions.show_network'),
- href: [context[:line_referential], object.network]
- )
+ action_link primary: :index do |l|
+ l.content h.t('lines.actions.show')
+ l.href { [context[:line_referential], object] }
+ end
- links << Link.new(
- content: h.t('lines.actions.show_company'),
- href: [context[:line_referential], object.company],
- disabled: object.company.nil?
- )
+ action_link do |l|
+ l.content h.t('lines.actions.show_network')
+ l.href { [context[:line_referential], object.network] }
+ end
- if h.policy(Chouette::Line).create? &&
- context[:line_referential].organisations.include?(
- context[:current_organisation]
- )
- links << Link.new(
- content: h.t('lines.actions.edit'),
- href: h.edit_line_referential_line_path(context[:line_referential], object.id)
- )
- end
+ action_link do |l|
+ l.content { h.t('lines.actions.show_company') }
+ l.href { [context[:line_referential], object.company] }
+ l.disabled { object.company.nil? }
+ end
- if h.policy(Chouette::Line).create? &&
- context[:line_referential].organisations.include?(
- context[:current_organisation]
- )
- links << Link.new(
- content: h.t('lines.actions.new'),
- href: h.new_line_referential_line_path(context[:line_referential])
- )
- end
+ can_edit_line = ->(){ h.policy(Chouette::Line).create? && context[:line_referential].organisations.include?(context[:current_organisation]) }
- if h.policy(object).deactivate?
- links << Link.new(
- content: h.deactivate_link_content('lines.actions.deactivate'),
- href: h.deactivate_line_referential_line_path(context[:line_referential], object),
- method: :put,
- data: {confirm: h.t('lines.actions.deactivate_confirm')},
- extra_class: "delete-action"
- )
+ with_condition can_edit_line do
+ action_link on: :index do |l|
+ l.content { h.t('lines.actions.new') }
+ l.href { h.new_line_referential_line_path(context[:line_referential]) }
end
- if h.policy(object).activate?
- links << Link.new(
- content: h.activate_link_content('lines.actions.activate'),
- href: h.activate_line_referential_line_path(context[:line_referential], object),
- method: :put,
- data: {confirm: h.t('lines.actions.activate_confirm')},
- extra_class: "delete-action"
- )
+ action_link on: %i(index show), primary: :show do |l|
+ l.content { h.t('lines.actions.edit') }
+ l.href { h.edit_line_referential_line_path(context[:line_referential], object.id) }
end
+ end
- if h.policy(object).destroy?
- links << Link.new(
- content: h.destroy_link_content('lines.actions.destroy'),
- href: h.line_referential_line_path(context[:line_referential], object),
- method: :delete,
- data: {confirm: h.t('lines.actions.destroy_confirm')}
- )
- end
+ ### the option :policy will automatically check for the corresponding method
+ ### on the object's policy
+
+ action_link policy: :deactivate, secondary: true do |l|
+ l.content { h.deactivate_link_content('lines.actions.deactivate') }
+ l.href { h.deactivate_line_referential_line_path(context[:line_referential], object) }
+ l.method :put
+ l.data confirm: h.t('lines.actions.deactivate_confirm')
+ l.extra_class "delete-action"
+ end
+
+ action_link policy: :activate, secondary: true do |l|
+ l.content { h.activate_link_content('lines.actions.activate') }
+ l.href { h.activate_line_referential_line_path(context[:line_referential], object) }
+ l.method :put
+ l.data confirm: h.t('lines.actions.activate_confirm')
+ l.extra_class "delete-action"
+ end
- links
+ action_link policy: :destroy do |l|
+ l.content { h.destroy_link_content('lines.actions.destroy') }
+ l.href { h.line_referential_line_path(context[:line_referential], object) }
+ l.method :delete
+ l.data confirm: h.t('lines.actions.destroy_confirm')
+ l.extra_class "delete-action"
end
end
diff --git a/app/helpers/table_builder_helper.rb b/app/helpers/table_builder_helper.rb
index dede51920..e66e9c942 100644
--- a/app/helpers/table_builder_helper.rb
+++ b/app/helpers/table_builder_helper.rb
@@ -309,7 +309,7 @@ module TableBuilderHelper
menu = content_tag :ul, class: 'dropdown-menu' do
(
CustomLinks.new(item, pundit_user, links, referential).links +
- item.action_links.select { |link| link.is_a?(Link) }
+ item.action_links
).map do |link|
gear_menu_link(link)
end.join.html_safe
diff --git a/app/views/lines/index.html.slim b/app/views/lines/index.html.slim
index b62263263..399a2d8e1 100644
--- a/app/views/lines/index.html.slim
+++ b/app/views/lines/index.html.slim
@@ -52,7 +52,6 @@
attribute: Proc.new { |n| n.transport_submode.present? ? t("enumerize.transport_submode.#{n.try(:transport_submode)}") : "-" } \
) \
],
- links: [:show],
cls: 'table has-filter has-search'
= new_pagination @lines, 'pull-right'
diff --git a/config/locales/lines.en.yml b/config/locales/lines.en.yml
index 4b2bdfdb8..8e0189bd8 100644
--- a/config/locales/lines.en.yml
+++ b/config/locales/lines.en.yml
@@ -17,6 +17,7 @@ en:
export_kml_all: "Export KML lines"
export_hub: "Export HUB line"
export_hub_all: "Export HUB lines"
+ show: 'Show'
show_network: 'Show network'
show_company: 'Show company'
new:
diff --git a/config/locales/lines.fr.yml b/config/locales/lines.fr.yml
index 6317e2930..2159f06ab 100644
--- a/config/locales/lines.fr.yml
+++ b/config/locales/lines.fr.yml
@@ -17,6 +17,7 @@ fr:
export_kml_all: "Export KML des lignes"
export_hub: "Export HUB de la ligne"
export_hub_all: "Export HUB des lignes"
+ show: 'Consulter'
show_network: 'Voir le réseau'
show_company: 'Voir le transporteur principal'
new:
diff --git a/lib/af83/decorator.rb b/lib/af83/decorator.rb
new file mode 100644
index 000000000..f1570008f
--- /dev/null
+++ b/lib/af83/decorator.rb
@@ -0,0 +1,124 @@
+class AF83::Decorator < Draper::Decorator
+ def self.action_link args={}
+ args[:if] = @_condition if args[:if].nil?
+ options, link_options = parse_options args
+
+ link = Link.new(link_options)
+ yield link if block_given?
+ raise IncompleteLinkDefinition.new(link.errors) unless link.complete?
+
+ weight = options[:weight] || 1
+ @_action_links ||= []
+ @_action_links[weight] ||= []
+ @_action_links[weight] << link
+ end
+
+ def self.with_condition condition, &block
+ @_condition = condition
+ instance_eval &block
+ @_condition = nil
+ end
+
+ def self.action_links action
+ (@_action_links || []).flatten.compact.select{|l| l.for_action?(action)}
+ end
+
+ def action_links action=:index
+ self.class.action_links(action)\
+ .map{|l| l.bind_to_context(self)}\
+ .select{|l| l.enabled?}
+ end
+
+ def check_policy policy
+ _object = policy.to_s == "create" ? object.class : object
+ method = "#{policy}?"
+ h.policy(_object).send(method)
+ end
+
+ private
+ def self.parse_options args
+ options = {}
+ %i(primary secondary permission weight).each do |k|
+ options[k] = args.delete(k) if args.has_key?(k)
+ end
+ link_options = args.dup
+ actions = args.delete :actions
+ actions ||= args.delete :on
+ actions ||= [args.delete(:action)]
+ actions = [actions] unless actions.is_a?(Array)
+ link_options[:_actions] = actions.compact
+ link_options[:_if] = args.delete(:if)
+ link_options[:_policy] = args.delete(:policy)
+ [options, link_options]
+ end
+
+ class Link
+ REQUIRED_ATTRIBUTES = %i(href content)
+
+ attr_reader :context
+
+ def initialize options={}
+ @options = options
+ end
+
+ def bind_to_context context
+ @context = context
+ self
+ end
+
+ def method *args
+ link_method *args
+ end
+
+ def method_missing name, *args, &block
+ if block_given?
+ @options[name] = block
+ elsif args.size == 0
+ out = @options[name]
+ out = context.instance_exec(&out) if out.is_a?(Proc)
+ out
+ else
+ @options[name] = args.first
+ end
+ end
+
+ def complete?
+ @missing_attributes = REQUIRED_ATTRIBUTES.select{|a| !@options[a].present?}
+ @missing_attributes.empty?
+ end
+
+ def enabled_actions
+ @options[:_actions].map(&:to_s) || []
+ end
+
+ def for_action? action
+ enabled_actions.empty? || enabled_actions.include?(action.to_s)
+ end
+
+ def enabled?
+ enabled = false
+ if @options[:_if].nil?
+ enabled = true
+ elsif @options[:_if].is_a?(Proc)
+ enabled = context.instance_exec(&@options[:_if])
+ else
+ enabled = !!@options[:_if]
+ end
+
+ enabled = enabled && check_policy(@options[:_policy]) if @options[:_policy].present?
+
+ enabled
+ end
+
+ def check_policy(policy)
+ @context.check_policy policy
+ end
+
+ def errors
+ "Missing attributes: #{@missing_attributes.to_sentence}"
+ end
+ end
+
+ class IncompleteLinkDefinition < RuntimeError
+ end
+end
diff --git a/spec/lib/af83/decorator/decorator_spec.rb b/spec/lib/af83/decorator/decorator_spec.rb
new file mode 100644
index 000000000..2e046b004
--- /dev/null
+++ b/spec/lib/af83/decorator/decorator_spec.rb
@@ -0,0 +1,423 @@
+RSpec.describe AF83::Decorator, type: :decorator do
+ describe(:parse_options) do
+ let(:options){
+ {primary: true, secondary: %i(index show), permission: :blublu, weight: 12}
+ }
+ let(:link_options){
+ {foo: :foo, bar: :bar}
+ }
+ let(:args){ options.dup.update(link_options.dup) }
+ it "should separate options from link_options" do
+ _options, _link_options = AF83::Decorator.send :parse_options, args
+ expect(_options).to eq options
+ link_options.each do |k, v|
+ expect(_link_options[k]).to eq v
+ end
+ end
+ end
+
+ link_should_match_options = ->(link, options){
+ options.each do |k, v|
+ expect(link.send(k)).to eq v
+ end
+ }
+
+ describe(:action_links) do
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj)
+ end
+
+ context "without links" do
+ let(:decorator) do
+ Class.new(AF83::Decorator)
+ end
+
+ it "should return no link" do
+ links = decorated.action_links
+ expect(links.size).to eq 0
+ end
+ end
+
+ context "with a single link" do
+ let(:link_options) do
+ {
+ href: "/foo/bar",
+ content: "Blublu"
+ }
+ end
+
+ context "incompletetly defined" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link href: "bar"
+ klass
+ end
+
+ it "should raise an error" do
+ expect{decorator}.to raise_error(AF83::Decorator::IncompleteLinkDefinition)
+ end
+ end
+
+ context "defined inline" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options
+ klass
+ end
+
+ it "should return the defined link" do
+ links = decorated.action_links
+ expect(links.size).to eq 1
+ instance_exec links.first, link_options, &link_should_match_options
+ end
+ end
+
+ context "defined in a block" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link do |l|
+ l.href link_options[:href]
+ l.content link_options[:content]
+ end
+ klass
+ end
+
+ it "should return the defined link" do
+ links = decorated.action_links
+ expect(links.size).to eq 1
+ instance_exec links.first, link_options, &link_should_match_options
+ end
+ end
+
+ context "with proc attributes" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link do |l|
+ l.href { context[:href] }
+ l.content link_options[:content]
+ end
+ klass
+ end
+
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj, context: {href: link_options[:href]})
+ end
+
+ it "should return the defined link" do
+ links = decorated.action_links
+ expect(links.size).to eq 1
+ expect(links.first.href).to eq link_options[:href]
+ end
+ end
+
+ context "with a method attributes" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link do |l|
+ l.href link_options[:href]
+ l.content link_options[:content]
+ l.method :put
+ end
+ klass
+ end
+
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj, context: {href: link_options[:href]})
+ end
+
+ it "should return the defined method" do
+ links = decorated.action_links
+ expect(links.size).to eq 1
+ expect(links.first.method).to eq :put
+ end
+ end
+ end
+
+ context "with 2 links" do
+ let(:link_options_1) do
+ {
+ href: "/foo/bar",
+ content: "Blublu"
+ }
+ end
+
+ let(:link_options_2) do
+ {
+ href: "/foo/bar/baz",
+ content: "Foo"
+ }
+ end
+
+ context "without weight" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1
+ klass.action_link link_options_2
+ klass
+ end
+
+ it "should return links in the sequence they were defined" do
+ links = decorated.action_links
+ expect(links.size).to eq 2
+ instance_exec links.first, link_options_1, &link_should_match_options
+ instance_exec links.last, link_options_2, &link_should_match_options
+ end
+ end
+
+ context "with weight" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(weight: 10)
+ klass.action_link link_options_2
+ klass
+ end
+
+ it "should return links in the sequence they were defined" do
+ links = decorated.action_links
+ expect(links.size).to eq 2
+ instance_exec links.first, link_options_2, &link_should_match_options
+ instance_exec links.last, link_options_1, &link_should_match_options
+ end
+ end
+
+ context "scoped by action" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(action: :index)
+ klass.action_link link_options_2
+ klass
+ end
+
+ it "should only return links defined for the given action" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ instance_exec links.first, link_options_2, &link_should_match_options
+ end
+ end
+
+ context "with a policy" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link href: "foo", content: "foo", policy: :edit
+ klass
+ end
+
+ context "when the policy is not met" do
+ before(:each) do
+ Draper::HelperProxy.any_instance.stub(:policy){
+ klass = Class.new do
+ def edit?
+ false
+ end
+ end.new
+ }
+ end
+
+ it "should not return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 0
+ end
+ end
+
+ context "when the policy is met" do
+ before(:each) do
+ Draper::HelperProxy.any_instance.stub(:policy){
+ klass = Class.new do
+ def edit?
+ true
+ end
+ end.new
+ }
+ end
+
+ it "should not return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ end
+ end
+ end
+
+ context "with a condition" do
+ context "set with 'with_condition'" do
+ context "as a value" do
+ context "when the condition is true" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.with_condition true do
+ action_link href: "foo", content: "foo"
+ end
+ klass
+ end
+
+ it "should return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ end
+ end
+
+ context "when the condition is false" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.with_condition false do
+ action_link href: "foo", content: "foo"
+ end
+ klass
+ end
+
+ it "should not return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 0
+ end
+ end
+ end
+
+ context "as a Proc" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.with_condition ->{context[:show_link]} do
+ action_link href: "foo", content: "foo"
+ end
+ klass
+ end
+
+ context "when the condition is true" do
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj, context: {show_link: true})
+ end
+
+ it "should return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ end
+ end
+
+ context "when the condition is false" do
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj, context: {show_link: false})
+ end
+
+ it "should not return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 0
+ end
+ end
+ end
+ end
+
+ context "set inline" do
+ context "as a value" do
+ context "when the condition is true" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(if: true)
+ klass
+ end
+
+ it "should return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ end
+ end
+
+ context "when the condition is false" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(if: false)
+ klass
+ end
+
+ it "should not return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 0
+ end
+ end
+ end
+
+ context "as a Proc" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(if: ->{context[:show_link]})
+ klass
+ end
+
+ context "when the condition is true" do
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj, context: {show_link: true})
+ end
+
+ it "should return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ end
+ end
+
+ context "when the condition is false" do
+ let(:decorated) do
+ obj = create :line
+ decorator.decorate(obj, context: {show_link: false})
+ end
+
+ it "should not return the link" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 0
+ end
+ end
+ end
+ end
+ end
+
+ context "scoped by action" do
+ context "with a single action" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(action: :index)
+ klass.action_link link_options_2
+ klass
+ end
+
+ it "should only return links defined for the given action" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ instance_exec links.first, link_options_2, &link_should_match_options
+ end
+ end
+
+ context "with several actions" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(actions: %i(index edit))
+ klass.action_link link_options_2.update(actions: %i(show edit))
+ klass
+ end
+
+ it "should only return links defined for the given action" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ instance_exec links.first, link_options_2, &link_should_match_options
+ end
+ end
+
+ context "with the keyword 'on'" do
+ let(:decorator) do
+ klass = Class.new(AF83::Decorator)
+ klass.action_link link_options_1.update(on: %i(index edit))
+ klass.action_link link_options_2.update(on: :show)
+ klass
+ end
+
+ it "should only return links defined for the given action" do
+ links = decorated.action_links(:show)
+ expect(links.size).to eq 1
+ instance_exec links.first, link_options_2, &link_should_match_options
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 2d13d3802..cde252236 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -100,7 +100,6 @@ RSpec.configure do |config|
# The different available types are documented in the features, such as in
# https://relishapp.com/rspec/rspec-rails/docs
config.infer_spec_type_from_file_location!
-
end
Shoulda::Matchers.configure do |config|
diff --git a/spec/views/lines/__snapshots__/lines/index.snap b/spec/views/lines/__snapshots__/lines/index.snap
new file mode 100644
index 000000000..f68f4f13b
--- /dev/null
+++ b/spec/views/lines/__snapshots__/lines/index.snap
@@ -0,0 +1 @@
+<div class="page_content"><div class="container-fluid"><div class="row"><div class="col-lg-12"><form class="form form-filter" id="chouette/line_search" action="/line_referentials/4/lines" accept-charset="UTF-8" method="get"><input name="utf8" type="hidden" value="&#x2713;" /><div class="ffg-row"><div class="input-group search_bar"><input placeholder="Recherche par nom, nom court ou ID Codif..." class="form-control" type="search" name="q[name_or_number_or_objectid_cont]" id="q_name_or_number_or_objectid_cont" /><span class="input-group-btn"><button class="btn btn-default" id="search-btn" type="submit"><span class="fa fa-search"></span></button></span></div></div><div class="ffg-row"><div class="form-group togglable"><label class="control-label" for="q_Réseau">Réseau</label><div class="form-group checkbox_list"><input type="hidden" name="q[network_id_eq_any][]" value="" /></div></div><div class="form-group togglable"><label class="control-label" for="q_Transporteur principal">Transporteur principal</label><div class="form-group checkbox_list"><input type="hidden" name="q[company_id_eq_any][]" value="" /></div></div><div class="form-group togglable"><label class="control-label" for="q_Mode de transport">Mode de transport</label><div class="form-group checkbox_list"><span class="checkbox"><label for="q_transport_mode_eq_any_bus"><input class="check_boxes optional" type="checkbox" value="bus" name="q[transport_mode_eq_any][]" id="q_transport_mode_eq_any_bus" /><span>Bus</span></label></span><span class="checkbox"><label for="q_transport_mode_eq_any_funicular"><input class="check_boxes optional" type="checkbox" value="funicular" name="q[transport_mode_eq_any][]" id="q_transport_mode_eq_any_funicular" /><span>Funiculaire</span></label></span><span class="checkbox"><label for="q_transport_mode_eq_any_metro"><input class="check_boxes optional" type="checkbox" value="metro" name="q[transport_mode_eq_any][]" id="q_transport_mode_eq_any_metro" /><span>Métro</span></label></span><span class="checkbox"><label for="q_transport_mode_eq_any_rail"><input class="check_boxes optional" type="checkbox" value="rail" name="q[transport_mode_eq_any][]" id="q_transport_mode_eq_any_rail" /><span>Train</span></label></span><span class="checkbox"><label for="q_transport_mode_eq_any_tram"><input class="check_boxes optional" type="checkbox" value="tram" name="q[transport_mode_eq_any][]" id="q_transport_mode_eq_any_tram" /><span>Tramway</span></label></span><input type="hidden" name="q[transport_mode_eq_any][]" value="" /></div></div><div class="form-group togglable"><label class="control-label" for="q_Sous mode de transport">Sous mode de transport</label><div class="form-group checkbox_list"><span class="checkbox"><label for="q_transport_submode_eq_any_highfrequencybus"><input class="check_boxes optional" type="checkbox" value="highFrequencyBus" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_highfrequencybus" /><span>Bus à haute fréquence</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_demandandresponsebus"><input class="check_boxes optional" type="checkbox" value="demandAndResponseBus" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_demandandresponsebus" /><span>Bus à la demande</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_nightbus"><input class="check_boxes optional" type="checkbox" value="nightBus" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_nightbus" /><span>Bus de nuit</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_expressbus"><input class="check_boxes optional" type="checkbox" value="expressBus" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_expressbus" /><span>Bus express</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_interregionalrail"><input class="check_boxes optional" type="checkbox" value="interregionalRail" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_interregionalrail" /><span>Intercités</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_airportlinkbus"><input class="check_boxes optional" type="checkbox" value="airportLinkBus" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_airportlinkbus" /><span>Navette interne aéroport</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_regionalrail"><input class="check_boxes optional" type="checkbox" value="regionalRail" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_regionalrail" /><span>TER</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_suburbanrailway"><input class="check_boxes optional" type="checkbox" value="suburbanRailway" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_suburbanrailway" /><span>Train</span></label></span><span class="checkbox"><label for="q_transport_submode_eq_any_railshuttle"><input class="check_boxes optional" type="checkbox" value="railShuttle" name="q[transport_submode_eq_any][]" id="q_transport_submode_eq_any_railshuttle" /><span>Val</span></label></span><input type="hidden" name="q[transport_submode_eq_any][]" value="" /></div></div></div><div class="actions"><a class="btn btn-link" href="/line_referentials/4/lines">Effacer</a><input type="submit" name="commit" value="Filtrer" class="btn btn-default" /></div></form></div></div><div class="row"><div class="col-lg-12"><table class="table has-filter has-search"><thead><tr><th>ID Codifligne</th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=number">Numéro<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=name">Nom de la ligne<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=deactivated">Activé<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=networks.name">Réseau<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=companies.name">Transporteur principal<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=transport_mode">Mode de transport<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th><a href="/line_referentials/4/lines?direction=desc&amp;sort=transport_submode">Sous mode de transport<span class="orderers"><span class="fa fa-sort-asc active"></span><span class="fa fa-sort-desc "></span></span></a></th><th></th></tr></thead><tbody><tr class="line-1"><td>1</td><td>1</td><td title="Voir"><a href="/line_referentials/4/lines/1">Line 1</a></td><td><span class="fa fa-check-circle fa-lg text-success"></span>Oui</td><td>Network 1</td><td>Company 1</td><td>Bus</td><td>-</td><td class="actions"><div class="btn-group"><div class="btn dropdown-toggle" data-toggle="dropdown"><span class="fa fa-cog"></span></div><ul class="dropdown-menu"><li><a href="/line_referentials/4/lines/1">Consulter</a></li><li><a href="/line_referentials/4/networks/1">Voir le réseau</a></li><li><a href="/line_referentials/4/companies/1">Voir le transporteur principal</a></li></ul></div></td></tr><tr class="line-2"><td>2</td><td>2</td><td title="Voir"><a href="/line_referentials/4/lines/2">Line 2</a></td><td><span class="fa fa-check-circle fa-lg text-success"></span>Oui</td><td>Network 2</td><td>Company 2</td><td>Bus</td><td>-</td><td class="actions"><div class="btn-group"><div class="btn dropdown-toggle" data-toggle="dropdown"><span class="fa fa-cog"></span></div><ul class="dropdown-menu"><li><a href="/line_referentials/4/lines/2">Consulter</a></li><li><a href="/line_referentials/4/networks/2">Voir le réseau</a></li><li><a href="/line_referentials/4/companies/2">Voir le transporteur principal</a></li></ul></div></td></tr></tbody></table><div class="pagination pull-right">Liste des lignes 1 à 2 sur 2</div></div></div></div></div> \ No newline at end of file
diff --git a/spec/views/lines/index.html.slim_spec.rb b/spec/views/lines/index.html.slim_spec.rb
index 498784912..9237487e3 100644
--- a/spec/views/lines/index.html.slim_spec.rb
+++ b/spec/views/lines/index.html.slim_spec.rb
@@ -32,6 +32,10 @@ describe "/lines/index", :type => :view do
common_items.call()
it { should have_the_right_number_of_links(lines, 3) }
+ it "should match the snapshot" do
+ expect(rendered).to match_snapshot("lines/index")
+ end
+
with_permission "lines.change_status" do
common_items.call()
it { should have_link_for_each_item(lines, "deactivate", -> (line){ view.deactivate_line_referential_line_path(line_referential, line) }) }