settings tab

This commit is contained in:
Krzysztof Kotlarek 2024-12-06 14:32:38 +11:00
parent 66b8ed4f80
commit ce26380bca
21 changed files with 266 additions and 150 deletions

View File

@ -0,0 +1,54 @@
import Component from "@glimmer/component";
import { tracked } from "@glimmer/tracking";
import didInsert from "@ember/render-modifiers/modifiers/did-insert";
import { service } from "@ember/service";
import DBreadcrumbsItem from "discourse/components/d-breadcrumbs-item";
import { ajax } from "discourse/lib/ajax";
import { bind } from "discourse-common/utils/decorators";
import { i18n } from "discourse-i18n";
import AdminFilteredSiteSettings from "admin/components/admin-filtered-site-settings";
import SiteSetting from "admin/models/site-setting";
export default class AdminConfigAreasEmbeddingSettings extends Component {
@service siteSettings;
@tracked settings;
@bind
loadSettings() {
ajax("/admin/config/site_settings.json", {
data: {
filter_area: "embedding",
},
}).then((result) => {
this.settings = [
{
name: "All",
nameKey: "all_results",
siteSettings: result.site_settings.map((setting) =>
SiteSetting.create(setting)
),
},
];
});
}
<template>
<DBreadcrumbsItem
@path="/admin/customize/embedding/settings"
@label={{i18n "settings"}}
/>
<div
class="content-body admin-config-area__settings admin-detail pull-left"
{{didInsert this.loadSettings}}
>
{{#if this.settings}}
<AdminFilteredSiteSettings
@initialFilter={{@initialFilter}}
@onFilterChanged={{@onFilterChanged}}
@settings={{this.settings}}
/>
{{/if}}
</div>
</template>
}

View File

@ -3,6 +3,7 @@ import { inject as controller } from "@ember/controller";
import { hash } from "@ember/helper";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import BackButton from "discourse/components/back-button";
import Form from "discourse/components/form";
import { popupAjaxError } from "discourse/lib/ajax-error";
@ -35,7 +36,7 @@ export default class AdminEmbeddingHostForm extends Component {
allowed_paths: this.args.host.allowed_paths,
category: this.args.host.category_id,
tags: this.args.host.tags,
user: this.args.host.user,
user: isEmpty(this.args.host.user) ? null : [this.args.host.user],
};
} else {
return {};

View File

@ -4,7 +4,7 @@ import { service } from "@ember/service";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { i18n } from "discourse-i18n";
export default class AdminEmbeddingCrawlerSettingsController extends Controller {
export default class AdminEmbeddingCrawlersController extends Controller {
@service toasts;
@controller adminEmbedding;
@ -23,7 +23,10 @@ export default class AdminEmbeddingCrawlerSettingsController extends Controller
const embedding = this.adminEmbedding.embedding;
try {
await embedding.update(data);
await embedding.update({
type: "crawlers",
...data,
});
this.toasts.success({
duration: 1500,
data: { message: i18n("admin.embedding.crawler_settings_saved") },

View File

@ -0,0 +1,46 @@
import Controller, { inject as controller } from "@ember/controller";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { i18n } from "discourse-i18n";
export default class AdminEmbeddingPostsAndTopicsController extends Controller {
@service toasts;
@controller adminEmbedding;
get formData() {
const embedding = this.adminEmbedding.embedding;
return {
embed_by_username: isEmpty(embedding.embed_by_username)
? null
: [embedding.embed_by_username],
embed_post_limit: embedding.embed_post_limit,
embed_title_scrubber: embedding.embed_title_scrubber,
embed_truncate: embedding.embed_truncate,
embed_unlisted: embedding.embed_unlisted,
};
}
@action
async save(data) {
const embedding = this.adminEmbedding.embedding;
try {
await embedding.update({
type: "posts_and_topics",
...data,
embed_by_username: data.embed_by_username[0],
});
this.toasts.success({
duration: 1500,
data: {
message: i18n("admin.embedding.posts_and_topics_settings_saved"),
},
});
} catch (error) {
popupAjaxError(error);
}
}
}

View File

@ -1,42 +1,12 @@
import Controller, { inject as controller } from "@ember/controller";
import Controller from "@ember/controller";
import { action } from "@ember/object";
import { service } from "@ember/service";
import { isEmpty } from "@ember/utils";
import { popupAjaxError } from "discourse/lib/ajax-error";
import { i18n } from "discourse-i18n";
export default class AdminEmbeddingSettingsController extends Controller {
@service toasts;
@controller adminEmbedding;
get formData() {
const embedding = this.adminEmbedding.embedding;
return {
embed_by_username: isEmpty(embedding.embed_by_username)
? null
: embedding.embed_by_username,
embed_post_limit: embedding.embed_post_limit,
embed_title_scrubber: embedding.embed_title_scrubber,
embed_truncate: embedding.embed_truncate,
embed_unlisted: embedding.embed_unlisted,
};
}
filter = "";
queryParams = ["filter"];
@action
async save(data) {
const embedding = this.adminEmbedding.embedding;
try {
await embedding.update({
...data,
embed_by_username: data.embed_by_username[0],
});
this.toasts.success({
duration: 1500,
data: { message: i18n("admin.embedding.embedding_settings_saved") },
});
} catch (error) {
popupAjaxError(error);
}
filterChangedCallback(filterData) {
this.set("filter", filterData.filter);
}
}

View File

@ -5,9 +5,10 @@ export default class AdminEmbeddingController extends Controller {
@service router;
get showHeader() {
return [
"adminEmbedding.crawlers",
"adminEmbedding.index",
"adminEmbedding.postsAndTopics",
"adminEmbedding.settings",
"adminEmbedding.crawler_settings",
].includes(this.router.currentRouteName);
}
}

View File

@ -105,7 +105,8 @@ export default function () {
function () {
this.route("index", { path: "/" });
this.route("settings");
this.route("crawler_settings");
this.route("postsAndTopics", { path: "/posts_and_topics" });
this.route("crawlers");
this.route("new");
this.route("edit", { path: "/:id" });
}

View File

@ -1,6 +1,6 @@
<AdminPageSubheader
@titleLabelTranslated={{i18n "admin.embedding.crawling_settings"}}
@descriptionLabelTranslated={{i18n "admin.embedding.crawling_description"}}
@titleLabelTranslated={{i18n "admin.embedding.crawlers"}}
@descriptionLabelTranslated={{i18n "admin.embedding.crawlers_description"}}
/>
<Form @onSubmit={{this.save}} @data={{this.formData}} as |form|>

View File

@ -0,0 +1,55 @@
<AdminPageSubheader
@titleLabelTranslated={{i18n "admin.embedding.posts_and_topics"}}
/>
<Form @onSubmit={{this.save}} @data={{this.formData}} as |form|>
<form.Field
@name="embed_by_username"
@title={{i18n "admin.embedding.embed_by_username"}}
@validation="required"
as |field|
>
<field.Custom>
<UserChooser
@value={{field.value}}
@onChange={{field.set}}
@options={{hash maximum=1 excludeCurrentUser=false}}
class="admin-embedding-posts-and-topics-form__embed_by_username"
/>
</field.Custom>
</form.Field>
<form.Field
@name="embed_post_limit"
@title={{i18n "admin.embedding.embed_post_limit"}}
@format="large"
as |field|
>
<field.Input />
</form.Field>
<form.Field
@name="embed_title_scrubber"
@title={{i18n "admin.embedding.embed_title_scrubber"}}
@format="large"
as |field|
>
<field.Input placeholder="- site.com$" />
</form.Field>
<form.CheckboxGroup as |checkboxGroup|>
<checkboxGroup.Field
@name="embed_truncate"
@title={{i18n "admin.embedding.embed_truncate"}}
as |field|
>
<field.Checkbox />
</checkboxGroup.Field>
<checkboxGroup.Field
@name="embed_unlisted"
@title={{i18n "admin.embedding.embed_unlisted"}}
as |field|
>
<field.Checkbox />
</checkboxGroup.Field>
</form.CheckboxGroup>
<form.Submit @label="admin.embedding.save" />
</Form>

View File

@ -1,53 +1,4 @@
<AdminPageSubheader @titleLabelTranslated={{i18n "admin.embedding.settings"}} />
<Form @onSubmit={{this.save}} @data={{this.formData}} as |form|>
<form.Field
@name="embed_by_username"
@title={{i18n "admin.embedding.embed_by_username"}}
@validation="required"
as |field|
>
<field.Custom>
<UserChooser
@value={{field.value}}
@onChange={{field.set}}
@options={{hash maximum=1 excludeCurrentUser=false}}
class="admin-embedding-settings-form__embed_by_username"
/>
</field.Custom>
</form.Field>
<form.Field
@name="embed_post_limit"
@title={{i18n "admin.embedding.embed_post_limit"}}
@format="large"
as |field|
>
<field.Input />
</form.Field>
<form.Field
@name="embed_title_scrubber"
@title={{i18n "admin.embedding.embed_title_scrubber"}}
@format="large"
as |field|
>
<field.Input placeholder="- site.com$" />
</form.Field>
<form.CheckboxGroup as |checkboxGroup|>
<checkboxGroup.Field
@name="embed_truncate"
@title={{i18n "admin.embedding.embed_truncate"}}
as |field|
>
<field.Checkbox />
</checkboxGroup.Field>
<checkboxGroup.Field
@name="embed_unlisted"
@title={{i18n "admin.embedding.embed_unlisted"}}
as |field|
>
<field.Checkbox />
</checkboxGroup.Field>
</form.CheckboxGroup>
<form.Submit @label="admin.embedding.save" />
</Form>
<AdminConfigAreas::EmbeddingSettings
@onFilterChanged={{this.filterChangedCallback}}
@initialFilter={{this.filter}}
/>

View File

@ -20,20 +20,25 @@
/>
</:actions>
<:tabs>
<NavItem
@route="adminEmbedding.settings"
@label="admin.embedding.nav.settings"
class="admin-embedding-tabs__settings"
/>
<NavItem
@route="adminEmbedding.index"
@label="admin.embedding.nav.hosts"
class="admin-embedding-tabs__hosts"
/>
<NavItem
@route="adminEmbedding.settings"
@label="admin.embedding.nav.embedding_settings"
class="admin-embedding-tabs__embedding-settings"
@route="adminEmbedding.postsAndTopics"
@label="admin.embedding.nav.posts_and_topics"
class="admin-embedding-tabs__posts-and-topics"
/>
<NavItem
@route="adminEmbedding.crawler_settings"
@label="admin.embedding.nav.crawler_settings"
class="admin-embedding-tabs__crawler-settings"
@route="adminEmbedding.crawlers"
@label="admin.embedding.nav.crawlers"
class="admin-embedding-tabs__crawlers"
/>
</:tabs>
</AdminPageHeader>

View File

@ -8,7 +8,11 @@ class Admin::EmbeddingController < Admin::AdminController
end
def update
Embedding.settings.each { |s| @embedding.public_send("#{s}=", params[:embedding][s]) }
raise InvalidAccess if !(%w[posts_and_topics crawlers].include?(params[:embedding][:type]))
Embedding
.send("#{params[:embedding][:type]}_settings")
.each { |s| @embedding.public_send("#{s}=", params[:embedding][s]) }
if @embedding.save
fetch_embedding
@ -24,12 +28,6 @@ class Admin::EmbeddingController < Admin::AdminController
def edit
end
def settings
end
def crawler_settings
end
protected
def fetch_embedding

View File

@ -6,16 +6,15 @@ class Embedding < OpenStruct
include HasErrors
def self.settings
%i[
embed_by_username
embed_post_limit
embed_title_scrubber
embed_truncate
embed_unlisted
allowed_embed_selectors
blocked_embed_selectors
allowed_embed_classnames
]
posts_and_topics_settings | crawlers_settings
end
def self.posts_and_topics_settings
%i[embed_by_username embed_post_limit embed_title_scrubber embed_truncate embed_unlisted]
end
def self.crawlers_settings
%i[allowed_embed_selectors blocked_embed_selectors allowed_embed_classnames]
end
def base_url

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true
class SiteSetting < ActiveRecord::Base
VALID_AREAS = %w[flags about emojis permalinks]
VALID_AREAS = %w[about embedding emojis flags permalinks]
extend GlobalPath
extend SiteSettingExtension

View File

@ -7319,9 +7319,9 @@ en:
tags: "Topic Tags"
post_author: "Post Author - Defaults to %{author}"
add_host: "Add Host"
settings: "Embedding Settings"
crawling_settings: "Crawler Settings"
crawling_description: "When Discourse creates topics for your posts, if no RSS/ATOM feed is present it will attempt to parse your content out of your HTML. Sometimes it can be challenging to extract your content, so we provide the ability to specify CSS rules to make extraction easier."
posts_and_topics: "Posts and Topics configuration"
crawlers: "Crawlers configuration"
crawlers_description: "When Discourse creates topics for your posts, if no RSS/ATOM feed is present it will attempt to parse your content out of your HTML. Sometimes it can be challenging to extract your content, so we provide the ability to specify CSS rules to make extraction easier."
embed_by_username: "Username for topic creation"
embed_post_limit: "Maximum number of posts to embed"
@ -7331,8 +7331,8 @@ en:
allowed_embed_selectors: "CSS selector for elements that are allowed in embeds"
blocked_embed_selectors: "CSS selector for elements that are removed from embeds"
allowed_embed_classnames: "Allowed CSS class names"
save: "Save Embedding Settings"
embedding_settings_saved: "Embedding settings saved."
save: "Save"
posts_and_topics_settings_saved: "Posts and Topics settings saved."
crawler_settings_saved: "Crawler settings saved."
back: "Back to Embedding"
more_options: "More options"
@ -7343,8 +7343,9 @@ en:
save: "Save"
nav:
hosts: "Hosts"
embedding_settings: "Embedding Settings"
crawler_settings: "Crawler Settings"
settings: "Settings"
posts_and_topics: "Posts and Topics"
crawlers: "Crawlers"
permalink:
title: "Permalinks"

View File

@ -223,10 +223,6 @@ Discourse::Application.routes.draw do
get "customize/permalinks" => "permalinks#index", :constraints => AdminConstraint.new
get "customize/embedding" => "embedding#show", :constraints => AdminConstraint.new
put "customize/embedding" => "embedding#update", :constraints => AdminConstraint.new
get "customize/embedding/settings" => "embedding#settings",
:constraints => AdminConstraint.new
get "customize/embedding/crawler_settings" => "embedding#crawler_settings",
:constraints => AdminConstraint.new
get "customize/embedding/:id" => "embedding#edit", :constraints => AdminConstraint.new
resources :themes,

View File

@ -1194,14 +1194,30 @@ posting:
choices:
- code-fences
- 4-spaces-indent
embed_any_origin: false
embed_topics_list: false
embed_set_canonical_url: false
embed_unlisted: false
import_embed_unlisted: true
embed_truncate: true
embed_support_markdown: false
allowed_embed_selectors: ""
embed_any_origin:
default: false
area: "embedding"
embed_topics_list:
default: false
area: "embedding"
embed_set_canonical_url:
default: false
area: "embedding"
embed_unlisted:
default: false
area: "embedding"
import_embed_unlisted:
default: true
area: "embedding"
embed_truncate:
default: true
area: "embedding"
embed_support_markdown:
default: false
area: "embedding"
allowed_embed_selectors:
default: ""
hidden: true
allowed_href_schemes:
client: true
default: ""

View File

@ -43,10 +43,11 @@ RSpec.describe Admin::EmbeddingController do
context "when logged in as an admin" do
before { sign_in(admin) }
it "updates embedding" do
it "updates posts and topics settings" do
put "/admin/customize/embedding.json",
params: {
embedding: {
type: "posts_and_topics",
embed_by_username: "system",
embed_post_limit: 200,
},
@ -56,6 +57,21 @@ RSpec.describe Admin::EmbeddingController do
expect(response.parsed_body["embedding"]["embed_by_username"]).to eq("system")
expect(response.parsed_body["embedding"]["embed_post_limit"]).to eq(200)
end
it "updates crawlers settings" do
put "/admin/customize/embedding.json",
params: {
embedding: {
type: "crawlers",
allowed_embed_selectors: "article",
blocked_embed_selectors: "p",
},
}
expect(response.status).to eq(200)
expect(response.parsed_body["embedding"]["allowed_embed_selectors"]).to eq("article")
expect(response.parsed_body["embedding"]["blocked_embed_selectors"]).to eq("p")
end
end
shared_examples "embedding updates not allowed" do
@ -63,6 +79,7 @@ RSpec.describe Admin::EmbeddingController do
put "/admin/customize/embedding.json",
params: {
embedding: {
type: "posts_and_topics",
embed_by_username: "system",
embed_post_limit: 200,
},

View File

@ -13,7 +13,9 @@ RSpec.describe "Admin EmbeddableHost Management", type: :system do
let(:admin_embedding_page) { PageObjects::Pages::AdminEmbedding.new }
let(:admin_embedding_host_form_page) { PageObjects::Pages::AdminEmbeddingHostForm.new }
let(:admin_embedding_settings_page) { PageObjects::Pages::AdminEmbeddingSettings.new }
let(:admin_embedding_posts_and_topics_page) do
PageObjects::Pages::AdminEmbeddingPostsAndTopics.new
end
it "allows admin to add, edit and delete embeddable hosts" do
admin_embedding_page.visit
@ -59,18 +61,18 @@ RSpec.describe "Admin EmbeddableHost Management", type: :system do
expect(page).not_to have_css(".admin-embedding-index__code")
end
it "allows admin to save embedding settings" do
it "allows admin to save posts and topics settings" do
Fabricate(:embeddable_host)
admin_embedding_page.visit
expect(page).not_to have_content("#{author.username}")
admin_embedding_page.click_embedding_settings_tab
admin_embedding_page.click_posts_and_topics_tab
admin_embedding_settings_page.fill_in_embed_by_username(author)
admin_embedding_settings_page.click_save
admin_embedding_posts_and_topics_page.fill_in_embed_by_username(author)
admin_embedding_posts_and_topics_page.click_save
admin_embedding_page.click_embedding_hosts_tab
admin_embedding_page.click_hosts_tab
expect(page).to have_content("#{author.username}")
end
end

View File

@ -8,11 +8,11 @@ module PageObjects
self
end
def click_embedding_settings_tab
find(".admin-embedding-tabs__embedding-settings").click
def click_posts_and_topics_tab
find(".admin-embedding-tabs__posts-and-topics").click
end
def click_embedding_hosts_tab
def click_hosts_tab
find(".admin-embedding-tabs__hosts").click
end

View File

@ -2,11 +2,11 @@
module PageObjects
module Pages
class AdminEmbeddingSettings < PageObjects::Pages::Base
class AdminEmbeddingPostsAndTopics < PageObjects::Pages::Base
def fill_in_embed_by_username(author)
dropdown =
PageObjects::Components::SelectKit.new(
".admin-embedding-settings-form__embed_by_username",
".admin-embedding-posts-and-topics-form__embed_by_username",
)
dropdown.expand
dropdown.search(author.username)