Skip to content

Commit 9588af0

Browse files
authored
Merge pull request #6679 from WoltLab/63-moderation-mark-as-read
Unify 'mark as read' function for moderation queue
2 parents 2692da0 + e262654 commit 9588af0

12 files changed

Lines changed: 210 additions & 79 deletions

File tree

com.woltlab.wcf/templates/moderationList.tpl

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,21 @@
66
{/capture}
77

88
{capture assign='contentInteractionButtons'}
9-
<button type="button" class="markAllAsReadButton contentInteractionButton button small jsOnly">{icon name='check'} <span>{lang}wcf.global.button.markAllAsRead{/lang}</span></button>
9+
{if $gridView->canMarkAsRead()}
10+
<button type="button" class="markAllModerationQueuesAsReadButton contentInteractionButton button small jsOnly">
11+
{icon name='check'}
12+
<span>{lang}wcf.global.button.markAllAsRead{/lang}</span>
13+
</button>
14+
15+
<script data-relocate="true">
16+
require(['WoltLabSuite/Core/Component/Moderation/MarkAllModerationQueuesAsRead'], ({ setup }) => {
17+
setup(
18+
document.querySelector('.markAllModerationQueuesAsReadButton'),
19+
document.getElementById('{unsafe:$gridView->getID()|encodeJS}_table')
20+
);
21+
});
22+
</script>
23+
{/if}
1024
<a href="{link controller='DeletedContentList'}{/link}" class="contentInteractionButton button small">{icon name='trash-can'} <span>{lang}wcf.moderation.showDeletedContent{/lang}</span></a>
1125
{/capture}
1226

@@ -16,10 +30,4 @@
1630
{unsafe:$gridView->render()}
1731
</div>
1832

19-
<script data-relocate="true">
20-
require(['WoltLabSuite/Core/Ui/Moderation/MarkAllAsRead'], (MarkAllAsRead) => {
21-
MarkAllAsRead.setup();
22-
});
23-
</script>
24-
2533
{include file='footer'}

ts/WoltLabSuite/Core/Component/GridView.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import { getRow } from "../Api/GridViews/GetRow";
1111
import { getRows } from "../Api/GridViews/GetRows";
1212
import { getBulkContextMenuOptions } from "../Api/Interactions/GetBulkContextMenuOptions";
13+
import { postObject } from "../Api/PostObject";
1314
import DomChangeListener from "../Dom/Change/Listener";
1415
import DomUtil from "../Dom/Util";
1516
import { promiseMutex } from "../Helper/PromiseMutex";
@@ -104,6 +105,16 @@ export class GridView {
104105
});
105106
}
106107
});
108+
109+
wheneverFirstSeen(`#${this.#table.id} tbody tr .gridView__row__markAsRead`, (button: HTMLButtonElement) => {
110+
button.addEventListener(
111+
"click",
112+
promiseMutex(async () => {
113+
await postObject(button.dataset.endpoint!);
114+
button.closest("tr")?.dispatchEvent(new CustomEvent("interaction:invalidate", { bubbles: true }));
115+
}),
116+
);
117+
});
107118
}
108119

109120
#initEventListeners(): void {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/**
2+
* Handles the 'mark as read' action for moderation queues.
3+
*
4+
* @author Marcel Werk
5+
* @copyright 2001-2026 WoltLab GmbH
6+
* @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7+
* @since 6.3
8+
* @woltlabExcludeBundle tiny
9+
*/
10+
11+
import { showDefaultSuccessSnackbar } from "WoltLabSuite/Core/Component/Snackbar";
12+
import { markAllModerationQueuesAsRead } from "WoltLabSuite/Core/Api/ModerationQueues/MarkAllModerationQueuesAsRead";
13+
import { promiseMutex } from "WoltLabSuite/Core/Helper/PromiseMutex";
14+
15+
async function markAllAsRead(button: HTMLElement, gridView?: HTMLElement): Promise<void> {
16+
(await markAllModerationQueuesAsRead()).unwrap();
17+
18+
if (gridView !== undefined) {
19+
gridView.dispatchEvent(new CustomEvent("interaction:invalidate-all"));
20+
}
21+
22+
button.remove();
23+
24+
showDefaultSuccessSnackbar();
25+
}
26+
27+
export function setup(button: HTMLElement, gridView?: HTMLElement): void {
28+
button.addEventListener(
29+
"click",
30+
promiseMutex(async () => {
31+
await markAllAsRead(button, gridView);
32+
}),
33+
);
34+
}

ts/WoltLabSuite/Core/Ui/Moderation/MarkAllAsRead.ts

Lines changed: 0 additions & 26 deletions
This file was deleted.

wcfsetup/install/files/js/WoltLabSuite/Core/Component/GridView.js

Lines changed: 7 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Component/Moderation/MarkAllModerationQueuesAsRead.js

Lines changed: 27 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

wcfsetup/install/files/js/WoltLabSuite/Core/Ui/Moderation/MarkAllAsRead.js

Lines changed: 0 additions & 24 deletions
This file was deleted.

wcfsetup/install/files/lib/system/gridView/AbstractGridView.class.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace wcf\system\gridView;
44

5+
use wcf\action\ApiAction;
56
use wcf\action\GridViewFilterAction;
67
use wcf\data\DatabaseObject;
78
use wcf\data\DatabaseObjectList;
@@ -64,6 +65,7 @@ abstract class AbstractGridView
6465
private ?IInteractionProvider $interactionProvider = null;
6566
private ?IBulkInteractionProvider $bulkInteractionProvider = null;
6667
private InteractionContextMenuComponent $interactionContextMenuComponent;
68+
private string $markAsReadEndpoint = '';
6769

6870
/**
6971
* @var array<string, string|int>
@@ -313,6 +315,10 @@ public function renderColumn(GridViewColumn $column, DatabaseObject $row): strin
313315
$value = $this->rowLink->render($value, $row, $column->isTitleColumn());
314316
}
315317

318+
if ($column->hasMarkAsReadButton() && $this->rowIsNew($row)) {
319+
$value = $this->renderMarkAsReadButton($row) . $value;
320+
}
321+
316322
return $value;
317323
}
318324

@@ -952,6 +958,49 @@ public function getAvailableFilters(): array
952958
return $this->availableFilters;
953959
}
954960

961+
/**
962+
* @since 6.3
963+
*/
964+
public function setMarkAsReadEndpoint(string $endpoint): void
965+
{
966+
$this->markAsReadEndpoint = $endpoint;
967+
}
968+
969+
/**
970+
* @since 6.3
971+
*/
972+
public function renderMarkAsReadButton(DatabaseObject $object): string
973+
{
974+
if (!$this->markAsReadEndpoint) {
975+
throw new \BadMethodCallException("No mark as read endpoint has been specified.");
976+
}
977+
978+
$endpoint = StringUtil::encodeHTML(
979+
LinkHandler::getInstance()->getControllerLink(ApiAction::class, ['id' => 'rpc']) .
980+
\sprintf($this->markAsReadEndpoint, $object->getObjectID())
981+
);
982+
$title = WCF::getLanguage()->get('wcf.global.button.markAsRead');
983+
984+
return <<<HTML
985+
<button
986+
type="button"
987+
class="gridView__row__markAsRead jsTooltip"
988+
title="{$title}"
989+
data-endpoint="{$endpoint}"
990+
>
991+
<span class="gridView__row__unread__indicator" aria-hidden="true"></span>
992+
</button>
993+
HTML;
994+
}
995+
996+
/**
997+
* @since 6.3
998+
*/
999+
public function rowIsNew(DatabaseObject $row): bool
1000+
{
1001+
return false;
1002+
}
1003+
9551004
private function init(): void
9561005
{
9571006
if (!isset($this->objectList)) {

wcfsetup/install/files/lib/system/gridView/GridViewColumn.class.php

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ final class GridViewColumn
3535
private bool $hidden = false;
3636
private bool $unsafeDisableEncoding = false;
3737
private bool $titleColumn = false;
38+
private bool $markAsReadButton = false;
3839

3940
private function __construct(private readonly string $id) {}
4041

@@ -302,6 +303,28 @@ public function applyRowLink(): bool
302303
)) === 0;
303304
}
304305

306+
/**
307+
* Sets whether the mark as read button is rendered in this column for unread rows.
308+
*
309+
* @since 6.3
310+
*/
311+
public function markAsReadButton(bool $markAsReadButton = true): static
312+
{
313+
$this->markAsReadButton = $markAsReadButton;
314+
315+
return $this;
316+
}
317+
318+
/**
319+
* Returns true if the mark as read button is rendered in this column for unread rows.
320+
*
321+
* @since 6.3
322+
*/
323+
public function hasMarkAsReadButton(): bool
324+
{
325+
return $this->markAsReadButton;
326+
}
327+
305328
/**
306329
* Returns the default renderer for the rendering of columns.
307330
*/

wcfsetup/install/files/lib/system/gridView/user/ModerationQueueGridView.class.php

Lines changed: 20 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -44,26 +44,15 @@ public function __construct()
4444
GridViewColumn::for('title')
4545
->label('wcf.global.title')
4646
->titleColumn()
47+
->markAsReadButton()
4748
->renderer(
4849
new class extends DefaultColumnRenderer {
4950
#[\Override]
5051
public function render(mixed $value, DatabaseObject $row): string
5152
{
5253
\assert($row instanceof ViewableModerationQueue);
53-
$title = StringUtil::encodeHTML($row->getTitle());
5454

55-
if ($row->isNew()) {
56-
$badgeLabel = WCF::getLanguage()->get('wcf.message.new');
57-
$badge = <<<HTML
58-
<span class="badge label newMessageBadge">{$badgeLabel}</span>
59-
HTML;
60-
} else {
61-
$badge = '';
62-
}
63-
64-
return <<<HTML
65-
{$title}{$badge}
66-
HTML;
55+
return StringUtil::encodeHTML($row->getTitle());
6756
}
6857
}
6958
),
@@ -216,6 +205,16 @@ public function render(mixed $value, DatabaseObject $row): string
216205
$this->setDefaultSortField("lastChangeTime");
217206
$this->setDefaultSortOrder("DESC");
218207
$this->addRowLink(new GridViewRowLink(isLinkableObject: true));
208+
$this->setMarkAsReadEndpoint('core/moderation-queues/%s/mark-as-read');
209+
}
210+
211+
public function canMarkAsRead(): bool
212+
{
213+
if (!WCF::getUser()->userID) {
214+
return false;
215+
}
216+
217+
return ModerationQueueManager::getInstance()->getUnreadModerationCount() > 0;
219218
}
220219

221220
private function getDefinitionFilter(): SelectFilter
@@ -275,4 +274,12 @@ protected function getInitializedEvent(): ModerationQueueGridViewInitialized
275274
{
276275
return new ModerationQueueGridViewInitialized($this);
277276
}
277+
278+
#[\Override]
279+
public function rowIsNew(DatabaseObject $row): bool
280+
{
281+
\assert($row instanceof ViewableModerationQueue);
282+
283+
return $row->isNew();
284+
}
278285
}

0 commit comments

Comments
 (0)