hiding stream items on the dashboard, closes #4387

This is permanent, if a stream item is updated it doesn't re-appear on
the dashboard. This is done by marking the stream item instance as
hidden, which means adding the hidden field to the two indexes.

Change-Id: Ifa544cef4ea2d46f4214e8317af4c9e3baed76eb
Reviewed-on: https://gerrit.instructure.com/3603
Tested-by: Hudson <hudson@instructure.com>
Tested-by: Selenium <selenium@instructure.com>
Reviewed-by: Zach Wily <zach@instructure.com>
This commit is contained in:
Brian Palmer 2011-05-11 16:02:16 -06:00
parent 0709430f8a
commit 8d76be0b8c
18 changed files with 107 additions and 41 deletions

View File

@ -223,6 +223,11 @@ class UsersController < ApplicationController
@current_user.ignore_item!(params[:asset_string], params[:purpose], params[:permanent] == '1')
render :json => @current_user.to_json
end
def ignore_stream_item
StreamItemInstance.update_all({ :hidden => true }, { :stream_item_id => params[:id], :user_id => @current_user.id })
render :json => { :hidden => true }
end
def close_notification
@current_user.close_notification(params[:id])

View File

@ -1309,8 +1309,10 @@ class User < ActiveRecord::Base
opts[:start_at] ||= 2.weeks.ago
opts[:fallback_start_at] = opts[:start_at]
# dont make the query do an stream_items.context_code IN ('course_20033','course_20237','course_20247' ...) if they dont pass any contexts, just assume it wants any context code.
items = stream_items_simple
items = stream_items_simple.scoped(:conditions => { 'stream_item_instances.hidden' => false })
# dont make the query do an stream_items.context_code IN
# ('course_20033','course_20237','course_20247' ...) if they dont pass any
# contexts, just assume it wants any context code.
if opts[:contexts]
# still need to optimize the query to use a root_context_code. that way a
# users course dashboard even if they have groups does a query with

View File

@ -865,11 +865,22 @@ ul.group_list
display: block
float: right
+opacity(.7)
a.disable_item_link
visibility: hidden
float: right
margin-right: 6px
.communication_message_hover
div.header
.link_box
a
+opacity(0.5)
a.disable_item_link
visibility: visible
+opacity(0.5)
&:hover
+opacity(1.0)
.brief_communication_message
div.header
.link_box
@ -1417,4 +1428,4 @@ h2.h-margin-top,h3.h-margin-top
background-color: #c3decf
img
vertical-align: middle

View File

@ -1,5 +1,6 @@
<% collab = dashboard_collaboration; show_context ||= false %>
<div style="<%= hidden unless collab %>" class="communication_message message_<%= collab.try_rescue(:context_code) || "no_context" %> <%= 'show_context_communication_message' if show_context %>">
<%= render :partial => 'context/dashboard_ignore_link', :object => stream_item %>
<div class="header">
<div class="header_title">
<%= image_tag "#{collab.try_rescue(:style_class) || 'collaboration'}_icon.ico", :alt => collab.try_rescue(:collaboration_type), :title => collab.try_rescue(:service_name), :class => "header_icon", :style => "padding: 7px 2px 2px;" %>

View File

@ -1,5 +1,6 @@
<% conference = dashboard_conference; show_context ||= false %>
<div style="<%= hidden unless conference %>" class="communication_message message_<%= conference.try_rescue(:context_code) || "no_context" %> <%= 'show_context_communication_message' if show_context %>">
<%= render :partial => 'context/dashboard_ignore_link', :object => stream_item %>
<div class="header">
<div class="header_title">
<%= image_tag "conference.png", :alt => 'web_conference', :title => "Web Conference", :class => "header_icon", :style => "width: 20px;" %>

View File

@ -7,6 +7,7 @@
post_date = ([message] + (message.try_rescue(:sub_messages) || [])).compact.last.try_rescue(:created_at)
%>
<div class="communication_message context_message message_<%= message.try_rescue(:context_code) || "no_context" %> <%= 'show_context_communication_message' if show_context %>" style="<%= hidden unless message %>" id="context_message_<%= message ? message.id : "blank" %>">
<%= render :partial => 'context/dashboard_ignore_link', :object => stream_item %>
<% if !brief && message %><a name="message_<%= message.id %>"></a><% end %>
<div class="header">
<% if !brief %>

View File

@ -0,0 +1 @@
<%= link_to(image_tag('earmark_hover.png', :alt => 'ignore'), dashboard_ignore_stream_item_url(dashboard_ignore_link), :class => 'disable_item_link', :title => 'Ignore this stream item') %>

View File

