diff --git a/app/assets/javascripts/admin/addon/components/admin-embedding-host-form.gjs b/app/assets/javascripts/admin/addon/components/admin-embedding-host-form.gjs new file mode 100644 index 00000000000..f0a82736969 --- /dev/null +++ b/app/assets/javascripts/admin/addon/components/admin-embedding-host-form.gjs @@ -0,0 +1,142 @@ +import Component from "@glimmer/component"; +import { inject as controller } from "@ember/controller"; +import { hash } from "@ember/helper"; +import { action } from "@ember/object"; +import { service } from "@ember/service"; +import BackButton from "discourse/components/back-button"; +import Form from "discourse/components/form"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { i18n } from "discourse-i18n"; +import AdminConfigAreaCard from "admin/components/admin-config-area-card"; +import CategoryChooser from "select-kit/components/category-chooser"; +import TagChooser from "select-kit/components/tag-chooser"; +import UserChooser from "select-kit/components/user-chooser"; + +export default class AdminEmbeddingHostForm extends Component { + @service router; + @service site; + @service store; + @controller adminEmbedding; + + get isUpdate() { + return this.args.host; + } + + get header() { + return this.isUpdate + ? "admin.embedding.host_form.edit_header" + : "admin.embedding.host_form.add_header"; + } + + get formData() { + if (this.isUpdate) { + return { + host: this.args.host.host, + allowed_paths: this.args.host.allowed_paths, + category: this.args.host.category_id, + tags: this.args.host.tags, + user: this.args.host.user, + }; + } else { + return {}; + } + } + + @action + async save(data) { + const host = this.args.host || this.store.createRecord("embeddable-host"); + + try { + await host.save({ + ...data, + user: data.user?.at(0), + category_id: data.category, + }); + if (!this.isUpdate) { + this.adminEmbedding.embedding.embeddable_hosts.push(host); + } + this.router.transitionTo("adminEmbedding"); + } catch (error) { + popupAjaxError(error); + } + } + + +} diff --git a/app/assets/javascripts/admin/addon/components/embeddable-host.hbs b/app/assets/javascripts/admin/addon/components/embeddable-host.hbs index eb52efd31e7..b8a5a87322d 100644 --- a/app/assets/javascripts/admin/addon/components/embeddable-host.hbs +++ b/app/assets/javascripts/admin/addon/components/embeddable-host.hbs @@ -1,87 +1,45 @@ -{{#if this.editing}} - -
{{i18n "admin.embedding.host"}}
- - - -
{{i18n "admin.embedding.allowed_paths"}}
- - - -
{{i18n "admin.embedding.category"}}
- - - -
{{i18n "admin.embedding.tags"}}
- - - -
{{i18n "admin.embedding.user"}}
- - - + + {{this.host.host}} + + + {{this.host.allowed_paths}} + + + {{category-badge this.category allowUncategorized=true}} + + + {{this.tags}} + + + {{this.user}} + + + +
- - -{{else}} - -
{{i18n "admin.embedding.host"}}
- {{this.host.host}} - - -
- {{i18n "admin.embedding.allowed_paths"}} -
- {{this.host.allowed_paths}} - - -
{{i18n "admin.embedding.category"}}
- {{category-badge this.category allowUncategorized=true}} - - - {{this.tags}} - - - {{this.user}} - - - - - -{{/if}} \ No newline at end of file + + + <:content> + + + + + + + +
+ \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/components/embeddable-host.js b/app/assets/javascripts/admin/addon/components/embeddable-host.js index 8d4ae85cdfe..7c5d9ec12f1 100644 --- a/app/assets/javascripts/admin/addon/components/embeddable-host.js +++ b/app/assets/javascripts/admin/addon/components/embeddable-host.js @@ -1,28 +1,18 @@ import Component from "@ember/component"; import { action } from "@ember/object"; -import { or } from "@ember/object/computed"; import { service } from "@ember/service"; -import { isEmpty } from "@ember/utils"; -import { tagName } from "@ember-decorators/component"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -import { bufferedProperty } from "discourse/mixins/buffered-content"; +import { classNames, tagName } from "@ember-decorators/component"; import Category from "discourse/models/category"; -import discourseComputed from "discourse-common/utils/decorators"; import { i18n } from "discourse-i18n"; @tagName("tr") -export default class EmbeddableHost extends Component.extend( - bufferedProperty("host") -) { +@classNames("d-admin-row__content") +export default class EmbeddableHost extends Component { @service dialog; - editToggled = false; - categoryId = null; category = null; tags = null; user = null; - @or("host.isNew", "editToggled") editing; - init() { super.init(...arguments); @@ -31,51 +21,10 @@ export default class EmbeddableHost extends Component.extend( const category = Category.findById(categoryId); this.set("category", category); - this.set("tags", host.tags || []); + this.set("tags", (host.tags || []).join(", ")); this.set("user", host.user); } - @discourseComputed("buffered.host", "host.isSaving") - cantSave(host, isSaving) { - return isSaving || isEmpty(host); - } - - @action - edit() { - this.set("editToggled", true); - } - - @action - onUserChange(user) { - this.set("user", user); - } - - @action - save() { - if (this.cantSave) { - return; - } - - const props = this.buffered.getProperties( - "host", - "allowed_paths", - "class_name" - ); - props.category_id = this.category.id; - props.tags = this.tags; - props.user = - Array.isArray(this.user) && this.user.length > 0 ? this.user[0] : null; - - const host = this.host; - - host - .save(props) - .then(() => { - this.set("editToggled", false); - }) - .catch(popupAjaxError); - } - @action delete() { return this.dialog.confirm({ @@ -87,15 +36,4 @@ export default class EmbeddableHost extends Component.extend( }, }); } - - @action - cancel() { - const host = this.host; - if (host.get("isNew")) { - this.deleteHost(host); - } else { - this.rollbackBuffer(); - this.set("editToggled", false); - } - } } diff --git a/app/assets/javascripts/admin/addon/components/embedding-setting.hbs b/app/assets/javascripts/admin/addon/components/embedding-setting.hbs deleted file mode 100644 index 40190589e47..00000000000 --- a/app/assets/javascripts/admin/addon/components/embedding-setting.hbs +++ /dev/null @@ -1,15 +0,0 @@ -{{#if this.isCheckbox}} - -{{else}} - - -{{/if}} - -
\ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/components/embedding-setting.js b/app/assets/javascripts/admin/addon/components/embedding-setting.js deleted file mode 100644 index 462f27c875a..00000000000 --- a/app/assets/javascripts/admin/addon/components/embedding-setting.js +++ /dev/null @@ -1,32 +0,0 @@ -import Component from "@ember/component"; -import { computed } from "@ember/object"; -import { dasherize } from "@ember/string"; -import { classNames } from "@ember-decorators/component"; -import discourseComputed from "discourse-common/utils/decorators"; - -@classNames("embed-setting") -export default class EmbeddingSetting extends Component { - @discourseComputed("field") - inputId(field) { - return dasherize(field); - } - - @discourseComputed("field") - translationKey(field) { - return `admin.embedding.${field}`; - } - - @discourseComputed("type") - isCheckbox(type) { - return type === "checkbox"; - } - - @computed("value") - get checked() { - return !!this.value; - } - - set checked(value) { - this.set("value", value); - } -} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-embedding-crawler-settings.js b/app/assets/javascripts/admin/addon/controllers/admin-embedding-crawler-settings.js new file mode 100644 index 00000000000..54a5deb31b1 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-embedding-crawler-settings.js @@ -0,0 +1,35 @@ +import Controller, { inject as controller } from "@ember/controller"; +import { action } from "@ember/object"; +import { service } from "@ember/service"; +import { popupAjaxError } from "discourse/lib/ajax-error"; +import { i18n } from "discourse-i18n"; + +export default class AdminEmbeddingCrawlerSettingsController extends Controller { + @service toasts; + @controller adminEmbedding; + + get formData() { + const embedding = this.adminEmbedding.embedding; + + return { + allowed_embed_selectors: embedding.allowed_embed_selectors, + blocked_embed_selectors: embedding.blocked_embed_selectors, + allowed_embed_classnames: embedding.allowed_embed_classnames, + }; + } + + @action + async save(data) { + const embedding = this.adminEmbedding.embedding; + + try { + await embedding.update(data); + this.toasts.success({ + duration: 1500, + data: { message: i18n("admin.embedding.crawler_settings_saved") }, + }); + } catch (error) { + popupAjaxError(error); + } + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-embedding-index.js b/app/assets/javascripts/admin/addon/controllers/admin-embedding-index.js new file mode 100644 index 00000000000..c03f6d9151b --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-embedding-index.js @@ -0,0 +1,44 @@ +import Controller, { inject as controller } from "@ember/controller"; +import { action } from "@ember/object"; +import { alias } from "@ember/object/computed"; +import { service } from "@ember/service"; +import discourseComputed from "discourse-common/utils/decorators"; + +export default class AdminEmbeddingIndexController extends Controller { + @service router; + @service site; + @controller adminEmbedding; + @alias("adminEmbedding.embedding") embedding; + + get showEmbeddingCode() { + const hosts = this.get("embedding.embeddable_hosts"); + return hosts.length > 0 && !this.site.isMobileDevice; + } + + @discourseComputed("embedding.base_url") + embeddingCode(baseUrl) { + const html = `
+ + + `; + + return html; + } + + @action + deleteHost(host) { + this.get("embedding.embeddable_hosts").removeObject(host); + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-embedding-settings.js b/app/assets/javascripts/admin/addon/controllers/admin-embedding-settings.js new file mode 100644 index 00000000000..885f620f225 --- /dev/null +++ b/app/assets/javascripts/admin/addon/controllers/admin-embedding-settings.js @@ -0,0 +1,42 @@ +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 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, + }; + } + + @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); + } + } +} diff --git a/app/assets/javascripts/admin/addon/controllers/admin-embedding.js b/app/assets/javascripts/admin/addon/controllers/admin-embedding.js index 2fecb6717a0..6365650d374 100644 --- a/app/assets/javascripts/admin/addon/controllers/admin-embedding.js +++ b/app/assets/javascripts/admin/addon/controllers/admin-embedding.js @@ -1,61 +1,13 @@ import Controller from "@ember/controller"; -import { action } from "@ember/object"; -import { popupAjaxError } from "discourse/lib/ajax-error"; -import discourseComputed from "discourse-common/utils/decorators"; +import { service } from "@ember/service"; export default class AdminEmbeddingController extends Controller { - saved = false; - embedding = null; - - // show settings if we have at least one created host - @discourseComputed("embedding.embeddable_hosts.@each.isCreated") - showSecondary() { - const hosts = this.get("embedding.embeddable_hosts"); - return hosts.length && hosts.findBy("isCreated"); - } - - @discourseComputed("embedding.base_url") - embeddingCode(baseUrl) { - const html = `
- - -`; - - return html; - } - - @action - saveChanges() { - const embedding = this.embedding; - const updates = embedding.getProperties(embedding.get("fields")); - - this.set("saved", false); - this.embedding - .update(updates) - .then(() => this.set("saved", true)) - .catch(popupAjaxError); - } - - @action - addHost() { - const host = this.store.createRecord("embeddable-host"); - this.get("embedding.embeddable_hosts").pushObject(host); - } - - @action - deleteHost(host) { - this.get("embedding.embeddable_hosts").removeObject(host); + @service router; + get showHeader() { + return [ + "adminEmbedding.index", + "adminEmbedding.settings", + "adminEmbedding.crawler_settings", + ].includes(this.router.currentRouteName); } } diff --git a/app/assets/javascripts/admin/addon/routes/admin-embedding-edit.js b/app/assets/javascripts/admin/addon/routes/admin-embedding-edit.js new file mode 100644 index 00000000000..68f92cddfca --- /dev/null +++ b/app/assets/javascripts/admin/addon/routes/admin-embedding-edit.js @@ -0,0 +1,13 @@ +import DiscourseRoute from "discourse/routes/discourse"; +import { i18n } from "discourse-i18n"; + +export default class AdminEmbeddingEditRoute extends DiscourseRoute { + async model(params) { + const embedding = await this.store.find("embedding"); + return embedding.embeddable_hosts.findBy("id", parseInt(params.id, 10)); + } + + titleToken() { + return i18n("admin.embedding.host_form.edit_header"); + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-embedding-new.js b/app/assets/javascripts/admin/addon/routes/admin-embedding-new.js new file mode 100644 index 00000000000..8edf5bc30b3 --- /dev/null +++ b/app/assets/javascripts/admin/addon/routes/admin-embedding-new.js @@ -0,0 +1,8 @@ +import DiscourseRoute from "discourse/routes/discourse"; +import { i18n } from "discourse-i18n"; + +export default class AdminEmbeddingNewRoute extends DiscourseRoute { + titleToken() { + return i18n("admin.embedding.host_form.add_header"); + } +} diff --git a/app/assets/javascripts/admin/addon/routes/admin-route-map.js b/app/assets/javascripts/admin/addon/routes/admin-route-map.js index 96a36e604b2..0c651cf3e48 100644 --- a/app/assets/javascripts/admin/addon/routes/admin-route-map.js +++ b/app/assets/javascripts/admin/addon/routes/admin-route-map.js @@ -96,10 +96,20 @@ export default function () { this.route("edit", { path: "/:permalink_id" }); } ); - this.route("adminEmbedding", { - path: "/embedding", - resetNamespace: true, - }); + this.route( + "adminEmbedding", + { + path: "/embedding", + resetNamespace: true, + }, + function () { + this.route("index", { path: "/" }); + this.route("settings"); + this.route("crawler_settings"); + this.route("new"); + this.route("edit", { path: "/:id" }); + } + ); this.route( "adminCustomizeEmailTemplates", { path: "/email_templates", resetNamespace: true }, diff --git a/app/assets/javascripts/admin/addon/templates/embedding-crawler-settings.hbs b/app/assets/javascripts/admin/addon/templates/embedding-crawler-settings.hbs new file mode 100644 index 00000000000..0070178df08 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/embedding-crawler-settings.hbs @@ -0,0 +1,32 @@ + + +
+ + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/embedding-edit.hbs b/app/assets/javascripts/admin/addon/templates/embedding-edit.hbs new file mode 100644 index 00000000000..93252280384 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/embedding-edit.hbs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/embedding-index.hbs b/app/assets/javascripts/admin/addon/templates/embedding-index.hbs new file mode 100644 index 00000000000..e0649c9d983 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/embedding-index.hbs @@ -0,0 +1,42 @@ +{{#if this.embedding.embeddable_hosts}} + + + + + + + {{#if this.embedding.embed_by_username}} + + {{else}} + + {{/if}} + + + {{#each this.embedding.embeddable_hosts as |host|}} + + {{/each}} + +
{{i18n "admin.embedding.host"}}{{i18n "admin.embedding.allowed_paths"}}{{i18n "admin.embedding.category"}}{{i18n "admin.embedding.tags"}}{{i18n + "admin.embedding.post_author" + author=this.embedding.embed_by_username + }}{{i18n "admin.embedding.post_author"}}
+{{else}} + +{{/if}} + + + +{{#if this.showEmbeddingCode}} +
+ {{html-safe (i18n "admin.embedding.sample")}} + +
+{{/if}} \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/embedding-new.hbs b/app/assets/javascripts/admin/addon/templates/embedding-new.hbs new file mode 100644 index 00000000000..6a602d64c8d --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/embedding-new.hbs @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/embedding-settings.hbs b/app/assets/javascripts/admin/addon/templates/embedding-settings.hbs new file mode 100644 index 00000000000..70342b0cb22 --- /dev/null +++ b/app/assets/javascripts/admin/addon/templates/embedding-settings.hbs @@ -0,0 +1,53 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/embedding.hbs b/app/assets/javascripts/admin/addon/templates/embedding.hbs index b090f37ec77..0e43542fc58 100644 --- a/app/assets/javascripts/admin/addon/templates/embedding.hbs +++ b/app/assets/javascripts/admin/addon/templates/embedding.hbs @@ -1,111 +1,45 @@ -
- {{#if this.embedding.embeddable_hosts}} - - - - - - - {{#if this.embedding.embed_by_username}} - - {{else}} - - {{/if}} - - - - {{#each this.embedding.embeddable_hosts as |host|}} - - {{/each}} - -
{{i18n "admin.embedding.host"}}{{i18n "admin.embedding.allowed_paths"}}{{i18n "admin.embedding.category"}}{{i18n "admin.embedding.tags"}}{{i18n - "admin.embedding.post_author" - author=this.embedding.embed_by_username - }}{{i18n "admin.embedding.post_author"}} 
- {{else}} -

{{i18n "admin.embedding.get_started"}}

+
+ {{#if this.showHeader}} + + <:breadcrumbs> + + + <:actions as |actions|> + + + <:tabs> + + + + + {{/if}} - - - -
- -{{#if this.showSecondary}} -
- {{html-safe (i18n "admin.embedding.sample")}} - +
+ {{outlet}}
- -
- -
-

{{i18n "admin.embedding.settings"}}

- - - - - - -
- -
-

{{i18n "admin.embedding.crawling_settings"}}

-

{{i18n "admin.embedding.crawling_description"}}

- - - - - - -
- -
- - - {{#if this.saved}}{{i18n "saved"}}{{/if}} -
-{{/if}} \ No newline at end of file +
\ No newline at end of file diff --git a/app/assets/javascripts/admin/addon/templates/permalinks-index.hbs b/app/assets/javascripts/admin/addon/templates/permalinks-index.hbs index 31e9d14a423..9e6cb6c37c4 100644 --- a/app/assets/javascripts/admin/addon/templates/permalinks-index.hbs +++ b/app/assets/javascripts/admin/addon/templates/permalinks-index.hbs @@ -68,7 +68,7 @@ class="btn-small admin-permalink-item__edit" @route="adminPermalinks.edit" @routeModels={{pl}} - @label="admin.config_areas.flags.edit" + @label="admin.config_areas.permalinks.edit" /> diff --git a/app/assets/javascripts/admin/addon/templates/permalinks.hbs b/app/assets/javascripts/admin/addon/templates/permalinks.hbs index 5873429d856..23dba1dc6aa 100644 --- a/app/assets/javascripts/admin/addon/templates/permalinks.hbs +++ b/app/assets/javascripts/admin/addon/templates/permalinks.hbs @@ -16,7 +16,6 @@ @route="adminPermalinks.new" @title="admin.permalink.add" @label="admin.permalink.add" - @icon="plus" class="admin-permalinks__header-add-permalink" /> diff --git a/app/assets/stylesheets/common/admin/customize.scss b/app/assets/stylesheets/common/admin/customize.scss index 94b3f013ee2..2688ab734f7 100644 --- a/app/assets/stylesheets/common/admin/customize.scss +++ b/app/assets/stylesheets/common/admin/customize.scss @@ -897,26 +897,11 @@ } } -.embedding-secondary { - h3 { - margin: 1em 0; +.admin-embeddable-host-item__delete { + color: var(--danger); + svg.d-icon { + color: var(--danger); } - margin-bottom: 2em; - .embed-setting { - input[type="text"] { - width: 50%; - } - margin: 0.75em 0; - } - p.description { - color: var(--primary-medium); - margin-bottom: 1em; - max-width: 700px; - } -} - -.embedding td input { - margin-bottom: 0; } .user-fields { diff --git a/app/controllers/admin/embeddable_hosts_controller.rb b/app/controllers/admin/embeddable_hosts_controller.rb index c8edbb71d5c..3ef3c1aa1db 100644 --- a/app/controllers/admin/embeddable_hosts_controller.rb +++ b/app/controllers/admin/embeddable_hosts_controller.rb @@ -26,7 +26,7 @@ class Admin::EmbeddableHostsController < Admin::AdminController host.host = params[:embeddable_host][:host] host.allowed_paths = params[:embeddable_host][:allowed_paths] host.category_id = params[:embeddable_host][:category_id] - host.category_id = SiteSetting.uncategorized_category_id if host.category_id.blank? + host.category_id = SiteSetting.uncategorized_category_id if host.category.blank? username = params[:embeddable_host][:user] diff --git a/app/controllers/admin/embedding_controller.rb b/app/controllers/admin/embedding_controller.rb index 51b0d48785e..1e8aa58e799 100644 --- a/app/controllers/admin/embedding_controller.rb +++ b/app/controllers/admin/embedding_controller.rb @@ -8,10 +8,6 @@ class Admin::EmbeddingController < Admin::AdminController end def update - if params[:embedding][:embed_by_username].blank? - return render_json_error(I18n.t("site_settings.embed_username_required")) - end - Embedding.settings.each { |s| @embedding.public_send("#{s}=", params[:embedding][s]) } if @embedding.save @@ -22,6 +18,18 @@ class Admin::EmbeddingController < Admin::AdminController end end + def new + end + + def edit + end + + def settings + end + + def crawler_settings + end + protected def fetch_embedding diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index ad255ff8204..ee3715a9cbd 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -5736,6 +5736,12 @@ en: title: "More options" move_up: "Move up" move_down: "Move down" + permalinks: + edit: "Edit" + delete: "Delete" + embeddable_host: + edit: "Edit" + delete: "Delete" look_and_feel: title: "Look and feel" description: "Customize and brand your Discourse site, giving it a distinctive style." @@ -7296,6 +7302,7 @@ en: embedding: get_started: "If you'd like to embed Discourse on another website, begin by adding its host." + delete: "Delete" confirm_delete: "Are you sure you want to delete that host?" sample: |

Paste the following HTML code into your site to create and embed Discourse topics. Replace EMBED_URL with the canonical URL of the page you are embedding it on.

@@ -7304,6 +7311,7 @@ en:

Replace DISCOURSE_USERNAME with the Discourse username of the author that should create the topic. Discourse will automatically lookup the user by the content attribute of the <meta> tags with name attribute set to discourse-username or author. The discourseUserName parameter has been deprecated and will be removed in Discourse 3.2.

title: "Embedding" + description: "Discourse has the ability to embed the comments from a topic in a remote site using a Javascript API that creates an IFRAME" host: "Allowed Hosts" allowed_paths: "Path Allowlist" edit: "edit" @@ -7324,6 +7332,18 @@ en: 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." + crawler_settings_saved: "Crawler settings saved." + back: "Back to Embedding" + more_options: "More options" + host_form: + add_header: "Add host" + edit_header: "Edit host" + save: "Save" + nav: + hosts: "Hosts" + embedding_settings: "Embedding Settings" + crawler_settings: "Crawler Settings" permalink: title: "Permalinks" diff --git a/config/routes.rb b/config/routes.rb index ea34bf4be68..08c1175b15c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -223,6 +223,11 @@ 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, only: %i[index create show update destroy], diff --git a/spec/system/admin_embeddable_hosts_spec.rb b/spec/system/admin_embeddable_hosts_spec.rb index 26fd6525cd0..424a92ffbd1 100644 --- a/spec/system/admin_embeddable_hosts_spec.rb +++ b/spec/system/admin_embeddable_hosts_spec.rb @@ -3,59 +3,74 @@ RSpec.describe "Admin EmbeddableHost Management", type: :system do fab!(:admin) fab!(:author) { Fabricate(:admin) } + fab!(:author_2) { Fabricate(:admin) } fab!(:category) - fab!(:category2) { Fabricate(:category) } + fab!(:category_2) { Fabricate(:category) } fab!(:tag) - fab!(:tag2) { Fabricate(:tag) } + fab!(:tag_2) { Fabricate(:tag) } before { sign_in(admin) } - it "allows admin to add and edit embeddable hosts" do - visit "/admin/customize/embedding" + 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 } - find("button.btn-icon-text", text: "Add Host").click - within find("tr.ember-view") do - find('input[placeholder="example.com"]').set("awesome-discourse-site.local") - find('input[placeholder="/blog/.*"]').set("/blog/.*") + it "allows admin to add, edit and delete embeddable hosts" do + admin_embedding_page.visit - category_chooser = PageObjects::Components::SelectKit.new(".category-chooser") - category_chooser.expand - category_chooser.select_row_by_name(category.name) + expect(page).not_to have_css(".admin-embedding-index__code") - tag_chooser = PageObjects::Components::SelectKit.new(".tag-chooser") - tag_chooser.expand - tag_chooser.select_row_by_name(tag.name) + admin_embedding_page.click_add_host + + admin_embedding_host_form_page.fill_in_allowed_hosts("awesome-discourse-site.local") + admin_embedding_host_form_page.fill_in_path_allow_list("/blog/.*") + admin_embedding_host_form_page.fill_in_category(category) + admin_embedding_host_form_page.fill_in_tags(tag) + admin_embedding_host_form_page.fill_in_post_author(author) + admin_embedding_host_form_page.click_save - find(".user-chooser").click - find(".select-kit-body .select-kit-filter input").fill_in with: author.username - find(".select-kit-body", text: author.username).click - end - find("td.editing-controls .btn.btn-primary").click expect(page).to have_content("awesome-discourse-site.local") expect(page).to have_content("/blog/.*") - expect(page).not_to have_content("#{tag.name},#{tag2.name}") expect(page).to have_content("#{tag.name}") + expect(page).to have_content("#{category.name}") + expect(page).to have_content("#{author.username}") - # Editing + expect(page).to have_css(".admin-embedding-index__code") - find(".embeddable-hosts tr:first-child .controls svg.d-icon-pencil").find(:xpath, "..").click + admin_embedding_page.click_edit_host - within find(".embeddable-hosts tr:first-child.ember-view") do - find('input[placeholder="example.com"]').set("updated-example.com") - find('input[placeholder="/blog/.*"]').set("/updated-blog/.*") + admin_embedding_host_form_page.fill_in_allowed_hosts("updated-example.com") + admin_embedding_host_form_page.fill_in_path_allow_list("/updated-blog/.*") + admin_embedding_host_form_page.fill_in_category(category_2) + admin_embedding_host_form_page.fill_in_tags(tag_2) + admin_embedding_host_form_page.fill_in_post_author(author_2) + admin_embedding_host_form_page.click_save - category_chooser = PageObjects::Components::SelectKit.new(".category-chooser") - category_chooser.expand - category_chooser.select_row_by_name(category2.name) - - tag_chooser = PageObjects::Components::SelectKit.new(".tag-chooser") - tag_chooser.expand - tag_chooser.select_row_by_name(tag2.name) - end - - find("td.editing-controls .btn.btn-primary").click expect(page).to have_content("updated-example.com") expect(page).to have_content("/updated-blog/.*") - expect(page).to have_content("#{tag.name},#{tag2.name}") + expect(page).to have_content("#{tag.name}, #{tag_2.name}") + expect(page).to have_content("#{category_2.name}") + expect(page).to have_content("#{author_2.username}") + + admin_embedding_page.open_embedding_host_menu + admin_embedding_page.click_delete + admin_embedding_page.confirm_delete + + expect(page).not_to have_css(".admin-embedding-index__code") + end + + it "allows admin to save embedding 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_settings_page.fill_in_embed_by_username(author) + admin_embedding_settings_page.click_save + + admin_embedding_page.click_embedding_hosts_tab + expect(page).to have_content("#{author.username}") end end diff --git a/spec/system/page_objects/pages/admin_embedding.rb b/spec/system/page_objects/pages/admin_embedding.rb new file mode 100644 index 00000000000..0663c584ab7 --- /dev/null +++ b/spec/system/page_objects/pages/admin_embedding.rb @@ -0,0 +1,46 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class AdminEmbedding < PageObjects::Pages::Base + def visit + page.visit("/admin/customize/embedding") + self + end + + def click_embedding_settings_tab + find(".admin-embedding-tabs__embedding-settings").click + end + + def click_embedding_hosts_tab + find(".admin-embedding-tabs__hosts").click + end + + def click_add_host + find(".admin-embedding__header-add-host").click + self + end + + def click_edit_host + find(".admin-embeddable-host-item__edit").click + self + end + + def open_embedding_host_menu + find(".embedding-host-menu-trigger").click + self + end + + def click_delete + find(".admin-embeddable-host-item__delete").click + self + end + + def confirm_delete + find(".dialog-footer .btn-primary").click + expect(page).to have_no_css(".dialog-body", wait: Capybara.default_max_wait_time * 3) + self + end + end + end +end diff --git a/spec/system/page_objects/pages/admin_embedding_host_form.rb b/spec/system/page_objects/pages/admin_embedding_host_form.rb new file mode 100644 index 00000000000..0c2876bf3ef --- /dev/null +++ b/spec/system/page_objects/pages/admin_embedding_host_form.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class AdminEmbeddingHostForm < PageObjects::Pages::Base + def fill_in_allowed_hosts(url) + form.field("host").fill_in(url) + self + end + + def fill_in_path_allow_list(path) + form.field("allowed_paths").fill_in(path) + self + end + + def fill_in_category(category) + dropdown = PageObjects::Components::SelectKit.new(".admin-embedding-host-form__category") + dropdown.expand + dropdown.search(category.name) + dropdown.select_row_by_value(category.id) + dropdown.collapse + self + end + + def fill_in_tags(tag) + dropdown = PageObjects::Components::SelectKit.new(".admin-embedding-host-form__tags") + dropdown.expand + dropdown.search(tag.name) + dropdown.select_row_by_value(tag.name) + dropdown.collapse + self + end + + def fill_in_post_author(author) + dropdown = PageObjects::Components::SelectKit.new(".admin-embedding-host-form__post_author") + dropdown.expand + dropdown.search(author.username) + dropdown.select_row_by_value(author.username) + dropdown.collapse + self + end + + def click_save + form.submit + expect(page).to have_css(".d-admin-table") + end + + def form + @form ||= PageObjects::Components::FormKit.new(".admin-embedding-host-form .form-kit") + end + end + end +end diff --git a/spec/system/page_objects/pages/admin_embedding_settings.rb b/spec/system/page_objects/pages/admin_embedding_settings.rb new file mode 100644 index 00000000000..014494fd330 --- /dev/null +++ b/spec/system/page_objects/pages/admin_embedding_settings.rb @@ -0,0 +1,24 @@ +# frozen_string_literal: true + +module PageObjects + module Pages + class AdminEmbeddingSettings < PageObjects::Pages::Base + def fill_in_embed_by_username(author) + dropdown = + PageObjects::Components::SelectKit.new( + ".admin-embedding-settings-form__embed_by_username", + ) + dropdown.expand + dropdown.search(author.username) + dropdown.select_row_by_value(author.username) + dropdown.collapse + self + end + + def click_save + form = PageObjects::Components::FormKit.new(".admin-embedding .form-kit") + form.submit + end + end + end +end