Feature/sort by event start date (#320)
FEATURE: - Added custom fields `sort_topics_by_event_start_date` and `disable_topic_resorting` - Sort topics of event categories by event start date. Event categories have custom field `sort_topics_by_event_start_date` set to true. - Disable re-sorting of categories with custom field `disable_topic_resorting` - Event date displayed beside the Topic title can optionally be set to show the local date-time, instead of relative date-time. -
This commit is contained in:
parent
139fdd9cc3
commit
6820f7a433
|
@ -0,0 +1,21 @@
|
|||
<section>
|
||||
<h3>{{i18n "category.settings_sections.event_sorting"}}</h3>
|
||||
|
||||
{{#if siteSettings.sort_categories_by_event_start_date_enabled}}
|
||||
<section class="field show-subcategory-list-field">
|
||||
<label>
|
||||
<Input @type="checkbox" @checked={{this.category.custom_fields.sort_topics_by_event_start_date}} />
|
||||
{{i18n "category.sort_topics_by_event_start_date"}}
|
||||
</label>
|
||||
</section>
|
||||
{{/if}}
|
||||
|
||||
{{#if siteSettings.disable_resorting_on_categories_enabled}}
|
||||
<section class="field show-subcategory-list-field">
|
||||
<label>
|
||||
<Input @type="checkbox" @checked={{this.category.custom_fields.disable_topic_resorting}} />
|
||||
{{i18n "category.disable_topic_resorting"}}
|
||||
</label>
|
||||
</section>
|
||||
{{/if}}
|
||||
</section>
|
|
@ -1,5 +1,6 @@
|
|||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import eventRelativeDate from "discourse/plugins/discourse-calendar/lib/event-relative-date";
|
||||
import eventLocalDate from "discourse/plugins/discourse-calendar/lib/event-local-date";
|
||||
|
||||
function initializeDecorateTopicTitle(api) {
|
||||
api.decorateTopicTitle((topic, node, topicTitleType) => {
|
||||
|
@ -25,8 +26,12 @@ function initializeDecorateTopicTitle(api) {
|
|||
eventdateContainer.appendChild(eventDate);
|
||||
node.appendChild(eventdateContainer);
|
||||
|
||||
// we force a first computation, as waiting for the auto update might take time
|
||||
eventRelativeDate(eventDate);
|
||||
if (topic.siteSettings.use_local_event_date) {
|
||||
eventLocalDate(eventDate);
|
||||
} else {
|
||||
// we force a first computation, as waiting for the auto update might take time
|
||||
eventRelativeDate(eventDate);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
import discourseComputed from "discourse-common/utils/decorators";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
|
||||
export default {
|
||||
name: "disable-sort",
|
||||
initialize() {
|
||||
withPluginApi("0.8", (api) => {
|
||||
api.modifyClass("component:topic-list", {
|
||||
@discourseComputed("category")
|
||||
sortable(category) {
|
||||
let disableSort = true;
|
||||
if (category && category.custom_fields) {
|
||||
disableSort = !!category.custom_fields["disable_topic_resorting"];
|
||||
}
|
||||
return !!this.changeSort && !disableSort;
|
||||
},
|
||||
});
|
||||
});
|
||||
},
|
||||
};
|
|
@ -0,0 +1,21 @@
|
|||
import guessDateFormat from "discourse/plugins/discourse-calendar/lib/guess-best-date-format";
|
||||
|
||||
export default function eventLocalDate(container) {
|
||||
container.classList.remove("past", "current", "future");
|
||||
container.innerHTML = "";
|
||||
|
||||
const startsAt = moment
|
||||
.utc(container.dataset.starts_at)
|
||||
.tz(moment.tz.guess());
|
||||
const endsAt = moment.utc(container.dataset.ends_at).tz(moment.tz.guess());
|
||||
|
||||
const format = guessDateFormat(startsAt);
|
||||
let title = startsAt.format(format);
|
||||
if (endsAt) {
|
||||
title += ` → ${endsAt.format(format)}`;
|
||||
}
|
||||
container.setAttribute("title", title);
|
||||
container.classList.add("past");
|
||||
|
||||
container.innerText = startsAt.format(format);
|
||||
}
|
|
@ -413,3 +413,8 @@ en:
|
|||
creator: "Creator"
|
||||
status: "Status"
|
||||
starts_at: "Starts at"
|
||||
category:
|
||||
sort_topics_by_event_start_date: "Sort topics by event start date."
|
||||
disable_topic_resorting: "Disable topic resorting."
|
||||
settings_sections:
|
||||
event_sorting: "Event Sorting"
|
||||
|
|
|
@ -33,6 +33,7 @@ en:
|
|||
discourse_post_event_enabled: "[experimental] Enables to attach an event to a post. Note: also needs `calendar enabled` to be enabled."
|
||||
displayed_invitees_limit: "Limits the numbers of invitees displayed on an event."
|
||||
display_post_event_date_on_topic_title: "Displays the date of the event after the topic title."
|
||||
use_local_event_date: "Use local date after topic title instead of relative time."
|
||||
discourse_post_event_allowed_on_groups: "Groups that are allowed to create events."
|
||||
discourse_post_event_allowed_custom_fields: "Allows to let each event to set the value of custom fields."
|
||||
discourse_post_event_edit_notifications_time_extension: "Extends (in minutes) the period after the end of an event when `going` invitees are still being notified from edit in the original post."
|
||||
|
@ -48,6 +49,8 @@ en:
|
|||
working_day_end_hour: "End time of the working day hours."
|
||||
close_to_working_day_hours_extension: "Set extension time in working day hours to highlight the timezones."
|
||||
events_calendar_categories: "Display an events calendar at the top of a category."
|
||||
sort_categories_by_event_start_date_enabled: "Enable the sorting of category topics by event start date."
|
||||
disable_resorting_on_categories_enabled: "Allow categories to disable the ability for users to sort on the event category."
|
||||
discourse_calendar:
|
||||
invite_user_notification: "%{username} invited you to: %{description}"
|
||||
calendar_must_be_in_first_post: "Calendar tag can only be used in first post of a topic."
|
||||
|
|
|
@ -64,6 +64,9 @@ discourse_post_event:
|
|||
display_post_event_date_on_topic_title:
|
||||
default: true
|
||||
client: true
|
||||
use_local_event_date:
|
||||
default: false
|
||||
client: true
|
||||
discourse_post_event_max_bulk_invitees:
|
||||
default: 500
|
||||
hidden: true
|
||||
|
@ -79,3 +82,10 @@ discourse_post_event:
|
|||
type: category_list
|
||||
client: true
|
||||
default: ""
|
||||
sort_categories_by_event_start_date_enabled:
|
||||
default: false
|
||||
client: true
|
||||
disable_resorting_on_categories_enabled:
|
||||
default: false
|
||||
client: true
|
||||
|
||||
|
|
24
plugin.rb
24
plugin.rb
|
@ -40,6 +40,30 @@ register_svg_icon 'fas fa-star'
|
|||
register_svg_icon 'fas fa-file-upload'
|
||||
|
||||
after_initialize do
|
||||
Category.register_custom_field_type("sort_topics_by_event_start_date", :boolean)
|
||||
Category.register_custom_field_type("disable_topic_resorting", :boolean)
|
||||
Site.preloaded_category_custom_fields << 'sort_topics_by_event_start_date'
|
||||
Site.preloaded_category_custom_fields << 'disable_topic_resorting'
|
||||
|
||||
add_to_serializer :basic_category, :sort_topics_by_event_start_date do
|
||||
object.custom_fields["sort_topics_by_event_start_date"]
|
||||
end
|
||||
add_to_serializer :basic_category, :disable_topic_resorting do
|
||||
object.custom_fields["disable_topic_resorting"]
|
||||
end
|
||||
|
||||
TopicQuery.add_custom_filter(:order_by_event_date) do |results, topic_query|
|
||||
if SiteSetting.sort_categories_by_event_start_date_enabled && topic_query.options[:category_id]
|
||||
category = Category.find_by(id: topic_query.options[:category_id])
|
||||
if category && category.custom_fields && category.custom_fields["sort_topics_by_event_start_date"]
|
||||
results = results.joins("LEFT JOIN topic_custom_fields AS custom_fields on custom_fields.topic_id = topics.id
|
||||
AND custom_fields.name = '#{DiscoursePostEvent::TOPIC_POST_EVENT_STARTS_AT}'
|
||||
").reorder("topics.pinned_at ASC, custom_fields.value ASC")
|
||||
end
|
||||
end
|
||||
results
|
||||
end
|
||||
|
||||
module ::DiscourseCalendar
|
||||
PLUGIN_NAME ||= 'discourse-calendar'
|
||||
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "rails_helper"
|
||||
|
||||
RSpec.describe ListController do
|
||||
fab!(:admin) { Fabricate(:admin) }
|
||||
fab!(:user) { Fabricate(:user) }
|
||||
fab!(:category) { Fabricate(:category) }
|
||||
fab!(:topic_1) { Fabricate(:topic, title: "This is the first topic", user: user, category: category) }
|
||||
fab!(:post_1) { Fabricate(:post, topic: topic_1) }
|
||||
fab!(:post_event_1) { Fabricate(:event, name: "event1", post: post_1, original_starts_at: 1.days.from_now) }
|
||||
fab!(:topic_2) { Fabricate(:topic, title: "This is the second topic", user: user, category: category) }
|
||||
fab!(:post_2) { Fabricate(:post, topic: topic_2) }
|
||||
fab!(:post_event_2) { Fabricate(:event, name: "event2", post: post_2, original_starts_at: 2.days.from_now) }
|
||||
|
||||
before do
|
||||
admin
|
||||
SiteSetting.calendar_enabled = true
|
||||
SiteSetting.sort_categories_by_event_start_date_enabled = true
|
||||
end
|
||||
|
||||
describe '#sort_event_topics' do
|
||||
it 'gets topics in order of event_date if sort_topics_by_event_start_date is true' do
|
||||
category.custom_fields["sort_topics_by_event_start_date"] = true
|
||||
category.save
|
||||
|
||||
get "/c/#{category.slug}/#{category.id}/l/latest.json?ascending=false"
|
||||
|
||||
topics = response.parsed_body["topic_list"]["topics"]
|
||||
|
||||
expect(topics[0]["id"]).to eq(topic_1.id)
|
||||
expect(topics[1]["id"]).to eq(topic_2.id)
|
||||
end
|
||||
|
||||
it 'does not gets topics in order of event_date if sort_topics_by_event_start_date is false' do
|
||||
category.custom_fields["sort_topics_by_event_start_date"] = false
|
||||
category.save
|
||||
|
||||
get "/c/#{category.slug}/#{category.id}/l/latest.json?ascending=false"
|
||||
|
||||
topics = response.parsed_body["topic_list"]["topics"]
|
||||
|
||||
expect(topics[0]["id"]).to eq(topic_2.id)
|
||||
expect(topics[1]["id"]).to eq(topic_1.id)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,24 @@
|
|||
import { acceptance, exists } from "discourse/tests/helpers/qunit-helpers";
|
||||
import { test } from "qunit";
|
||||
import { visit } from "@ember/test-helpers";
|
||||
import { cloneJSON } from "discourse-common/lib/object";
|
||||
import CategoryFixtures from "discourse/tests/fixtures/category-fixtures";
|
||||
|
||||
acceptance("Calendar - Disable sorting headers", function (needs) {
|
||||
needs.user();
|
||||
needs.pretender((server, helper) => {
|
||||
const categoryResponse = cloneJSON(CategoryFixtures["/c/1/show.json"]);
|
||||
categoryResponse.category.custom_fields["disable_topic_resorting"] = true;
|
||||
server.get("/c/1/show.json", () => helper.response(categoryResponse));
|
||||
});
|
||||
|
||||
test("visiting a category page", async function (assert) {
|
||||
await visit("/c/bug");
|
||||
assert.ok(exists(".topic-list"), "The list of topics was rendered");
|
||||
assert.ok(
|
||||
exists(".topic-list .topic-list-data"),
|
||||
"The headers were rendered"
|
||||
);
|
||||
assert.ok(!exists(".topic-list .sortable"), "The headers are not sortable");
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue