refactor: crossposts.get to return limited category data (name, icon, etc.), fixed up crosspost modal to hide uncategorized and all categories options

This commit is contained in:
Julian Lam
2025-12-15 10:38:51 -05:00
parent 3301fcf45d
commit eba7d0efbe
8 changed files with 45 additions and 3 deletions

View File

@@ -150,6 +150,7 @@
"load-categories": "Loading Categories",
"confirm-move": "Move",
"confirm-crosspost": "Cross-post",
"confirm-fork": "Fork",
"bookmark": "Bookmark",
@@ -162,6 +163,7 @@
"loading-more-posts": "Loading More Posts",
"move-topic": "Move Topic",
"move-topics": "Move Topics",
"crosspost-topic": "Cross-post Topic",
"move-post": "Move Post",
"post-moved": "Post moved!",
"fork-topic": "Fork Topic",
@@ -182,6 +184,7 @@
"topic-id": "Topic ID",
"move-posts-instruction": "Click the posts you want to move then enter a topic ID or go to the target topic",
"move-topic-instruction": "Select the target category and then click move",
"crosspost-topic-instruction": "Select one or more categories to cross-post to. Topic(s) will be accessible from the original category and all cross-posted categories.",
"change-owner-instruction": "Click the posts you want to assign to another user",
"manage-editors-instruction": "Manage the users who can edit this post below.",

View File

@@ -117,7 +117,9 @@ define('forum/topic/threadTools', [
});
topicContainer.on('click', '[component="topic/crosspost"]', () => {
console.log('tbd');
require(['forum/topic/crosspost'], (crosspost) => {
crosspost.init(tid, ajaxify.data.cid);
});
});
topicContainer.on('click', '[component="topic/delete/posts"]', function () {

View File

@@ -77,6 +77,7 @@ define('categorySearch', ['alerts', 'bootstrap', 'api'], function (alerts, boots
states: options.states,
showLinks: options.showLinks,
localOnly: options.localOnly,
hideUncategorized: options.hideUncategorized,
}, function (err, { categories }) {
if (err) {
return alerts.error(err);
@@ -94,6 +95,7 @@ define('categorySearch', ['alerts', 'bootstrap', 'api'], function (alerts, boots
categoryItems: categories.slice(0, 200),
selectedCategory: ajaxify.data.selectedCategory,
allCategoriesUrl: ajaxify.data.allCategoriesUrl,
hideAll: options.hideAll,
}, function (html) {
el.find('[component="category/list"]')
.html(html.find('[component="category/list"]').html());

View File

@@ -9,6 +9,7 @@ const messaging = require('../messaging');
const privileges = require('../privileges');
const meta = require('../meta');
const plugins = require('../plugins');
const utils = require('../utils');
const controllersHelpers = require('../controllers/helpers');
@@ -29,9 +30,12 @@ searchApi.categories = async (caller, data) => {
({ cids, matchedCids } = await findMatchedCids(caller.uid, data));
} else {
cids = await loadCids(caller.uid, data.parentCid);
if (meta.config.activitypubEnabled) {
if (!data.hideUncategorized && meta.config.activitypubEnabled) {
cids.unshift(-1);
}
if (data.localOnly) {
cids = cids.filter(cid => utils.isNumber(cid));
}
}
const visibleCategories = await controllersHelpers.getVisibleCategories({

View File

@@ -123,8 +123,9 @@ topicsController.get = async function getTopic(req, res, next) {
p => parseInt(p.index, 10) === parseInt(Math.max(0, postIndex - 1), 10)
);
const [author] = await Promise.all([
const [author, crossposts] = await Promise.all([
user.getUserFields(topicData.uid, ['username', 'userslug']),
topics.crossposts.get(topicData.tid),
buildBreadcrumbs(topicData),
addOldCategory(topicData, userPrivileges),
addTags(topicData, req, res, currentPage, postAtIndex),
@@ -134,6 +135,7 @@ topicsController.get = async function getTopic(req, res, next) {
]);
topicData.author = author;
topicData.crossposts = crossposts;
topicData.pagination = pagination.create(currentPage, pageCount, req.query);
topicData.pagination.rel.forEach((rel) => {
rel.href = `${url}/topic/${topicData.slug}${rel.href}`;

View File

@@ -12,8 +12,20 @@ const Crossposts = module.exports;
Crossposts.get = async function (tid) {
const crosspostIds = await db.getSortedSetMembers(`tid:${tid}:crossposts`);
let crossposts = await db.getObjects(crosspostIds.map(id => `crosspost:${id}`));
const cids = crossposts.reduce((cids, crossposts) => {
cids.add(crossposts.cid);
return cids;
}, new Set());
let categoriesData = await categories.getCategoriesFields(
cids, ['cid', 'name', 'icon', 'bgColor', 'color', 'slug']
);
categoriesData = categoriesData.reduce((map, category) => {
map.set(parseInt(category.cid, 10), category);
return map;
}, new Map());
crossposts = crossposts.map((crosspost, idx) => {
crosspost.id = crosspostIds[idx];
crosspost.category = categoriesData.get(parseInt(crosspost.cid, 10));
return crosspost;
});

View File

@@ -0,0 +1,15 @@
<div class="card tool-modal shadow">
<h5 class="card-header">
[[topic:crosspost-topic]]
</h5>
<div class="card-body">
<p>
[[topic:crosspost-topic-instruction]]
</p>
<!-- IMPORT partials/category/filter-dropdown-right.tpl -->
</div>
<div class="card-footer text-end">
<button type="button" class="btn btn-sm btn-outline-secondary" id="crosspost_topic_cancel">[[global:buttons.close]]</button>
<button type="button" class="btn btn-sm btn-primary" id="crosspost_thread_commit" disabled>[[topic:confirm-crosspost]]</button>
</div>
</div>

View File

@@ -16,12 +16,14 @@
</div>
<ul component="category/list" class="list-unstyled mb-0 text-sm category-dropdown-menu ghost-scrollbar" role="menu">
{{{ if !hideAll }}}
<li role="presentation" class="category" data-cid="all">
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2" role="menuitem" href="{{{ if allCategoriesUrl }}}{config.relative_path}/{allCategoriesUrl}{{{ else }}}#{{{ end }}}">
<div class="flex-grow-1">[[unread:all-categories]]</div>
<i component="category/select/icon" class="flex-shrink-0 fa fa-fw fa-check {{{if selectedCategory}}}invisible{{{end}}}"></i>
</a>
</li>
{{{ end }}}
{{{each categoryItems}}}
<li role="presentation" class="category {{{ if ./disabledClass }}}disabled{{{ end }}}" data-cid="{./cid}" data-parent-cid="{./parentCid}" data-name="{./name}">
<a class="dropdown-item rounded-1 d-flex align-items-center gap-2 {{{ if ./disabledClass }}}disabled{{{ end }}}" role="menuitem" href="#">