@ -1,5 +1,6 @@
<% message = dashboard_notification; show_context ||= false %>
<div style="<%= hidden unless message %>" class="communication_message message_<%= message.try_rescue(:context_code) %> <%= 'show_context_communication_message' if show_context %> dashboard_notification">
<%= render :partial => 'context/dashboard_ignore_link', :object => stream_item %>
<div class="header">
<div class="header_title">
<%= image_tag "#{slugify(message.try_rescue(:notification_category)) || 'notification'}_icon.png", :alt => 'notification', :title => message.try_rescue(:notification_name), :class => "header_icon", :style => "padding: 7px 2px 2px;" %>

View File

@ -1,16 +1,13 @@
<% item = dashboard_stream_item %>
<% if item.type == 'Submission' %>
<%= render :partial => 'context/dashboard_submission', :object => item %>
<% elsif item.type == 'Assignment' %>
<!--%= render :partial => 'context/assignment', :object => item %-->
<% elsif item.type == 'Collaboration' %>
<%= render :partial => 'context/dashboard_collaboration', :object => item %>
<% elsif item.type == 'WebConference' %>
<%= render :partial => 'context/dashboard_conference', :object => item %>
<% elsif item.type == 'ContextMessage' %>
<%= render :partial => 'context/dashboard_context_message', :object => item %>
<% elsif item.type == 'Message' %>
<%= render :partial => 'context/dashboard_notification', :object => item %>
<% elsif item.type == 'DiscussionTopic' || item.type == 'Announcement' %>
<%= render :partial => 'context/dashboard_topic', :object => item %>
<% end %>
<%
item = dashboard_stream_item.stream_data(@current_user.id)
partial_name = case item.type
when 'Submission'; 'dashboard_submission'
when 'WebConference'; 'dashboard_conference'
when 'ContextMessage'; 'dashboard_context_message'
when 'Message'; 'dashboard_notification'
when 'DiscussionTopic','Announcement'
'dashboard_topic'
when 'Collaboration'; 'dashboard_collaboration'
end
%>
<%= render(:partial => "context/#{partial_name}", :object => item, :locals => { :stream_item => dashboard_stream_item }) if partial_name %>

View File

@ -3,6 +3,7 @@
<% show_context ||= false %>
<% post_date = ([latest_date] + comments.map(&:created_at)).max %>
<div style="<%= hidden unless dashboard_submission %>" class="communication_message message_<%= context_code || 'blank' %> <%= 'show_context_communication_message' if show_context %>">
<%= render :partial => 'context/dashboard_ignore_link', :object => stream_item %>
<div class="header">
<div class="post_date time_ago_date"><%= datetime_string(post_date) || nbsp %></div>
<%= image_tag "grading_icon.png", :class => "header_icon", :alt => "submission", :title => "Assignment Submission", :style => "padding: 7px 2px 2px 2px;" %>

View File

@ -3,6 +3,7 @@
<% post_date = ([topic] + topic.try_rescue(:root_discussion_entries) || []).compact.last.created_at %>
<% if !topic || can_do(topic, @current_user, :read) %>
<div style="<%= hidden unless topic %>" class="<%= is_announcement || topic.try_rescue(:type) == 'Announcement' || topic.try_rescue(:is_announcement) ? 'announcement' : 'discussion_topic' %> message_<%= contextless ? "blank" : context_code %> communication_message">
<%= render :partial => 'context/dashboard_ignore_link', :object => stream_item %>
<div class="header">
<div class="header_title">
<%= image_tag "announcement.png", :class => "header_icon announcement_header_icon", :alt => "announcement", :title => "Announcement", :style => "width: 20px;" %>

View File

@ -34,23 +34,7 @@
<% recent_messages.each_with_index do |topic, idx| %>
<div class="topic_message <%= 'hidden_until_scroll' if idx > show_limit %>">
<% cache(['dashboard_item_render', (@current_user.cache_key rescue 'nobody'), (topic.cache_key rescue 'no_content')].join('/')) do %>
<% case topic; when ContextMessage %>
<%= render :partial => "context/dashboard_context_message", :object => topic, :locals => {:brief => true} %>
<% when StreamItem %>
<% topic = topic.stream_data(@current_user.id) %>
<%= render :partial => "context/dashboard_stream_item", :object => topic %>
<% when Submission %>
<%= render :partial => 'context/dashboard_submission', :object => topic, :locals => {:brief => true} %>
<% when Message %>
<%= render :partial => 'context/dashboard_notification', :object => topic %>
<% when Collaboration %>
<%= render :partial => 'context/dashboard_collaboration', :object => topic %>
<% when WebConference %>
<%= render :partial => 'context/dashboard_conference', :object => topic %>
<% when Assignment %>
<% else %>
<%= render :partial => "context/dashboard_topic", :object => topic %>
<% end %>
<%= render :partial => "context/dashboard_stream_item", :object => topic %>
<% end %>
</div>
<% end %>

View File

@ -534,6 +534,7 @@ ActionController::Routing::Routes.draw do |map|
dashboard.resources :rubrics, :as => :assessments
dashboard.comment_session "comment_session", :controller => "users", :action => "kaltura_session"
dashboard.ignore_item 'ignore_item/:asset_string/:purpose', :controller => 'users', :action => 'ignore_item', :conditions => {:method => :delete}
dashboard.ignore_stream_item 'ignore_stream_item/:id', :controller => 'users', :action => 'ignore_stream_item', :conditions => {:method => :delete}
end
map.dashboard_ignore_channel 'dashboard/ignore_path', :controller => "users", :action => "ignore_channel", :conditions => {:method => :post}

View File

@ -0,0 +1,12 @@
class AddStreamItemInstanceHidden < ActiveRecord::Migration
def self.up
add_column :stream_item_instances, :hidden, :boolean, :default => false, :null => false
add_index :stream_item_instances, %w(user_id hidden id stream_item_id), :name => "index_stream_item_instances_global"
add_index :stream_item_instances, %w(user_id context_code hidden id stream_item_id), :name => "index_stream_item_instances_context"
end
def self.down
remove_column :stream_item_instances, :hidden
end
end

View File

@ -112,7 +112,7 @@ $(function initDashbardJs(){
for(var idx in notifications) {
if(notifications[idx].length > 3) {
var $template = $(notifications[idx][0]).clone();
$template.find(".content,.under_links").remove();
$template.find(".content,.under_links,.disable_item_link").remove();
$template.find(".context_code").text("click to show these notifications in the stream");
$template.find(".subject").attr('href', '#').text(notifications[idx].length + " " + idx);
$template.data('items', notifications[idx]);

View File

@ -808,9 +808,9 @@ jQuery(function($) {
$(this).closest("li").slideUp().parents("ul").children(":hidden").slideDown().first().find(":tabbable:first").focus();
return false;
});
$(".to-do-list").delegate('.disable_item_link', 'click', function(event) {
$(".to-do-list, #topic_list").delegate('.disable_item_link', 'click', function(event) {
event.preventDefault();
var $item = $(this).parents("li");
var $item = $(this).parents("li, div.topic_message");
var url = $(this).attr('href');
function remove(delete_url) {
$item.confirmDelete({

View File

@ -121,7 +121,7 @@ shared_examples_for "all selenium tests" do
attr_reader :selenium_driver
alias_method :driver, :selenium_driver
def login_as(username, password)
def login_as(username = "nobody@example.com", password = "asdfasdf")
# log out (just in case)
driver.navigate.to(app_host + '/logout')
@ -130,7 +130,8 @@ shared_examples_for "all selenium tests" do
password_element.send_keys(password)
password_element.submit
end
alias_method :login, :login_as
def wait_for_dom_ready
driver.execute_script <<-JS
window.seleniumDOMIsReady = false;

View File

@ -0,0 +1,46 @@
require File.expand_path(File.dirname(__FILE__) + '/common')
shared_examples_for "dashboard selenium tests" do
it_should_behave_like "in-process server selenium tests"
before(:each) do
course_with_student(:active_all => true)
user_with_pseudonym(:user => @user)
factory_with_protected_attributes(Announcement, :context => @course, :title => "hey all read this k", :message => "announcement")
end
def test_hiding(url)
items = @user.stream_item_instances
items.size.should == 1
items.first.hidden.should == false
login
get url
find_all_with_jquery("div.communication_message.announcement").size.should == 1
# force the element to be visible so we can click it -- webdriver has a
# hover() event but it only works on Windows so far
driver.execute_script("$('div.communication_message.announcement .disable_item_link').css('visibility', 'visible')")
driver.find_element(:css, "div.communication_message.announcement .disable_item_link").click
keep_trying { find_all_with_jquery("div.communication_message.announcement").size.should == 0 }
# should still be gone on reload
get url
find_all_with_jquery("div.communication_message.announcement").size.should == 0
@user.stream_items.size.should == 0
items.first.reload.hidden.should == true
end
it "should allow hiding a stream item on the dashboard" do
test_hiding("/")
end
it "should allow hiding a stream item on the course page" do
test_hiding("/courses/#{@course.to_param}")
end
end
describe "cross-listing Windows-Firefox-Tests" do
it_should_behave_like "dashboard selenium tests"
end