UX: admins embedding page follows admin ux guideline
Conversion of `/admin/customize/embedding` page to follow admin UX guidelines.
This commit is contained in:
parent
b3fa335c7d
commit
f1a5e4d968
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
<template>
|
||||
<BackButton @route="adminEmbedding" @label="admin.embedding.back" />
|
||||
<div class="admin-config-area">
|
||||
<div class="admin-config-area__primary-content admin-embedding-host-form">
|
||||
<AdminConfigAreaCard @heading={{this.header}}>
|
||||
<:content>
|
||||
<Form @onSubmit={{this.save}} @data={{this.formData}} as |form|>
|
||||
<form.Field
|
||||
@name="host"
|
||||
@title={{i18n "admin.embedding.host"}}
|
||||
@validation="required"
|
||||
@format="large"
|
||||
as |field|
|
||||
>
|
||||
<field.Input placeholder="example.com" />
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="allowed_paths"
|
||||
@title={{i18n "admin.embedding.allowed_paths"}}
|
||||
@format="large"
|
||||
as |field|
|
||||
>
|
||||
<field.Input placeholder="/blog/.*" />
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="category"
|
||||
@title={{i18n "admin.embedding.category"}}
|
||||
as |field|
|
||||
>
|
||||
<field.Custom>
|
||||
<CategoryChooser
|
||||
@value={{field.value}}
|
||||
@onChange={{field.set}}
|
||||
class="admin-embedding-host-form__category"
|
||||
/>
|
||||
</field.Custom>
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="tags"
|
||||
@title={{i18n "admin.embedding.tags"}}
|
||||
as |field|
|
||||
>
|
||||
<field.Custom>
|
||||
<TagChooser
|
||||
@tags={{field.value}}
|
||||
@everyTag={{true}}
|
||||
@excludeSynonyms={{true}}
|
||||
@unlimitedTagCount={{true}}
|
||||
@onChange={{field.set}}
|
||||
@options={{hash
|
||||
filterPlaceholder="category.tags_placeholder"
|
||||
}}
|
||||
class="admin-embedding-host-form__tags"
|
||||
/>
|
||||
</field.Custom>
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="user"
|
||||
@title={{i18n "admin.embedding.post_author"}}
|
||||
as |field|
|
||||
>
|
||||
<field.Custom>
|
||||
<UserChooser
|
||||
@value={{field.value}}
|
||||
@onChange={{field.set}}
|
||||
@options={{hash maximum=1 excludeCurrentUser=false}}
|
||||
class="admin-embedding-host-form__post_author"
|
||||
/>
|
||||
</field.Custom>
|
||||
</form.Field>
|
||||
|
||||
<form.Submit @label="admin.embedding.host_form.save" />
|
||||
</Form>
|
||||
</:content>
|
||||
</AdminConfigAreaCard>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
}
|
|
@ -1,87 +1,45 @@
|
|||
{{#if this.editing}}
|
||||
<td class="editing-input">
|
||||
<div class="label">{{i18n "admin.embedding.host"}}</div>
|
||||
<Input
|
||||
@value={{this.buffered.host}}
|
||||
placeholder="example.com"
|
||||
@enter={{this.save}}
|
||||
class="host-name"
|
||||
autofocus={{true}}
|
||||
/>
|
||||
</td>
|
||||
<td class="editing-input">
|
||||
<div class="label">{{i18n "admin.embedding.allowed_paths"}}</div>
|
||||
<Input
|
||||
@value={{this.buffered.allowed_paths}}
|
||||
placeholder="/blog/.*"
|
||||
@enter={{this.save}}
|
||||
class="path-allowlist"
|
||||
/>
|
||||
</td>
|
||||
<td class="editing-input">
|
||||
<div class="label">{{i18n "admin.embedding.category"}}</div>
|
||||
<CategoryChooser
|
||||
@value={{this.category.id}}
|
||||
@onChangeCategory={{fn (mut this.category)}}
|
||||
class="small"
|
||||
/>
|
||||
</td>
|
||||
<td class="editing-input">
|
||||
<div class="label">{{i18n "admin.embedding.tags"}}</div>
|
||||
<TagChooser
|
||||
@tags={{this.tags}}
|
||||
@everyTag={{true}}
|
||||
@excludeSynonyms={{true}}
|
||||
@unlimitedTagCount={{true}}
|
||||
@onChange={{fn (mut this.tags)}}
|
||||
@options={{hash filterPlaceholder="category.tags_placeholder"}}
|
||||
/>
|
||||
</td>
|
||||
<td class="editing-input">
|
||||
<div class="label">{{i18n "admin.embedding.user"}}</div>
|
||||
<UserChooser
|
||||
@value={{this.user}}
|
||||
@onChange={{action "onUserChange"}}
|
||||
@options={{hash maximum=1 excludeCurrentUser=false}}
|
||||
/>
|
||||
</td>
|
||||
<td class="editing-controls">
|
||||
<td class="d-admin-row__detail">
|
||||
{{this.host.host}}
|
||||
</td>
|
||||
<td class="d-admin-row__detail">
|
||||
{{this.host.allowed_paths}}
|
||||
</td>
|
||||
<td class="d-admin-row__detail">
|
||||
{{category-badge this.category allowUncategorized=true}}
|
||||
</td>
|
||||
<td class="d-admin-row__detail">
|
||||
{{this.tags}}
|
||||
</td>
|
||||
<td class="d-admin-row__detail">
|
||||
{{this.user}}
|
||||
</td>
|
||||
|
||||
<td class="d-admin-row__controls">
|
||||
<div class="d-admin-row__controls-options">
|
||||
<DButton
|
||||
@icon="check"
|
||||
@action={{this.save}}
|
||||
@disabled={{this.cantSave}}
|
||||
class="btn-primary"
|
||||
class="btn-small admin-embeddable-host-item__edit"
|
||||
@route="adminEmbedding.edit"
|
||||
@routeModels={{this.host}}
|
||||
@label="admin.embedding.edit"
|
||||
/>
|
||||
<DButton
|
||||
@icon="xmark"
|
||||
@action={{this.cancel}}
|
||||
@disabled={{this.host.isSaving}}
|
||||
class="btn-danger"
|
||||
/>
|
||||
</td>
|
||||
{{else}}
|
||||
<td>
|
||||
<div class="label">{{i18n "admin.embedding.host"}}</div>
|
||||
{{this.host.host}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="label">
|
||||
{{i18n "admin.embedding.allowed_paths"}}
|
||||
</div>
|
||||
{{this.host.allowed_paths}}
|
||||
</td>
|
||||
<td>
|
||||
<div class="label">{{i18n "admin.embedding.category"}}</div>
|
||||
{{category-badge this.category allowUncategorized=true}}
|
||||
</td>
|
||||
<td>
|
||||
{{this.tags}}
|
||||
</td>
|
||||
<td>
|
||||
{{this.user}}
|
||||
</td>
|
||||
<td class="controls">
|
||||
<DButton @icon="pencil" @action={{this.edit}} />
|
||||
<DButton @icon="trash-can" @action={{this.delete}} class="btn-danger" />
|
||||
</td>
|
||||
{{/if}}
|
||||
|
||||
<DMenu
|
||||
@identifier="embedding-host-menu"
|
||||
@title={{i18n "admin.embedding.more_options"}}
|
||||
@icon="ellipsis-vertical"
|
||||
>
|
||||
<:content>
|
||||
<DropdownMenu as |dropdown|>
|
||||
<dropdown.item>
|
||||
<DButton
|
||||
@action={{this.delete}}
|
||||
@icon="trash-can"
|
||||
class="btn-transparent admin-embeddable-host-item__delete"
|
||||
@label="admin.embedding.delete"
|
||||
/>
|
||||
</dropdown.item>
|
||||
</DropdownMenu>
|
||||
</:content>
|
||||
</DMenu>
|
||||
</div>
|
||||
</td>
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +0,0 @@
|
|||
{{#if this.isCheckbox}}
|
||||
<label for={{this.inputId}}>
|
||||
<Input @checked={{this.checked}} id={{this.inputId}} @type="checkbox" />
|
||||
{{i18n this.translationKey}}
|
||||
</label>
|
||||
{{else}}
|
||||
<label for={{this.inputId}}>{{i18n this.translationKey}}</label>
|
||||
<Input
|
||||
@value={{this.value}}
|
||||
id={{this.inputId}}
|
||||
placeholder={{this.placeholder}}
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<div class="clearfix"></div>
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 = `<div id='discourse-comments'></div>
|
||||
<meta name='discourse-username' content='DISCOURSE_USERNAME'>
|
||||
|
||||
<script type="text/javascript">
|
||||
DiscourseEmbed = {
|
||||
discourseUrl: '${baseUrl}/',
|
||||
discourseEmbedUrl: 'EMBED_URL',
|
||||
// className: 'CLASS_NAME',
|
||||
};
|
||||
|
||||
(function() {
|
||||
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
|
||||
d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
|
||||
})();
|
||||
</script>`;
|
||||
|
||||
return html;
|
||||
}
|
||||
|
||||
@action
|
||||
deleteHost(host) {
|
||||
this.get("embedding.embeddable_hosts").removeObject(host);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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 = `<div id='discourse-comments'></div>
|
||||
<meta name='discourse-username' content='DISCOURSE_USERNAME'>
|
||||
|
||||
<script type="text/javascript">
|
||||
DiscourseEmbed = {
|
||||
discourseUrl: '${baseUrl}/',
|
||||
discourseEmbedUrl: 'EMBED_URL',
|
||||
// className: 'CLASS_NAME',
|
||||
};
|
||||
|
||||
(function() {
|
||||
var d = document.createElement('script'); d.type = 'text/javascript'; d.async = true;
|
||||
d.src = DiscourseEmbed.discourseUrl + 'javascripts/embed.js';
|
||||
(document.getElementsByTagName('head')[0] || document.getElementsByTagName('body')[0]).appendChild(d);
|
||||
})();
|
||||
</script>`;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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");
|
||||
}
|
||||
}
|
|
@ -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 },
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
<AdminPageSubheader
|
||||
@titleLabelTranslated={{i18n "admin.embedding.crawling_settings"}}
|
||||
@descriptionLabelTranslated={{i18n "admin.embedding.crawling_description"}}
|
||||
/>
|
||||
|
||||
<Form @onSubmit={{this.save}} @data={{this.formData}} as |form|>
|
||||
<form.Field
|
||||
@name="allowed_embed_selectors"
|
||||
@title={{i18n "admin.embedding.allowed_embed_selectors"}}
|
||||
@format="large"
|
||||
as |field|
|
||||
>
|
||||
<field.Input placeholder="article, #story, .post" />
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="blocked_embed_selectors"
|
||||
@title={{i18n "admin.embedding.blocked_embed_selectors"}}
|
||||
@format="large"
|
||||
as |field|
|
||||
>
|
||||
<field.Input placeholder=".ad-unit, header" />
|
||||
</form.Field>
|
||||
<form.Field
|
||||
@name="allowed_embed_classnames"
|
||||
@title={{i18n "admin.embedding.allowed_embed_classnames"}}
|
||||
@format="large"
|
||||
as |field|
|
||||
>
|
||||
<field.Input placeholder="emoji, classname" />
|
||||
</form.Field>
|
||||
<form.Submit @label="admin.embedding.save" />
|
||||
</Form>
|
|
@ -0,0 +1 @@
|
|||
<AdminEmbeddingHostForm @host={{this.model}} />
|
|
@ -0,0 +1,42 @@
|
|||
{{#if this.embedding.embeddable_hosts}}
|
||||
<table class="d-admin-table">
|
||||
<thead>
|
||||
<th>{{i18n "admin.embedding.host"}}</th>
|
||||
<th>{{i18n "admin.embedding.allowed_paths"}}</th>
|
||||
<th>{{i18n "admin.embedding.category"}}</th>
|
||||
<th>{{i18n "admin.embedding.tags"}}</th>
|
||||
{{#if this.embedding.embed_by_username}}
|
||||
<th>{{i18n
|
||||
"admin.embedding.post_author"
|
||||
author=this.embedding.embed_by_username
|
||||
}}</th>
|
||||
{{else}}
|
||||
<th>{{i18n "admin.embedding.post_author"}}</th>
|
||||
{{/if}}
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.embedding.embeddable_hosts as |host|}}
|
||||
<EmbeddableHost @host={{host}} @deleteHost={{action "deleteHost"}} />
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<AdminConfigAreaEmptyList
|
||||
@ctaLabel="admin.embedding.add_host"
|
||||
@ctaRoute="adminEmbedding.new"
|
||||
@ctaClass="admin-embedding__add-host"
|
||||
@emptyLabel="admin.embedding.get_started"
|
||||
/>
|
||||
{{/if}}
|
||||
|
||||
<PluginOutlet
|
||||
@name="after-embeddable-hosts-table"
|
||||
@outletArgs={{hash embedding=this.embedding}}
|
||||
/>
|
||||
|
||||
{{#if this.showEmbeddingCode}}
|
||||
<div class="admin-embedding-index__code">
|
||||
{{html-safe (i18n "admin.embedding.sample")}}
|
||||
<HighlightedCode @code={{this.embeddingCode}} @lang="html" />
|
||||
</div>
|
||||
{{/if}}
|
|
@ -0,0 +1 @@
|
|||
<AdminEmbeddingHostForm />
|
|
@ -0,0 +1,53 @@
|
|||
<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>
|
|
@ -1,111 +1,45 @@
|
|||
<div class="embeddable-hosts">
|
||||
{{#if this.embedding.embeddable_hosts}}
|
||||
<table class="embedding grid">
|
||||
<thead>
|
||||
<th style="width: 18%">{{i18n "admin.embedding.host"}}</th>
|
||||
<th style="width: 18%">{{i18n "admin.embedding.allowed_paths"}}</th>
|
||||
<th style="width: 18%">{{i18n "admin.embedding.category"}}</th>
|
||||
<th style="width: 18%">{{i18n "admin.embedding.tags"}}</th>
|
||||
{{#if this.embedding.embed_by_username}}
|
||||
<th style="width: 18%">{{i18n
|
||||
"admin.embedding.post_author"
|
||||
author=this.embedding.embed_by_username
|
||||
}}</th>
|
||||
{{else}}
|
||||
<th style="width: 18%">{{i18n "admin.embedding.post_author"}}</th>
|
||||
{{/if}}
|
||||
<th style="width: 10%"> </th>
|
||||
</thead>
|
||||
<tbody>
|
||||
{{#each this.embedding.embeddable_hosts as |host|}}
|
||||
<EmbeddableHost @host={{host}} @deleteHost={{action "deleteHost"}} />
|
||||
{{/each}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{else}}
|
||||
<p>{{i18n "admin.embedding.get_started"}}</p>
|
||||
<div class="admin-embedding admin-config-page">
|
||||
{{#if this.showHeader}}
|
||||
<AdminPageHeader
|
||||
@titleLabel="admin.embedding.title"
|
||||
@descriptionLabel="admin.embedding.description"
|
||||
@learnMoreUrl="https://meta.discourse.org/t/embed-discourse-comments-on-another-website-via-javascript/31963"
|
||||
>
|
||||
<:breadcrumbs>
|
||||
<DBreadcrumbsItem
|
||||
@path="/admin/customize/embedding"
|
||||
@label={{i18n "admin.embedding.title"}}
|
||||
/>
|
||||
</:breadcrumbs>
|
||||
<:actions as |actions|>
|
||||
<actions.Primary
|
||||
@route="adminEmbedding.new"
|
||||
@title="admin.embedding.add_host"
|
||||
@label="admin.embedding.add_host"
|
||||
class="admin-embedding__header-add-host"
|
||||
/>
|
||||
</:actions>
|
||||
<:tabs>
|
||||
<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"
|
||||
/>
|
||||
<NavItem
|
||||
@route="adminEmbedding.crawler_settings"
|
||||
@label="admin.embedding.nav.crawler_settings"
|
||||
class="admin-embedding-tabs__crawler-settings"
|
||||
/>
|
||||
</:tabs>
|
||||
</AdminPageHeader>
|
||||
{{/if}}
|
||||
|
||||
<DButton
|
||||
@label="admin.embedding.add_host"
|
||||
@action={{this.addHost}}
|
||||
@icon="plus"
|
||||
class="btn-primary add-host"
|
||||
/>
|
||||
|
||||
<PluginOutlet
|
||||
@name="after-embeddable-hosts-table"
|
||||
@outletArgs={{hash embedding=this.embedding}}
|
||||
/>
|
||||
<div class="admin-container admin-config-page__main-area">
|
||||
{{outlet}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{#if this.showSecondary}}
|
||||
<div class="embedding-secondary">
|
||||
{{html-safe (i18n "admin.embedding.sample")}}
|
||||
<HighlightedCode @code={{this.embeddingCode}} @lang="html" />
|
||||
</div>
|
||||
|
||||
<hr />
|
||||
|
||||
<div class="embedding-secondary">
|
||||
<h3>{{i18n "admin.embedding.settings"}}</h3>
|
||||
|
||||
<EmbeddingSetting
|
||||
@field="embed_by_username"
|
||||
@value={{this.embedding.embed_by_username}}
|
||||
/>
|
||||
<EmbeddingSetting
|
||||
@field="embed_post_limit"
|
||||
@value={{this.embedding.embed_post_limit}}
|
||||
/>
|
||||
<EmbeddingSetting
|
||||
@field="embed_title_scrubber"
|
||||
@value={{this.embedding.embed_title_scrubber}}
|
||||
@placeholder="- site.com$"
|
||||
/>
|
||||
<EmbeddingSetting
|
||||
@field="embed_truncate"
|
||||
@value={{this.embedding.embed_truncate}}
|
||||
@type="checkbox"
|
||||
/>
|
||||
<EmbeddingSetting
|
||||
@field="embed_unlisted"
|
||||
@value={{this.embedding.embed_unlisted}}
|
||||
@type="checkbox"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="embedding-secondary">
|
||||
<h3>{{i18n "admin.embedding.crawling_settings"}}</h3>
|
||||
<p class="description">{{i18n "admin.embedding.crawling_description"}}</p>
|
||||
|
||||
<EmbeddingSetting
|
||||
@field="allowed_embed_selectors"
|
||||
@value={{this.embedding.allowed_embed_selectors}}
|
||||
@placeholder="article, #story, .post"
|
||||
/>
|
||||
|
||||
<EmbeddingSetting
|
||||
@field="blocked_embed_selectors"
|
||||
@value={{this.embedding.blocked_embed_selectors}}
|
||||
@placeholder=".ad-unit, header"
|
||||
/>
|
||||
|
||||
<EmbeddingSetting
|
||||
@field="allowed_embed_classnames"
|
||||
@value={{this.embedding.allowed_embed_classnames}}
|
||||
@placeholder="emoji, classname"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="embedding-secondary">
|
||||
<DButton
|
||||
@label="admin.embedding.save"
|
||||
@action={{this.saveChanges}}
|
||||
@disabled={{this.embedding.isSaving}}
|
||||
class="btn-primary embed-save"
|
||||
/>
|
||||
|
||||
{{#if this.saved}}{{i18n "saved"}}{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
|
@ -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"
|
||||
/>
|
||||
|
||||
<DMenu
|
||||
|
@ -84,7 +84,7 @@
|
|||
@action={{fn this.destroyRecord pl}}
|
||||
@icon="trash-can"
|
||||
class="btn-transparent admin-permalink-item__delete"
|
||||
@label="admin.config_areas.flags.delete"
|
||||
@label="admin.config_areas.permalinks.delete"
|
||||
/>
|
||||
</dropdown.item>
|
||||
</DropdownMenu>
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
@route="adminPermalinks.new"
|
||||
@title="admin.permalink.add"
|
||||
@label="admin.permalink.add"
|
||||
@icon="plus"
|
||||
class="admin-permalinks__header-add-permalink"
|
||||
/>
|
||||
</:actions>
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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: |
|
||||
<p>Paste the following HTML code into your site to create and embed Discourse topics. Replace <b>EMBED_URL</b> with the canonical URL of the page you are embedding it on.</p>
|
||||
|
@ -7304,6 +7311,7 @@ en:
|
|||
|
||||
<p>Replace <b>DISCOURSE_USERNAME</b> with the Discourse username of the author that should create the topic. Discourse will automatically lookup the user by the <code>content</code> attribute of the <code><meta></code> tags with <code>name</code> attribute set to <code>discourse-username</code> or <code>author</code>. The <code>discourseUserName</code> parameter has been deprecated and will be removed in Discourse 3.2.</p>
|
||||
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"
|
||||
|
|
|
@ -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],
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue