DEV: Refactor the Automation Plugin UI to match admin UI guidelines (#31060)

This change updates the Automation plugin to make use of the `use_new_show_route` plugin flag, as well as generally updating the UI to match current admin UI guidelines. Notable changes include:

- Moving template/router/controller files to make use of the `admin.adminPlugins.show` route.
- Changing the URIs from `/admin/plugins/discourse-automation` to `/admin/plugins/automation`, to match the `PLUGIN_NAME`.
- Adding UI wrappers around the New/Edit forms, and polishing the list of defined automations.
This commit is contained in:
Gary Pendergast
2025-02-05 14:34:15 +11:00
committed by GitHub
parent a2dbcedbd9
commit f439bf14cc
26 changed files with 432 additions and 421 deletions

View File

@ -2,7 +2,7 @@ import RestAdapter from "discourse/adapters/rest";
export default class Adapter extends RestAdapter { export default class Adapter extends RestAdapter {
basePath() { basePath() {
return "/admin/plugins/discourse-automation/"; return "/admin/plugins/automation/";
} }
pathFor() { pathFor() {

View File

@ -1,19 +0,0 @@
import Controller from "@ember/controller";
import { action, computed } from "@ember/object";
import { service } from "@ember/service";
export default class Automation extends Controller {
@service router;
@computed("router.currentRouteName")
get showNewAutomation() {
return (
this.router.currentRouteName === "adminPlugins.discourse-automation.index"
);
}
@action
newAutomation() {
this.router.transitionTo("adminPlugins.discourse-automation.new");
}
}

View File

@ -1,5 +0,0 @@
import DiscourseRoute from "discourse/routes/discourse";
export default class Automation extends DiscourseRoute {
controllerName = "admin-plugins-discourse-automation";
}

View File

@ -1,174 +0,0 @@
<section class="discourse-automation-form edit">
<form class="form-horizontal">
<FormError @error={{this.error}} />
<section class="form-section edit">
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.automation.name.label"}}
</label>
<div class="controls">
<TextField
@value={{this.automationForm.name}}
@type="text"
@autofocus={{true}}
@name="automation-name"
class="input-large"
@input={{with-event-value (fn (mut this.automationForm.name))}}
/>
</div>
</div>
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.script.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{this.automationForm.script}}
@content={{this.model.scriptables}}
@onChange={{this.onChangeScript}}
@options={{hash filterable=true}}
class="scriptables"
/>
</div>
</div>
</section>
<section class="trigger-section form-section edit">
<h2 class="title">
{{i18n "discourse_automation.edit_automation.trigger_section.title"}}
</h2>
<div class="control-group">
{{#if this.model.automation.script.forced_triggerable}}
<div class="alert alert-warning">
{{i18n
"discourse_automation.edit_automation.trigger_section.forced"
}}
</div>
{{/if}}
<label class="control-label">
{{i18n "discourse_automation.models.trigger.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{this.automationForm.trigger}}
@content={{this.model.triggerables}}
@onChange={{this.onChangeTrigger}}
@options={{hash
filterable=true
none="discourse_automation.select_trigger"
disabled=this.model.automation.script.forced_triggerable
}}
class="triggerables"
/>
</div>
</div>
{{#if this.automationForm.trigger}}
{{#if this.model.automation.trigger.doc}}
<div class="alert alert-info">
<p>{{this.model.automation.trigger.doc}}</p>
</div>
{{/if}}
{{#if
(and
this.model.automation.enabled
this.model.automation.trigger.settings.manual_trigger
)
}}
<div class="alert alert-info next-trigger">
{{#if this.nextPendingAutomationAtFormatted}}
<p>
{{i18n
"discourse_automation.edit_automation.trigger_section.next_pending_automation"
date=this.nextPendingAutomationAtFormatted
}}
</p>
{{/if}}
<DButton
@label="discourse_automation.edit_automation.trigger_section.trigger_now"
@isLoading={{this.isTriggeringAutomation}}
@action={{fn
this.onManualAutomationTrigger
this.model.automation.id
}}
class="btn-primary trigger-now-btn"
/>
</div>
{{/if}}
{{#each this.triggerFields as |field|}}
<AutomationField
@automation={{this.automation}}
@field={{field}}
@saveAutomation={{fn this.saveAutomation this.automation}}
/>
{{/each}}
{{/if}}
</section>
{{#if this.automationForm.trigger}}
{{#if this.scriptFields}}
<section class="fields-section form-section edit">
<h2 class="title">
{{i18n "discourse_automation.edit_automation.fields_section.title"}}
</h2>
{{#if this.model.automation.script.with_trigger_doc}}
<div class="alert alert-info">
<p>{{this.model.automation.script.with_trigger_doc}}</p>
</div>
{{/if}}
<div class="control-group">
{{#each this.scriptFields as |field|}}
<AutomationField
@automation={{this.automation}}
@field={{field}}
@saveAutomation={{fn this.saveAutomation this.automation}}
/>
{{/each}}
</div>
</section>
{{/if}}
{{#if this.automationForm.trigger}}
<div
class="control-group automation-enabled alert
{{if this.automationForm.enabled 'alert-info' 'alert-warning'}}"
>
<span>{{i18n
"discourse_automation.models.automation.enabled.label"
}}</span>
<Input
@type="checkbox"
@checked={{this.automationForm.enabled}}
{{on
"click"
(action (mut this.automationForm.enabled) value="target.checked")
}}
/>
</div>
{{/if}}
<div class="control-group">
<DButton
@isLoading={{this.isUpdatingAutomation}}
@label="discourse_automation.update"
@type="submit"
@action={{fn this.saveAutomation this.automation true}}
class="btn-primary update-automation"
/>
</div>
{{/if}}
</form>
</section>

View File

@ -1,117 +0,0 @@
{{#if this.model.length}}
<table class="d-admin-table automations">
<thead>
<tr>
<th></th>
<th>{{i18n "discourse_automation.models.automation.name.label"}}</th>
<th>{{i18n "discourse_automation.models.automation.trigger.label"}}</th>
<th>{{i18n "discourse_automation.models.automation.script.label"}}</th>
<th>{{i18n
"discourse_automation.models.automation.last_updated_by.label"
}}</th>
<th></th>
</tr>
</thead>
<tbody>
{{#each this.model as |automation|}}
<tr class="d-admin-row__content">
{{#if automation.script.not_found}}
<td colspan="5" class="d-admin-row__detail alert alert-danger">
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.status.label"}}
</div>
{{i18n
"discourse_automation.scriptables.not_found"
script=automation.script.id
automation=automation.name
}}
</td>
{{else if automation.trigger.not_found}}
<td colspan="5" class="d-admin-row__detail alert alert-danger">
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.status.label"}}
</div>
{{i18n
"discourse_automation.triggerables.not_found"
trigger=automation.trigger.id
automation=automation.name
}}
</td>
{{else}}
<td
class="d-admin-row__detail automations__status"
role="button"
{{on "click" (fn this.editAutomation automation)}}
>
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.status.label"}}
</div>
{{format-enabled-automation
automation.enabled
automation.trigger
}}
</td>
<td
class="d-admin-row__overview automations__name"
tabindex="0"
role="button"
{{on "keypress" (fn this.editAutomation automation)}}
{{on "click" (fn this.editAutomation automation)}}
>
{{if
automation.name
automation.name
(i18n "discourse_automation.unnamed_automation")
}}
</td>
<td
class="d-admin-row__detail automations__script"
role="button"
{{on "click" (fn this.editAutomation automation)}}
>
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.trigger.label"}}
</div>
{{if automation.trigger.id automation.trigger.name "-"}}
</td>
<td
class="d-admin-row__detail automations__version"
role="button"
{{on "click" (fn this.editAutomation automation)}}
>
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.script.label"}}
</div>
{{automation.script.name}}
(v{{automation.script.version}})
</td>
<td class="d-admin-row__detail automations__updated-by">
<div class="d-admin-row__mobile-label">
{{i18n
"discourse_automation.models.automation.last_updated_by.label"
}}
</div>
<div class="automations__user-timestamp">
<a
href={{automation.last_updated_by.userPath}}
data-user-card={{automation.last_updated_by.username}}
>
{{avatar automation.last_updated_by imageSize="small"}}
</a>
{{format-date automation.updated_at leaveAgo="true"}}
</div>
</td>
{{/if}}
<td class="d-admin-row__controls automations__delete">
<DButton
@icon="trash-can"
@action={{action "destroyAutomation" automation}}
class="btn-danger"
/>
</td>
</tr>
{{/each}}
</tbody>
</table>
{{/if}}

View File

@ -1,33 +0,0 @@
<section class="discourse-automation-form new">
<div
class="admin-section-landing__header"
{{did-insert this.resetFilterText}}
>
<h2>{{i18n "discourse_automation.select_script"}}</h2>
<input
type="text"
placeholder={{i18n "discourse_automation.filter_placeholder"}}
{{on "input" this.updateFilterText}}
class="admin-section-landing__header-filter"
/>
</div>
{{#unless this.model.scripts.length}}
<div class="alert alert-info">
<p>{{i18n "discourse_automation.no_automation_yet"}}</p>
</div>
{{/unless}}
<div class="admin-section-landing__wrapper">
{{#each this.scriptableContent as |script|}}
<AdminSectionLandingItem
{{on "click" (fn this.selectScriptToEdit script)}}
@titleLabelTranslated={{script.name}}
@descriptionLabelTranslated={{script.description}}
/>
{{/each}}
</div>
</section>

View File

@ -1,21 +0,0 @@
<LinkTo
@route="adminPlugins.discourse-automation"
class="discourse-automation-title"
>
<h1 class="title">
{{i18n "discourse_automation.title"}}
</h1>
{{#if this.showNewAutomation}}
<DButton
@label="discourse_automation.create"
@icon="plus"
@action={{action "newAutomation"}}
class="new-automation"
/>
{{/if}}
</LinkTo>
<hr />
{{outlet}}

View File

@ -31,7 +31,7 @@ export default class AutomationEdit extends Controller {
this.setProperties({ error: null, isUpdatingAutomation: true }); this.setProperties({ error: null, isUpdatingAutomation: true });
return ajax( return ajax(
`/admin/plugins/discourse-automation/automations/${this.model.automation.id}.json`, `/admin/plugins/automation/automations/${this.model.automation.id}.json`,
{ {
type: "PUT", type: "PUT",
data: JSON.stringify({ automation: this.automationForm }), data: JSON.stringify({ automation: this.automationForm }),
@ -42,7 +42,7 @@ export default class AutomationEdit extends Controller {
.then(() => { .then(() => {
this.send("refreshRoute"); this.send("refreshRoute");
if (routeToIndex) { if (routeToIndex) {
this.router.transitionTo("adminPlugins.discourse-automation.index"); this.router.transitionTo("adminPlugins.show.automation.index");
} }
}) })
.catch((e) => this._showError(e)) .catch((e) => this._showError(e))

View File

@ -12,14 +12,14 @@ export default class AutomationIndex extends Controller {
@action @action
editAutomation(automation) { editAutomation(automation) {
this.router.transitionTo( this.router.transitionTo(
"adminPlugins.discourse-automation.edit", "adminPlugins.show.automation.edit",
automation.id automation.id
); );
} }
@action @action
newAutomation() { newAutomation() {
this.router.transitionTo("adminPlugins.discourse-automation.new"); this.router.transitionTo("adminPlugins.show.automation.new");
} }
@action @action

View File

@ -38,7 +38,7 @@ export default class AutomationNew extends Controller {
selectScriptToEdit(newScript) { selectScriptToEdit(newScript) {
this.model.automation.save({ script: newScript.id }).then(() => { this.model.automation.save({ script: newScript.id }).then(() => {
this.router.transitionTo( this.router.transitionTo(
"adminPlugins.discourse-automation.edit", "adminPlugins.show.automation.edit",
this.model.automation.id this.model.automation.id
); );
}); });

View File

@ -2,18 +2,16 @@ import { action } from "@ember/object";
import { hash } from "rsvp"; import { hash } from "rsvp";
import { ajax } from "discourse/lib/ajax"; import { ajax } from "discourse/lib/ajax";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
import Field from "../models/discourse-automation-field"; import Field from "discourse/plugins/automation/admin/models/discourse-automation-field";
export default class AutomationEdit extends DiscourseRoute { export default class AutomationEdit extends DiscourseRoute {
controllerName = "admin-plugins-discourse-automation-edit";
model(params) { model(params) {
return hash({ return hash({
scriptables: this.store scriptables: this.store
.findAll("discourse-automation-scriptable") .findAll("discourse-automation-scriptable")
.then((result) => result.content), .then((result) => result.content),
triggerables: ajax( triggerables: ajax(
`/admin/plugins/discourse-automation/triggerables.json?automation_id=${params.id}` `/admin/plugins/automation/triggerables.json?automation_id=${params.id}`
).then((result) => (result ? result.triggerables : [])), ).then((result) => (result ? result.triggerables : [])),
automation: this.store.find("discourse-automation-automation", params.id), automation: this.store.find("discourse-automation-automation", params.id),
}); });

View File

@ -5,18 +5,10 @@ import DiscourseRoute from "discourse/routes/discourse";
export default class AutomationIndex extends DiscourseRoute { export default class AutomationIndex extends DiscourseRoute {
@service router; @service router;
controllerName = "admin-plugins-discourse-automation-index";
model() { model() {
return this.store.findAll("discourse-automation-automation"); return this.store.findAll("discourse-automation-automation");
} }
afterModel(model) {
if (!model.length) {
this.router.transitionTo("adminPlugins.discourse-automation.new");
}
}
@action @action
triggerRefresh() { triggerRefresh() {
this.refresh(); this.refresh();

View File

@ -2,8 +2,6 @@ import { hash } from "rsvp";
import DiscourseRoute from "discourse/routes/discourse"; import DiscourseRoute from "discourse/routes/discourse";
export default class AutomationNew extends DiscourseRoute { export default class AutomationNew extends DiscourseRoute {
controllerName = "admin-plugins-discourse-automation-new";
model() { model() {
return hash({ return hash({
scripts: this.store.findAll("discourse-automation-automation"), scripts: this.store.findAll("discourse-automation-automation"),

View File

@ -0,0 +1,189 @@
<div class="admin-detail discourse-automation-edit discourse-automation-form">
<BackButton
@label="discourse_automation.back"
@route="adminPlugins.show.automation.index"
class="discourse-automation-back"
/>
<AdminConfigAreaCard @heading="discourse_automation.select_script">
<:content>
<form class="form-horizontal">
<FormError @error={{this.error}} />
<section class="form-section edit">
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.automation.name.label"}}
</label>
<div class="controls">
<TextField
@value={{this.automationForm.name}}
@type="text"
@autofocus={{true}}
@name="automation-name"
class="input-large"
@input={{with-event-value (fn (mut this.automationForm.name))}}
/>
</div>
</div>
<div class="control-group">
<label class="control-label">
{{i18n "discourse_automation.models.script.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{this.automationForm.script}}
@content={{this.model.scriptables}}
@onChange={{this.onChangeScript}}
@options={{hash filterable=true}}
class="scriptables"
/>
</div>
</div>
</section>
<section class="trigger-section form-section edit">
<h2 class="title">
{{i18n
"discourse_automation.edit_automation.trigger_section.title"
}}
</h2>
<div class="control-group">
{{#if this.model.automation.script.forced_triggerable}}
<div class="alert alert-warning">
{{i18n
"discourse_automation.edit_automation.trigger_section.forced"
}}
</div>
{{/if}}
<label class="control-label">
{{i18n "discourse_automation.models.trigger.name.label"}}
</label>
<div class="controls">
<ComboBox
@value={{this.automationForm.trigger}}
@content={{this.model.triggerables}}
@onChange={{this.onChangeTrigger}}
@options={{hash
filterable=true
none="discourse_automation.select_trigger"
disabled=this.model.automation.script.forced_triggerable
}}
class="triggerables"
/>
</div>
</div>
{{#if this.automationForm.trigger}}
{{#if this.model.automation.trigger.doc}}
<div class="alert alert-info">
<p>{{this.model.automation.trigger.doc}}</p>
</div>
{{/if}}
{{#if
(and
this.model.automation.enabled
this.model.automation.trigger.settings.manual_trigger
)
}}
<div class="alert alert-info next-trigger">
{{#if this.nextPendingAutomationAtFormatted}}
<p>
{{i18n
"discourse_automation.edit_automation.trigger_section.next_pending_automation"
date=this.nextPendingAutomationAtFormatted
}}
</p>
{{/if}}
<DButton
@label="discourse_automation.edit_automation.trigger_section.trigger_now"
@isLoading={{this.isTriggeringAutomation}}
@action={{fn
this.onManualAutomationTrigger
this.model.automation.id
}}
class="btn-primary trigger-now-btn"
/>
</div>
{{/if}}
{{#each this.triggerFields as |field|}}
<AutomationField
@automation={{this.automation}}
@field={{field}}
@saveAutomation={{fn this.saveAutomation this.automation}}
/>
{{/each}}
{{/if}}
</section>
{{#if this.automationForm.trigger}}
{{#if this.scriptFields}}
<section class="fields-section form-section edit">
<h2 class="title">
{{i18n
"discourse_automation.edit_automation.fields_section.title"
}}
</h2>
{{#if this.model.automation.script.with_trigger_doc}}
<div class="alert alert-info">
<p>{{this.model.automation.script.with_trigger_doc}}</p>
</div>
{{/if}}
<div class="control-group">
{{#each this.scriptFields as |field|}}
<AutomationField
@automation={{this.automation}}
@field={{field}}
@saveAutomation={{fn this.saveAutomation this.automation}}
/>
{{/each}}
</div>
</section>
{{/if}}
{{#if this.automationForm.trigger}}
<div
class="control-group automation-enabled alert
{{if this.automationForm.enabled 'alert-info' 'alert-warning'}}"
>
<span>{{i18n
"discourse_automation.models.automation.enabled.label"
}}</span>
<Input
@type="checkbox"
@checked={{this.automationForm.enabled}}
{{on
"click"
(action
(mut this.automationForm.enabled) value="target.checked"
)
}}
/>
</div>
{{/if}}
<div class="control-group">
<DButton
@isLoading={{this.isUpdatingAutomation}}
@label="discourse_automation.update"
@type="submit"
@action={{fn this.saveAutomation this.automation true}}
class="btn-primary update-automation"
/>
</div>
{{/if}}
</form>
</:content>
</AdminConfigAreaCard>
</div>

View File

@ -0,0 +1,131 @@
<section class="discourse-automations-table">
<DPageSubheader @titleLabel={{i18n "discourse_automation.table_title"}}>
<:actions as |actions|>
<actions.Primary
@label="discourse_automation.create"
@route="adminPlugins.show.automation.new"
@icon="plus"
class="discourse-automation__create-btn"
/>
</:actions>
</DPageSubheader>
{{#if this.model.length}}
<table class="d-admin-table automations">
<thead>
<tr>
<th></th>
<th>{{i18n "discourse_automation.models.automation.name.label"}}</th>
<th>{{i18n
"discourse_automation.models.automation.trigger.label"
}}</th>
<th>{{i18n
"discourse_automation.models.automation.script.label"
}}</th>
<th>{{i18n
"discourse_automation.models.automation.last_updated_by.label"
}}</th>
<th></th>
</tr>
</thead>
<tbody>
{{#each this.model as |automation|}}
<tr class="d-admin-row__content">
{{#if automation.script.not_found}}
<td colspan="5" class="d-admin-row__detail alert alert-danger">
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.status.label"}}
</div>
{{i18n
"discourse_automation.scriptables.not_found"
script=automation.script.id
automation=automation.name
}}
</td>
{{else if automation.trigger.not_found}}
<td colspan="5" class="d-admin-row__detail alert alert-danger">
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.status.label"}}
</div>
{{i18n
"discourse_automation.triggerables.not_found"
trigger=automation.trigger.id
automation=automation.name
}}
</td>
{{else}}
<td class="d-admin-row__detail automations__status">
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.status.label"}}
</div>
{{format-enabled-automation
automation.enabled
automation.trigger
}}
</td>
<td class="d-admin-row__overview automations__name">
{{if
automation.name
automation.name
(i18n "discourse_automation.unnamed_automation")
}}
</td>
<td class="d-admin-row__detail automations__script">
<div class="d-admin-row__mobile-label">
{{i18n
"discourse_automation.models.automation.trigger.label"
}}
</div>
{{if automation.trigger.id automation.trigger.name "-"}}
</td>
<td class="d-admin-row__detail automations__version">
<div class="d-admin-row__mobile-label">
{{i18n "discourse_automation.models.automation.script.label"}}
</div>
{{automation.script.name}}
(v{{automation.script.version}})
</td>
<td class="d-admin-row__detail automations__updated-by">
<div class="d-admin-row__mobile-label">
{{i18n
"discourse_automation.models.automation.last_updated_by.label"
}}
</div>
<div class="automations__user-timestamp">
<a
href={{automation.last_updated_by.userPath}}
data-user-card={{automation.last_updated_by.username}}
>
{{avatar automation.last_updated_by imageSize="small"}}
</a>
{{format-date automation.updated_at leaveAgo="true"}}
</div>
</td>
{{/if}}
<td class="d-admin-row__controls automations__controls">
<DButton
@label="discourse_automation.edit"
class="btn-small"
@action={{action "editAutomation" automation}}
/>
<DButton
@icon="trash-can"
@action={{action "destroyAutomation" automation}}
class="btn-small btn-danger"
/>
</td>
</tr>
{{/each}}
</tbody>
</table>
{{else}}
<AdminConfigAreaEmptyList
@ctaLabel="discourse_automation.create"
@ctaRoute="adminPlugins.show.automation.new"
@ctaClass="discourse-automation__create-btn"
@emptyLabel="discourse_automation.no_automation_yet"
/>
{{/if}}
</section>

View File

@ -0,0 +1,27 @@
<div class="admin-detail discourse-automation-new discourse-automation-form">
<BackButton
@label="discourse_automation.back"
@route="adminPlugins.show.automation.index"
class="discourse-automation-back"
/>
<AdminConfigAreaCard @heading="discourse_automation.select_script">
<:content>
<input
type="text"
placeholder={{i18n "discourse_automation.filter_placeholder"}}
{{on "input" this.updateFilterText}}
class="admin-section-landing__header-filter"
/>
<div class="admin-section-landing__wrapper">
{{#each this.scriptableContent as |script|}}
<AdminSectionLandingItem
{{on "click" (fn this.selectScriptToEdit script)}}
@titleLabelTranslated={{script.name}}
@descriptionLabelTranslated={{script.description}}
/>
{{/each}}
</div>
</:content>
</AdminConfigAreaCard>
</div>

View File

@ -1,11 +1,11 @@
export default { export default {
resource: "admin.adminPlugins", resource: "admin.adminPlugins.show",
path: "/plugins", path: "/plugins",
map() { map() {
this.route( this.route(
"discourse-automation", "automation",
function () { function () {
this.route("new"); this.route("new");

View File

@ -0,0 +1,21 @@
import { withPluginApi } from "discourse/lib/plugin-api";
export default {
name: "automation-admin-plugin-configuration-nav",
initialize(container) {
const currentUser = container.lookup("service:current-user");
if (!currentUser?.admin) {
return;
}
withPluginApi("1.1.0", (api) => {
api.addAdminPluginConfigurationNav("automation", [
{
label: "discourse_automation.title",
route: "adminPlugins.show.automation",
},
]);
});
},
};

View File

@ -1,4 +1,4 @@
.discourse-automation { .admin-plugins.automation {
.automations { .automations {
.relative-date { .relative-date {
font-size: $font-down-1; font-size: $font-down-1;
@ -13,6 +13,10 @@
} }
} }
.discourse-automations-table {
margin-top: 1em;
}
.d-admin-table.automations { .d-admin-table.automations {
.d-admin-row__content { .d-admin-row__content {
@include breakpoint("tablet") { @include breakpoint("tablet") {
@ -51,6 +55,18 @@
order: 5; order: 5;
} }
} }
.d-admin-row__controls.automations__controls {
text-align: right;
display: flex;
flex-direction: row;
gap: 0.5em;
justify-content: flex-end;
@include breakpoint("tablet") {
order: 6;
}
}
} }
.admin-section-landing__header { .admin-section-landing__header {

View File

@ -7,13 +7,16 @@ en:
delete_automation: delete automation delete_automation: delete automation
discourse_automation: discourse_automation:
title: Automation title: Automation
create: Create table_title: Automations
update: Update create: Add automation
update: Update automation
back: Back
edit: Edit
select_script: Select a script select_script: Select a script
select_trigger: Select a trigger select_trigger: Select a trigger
confirm_automation_reset: This action will reset script and trigger options, new state will be saved, do you want to proceed? confirm_automation_reset: This action will reset script and trigger options, new state will be saved, do you want to proceed?
confirm_automation_trigger: This action will trigger the automation, do you want to proceed? confirm_automation_trigger: This action will trigger the automation, do you want to proceed?
no_automation_yet: You haven’t created any automations yet. Choose an option below to get started. no_automation_yet: There are currently no automations configured.
filter_placeholder: Filter by name or description... filter_placeholder: Filter by name or description...
edit_automation: edit_automation:
trigger_section: trigger_section:

View File

@ -10,13 +10,13 @@ DiscourseAutomation::Engine.routes.draw do
put "/append-last-checked-by/:post_id" => "append_last_checked_by#post_checked" put "/append-last-checked-by/:post_id" => "append_last_checked_by#post_checked"
end end
scope "/admin/plugins/discourse-automation", scope "/admin/plugins/automation",
as: "admin_discourse_automation", as: "admin_discourse_automation",
constraints: AdminConstraint.new do constraints: AdminConstraint.new do
scope format: false do scope format: false do
get "/" => "admin#index" get "/automation" => "admin#index"
get "/new" => "admin#new" get "/automation/new" => "admin#new"
get "/:id" => "admin#edit" get "/automation/:id" => "admin#edit"
end end
scope format: :json do scope format: :json do

View File

@ -87,7 +87,7 @@ after_initialize do
Plugin::Instance.prepend DiscourseAutomation::PluginInstanceExtension Plugin::Instance.prepend DiscourseAutomation::PluginInstanceExtension
end end
add_admin_route "discourse_automation.title", "discourse-automation" add_admin_route "discourse_automation.title", "automation", use_new_show_route: true
add_api_key_scope( add_api_key_scope(
:automations_trigger, :automations_trigger,

View File

@ -32,7 +32,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:admin)) } before { sign_in(Fabricate(:admin)) }
it "shows the automation" do it "shows the automation" do
get "/admin/plugins/discourse-automation/automations/#{automation.id}.json" get "/admin/plugins/automation/automations/#{automation.id}.json"
expect(response.status).to eq(200) expect(response.status).to eq(200)
expect(response.parsed_body["automation"]["id"]).to eq(automation.id) expect(response.parsed_body["automation"]["id"]).to eq(automation.id)
end end
@ -42,7 +42,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:user)) } before { sign_in(Fabricate(:user)) }
it "raises a 404" do it "raises a 404" do
get "/admin/plugins/discourse-automation/automations/#{automation.id}.json" get "/admin/plugins/automation/automations/#{automation.id}.json"
expect(response.status).to eq(404) expect(response.status).to eq(404)
end end
end end
@ -63,7 +63,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:admin)) } before { sign_in(Fabricate(:admin)) }
it "creates the 'forced triggerable' automation" do it "creates the 'forced triggerable' automation" do
post "/admin/plugins/discourse-automation/automations.json", post "/admin/plugins/automation/automations.json",
params: { params: {
automation: { automation: {
name: "foobar", name: "foobar",
@ -78,7 +78,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:user)) } before { sign_in(Fabricate(:user)) }
it "raises a 404" do it "raises a 404" do
post "/admin/plugins/discourse-automation/automations.json", post "/admin/plugins/automation/automations.json",
params: { params: {
automation: { automation: {
name: "foobar", name: "foobar",
@ -95,7 +95,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:admin)) } before { sign_in(Fabricate(:admin)) }
it "updates the automation" do it "updates the automation" do
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
trigger: "another-trigger", trigger: "another-trigger",
@ -106,7 +106,7 @@ describe DiscourseAutomation::AdminAutomationsController do
describe "invalid field’s component" do describe "invalid field’s component" do
it "errors" do it "errors" do
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
script: automation.script, script: automation.script,
@ -129,7 +129,7 @@ describe DiscourseAutomation::AdminAutomationsController do
end end
it "errors" do it "errors" do
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
script: automation.script, script: automation.script,
@ -147,7 +147,7 @@ describe DiscourseAutomation::AdminAutomationsController do
it "forces the automation to be disabled" do it "forces the automation to be disabled" do
expect(automation.enabled).to eq(true) expect(automation.enabled).to eq(true)
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
script: "bar", script: "bar",
@ -164,7 +164,7 @@ describe DiscourseAutomation::AdminAutomationsController do
it "forces the automation to be disabled" do it "forces the automation to be disabled" do
expect(automation.enabled).to eq(true) expect(automation.enabled).to eq(true)
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
script: automation.script, script: automation.script,
@ -181,7 +181,7 @@ describe DiscourseAutomation::AdminAutomationsController do
it "disables the automation" do it "disables the automation" do
expect(automation.enabled).to eq(true) expect(automation.enabled).to eq(true)
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
trigger: automation.trigger, trigger: automation.trigger,
@ -196,7 +196,7 @@ describe DiscourseAutomation::AdminAutomationsController do
context "with invalid field’s metadata" do context "with invalid field’s metadata" do
it "errors" do it "errors" do
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
script: automation.script, script: automation.script,
@ -214,7 +214,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:user)) } before { sign_in(Fabricate(:user)) }
it "raises a 404" do it "raises a 404" do
put "/admin/plugins/discourse-automation/automations/#{automation.id}.json", put "/admin/plugins/automation/automations/#{automation.id}.json",
params: { params: {
automation: { automation: {
trigger: "another-trigger", trigger: "another-trigger",
@ -232,13 +232,13 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:admin)) } before { sign_in(Fabricate(:admin)) }
it "destroys the automation" do it "destroys the automation" do
delete "/admin/plugins/discourse-automation/automations/#{automation.id}.json" delete "/admin/plugins/automation/automations/#{automation.id}.json"
expect(DiscourseAutomation::Automation.find_by(id: automation.id)).to eq(nil) expect(DiscourseAutomation::Automation.find_by(id: automation.id)).to eq(nil)
end end
context "when the automation is not found" do context "when the automation is not found" do
it "raises a 404" do it "raises a 404" do
delete "/admin/plugins/discourse-automation/automations/999.json" delete "/admin/plugins/automation/automations/999.json"
expect(response.status).to eq(404) expect(response.status).to eq(404)
end end
end end
@ -248,7 +248,7 @@ describe DiscourseAutomation::AdminAutomationsController do
before { sign_in(Fabricate(:user)) } before { sign_in(Fabricate(:user)) }
it "raises a 404" do it "raises a 404" do
delete "/admin/plugins/discourse-automation/automations/#{automation.id}.json" delete "/admin/plugins/automation/automations/#{automation.id}.json"
expect(response.status).to eq(404) expect(response.status).to eq(404)
end end
end end

View File

@ -4,7 +4,7 @@ module PageObjects
module Pages module Pages
class Automation < PageObjects::Pages::Base class Automation < PageObjects::Pages::Base
def visit(automation) def visit(automation)
super("/admin/plugins/discourse-automation/#{automation.id}") super("/admin/plugins/automation/automation/#{automation.id}")
self self
end end
@ -34,7 +34,7 @@ module PageObjects
end end
def form def form
@form ||= find(".discourse-automation-form.edit") @form ||= find(".discourse-automation-edit")
end end
end end
end end

View File

@ -4,7 +4,7 @@ module PageObjects
module Pages module Pages
class NewAutomation < PageObjects::Pages::Base class NewAutomation < PageObjects::Pages::Base
def visit def visit
super("/admin/plugins/discourse-automation/new") super("/admin/plugins/automation/automation/new")
self self
end end

View File

@ -21,7 +21,10 @@ describe "DiscourseAutomation | smoke test", type: :system do
after { DiscourseAutomation::Scriptable.remove("test") } after { DiscourseAutomation::Scriptable.remove("test") }
it "populate correctly" do it "populate correctly" do
visit("/admin/plugins/discourse-automation") visit("/admin/plugins/automation")
find(".admin-config-area-empty-list__cta-button").click
find(".admin-section-landing__header-filter").set("test") find(".admin-section-landing__header-filter").set("test")
find(".admin-section-landing-item__content", match: :first).click find(".admin-section-landing-item__content", match: :first).click
fill_in("automation-name", with: "aaaaa") fill_in("automation-name", with: "aaaaa")
@ -34,7 +37,9 @@ describe "DiscourseAutomation | smoke test", type: :system do
end end
it "works" do it "works" do
visit("/admin/plugins/discourse-automation") visit("/admin/plugins/automation")
find(".admin-config-area-empty-list__cta-button").click
find(".admin-section-landing__header-filter").set("user group membership through badge") find(".admin-section-landing__header-filter").set("user group membership through badge")
find(".admin-section-landing-item__content", match: :first).click find(".admin-section-landing-item__content", match: :first).click
@ -51,6 +56,6 @@ describe "DiscourseAutomation | smoke test", type: :system do
find(".automation-enabled input").click find(".automation-enabled input").click
find(".update-automation").click find(".update-automation").click
expect(page).to have_css('[role="button"]', text: "aaaaa") expect(page).to have_css(".automations__name", text: "aaaaa")
end end
end end