FEAT: add cc addresses and post_id to sent email logs (#25014)

* add cc addresses and post_id to sent email logs
* sort cc addresses by email address filter value and collapse additional addreses into tooltip
* add slice helper for use in ember tempaltes
This commit is contained in:
Kelv
2024-01-03 09:27:25 +08:00
committed by GitHub
parent 7b12be866d
commit b4a89ea610
8 changed files with 254 additions and 20 deletions

View File

@@ -4,6 +4,28 @@ import discourseDebounce from "discourse-common/lib/debounce";
import AdminEmailLogsController from "admin/controllers/admin-email-logs";
export default class AdminEmailSentController extends AdminEmailLogsController {
ccAddressDisplayThreshold = 2;
sortWithAddressFilter = (addresses) => {
if (!Array.isArray(addresses) || addresses.length === 0) {
return [];
}
const targetEmail = this.filter.address;
if (!targetEmail) {
return addresses;
}
return addresses.sort((a, b) => {
if (a.includes(targetEmail) && !b.includes(targetEmail)) {
return -1;
}
if (!a.includes(targetEmail) && b.includes(targetEmail)) {
return 1;
}
return 0;
});
};
@observes("filter.{status,user,address,type,reply_key}")
filterEmailLogs() {
discourseDebounce(this, this.loadLogs, INPUT_DELAY);

View File

@@ -54,7 +54,53 @@
"redo"
title="admin.email.bounced"
}}{{/if}}
<a href="mailto:{{l.to_address}}">{{l.to_address}}</a>
<p><a
href="mailto:{{l.to_address}}"
title="TO"
>{{l.to_address}}</a></p>
{{#if l.cc_addresses}}
{{#if (gt l.cc_addresses.length this.ccAddressDisplayThreshold)}}
{{#each
(slice
0
this.ccAddressDisplayThreshold
(fn this.sortWithAddressFilter l.cc_addresses)
)
as |cc|
}}
<p><a href="mailto:{{cc}}" title="CC">{{cc}}</a></p>
{{/each}}
<DTooltip
@placement="right-start"
@arrow={{true}}
@identifier="email-log-cc-addresses"
@interactive={{true}}
>
<:trigger>
{{i18n "admin.email.logs.email_addresses.see_more"}}
</:trigger>
<:content>
<ul>
{{#each
(slice this.ccAddressDisplayThreshold l.cc_addresses)
as |cc|
}}
<li>
<span>
<a href="mailto:{{cc}}" title="CC">{{cc}}</a>
</span>
</li>
{{/each}}
</ul>
</:content>
</DTooltip>
{{else}}
{{#each l.cc_addresses as |cc|}}
<p><a href="mailto:{{cc}}" title="CC">{{cc}}</a></p>
{{/each}}
{{/if}}
{{/if}}
</td>
<td class="sent-email-type">{{l.email_type}}</td>
<td class="sent-email-reply-key">
@@ -62,8 +108,12 @@
</td>
<td class="sent-email-post-link-with-smtp-response">
{{#if l.post_url}}
<a href={{l.post_url}}>{{l.post_description}}</a><br />
{{/if}}
<a href={{l.post_url}}>
{{l.post_description}}
</a>
{{i18n "admin.email.logs.post_id" post_id=l.post_id}}
<br />
/{{/if}}
<code
title={{l.smtp_transaction_response}}
>{{l.smtp_transaction_response}}</code>

View File

@@ -0,0 +1,10 @@
export default function slice(...args) {
let array = args.pop();
if (array instanceof Function) {
array = array.call();
}
if (!Array.isArray(array) || array.length === 0) {
return [];
}
return array.slice(...args);
}

View File

@@ -0,0 +1,70 @@
import { run } from "@ember/runloop";
import { render } from "@ember/test-helpers";
import { hbs } from "ember-cli-htmlbars";
import { setupRenderingTest } from "ember-qunit";
import { module, test } from "qunit";
module("Integration | Helper | {{slice}}", function (hooks) {
setupRenderingTest(hooks);
test("it slices an array with positional params", async function (assert) {
this.set("array", [2, 4, 6]);
await render(hbs`
{{slice 1 3 this.array}}
`);
assert.dom().hasText("4,6", "sliced values");
});
test("it slices when only 2 params are passed", async function (assert) {
this.set("array", [2, 4, 6]);
await render(hbs`
{{slice 1 this.array}}
`);
assert.dom().hasText("4,6", "sliced values");
});
test("it recomputes the slice if an item in the array changes", async function (assert) {
let array = [2, 4, 6];
this.set("array", array);
await render(hbs`
{{slice 1 3 this.array}}
`);
assert.dom().hasText("4,6", "sliced values");
run(() => array.replace(2, 1, [5]));
assert.dom().hasText("4,5", "sliced values");
});
test("it allows null array", async function (assert) {
this.set("array", null);
await render(hbs`
this is all that will render
{{#each (slice 1 2 this.array) as |value|}}
{{value}}
{{/each}}
`);
assert.dom().hasText("this is all that will render", "no error is thrown");
});
test("it allows undefined array", async function (assert) {
this.set("array", undefined);
await render(hbs`
this is all that will render
{{#each (slice 1 2 this.array) as |value|}}
{{value}}
{{/each}}
`);
assert.dom().hasText("this is all that will render", "no error is thrown");
});
});