Compare commits
1 Commits
main
...
fix-tag-in
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6a68ba147b |
@ -2,7 +2,7 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Graceful",
|
||||
value: "https://github.com/discourse/graceful",
|
||||
preview: "https://discourse.theme-creator.io/theme/awesomerobot/graceful",
|
||||
preview: "https://theme-creator.discourse.org/theme/awesomerobot/graceful",
|
||||
description: "A light and graceful theme for Discourse.",
|
||||
meta_url:
|
||||
"https://meta.discourse.org/t/a-graceful-theme-for-discourse/93040",
|
||||
@ -10,7 +10,8 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Material Design Theme",
|
||||
value: "https://github.com/discourse/material-design-stock-theme",
|
||||
preview: "https://discourse.theme-creator.io/theme/tshenry/material-design",
|
||||
preview:
|
||||
"https://theme-creator.discourse.org/theme/tshenry/material-design",
|
||||
description:
|
||||
"Inspired by Material Design, this theme comes with several color palettes (incl. a dark one).",
|
||||
meta_url: "https://meta.discourse.org/t/material-design-stock-theme/47142",
|
||||
@ -18,7 +19,7 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Minima",
|
||||
value: "https://github.com/discourse/minima",
|
||||
preview: "https://discourse.theme-creator.io/theme/awesomerobot/minima",
|
||||
preview: "https://theme-creator.discourse.org/theme/awesomerobot/minima",
|
||||
description: "A minimal theme with reduced UI elements and focus on text.",
|
||||
meta_url:
|
||||
"https://meta.discourse.org/t/minima-a-minimal-theme-for-discourse/108178",
|
||||
@ -26,7 +27,7 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Sam's Simple Theme",
|
||||
value: "https://github.com/discourse/discourse-simple-theme",
|
||||
preview: "https://discourse.theme-creator.io/theme/sam/simple",
|
||||
preview: "https://theme-creator.discourse.org/theme/sam/simple",
|
||||
description:
|
||||
"Simplified front page design with classic colors and typography.",
|
||||
meta_url:
|
||||
@ -35,8 +36,6 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Brand Header",
|
||||
value: "https://github.com/discourse/discourse-brand-header",
|
||||
preview:
|
||||
"https://discourse.theme-creator.io/theme/vinothkannans/brand-header",
|
||||
description:
|
||||
"Add an extra top header with your logo, navigation links and social icons.",
|
||||
meta_url: "https://meta.discourse.org/t/brand-header-theme-component/77977",
|
||||
@ -46,7 +45,7 @@ export const POPULAR_THEMES = [
|
||||
name: "Custom Header Links",
|
||||
value: "https://github.com/discourse/discourse-custom-header-links",
|
||||
preview:
|
||||
"https://discourse.theme-creator.io/theme/awesomerobot/custom-header-links",
|
||||
"https://theme-creator.discourse.org/theme/Johani/custom-header-links",
|
||||
description: "Easily add custom text-based links to the header.",
|
||||
meta_url: "https://meta.discourse.org/t/custom-header-links/90588",
|
||||
component: true,
|
||||
@ -62,7 +61,7 @@ export const POPULAR_THEMES = [
|
||||
name: "Category Banners",
|
||||
value: "https://github.com/discourse/discourse-category-banners",
|
||||
preview:
|
||||
"https://discourse.theme-creator.io/theme/awesomerobot/discourse-category-banners",
|
||||
"https://theme-creator.discourse.org/theme/awesomerobot/discourse-category-banners",
|
||||
description:
|
||||
"Show banners on category pages using your existing category details.",
|
||||
meta_url: "https://meta.discourse.org/t/discourse-category-banners/86241",
|
||||
@ -71,7 +70,7 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Kanban Board",
|
||||
value: "https://github.com/discourse/discourse-kanban-theme",
|
||||
preview: "https://discourse.theme-creator.io/theme/david/kanban",
|
||||
preview: "https://theme-creator.discourse.org/theme/david/kanban",
|
||||
description: "Display and organize topics using a Kanban board interface.",
|
||||
meta_url:
|
||||
"https://meta.discourse.org/t/kanban-board-theme-component/118164",
|
||||
@ -85,19 +84,10 @@ export const POPULAR_THEMES = [
|
||||
meta_url: "https://meta.discourse.org/t/hamburger-theme-selector/61210",
|
||||
component: true,
|
||||
},
|
||||
{
|
||||
name: "Sidebar Theme Toggle",
|
||||
value: "https://github.com/discourse/discourse-sidebar-theme-toggle",
|
||||
description:
|
||||
"Displays a theme selector in the sidebar menu’s footer provided there is more than one user-selectable theme.",
|
||||
meta_url: "https://meta.discourse.org/t/sidebar-theme-toggle/242802",
|
||||
component: true,
|
||||
},
|
||||
{
|
||||
name: "Header Submenus",
|
||||
value: "https://github.com/discourse/discourse-header-submenus",
|
||||
preview:
|
||||
"https://discourse.theme-creator.io/theme/awesomerobot/header-submenus",
|
||||
preview: "https://theme-creator.discourse.org/theme/Johani/header-submenus",
|
||||
description: "Lets you build a header menu with submenus (dropdowns).",
|
||||
meta_url: "https://meta.discourse.org/t/header-submenus/94584",
|
||||
component: true,
|
||||
@ -114,7 +104,7 @@ export const POPULAR_THEMES = [
|
||||
{
|
||||
name: "Easy Responsive Footer",
|
||||
value: "https://github.com/discourse/Discourse-easy-footer",
|
||||
preview: "https://discourse.theme-creator.io/theme/Johani/easy-footer",
|
||||
preview: "https://theme-creator.discourse.org/theme/Johani/easy-footer",
|
||||
description: "Add a fully responsive footer without writing any HTML.",
|
||||
meta_url: "https://meta.discourse.org/t/easy-responsive-footer/95818",
|
||||
component: true,
|
||||
|
||||
@ -102,8 +102,13 @@ class TagsController < ::ApplicationController
|
||||
Discourse.filters.each do |filter|
|
||||
define_method("show_#{filter}") do
|
||||
@tag_id = params[:tag_id].force_encoding("UTF-8")
|
||||
@additional_tags =
|
||||
params[:additional_tag_ids].to_s.split("/").map { |t| t.force_encoding("UTF-8") }
|
||||
if params[:additional_tag_ids]
|
||||
@additional_tags = params[:additional_tag_ids].to_s.split("/")
|
||||
elsif params[:tags]
|
||||
# Set additional tags to all passed tags excluding the primary tag (tag_id)
|
||||
@additional_tags = params[:tags].reject { |t| t == params[:tag_id] }
|
||||
end
|
||||
@additional_tags = @additional_tags&.map { |t| t.force_encoding("UTF-8") }
|
||||
|
||||
list_opts = build_topic_list_options
|
||||
@list = nil
|
||||
@ -483,6 +488,9 @@ class TagsController < ::ApplicationController
|
||||
def url_method(opts = {})
|
||||
if opts[:category_slug_path_with_id]
|
||||
"tag_category_#{action_name}_path"
|
||||
# expect tag intersection if multiple tags are present
|
||||
elsif opts[:tags] && opts[:tags].length > 1
|
||||
"tag_intersection_path"
|
||||
else
|
||||
"tag_#{action_name}_path"
|
||||
end
|
||||
|
||||
@ -46,8 +46,7 @@ class Bookmark < ActiveRecord::Base
|
||||
validates :name, length: { maximum: 100 }
|
||||
|
||||
def registered_bookmarkable
|
||||
type = Bookmark.polymorphic_class_for(self.bookmarkable_type).name
|
||||
Bookmark.registered_bookmarkable_from_type(type)
|
||||
Bookmark.registered_bookmarkable_from_type(self.bookmarkable_type)
|
||||
end
|
||||
|
||||
def polymorphic_columns_present
|
||||
|
||||
@ -213,10 +213,7 @@ task "docker:test" do
|
||||
@good &&= run_or_fail("bundle exec rspec #{params.join(" ")}".strip)
|
||||
end
|
||||
|
||||
if ENV["RUN_SYSTEM_TESTS"]
|
||||
@good &&= run_or_fail("bin/ember-cli --build")
|
||||
@good &&= run_or_fail("bundle exec rspec spec/system")
|
||||
end
|
||||
@good &&= run_or_fail("bundle exec rspec spec/system".strip) if ENV["RUN_SYSTEM_TESTS"]
|
||||
end
|
||||
|
||||
unless ENV["SKIP_PLUGINS"]
|
||||
|
||||
@ -613,7 +613,6 @@ export default class ChatLivePane extends Component {
|
||||
const message = ChatMessage.create(this.args.channel, data.chat_message);
|
||||
this.args.channel.addMessages([message]);
|
||||
this.scrollToLatestMessage();
|
||||
this.updateLastReadMessage();
|
||||
} else {
|
||||
// If we are almost at the bottom, we append the message and notice the user
|
||||
const message = ChatMessage.create(this.args.channel, data.chat_message);
|
||||
@ -896,19 +895,16 @@ export default class ChatLivePane extends Component {
|
||||
@action
|
||||
editLastMessageRequested() {
|
||||
const lastUserMessage = this.args.channel.messages.findLast(
|
||||
(message) => message.user.id === this.currentUser.id
|
||||
(message) =>
|
||||
message.user.id === this.currentUser.id &&
|
||||
!message.staged &&
|
||||
!message.error
|
||||
);
|
||||
|
||||
if (!lastUserMessage) {
|
||||
return;
|
||||
if (lastUserMessage) {
|
||||
this.editingMessage = lastUserMessage;
|
||||
this._focusComposer();
|
||||
}
|
||||
|
||||
if (lastUserMessage.staged || lastUserMessage.error) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.editingMessage = lastUserMessage;
|
||||
this._focusComposer();
|
||||
}
|
||||
|
||||
@action
|
||||
|
||||
@ -2,18 +2,30 @@
|
||||
{{#if this.hasUploads}}
|
||||
{{html-safe @cooked}}
|
||||
|
||||
<Collapser @header={{this.uploadsHeader}} @onToggle={{@onToggleCollapse}}>
|
||||
<div class="chat-uploads">
|
||||
{{#each @uploads as |upload|}}
|
||||
<ChatUpload @upload={{upload}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
<Collapser
|
||||
@header={{this.uploadsHeader}}
|
||||
@onToggle={{@onToggleCollapse}}
|
||||
as |collapsed|
|
||||
>
|
||||
{{#unless collapsed}}
|
||||
<div class="chat-uploads">
|
||||
{{#each @uploads as |upload|}}
|
||||
<ChatUpload @upload={{upload}} />
|
||||
{{/each}}
|
||||
</div>
|
||||
{{/unless}}
|
||||
</Collapser>
|
||||
{{else}}
|
||||
{{#each this.cookedBodies as |cooked|}}
|
||||
{{#if cooked.needsCollapser}}
|
||||
<Collapser @header={{cooked.header}} @onToggle={{@onToggleCollapse}}>
|
||||
{{cooked.body}}
|
||||
<Collapser
|
||||
@header={{cooked.header}}
|
||||
@onToggle={{@onToggleCollapse}}
|
||||
as |collapsed|
|
||||
>
|
||||
{{#unless collapsed}}
|
||||
{{cooked.body}}
|
||||
{{/unless}}
|
||||
</Collapser>
|
||||
{{else}}
|
||||
{{cooked.body}}
|
||||
|
||||
@ -384,7 +384,6 @@ $float-height: 530px;
|
||||
|
||||
.d-icon {
|
||||
color: var(--secondary);
|
||||
margin-left: 1px; // "fixes" the 1px svg shift
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -56,9 +56,7 @@
|
||||
}
|
||||
|
||||
.chat-message-separator__text-container {
|
||||
align-items: center;
|
||||
display: flex;
|
||||
height: 40px;
|
||||
padding-top: 7px;
|
||||
position: sticky;
|
||||
top: -1px;
|
||||
|
||||
@ -100,7 +98,11 @@
|
||||
|
||||
.chat-message-separator__line {
|
||||
border-top: 1px solid var(--secondary-high);
|
||||
left: 0;
|
||||
margin: 0 0 -1px;
|
||||
position: relative;
|
||||
right: 0;
|
||||
top: -1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,41 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe BookmarksController do
|
||||
let(:current_user) { Fabricate(:user) }
|
||||
let(:bookmark_message) { Fabricate(:chat_message) }
|
||||
let(:bookmark_user) { current_user }
|
||||
|
||||
before do
|
||||
register_test_bookmarkable(Chat::MessageBookmarkable)
|
||||
sign_in(current_user)
|
||||
end
|
||||
|
||||
after { DiscoursePluginRegistry.reset_register!(:bookmarkables) }
|
||||
|
||||
context "when bookmarking a chat message" do
|
||||
describe "#create" do
|
||||
it "creates the bookmark" do
|
||||
post "/bookmarks.json",
|
||||
params: {
|
||||
bookmarkable_id: bookmark_message.id,
|
||||
bookmarkable_type: "Chat::Message",
|
||||
reminder_at: (Time.zone.now + 1.day).iso8601,
|
||||
}
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(Bookmark.find_by(bookmarkable: bookmark_message).user_id).to eq(current_user.id)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#destroy" do
|
||||
let!(:bookmark) { Fabricate(:bookmark, bookmarkable: bookmark_message, user: bookmark_user) }
|
||||
|
||||
it "destroys the bookmark" do
|
||||
delete "/bookmarks/#{bookmark.id}.json"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(Bookmark.find_by(id: bookmark.id)).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@ -1,39 +0,0 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe "Channel message selection", type: :system, js: true do
|
||||
fab!(:current_user) { Fabricate(:user) }
|
||||
fab!(:channel_1) { Fabricate(:chat_channel) }
|
||||
fab!(:message_1) { Fabricate(:chat_message, chat_channel: channel_1) }
|
||||
|
||||
let(:chat) { PageObjects::Pages::Chat.new }
|
||||
let(:channel) { PageObjects::Pages::ChatChannel.new }
|
||||
let(:image) do
|
||||
Fabricate(
|
||||
:upload,
|
||||
original_filename: "test_image.jpg",
|
||||
width: 400,
|
||||
height: 300,
|
||||
extension: "jpg",
|
||||
)
|
||||
end
|
||||
|
||||
before do
|
||||
chat_system_bootstrap
|
||||
channel_1.add(current_user)
|
||||
sign_in(current_user)
|
||||
message_1.attach_uploads([image])
|
||||
end
|
||||
|
||||
it "can collapse/expand an image and still have lightbox working" do
|
||||
chat.visit_channel(channel_1)
|
||||
|
||||
find(".chat-message-collapser-button").click
|
||||
expect(page).to have_css(".chat-message-collapser-body.hidden", visible: :false)
|
||||
find(".chat-message-collapser-button").click
|
||||
expect(page).to have_no_css(".chat-message-collapser-body.hidden")
|
||||
find(".chat-img-upload").click
|
||||
|
||||
# visible false is because the upload doesn’t exist but it's enough to know lightbox is working
|
||||
expect(page).to have_css(".mfp-image-holder img[src*='#{image.url}']", visible: false)
|
||||
end
|
||||
end
|
||||
@ -70,19 +70,5 @@ RSpec.describe "Shortcuts | chat composer", type: :system, js: true do
|
||||
|
||||
expect(page.find(".chat-composer-message-details")).to have_content(message_1.message)
|
||||
end
|
||||
|
||||
context "when last message is not editable" do
|
||||
after { page.driver.browser.network_conditions = { offline: false } }
|
||||
|
||||
it "does not edit a message" do
|
||||
chat.visit_channel(channel_1)
|
||||
page.driver.browser.network_conditions = { offline: true }
|
||||
channel_page.send_message("Hello world")
|
||||
|
||||
find(".chat-composer-input").send_keys(:arrow_up)
|
||||
|
||||
expect(page).to have_no_css(".chat-composer-message-details")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@ -392,6 +392,24 @@ RSpec.describe TagsController do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with a tag intersection" do
|
||||
it "should generate a tag intersection `load_more_topic` url" do
|
||||
tag = Fabricate(:tag)
|
||||
tag_2 = Fabricate(:tag)
|
||||
|
||||
# Create topics with both tags included
|
||||
3.times { Fabricate(:topic, tags: [tag, tag_2]) }
|
||||
|
||||
sign_in(admin)
|
||||
get "/tags/intersection/#{tag.name}/#{tag_2.name}.json?per_page=2"
|
||||
|
||||
expect(response.status).to eq(200)
|
||||
expect(response.parsed_body["topic_list"]["more_topics_url"]).to eq(
|
||||
"/tags/intersection/#{tag.name}/#{tag_2.name}?match_all_tags=true&page=1&per_page=2&tags%5B%5D=#{tag.name}&tags%5B%5D=#{tag_2.name}",
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#show" do
|
||||
|
||||
Reference in New Issue
Block a user