Moderation Checklist V1.5 (#3980)

* starting on new checklist implementation

Change default shouldShow behavior for stages.
add new messages and stages.
Change some existing stage logic.
Add placeholder var for the rules.

Co-Authored-By: @coolbot100s

* misc fixes + corrections

* Add clickable link previews to links stage

* Correct mislabeled title message and add new title messages

* Change message formatting, use rules variable, correct wip desc and title 1.8 messages, add tags buttons

* More applications of rules placeholder

* Add new status alerts stage

* change order of statusAlerts

* Update title related messages, add navigation based vars

* Overhaul Links stage and add new messages.

* Set message weights, add some disables

* message.mds now obey lint >:(

* fixed links text message formatting and changed an icon

* Combine title and slug stages

* Add more info to some stages and properly case stage ids

* tweak summary text formatting

* Improved tags stage info and more navigation placeholders

* redo reupload stage, more navigation placeholders, licensing stage improvements, versions stage improvements, status alerts stage improvements

* Allow modpack permissions stage to appear again by adding a dummy button.

* Update modpack permissions guidance

* fix: blog path issues

* fix: lint issues

* fix license stage text formatting

* Improve license stage

* feat: move links into one md file to be cleaner

* Update packages/moderation/data/stages/links.ts

Signed-off-by: IMB11 <hendersoncal117@gmail.com>

---------

Signed-off-by: IMB11 <hendersoncal117@gmail.com>
Co-authored-by: IMB11 <hendersoncal117@gmail.com>
Co-authored-by: IMB11 <calum@modrinth.com>
This commit is contained in:
coolbot
2025-07-16 10:48:26 -08:00
committed by GitHub
parent eb595cdc3e
commit 62f5a23fcb
93 changed files with 954 additions and 366 deletions

View File

@@ -1,16 +1,16 @@
import { promises as fs } from 'fs'
import * as path from 'path'
import fastGlob from 'fast-glob'
import { repoPath, toVarName } from './utils'
import { glob } from 'glob'
import { PUBLIC_SRC, PUBLIC_LOCATIONS, ARTICLES_GLOB, COMPILED_DIR } from './blog.config'
async function checkPublicAssets() {
const srcFiles = await fastGlob(['**/*'], { cwd: PUBLIC_SRC, dot: true })
const srcFiles = await glob('**/*', { cwd: PUBLIC_SRC, dot: true })
let allOk = true
for (const target of PUBLIC_LOCATIONS) {
for (const relativeFile of srcFiles) {
const shouldExist = path.join(target, relativeFile)
const shouldExist = path.posix.join(target, relativeFile)
try {
await fs.access(shouldExist)
} catch {
@@ -26,15 +26,15 @@ async function checkPublicAssets() {
}
async function checkCompiledArticles() {
const mdFiles = await fastGlob([ARTICLES_GLOB])
const compiledFiles = await fastGlob([`${COMPILED_DIR}/*.ts`])
const mdFiles = await glob(ARTICLES_GLOB)
const compiledFiles = await glob(`${COMPILED_DIR}/*.ts`)
const compiledVarNames = compiledFiles.map((f) => path.basename(f, '.ts'))
// Check all .md have compiled .ts and .content.ts and the proper public thumbnail
for (const file of mdFiles) {
const varName = toVarName(path.basename(file, '.md'))
const compiledPath = path.join(COMPILED_DIR, varName + '.ts')
const contentPath = path.join(COMPILED_DIR, varName + '.content.ts')
const compiledPath = path.posix.join(COMPILED_DIR, varName + '.ts')
const contentPath = path.posix.join(COMPILED_DIR, varName + '.content.ts')
if (!compiledVarNames.includes(varName)) {
console.error(`⚠️ Missing compiled article for: ${file} (should be: ${compiledPath})`)
process.exit(1)
@@ -59,7 +59,7 @@ async function checkCompiledArticles() {
if (varName === 'index' || varName.endsWith('.content')) continue
const mdPathGlob = repoPath(`packages/blog/articles/**/${varName.replace(/_/g, '*')}.md`)
const found = await fastGlob([mdPathGlob])
const found = await glob(mdPathGlob)
if (!found.length) {
console.error(`❌ Compiled article ${compiled} has no matching markdown source!`)
process.exit(1)

View File

@@ -1,12 +1,12 @@
import { promises as fs } from 'fs'
import * as path from 'path'
import fg from 'fast-glob'
import matter from 'gray-matter'
import { md } from '@modrinth/utils'
import { minify } from 'html-minifier-terser'
import { copyDir, toVarName } from './utils'
import RSS from 'rss'
import { parseStringPromise } from 'xml2js'
import { glob } from 'glob'
import {
ARTICLES_GLOB,
@@ -24,7 +24,7 @@ async function ensureCompiledDir() {
}
async function hasThumbnail(slug: string): Promise<boolean> {
const thumbnailPath = path.join(PUBLIC_SRC, slug, 'thumbnail.webp')
const thumbnailPath = path.posix.join(PUBLIC_SRC, slug, 'thumbnail.webp')
try {
await fs.access(thumbnailPath)
return true
@@ -48,7 +48,7 @@ function getThumbnailUrl(slug: string, hasThumb: boolean): string {
async function compileArticles() {
await ensureCompiledDir()
const files = await fg([ARTICLES_GLOB])
const files = await glob(ARTICLES_GLOB)
console.log(`🔎 Found ${files.length} markdown articles!`)
const articleExports: string[] = []
const articlesArray: string[] = []
@@ -75,8 +75,8 @@ async function compileArticles() {
const slug = frontSlug || path.basename(file, '.md')
const varName = toVarName(slug)
const exportFile = path.join(COMPILED_DIR, `${varName}.ts`)
const contentFile = path.join(COMPILED_DIR, `${varName}.content.ts`)
const exportFile = path.posix.join(COMPILED_DIR, `${varName}.ts`)
const contentFile = path.posix.join(COMPILED_DIR, `${varName}.content.ts`)
const thumbnailPresent = await hasThumbnail(slug)
const contentTs = `
@@ -221,7 +221,7 @@ async function deleteDirContents(dir: string) {
const entries = await fs.readdir(dir, { withFileTypes: true })
await Promise.all(
entries.map(async (entry) => {
const fullPath = path.join(dir, entry.name)
const fullPath = path.posix.join(dir, entry.name)
if (entry.isDirectory()) {
await fs.rm(fullPath, { recursive: true, force: true })
} else {

View File

@@ -1,56 +1,56 @@
// AUTO-GENERATED FILE - DO NOT EDIT
import { article as a_new_chapter_for_modrinth_servers } from './a_new_chapter_for_modrinth_servers'
import { article as accelerating_development } from './accelerating_development'
import { article as becoming_sustainable } from './becoming_sustainable'
import { article as capital_return } from './capital_return'
import { article as carbon_ads } from './carbon_ads'
import { article as creator_monetization } from './creator_monetization'
import { article as creator_update } from './creator_update'
import { article as creator_updates_july_2025 } from './creator_updates_july_2025'
import { article as design_refresh } from './design_refresh'
import { article as download_adjustment } from './download_adjustment'
import { article as knossos_v2_1_0 } from './knossos_v2_1_0'
import { article as licensing_guide } from './licensing_guide'
import { article as modpack_changes } from './modpack_changes'
import { article as modpacks_alpha } from './modpacks_alpha'
import { article as modrinth_app_beta } from './modrinth_app_beta'
import { article as modrinth_beta } from './modrinth_beta'
import { article as modrinth_servers_beta } from './modrinth_servers_beta'
import { article as new_site_beta } from './new_site_beta'
import { article as plugins_resource_packs } from './plugins_resource_packs'
import { article as pride_campaign_2025 } from './pride_campaign_2025'
import { article as redesign } from './redesign'
import { article as skins_now_in_modrinth_app } from './skins_now_in_modrinth_app'
import { article as two_years_of_modrinth_history } from './two_years_of_modrinth_history'
import { article as two_years_of_modrinth } from './two_years_of_modrinth'
import { article as whats_modrinth } from './whats_modrinth'
import { article as windows_borderless_malware_disclosure } from './windows_borderless_malware_disclosure'
import { article as whats_modrinth } from './whats_modrinth'
import { article as two_years_of_modrinth } from './two_years_of_modrinth'
import { article as two_years_of_modrinth_history } from './two_years_of_modrinth_history'
import { article as skins_now_in_modrinth_app } from './skins_now_in_modrinth_app'
import { article as redesign } from './redesign'
import { article as pride_campaign_2025 } from './pride_campaign_2025'
import { article as plugins_resource_packs } from './plugins_resource_packs'
import { article as new_site_beta } from './new_site_beta'
import { article as modrinth_servers_beta } from './modrinth_servers_beta'
import { article as modrinth_beta } from './modrinth_beta'
import { article as modrinth_app_beta } from './modrinth_app_beta'
import { article as modpacks_alpha } from './modpacks_alpha'
import { article as modpack_changes } from './modpack_changes'
import { article as licensing_guide } from './licensing_guide'
import { article as knossos_v2_1_0 } from './knossos_v2_1_0'
import { article as download_adjustment } from './download_adjustment'
import { article as design_refresh } from './design_refresh'
import { article as creator_updates_july_2025 } from './creator_updates_july_2025'
import { article as creator_update } from './creator_update'
import { article as creator_monetization } from './creator_monetization'
import { article as carbon_ads } from './carbon_ads'
import { article as capital_return } from './capital_return'
import { article as becoming_sustainable } from './becoming_sustainable'
import { article as accelerating_development } from './accelerating_development'
import { article as a_new_chapter_for_modrinth_servers } from './a_new_chapter_for_modrinth_servers'
export const articles = [
a_new_chapter_for_modrinth_servers,
accelerating_development,
becoming_sustainable,
capital_return,
carbon_ads,
creator_monetization,
creator_update,
creator_updates_july_2025,
design_refresh,
download_adjustment,
knossos_v2_1_0,
licensing_guide,
modpack_changes,
modpacks_alpha,
modrinth_app_beta,
modrinth_beta,
modrinth_servers_beta,
new_site_beta,
plugins_resource_packs,
pride_campaign_2025,
redesign,
skins_now_in_modrinth_app,
two_years_of_modrinth_history,
two_years_of_modrinth,
whats_modrinth,
windows_borderless_malware_disclosure,
whats_modrinth,
two_years_of_modrinth,
two_years_of_modrinth_history,
skins_now_in_modrinth_app,
redesign,
pride_campaign_2025,
plugins_resource_packs,
new_site_beta,
modrinth_servers_beta,
modrinth_beta,
modrinth_app_beta,
modpacks_alpha,
modpack_changes,
licensing_guide,
knossos_v2_1_0,
download_adjustment,
design_refresh,
creator_updates_july_2025,
creator_update,
creator_monetization,
carbon_ads,
capital_return,
becoming_sustainable,
accelerating_development,
a_new_chapter_for_modrinth_servers,
]

View File

@@ -9,6 +9,7 @@
"fix": "jiti ./compile.ts && eslint . --fix && prettier --write ."
},
"devDependencies": {
"@types/glob": "^9.0.0",
"@types/html-minifier-terser": "^7.0.2",
"@types/rss": "^0.0.32",
"@types/xml2js": "^0.4.14",
@@ -19,7 +20,7 @@
},
"dependencies": {
"@modrinth/utils": "workspace:*",
"fast-glob": "^3.3.3",
"glob": "^10.2.7",
"gray-matter": "^4.0.3",
"html-minifier-terser": "^7.2.0",
"rss": "^1.2.2",

View File

@@ -8,7 +8,7 @@ export function getRepoRoot(): string {
}
export function repoPath(...segments: string[]): string {
return path.join(getRepoRoot(), ...segments)
return path.posix.join(getRepoRoot(), ...segments)
}
export async function copyDir(
@@ -20,8 +20,8 @@ export async function copyDir(
await fs.mkdir(dest, { recursive: true })
const entries = await fs.readdir(src, { withFileTypes: true })
for (const entry of entries) {
const srcPath = path.join(src, entry.name)
const destPath = path.join(dest, entry.name)
const srcPath = path.posix.join(src, entry.name)
const destPath = path.posix.join(dest, entry.name)
if (entry.isDirectory()) {
await copyDir(srcPath, destPath, logFn)
} else if (entry.isFile()) {