Coolbot/moderation updates for versions changes (#4942)

* update reports message to the correct support bubble color

* update checklist to direct to new settings pages and use v3 env info

* fix: project v2 + v3 in moderation checklist funcs

* Split environment stage if project uses mixed environments.

---------

Co-authored-by: Calum H. (IMB11) <contact@cal.engineer>
This commit is contained in:
coolbot
2025-12-22 15:37:44 -08:00
committed by GitHub
parent 6a0bf5858e
commit 543bd5acf7
23 changed files with 216 additions and 140 deletions

View File

@@ -84,8 +84,8 @@
<div v-else-if="isModpackPermissionsStage"> <div v-else-if="isModpackPermissionsStage">
<ModpackPermissionsFlow <ModpackPermissionsFlow
v-model="modpackJudgements" v-model="modpackJudgements"
:project-id="project.id" :project-id="projectV2.id"
:project-updated="project.updated" :project-updated="projectV2.updated"
@complete="handleModpackPermissionsComplete" @complete="handleModpackPermissionsComplete"
/> />
</div> </div>
@@ -282,7 +282,7 @@
</button> </button>
</ButtonStyled> </ButtonStyled>
<ButtonStyled color="green"> <ButtonStyled color="green">
<button @click="sendMessage(project.requested_status ?? 'approved')"> <button @click="sendMessage(projectV2.requested_status ?? 'approved')">
<CheckIcon aria-hidden="true" /> <CheckIcon aria-hidden="true" />
Approve Approve
</button> </button>
@@ -360,7 +360,9 @@ import {
expandVariables, expandVariables,
finalPermissionMessages, finalPermissionMessages,
findMatchingVariant, findMatchingVariant,
flattenProjectV3Variables,
flattenProjectVariables, flattenProjectVariables,
flattenStaticVariables,
getActionIdForStage, getActionIdForStage,
getActionMessage, getActionMessage,
getVisibleInputs, getVisibleInputs,
@@ -380,6 +382,7 @@ import {
Collapsible, Collapsible,
DropdownSelect, DropdownSelect,
injectNotificationManager, injectNotificationManager,
injectProjectPageContext,
MarkdownEditor, MarkdownEditor,
OverflowMenu, OverflowMenu,
type OverflowMenuOption, type OverflowMenuOption,
@@ -387,7 +390,6 @@ import {
import { import {
type ModerationJudgements, type ModerationJudgements,
type ModerationModpackItem, type ModerationModpackItem,
type Project,
type ProjectStatus, type ProjectStatus,
renderHighlightedString, renderHighlightedString,
} from '@modrinth/utils' } from '@modrinth/utils'
@@ -404,14 +406,19 @@ const { addNotification } = notifications
const keybindsModal = ref<InstanceType<typeof KeybindsModal>>() const keybindsModal = ref<InstanceType<typeof KeybindsModal>>()
const props = defineProps<{ const props = defineProps<{
project: Project
collapsed: boolean collapsed: boolean
}>() }>()
const { projectV2, projectV3 } = injectProjectPageContext()
const moderationStore = useModerationStore() const moderationStore = useModerationStore()
const variables = computed(() => { const variables = computed(() => {
return flattenProjectVariables(props.project) return {
...flattenStaticVariables(),
...flattenProjectVariables(projectV2.value),
...flattenProjectV3Variables(projectV3.value),
}
}) })
const modpackPermissionsComplete = ref(false) const modpackPermissionsComplete = ref(false)
@@ -445,12 +452,12 @@ function resetProgress() {
message.value = '' message.value = ''
loadingMessage.value = false loadingMessage.value = false
localStorage.removeItem(`modpack-permissions-${props.project.id}`) localStorage.removeItem(`modpack-permissions-${projectV2.value.id}`)
localStorage.removeItem(`modpack-permissions-index-${props.project.id}`) localStorage.removeItem(`modpack-permissions-index-${projectV2.value.id}`)
sessionStorage.removeItem(`modpack-permissions-data-${props.project.id}`) sessionStorage.removeItem(`modpack-permissions-data-${projectV2.value.id}`)
sessionStorage.removeItem(`modpack-permissions-permanent-no-${props.project.id}`) sessionStorage.removeItem(`modpack-permissions-permanent-no-${projectV2.value.id}`)
sessionStorage.removeItem(`modpack-permissions-updated-${props.project.id}`) sessionStorage.removeItem(`modpack-permissions-updated-${projectV2.value.id}`)
modpackPermissionsComplete.value = false modpackPermissionsComplete.value = false
modpackJudgements.value = {} modpackJudgements.value = {}
@@ -468,7 +475,7 @@ function findFirstValidStage(): number {
} }
const currentStageObj = computed(() => checklist[currentStage.value]) const currentStageObj = computed(() => checklist[currentStage.value])
const currentStage = useLocalStorage(`moderation-stage-${props.project.slug}`, () => const currentStage = useLocalStorage(`moderation-stage-${projectV2.value.slug}`, () =>
findFirstValidStage(), findFirstValidStage(),
) )
@@ -477,7 +484,12 @@ const stageTextExpanded = computedAsync(async () => {
const stage = checklist[stageIndex] const stage = checklist[stageIndex]
if (stage.text) { if (stage.text) {
return renderHighlightedString( return renderHighlightedString(
expandVariables(await stage.text(props.project), props.project, variables.value), expandVariables(
await stage.text(projectV2.value, projectV3.value),
projectV2.value,
projectV3.value,
variables.value,
),
) )
} }
return null return null
@@ -489,7 +501,7 @@ interface ActionState {
} }
const persistedActionStates = useLocalStorage( const persistedActionStates = useLocalStorage(
`moderation-actions-${props.project.slug}`, `moderation-actions-${projectV2.value.slug}`,
{}, {},
{ {
serializer: { serializer: {
@@ -502,7 +514,7 @@ const persistedActionStates = useLocalStorage(
const router = useRouter() const router = useRouter()
const persistedTextInputs = useLocalStorage( const persistedTextInputs = useLocalStorage(
`moderation-inputs-${props.project.slug}`, `moderation-inputs-${projectV2.value.slug}`,
{} as Record<string, string>, {} as Record<string, string>,
) )
@@ -530,7 +542,7 @@ function handleKeybinds(event: KeyboardEvent) {
handleKeybind( handleKeybind(
event, event,
{ {
project: props.project, project: projectV2.value,
state: { state: {
currentStage: currentStage.value, currentStage: currentStage.value,
totalStages: checklist.length, totalStages: checklist.length,
@@ -562,7 +574,7 @@ function handleKeybinds(event: KeyboardEvent) {
tryResetProgress: resetProgress, tryResetProgress: resetProgress,
tryExitModeration: () => emit('exit'), tryExitModeration: () => emit('exit'),
tryApprove: () => sendMessage(props.project.requested_status), tryApprove: () => sendMessage(projectV2.value.requested_status ?? 'approved'),
tryReject: () => sendMessage('rejected'), tryReject: () => sendMessage('rejected'),
tryWithhold: () => sendMessage('withheld'), tryWithhold: () => sendMessage('withheld'),
tryEditMessage: goBackToStages, tryEditMessage: goBackToStages,
@@ -656,7 +668,7 @@ watch(
(newIndex) => { (newIndex) => {
const stage = checklist[newIndex] const stage = checklist[newIndex]
if (stage?.navigate) { if (stage?.navigate) {
router.push(`/${props.project.project_type}/${props.project.slug}${stage.navigate}`) router.push(`/${projectV2.value.project_type}/${projectV2.value.slug}${stage.navigate}`)
} }
initializeCurrentStage() initializeCurrentStage()
@@ -858,11 +870,11 @@ function getModpackFilesFromStorage(): {
permanentNo: ModerationModpackItem[] permanentNo: ModerationModpackItem[]
} { } {
try { try {
const sessionData = sessionStorage.getItem(`modpack-permissions-data-${props.project.id}`) const sessionData = sessionStorage.getItem(`modpack-permissions-data-${projectV2.value.id}`)
const interactive = sessionData ? (JSON.parse(sessionData) as ModerationModpackItem[]) : [] const interactive = sessionData ? (JSON.parse(sessionData) as ModerationModpackItem[]) : []
const permanentNoData = sessionStorage.getItem( const permanentNoData = sessionStorage.getItem(
`modpack-permissions-permanent-no-${props.project.id}`, `modpack-permissions-permanent-no-${projectV2.value.id}`,
) )
const permanentNo = permanentNoData const permanentNo = permanentNoData
? (JSON.parse(permanentNoData) as ModerationModpackItem[]) ? (JSON.parse(permanentNoData) as ModerationModpackItem[])
@@ -894,7 +906,8 @@ async function assembleFullMessage() {
.map((part) => part.content) .map((part) => part.content)
.filter((content) => content.trim().length > 0) .filter((content) => content.trim().length > 0)
.join('\n\n'), .join('\n\n'),
props.project, projectV2.value,
projectV3.value,
) )
return finalMessage return finalMessage
@@ -1048,7 +1061,7 @@ function shouldShowStage(stage: Stage): boolean {
} }
if (typeof stage.shouldShow === 'function') { if (typeof stage.shouldShow === 'function') {
return stage.shouldShow(props.project) return stage.shouldShow(projectV2.value, projectV3.value)
} }
return true return true
@@ -1056,7 +1069,7 @@ function shouldShowStage(stage: Stage): boolean {
function shouldShowAction(action: Action): boolean { function shouldShowAction(action: Action): boolean {
if (typeof action.shouldShow === 'function') { if (typeof action.shouldShow === 'function') {
return action.shouldShow(props.project) return action.shouldShow(projectV2.value)
} }
return true return true
@@ -1065,7 +1078,7 @@ function shouldShowAction(action: Action): boolean {
function getVisibleDropdownOptions(action: DropdownAction) { function getVisibleDropdownOptions(action: DropdownAction) {
return action.options.filter((option) => { return action.options.filter((option) => {
if (typeof option.shouldShow === 'function') { if (typeof option.shouldShow === 'function') {
return option.shouldShow(props.project) return option.shouldShow(projectV2.value)
} }
return true return true
}) })
@@ -1074,7 +1087,7 @@ function getVisibleDropdownOptions(action: DropdownAction) {
function getVisibleMultiSelectOptions(action: MultiSelectChipsAction) { function getVisibleMultiSelectOptions(action: MultiSelectChipsAction) {
return action.options.filter((option) => { return action.options.filter((option) => {
if (typeof option.shouldShow === 'function') { if (typeof option.shouldShow === 'function') {
return option.shouldShow(props.project) return option.shouldShow(projectV2.value)
} }
return true return true
}) })
@@ -1141,13 +1154,13 @@ async function generateMessage() {
loadingMessage.value = true loadingMessage.value = true
router.push(`/${props.project.project_type}/${props.project.slug}/moderation`) router.push(`/${projectV2.value.project_type}/${projectV2.value.slug}/moderation`)
try { try {
const baseMessage = await assembleFullMessage() const baseMessage = await assembleFullMessage()
let fullMessage = baseMessage let fullMessage = baseMessage
if (props.project.project_type === 'modpack') { if (projectV2.value.project_type === 'modpack') {
const modpackFilesData = getModpackFilesFromStorage() const modpackFilesData = getModpackFilesFromStorage()
if (modpackFilesData.interactive.length > 0 || modpackFilesData.permanentNo.length > 0) { if (modpackFilesData.interactive.length > 0 || modpackFilesData.permanentNo.length > 0) {
@@ -1239,7 +1252,7 @@ function generateModpackMessage(allFiles: {
const hasNextProject = ref(false) const hasNextProject = ref(false)
async function sendMessage(status: ProjectStatus) { async function sendMessage(status: ProjectStatus) {
try { try {
await useBaseFetch(`project/${props.project.id}`, { await useBaseFetch(`project/${projectV2.value.id}`, {
method: 'PATCH', method: 'PATCH',
body: { body: {
status, status,
@@ -1247,7 +1260,7 @@ async function sendMessage(status: ProjectStatus) {
}) })
if (message.value) { if (message.value) {
await useBaseFetch(`thread/${props.project.thread_id}`, { await useBaseFetch(`thread/${projectV2.value.thread_id}`, {
method: 'POST', method: 'POST',
body: { body: {
body: { body: {
@@ -1259,7 +1272,7 @@ async function sendMessage(status: ProjectStatus) {
} }
if ( if (
props.project.project_type === 'modpack' && projectV2.value.project_type === 'modpack' &&
Object.keys(modpackJudgements.value).length > 0 Object.keys(modpackJudgements.value).length > 0
) { ) {
await useBaseFetch(`moderation/project`, { await useBaseFetch(`moderation/project`, {
@@ -1272,7 +1285,7 @@ async function sendMessage(status: ProjectStatus) {
done.value = true done.value = true
hasNextProject.value = await moderationStore.completeCurrentProject( hasNextProject.value = await moderationStore.completeCurrentProject(
props.project.id, projectV2.value.id,
'completed', 'completed',
) )
} catch (error) { } catch (error) {
@@ -1326,21 +1339,21 @@ async function endChecklist(status?: string) {
} }
async function skipCurrentProject() { async function skipCurrentProject() {
hasNextProject.value = await moderationStore.completeCurrentProject(props.project.id, 'skipped') hasNextProject.value = await moderationStore.completeCurrentProject(projectV2.value.id, 'skipped')
await endChecklist('skipped') await endChecklist('skipped')
} }
function clearProjectLocalStorage() { function clearProjectLocalStorage() {
localStorage.removeItem(`modpack-permissions-${props.project.id}`) localStorage.removeItem(`modpack-permissions-${projectV2.value.id}`)
localStorage.removeItem(`modpack-permissions-index-${props.project.id}`) localStorage.removeItem(`modpack-permissions-index-${projectV2.value.id}`)
localStorage.removeItem(`moderation-actions-${props.project.slug}`) localStorage.removeItem(`moderation-actions-${projectV2.value.slug}`)
localStorage.removeItem(`moderation-inputs-${props.project.slug}`) localStorage.removeItem(`moderation-inputs-${projectV2.value.slug}`)
localStorage.removeItem(`moderation-stage-${props.project.slug}`) localStorage.removeItem(`moderation-stage-${projectV2.value.slug}`)
sessionStorage.removeItem(`modpack-permissions-data-${props.project.id}`) sessionStorage.removeItem(`modpack-permissions-data-${projectV2.value.id}`)
sessionStorage.removeItem(`modpack-permissions-permanent-no-${props.project.id}`) sessionStorage.removeItem(`modpack-permissions-permanent-no-${projectV2.value.id}`)
sessionStorage.removeItem(`modpack-permissions-updated-${props.project.id}`) sessionStorage.removeItem(`modpack-permissions-updated-${projectV2.value.id}`)
actionStates.value = {} actionStates.value = {}
} }

View File

@@ -930,7 +930,6 @@
class="moderation-checklist" class="moderation-checklist"
> >
<ModerationChecklist <ModerationChecklist
:project="project"
:collapsed="collapsedModerationChecklist" :collapsed="collapsedModerationChecklist"
@exit="showModerationChecklist = false" @exit="showModerationChecklist = false"
@toggle-collapsed="collapsedModerationChecklist = !collapsedModerationChecklist" @toggle-collapsed="collapsedModerationChecklist = !collapsedModerationChecklist"

View File

@@ -2,13 +2,14 @@ import type { Stage } from '../types/stage'
import modpackPermissionsStage from './modpack-permissions-stage' import modpackPermissionsStage from './modpack-permissions-stage'
import categories from './stages/categories' import categories from './stages/categories'
import description from './stages/description' import description from './stages/description'
import environment from './stages/environment/environment'
import environmentMultiple from './stages/environment/environment-multiple'
import gallery from './stages/gallery' import gallery from './stages/gallery'
import license from './stages/license' import license from './stages/license'
import links from './stages/links' import links from './stages/links'
import postApproval from './stages/post-approval' import postApproval from './stages/post-approval'
import reupload from './stages/reupload' import reupload from './stages/reupload'
import ruleFollowing from './stages/rule-following' import ruleFollowing from './stages/rule-following'
import sideTypes from './stages/side-types'
import statusAlerts from './stages/status-alerts' import statusAlerts from './stages/status-alerts'
import summary from './stages/summary' import summary from './stages/summary'
import titleSlug from './stages/title-slug' import titleSlug from './stages/title-slug'
@@ -22,7 +23,8 @@ export default [
links, links,
license, license,
categories, categories,
sideTypes, environment,
environmentMultiple,
gallery, gallery,
versions, versions,
reupload, reupload,

View File

@@ -0,0 +1,2 @@
**Unique environments:** %PROJECT_V3_ENVIRONMENT_COUNT% \
**Environments:** `%PROJECT_V3_ALL_ENVIRONMENTS%`

View File

@@ -1,2 +1,4 @@
**Environment:** `%PROJECT_V3_ENVIRONMENT_0%`
**Client:** `%PROJECT_CLIENT_SIDE%` \ **Client:** `%PROJECT_CLIENT_SIDE%` \
**Server:** `%PROJECT_SERVER_SIDE%` **Server:** `%PROJECT_SERVER_SIDE%`

View File

@@ -0,0 +1,6 @@
## Environment Metadata
Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including Environment Information.
We've recently overhauled how environment metadata works on Modrinth, you can now edit this in your project's [Version Settings](https://modrinth.com/project/%PROJECT_ID%/settings/versions).
Please [read this blogpost](%NEW_ENVIRONMENTS_LINK%) for full details and information on how to ensure your project is labeled correctly.

View File

@@ -1,6 +1,6 @@
## Insufficient Gallery Images ## Insufficient Gallery Images
We ask that projects like yours show off their content using images in the Gallery, or optionally in the Description, in order to effectively and clearly inform users of its content per section 2.1 of %RULES%. We ask that projects like yours show off their content using images in the %PROJECT_GALLERY_FLINK%, or optionally in the Description, in order to effectively and clearly inform users of its content per section 2.1 of %RULES%.
Keep in mind that you should: Keep in mind that you should:
- Set a featured image that best represents your project. - Set a featured image that best represents your project.

View File

@@ -1,3 +1,3 @@
## Unrelated Gallery Images ## Unrelated Gallery Images
Per section 5.5 of %RULES%, any images in your project's Gallery must be relevant to the project and also include a Title. Per section 5.5 of %RULES%, any images in your project's %PROJECT_GALLERY_FLINK% must be relevant to the project and also include a Title.

View File

@@ -2,4 +2,4 @@ Unfortunately, the Moderation team is unable to assist with your issue.
The reporting system is exclusively for reporting issues to Moderation staff; only violations of [Modrinth's Content Rules](https://modrinth.com/legal/rules) should be reported. The reporting system is exclusively for reporting issues to Moderation staff; only violations of [Modrinth's Content Rules](https://modrinth.com/legal/rules) should be reported.
Please visit the [Modrinth Help Center](https://support.modrinth.com/) and click the green bubble to contact support so our support agents can better assist you. Please visit the [Modrinth Help Center](https://support.modrinth.com/) and click the blue bubble to contact support so our support agents can better assist you.

View File

@@ -1,5 +0,0 @@
## Environment Metadata
Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including %PROJECT_ENVIRONMENT_FLINK%.
We've recently overhauled how environment metadata works on Modrinth, please [Read this blogpost](%NEW_ENVIRONMENTS_LINK%) for full details and information on how to ensure your project is labeled correctly.

View File

@@ -1,5 +0,0 @@
## Environment Metadata
Per section 5.1 of %RULES%, it is important that the metadata of your projects is accurate, including %PROJECT_ENVIRONMENT_FLINK%.
We've recently overhauled how environment metadata works on Modrinth, please [Read this blogpost](%NEW_ENVIRONMENTS_LINK%) for full details and information on how to ensure your project is labeled correctly.

View File

@@ -1,5 +1,6 @@
import type { Labrinth } from '@modrinth/api-client'
import { PackageOpenIcon } from '@modrinth/assets' import { PackageOpenIcon } from '@modrinth/assets'
import type { ModerationModpackPermissionApprovalType, Project } from '@modrinth/utils' import type { ModerationModpackPermissionApprovalType } from '@modrinth/utils'
import type { Stage } from '../types/stage' import type { Stage } from '../types/stage'
@@ -10,7 +11,7 @@ export default {
// Replace me please. // Replace me please.
guidance_url: guidance_url:
'https://www.notion.so/Content-Moderation-Cheat-Sheets-22d5ee711bf081a4920ef08879fe6bf5?source=copy_link#22d5ee711bf08116bd8bc1186f357062', 'https://www.notion.so/Content-Moderation-Cheat-Sheets-22d5ee711bf081a4920ef08879fe6bf5?source=copy_link#22d5ee711bf08116bd8bc1186f357062',
shouldShow: (project: Project) => project.project_type === 'modpack', shouldShow: (project: Labrinth.Projects.v2.Project) => project.project_type === 'modpack',
actions: [ actions: [
{ {
id: 'button', id: 'button',

View File

@@ -1,4 +1,4 @@
import type { Project } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
import { defineMessage, useVIntl } from '@vintl/vintl' import { defineMessage, useVIntl } from '@vintl/vintl'
import type { Nag, NagContext } from '../../types/nags' import type { Nag, NagContext } from '../../types/nags'
@@ -8,7 +8,7 @@ const allResolutionTags = ['8x-', '16x', '32x', '48x', '64x', '128x', '256x', '5
const MAX_TAG_COUNT = 8 const MAX_TAG_COUNT = 8
function getCategories( function getCategories(
project: Project & { actualProjectType: string }, project: Labrinth.Projects.v2.Project & { actualProjectType: string },
tags: { tags: {
categories?: { categories?: {
project_type: string project_type: string
@@ -120,7 +120,7 @@ export const tagsNags: Nag[] = [
description: (context: NagContext) => { description: (context: NagContext) => {
const { formatMessage } = useVIntl() const { formatMessage } = useVIntl()
const categoriesForProjectType = getCategories( const categoriesForProjectType = getCategories(
context.project as Project & { actualProjectType: string }, context.project as Labrinth.Projects.v2.Project & { actualProjectType: string },
context.tags, context.tags,
) )
const totalAvailableTags = categoriesForProjectType.length const totalAvailableTags = categoriesForProjectType.length
@@ -139,7 +139,7 @@ export const tagsNags: Nag[] = [
status: 'required', status: 'required',
shouldShow: (context: NagContext) => { shouldShow: (context: NagContext) => {
const categoriesForProjectType = getCategories( const categoriesForProjectType = getCategories(
context.project as Project & { actualProjectType: string }, context.project as Labrinth.Projects.v2.Project & { actualProjectType: string },
context.tags, context.tags,
) )
const totalSelectedTags = const totalSelectedTags =

View File

@@ -0,0 +1,29 @@
import { GlobeIcon } from '@modrinth/assets'
import type { ButtonAction } from '../../../types/actions'
import type { Stage } from '../../../types/stage'
const environmentMultiple: Stage = {
title: "Is the project's environment information accurate?",
id: 'environment',
navigate: '/settings/versions',
icon: GlobeIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
text: async () =>
(await import('../../messages/checklist-text/environment/environment-multiple.md?raw')).default,
shouldShow: (project, projectV3) => (projectV3?.environment?.length ?? 0) !== 1,
actions: [
{
id: 'side_types_inaccurate',
type: 'button',
label: 'Inaccurate',
weight: 800,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.project_type === 'mod' || project.project_type === 'modpack',
message: async () => (await import('../../messages/environment/inaccurate.md?raw')).default,
} as ButtonAction,
],
}
export default environmentMultiple

View File

@@ -0,0 +1,29 @@
import { GlobeIcon } from '@modrinth/assets'
import type { ButtonAction } from '../../../types/actions'
import type { Stage } from '../../../types/stage'
const environment: Stage = {
title: "Is the project's environment information accurate?",
id: 'environment',
navigate: '/settings/environment',
icon: GlobeIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
text: async () =>
(await import('../../messages/checklist-text/environment/environment.md?raw')).default,
shouldShow: (project, projectV3) => (projectV3?.environment?.length ?? 0) === 1,
actions: [
{
id: 'side_types_inaccurate',
type: 'button',
label: 'Inaccurate',
weight: 800,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.project_type === 'mod' || project.project_type === 'modpack',
message: async () => (await import('../../messages/environment/inaccurate.md?raw')).default,
} as ButtonAction,
],
}
export default environment

View File

@@ -1,38 +0,0 @@
import { GlobeIcon } from '@modrinth/assets'
import type { ButtonAction } from '../../types/actions'
import type { Stage } from '../../types/stage'
const sideTypes: Stage = {
title: "Is the project's environment information accurate?",
id: 'environment',
icon: GlobeIcon,
guidance_url: 'https://modrinth.com/legal/rules#miscellaneous',
navigate: '/settings/environment',
text: async () => (await import('../messages/checklist-text/side_types.md?raw')).default,
actions: [
{
id: 'side_types_inaccurate_modpack',
type: 'button',
label: 'Inaccurate',
weight: 800,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.project_type === 'modpack',
message: async () =>
(await import('../messages/side-types/inaccurate-modpack.md?raw')).default,
} as ButtonAction,
{
id: 'side_types_inaccurate_mod',
type: 'button',
label: 'Inaccurate',
weight: 800,
suggestedStatus: 'flagged',
severity: 'low',
shouldShow: (project) => project.project_type === 'mod',
message: async () => (await import('../messages/side-types/inaccurate-mod.md?raw')).default,
} as ButtonAction,
],
}
export default sideTypes

View File

@@ -1,9 +1,9 @@
import type { Labrinth } from '@modrinth/api-client'
import { BookOpenIcon } from '@modrinth/assets' import { BookOpenIcon } from '@modrinth/assets'
import type { Project } from '@modrinth/utils'
import type { Stage } from '../../types/stage' import type { Stage } from '../../types/stage'
function hasCustomSlug(project: Project): boolean { function hasCustomSlug(project: Labrinth.Projects.v2.Project): boolean {
return ( return (
project.slug !== project.slug !==
project.title project.title

View File

@@ -1,4 +1,4 @@
import type { Project } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
import type { WeightedMessage } from './messages' import type { WeightedMessage } from './messages'
@@ -60,7 +60,7 @@ export interface BaseAction {
* *
* By default, it returns `true`, meaning the action is always shown. * By default, it returns `true`, meaning the action is always shown.
*/ */
shouldShow?: (project: Project) => boolean shouldShow?: (project: Labrinth.Projects.v2.Project) => boolean
} }
/** /**
@@ -165,7 +165,7 @@ export interface DropdownActionOption extends WeightedMessage {
* *
* By default, it returns `true`, meaning the option is always shown. * By default, it returns `true`, meaning the option is always shown.
*/ */
shouldShow?: (project: Project) => boolean shouldShow?: (project: Labrinth.Projects.v2.Project) => boolean
} }
export interface DropdownAction extends BaseAction { export interface DropdownAction extends BaseAction {
@@ -198,7 +198,7 @@ export interface MultiSelectChipsOption extends WeightedMessage {
* *
* By default, it returns `true`, meaning the option is always shown. * By default, it returns `true`, meaning the option is always shown.
*/ */
shouldShow?: (project: Project) => boolean shouldShow?: (project: Labrinth.Projects.v2.Project) => boolean
} }
export interface MultiSelectChipsAction extends BaseAction { export interface MultiSelectChipsAction extends BaseAction {

View File

@@ -1,4 +1,4 @@
import type { Project } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
export interface ModerationActions { export interface ModerationActions {
tryGoNext: () => void tryGoNext: () => void
@@ -44,7 +44,7 @@ export interface ModerationState {
} }
export interface ModerationContext { export interface ModerationContext {
project: Project project: Labrinth.Projects.v2.Project
state: ModerationState state: ModerationState
actions: ModerationActions actions: ModerationActions
} }

View File

@@ -1,4 +1,5 @@
import type { Project, User, Version } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
import type { User, Version } from '@modrinth/utils'
import type { MessageDescriptor } from '@vintl/vintl' import type { MessageDescriptor } from '@vintl/vintl'
import type { FunctionalComponent, SVGAttributes } from 'vue' import type { FunctionalComponent, SVGAttributes } from 'vue'
@@ -20,7 +21,7 @@ export interface NagContext {
/** /**
* The project associated with the nag. * The project associated with the nag.
*/ */
project: Project project: Labrinth.Projects.v2.Project
/** /**
* The versions associated with the project. * The versions associated with the project.
*/ */

View File

@@ -1,4 +1,5 @@
import type { Project, Report, Thread, User, Version } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
import type { Report, Thread, User, Version } from '@modrinth/utils'
export interface OwnershipTarget { export interface OwnershipTarget {
name: string name: string
@@ -10,7 +11,7 @@ export interface OwnershipTarget {
export interface ExtendedReport extends Report { export interface ExtendedReport extends Report {
thread: Thread thread: Thread
reporter_user: User reporter_user: User
project?: Project project?: Labrinth.Projects.v2.Project
user?: User user?: User
version?: Version version?: Version
target?: OwnershipTarget target?: OwnershipTarget

View File

@@ -1,4 +1,4 @@
import type { Project } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
import type { FunctionalComponent, SVGAttributes } from 'vue' import type { FunctionalComponent, SVGAttributes } from 'vue'
import type { Action } from './actions' import type { Action } from './actions'
@@ -15,7 +15,10 @@ export interface Stage {
/** /**
* An optional description or additional text for the stage. * An optional description or additional text for the stage.
*/ */
text?: (project: Project) => Promise<string> text?: (
project: Labrinth.Projects.v2.Project,
projectV3?: Labrinth.Projects.v3.Project,
) => Promise<string>
/** /**
* Optional id for the stage, used for identification in the checklist. Will be used in the stage list as well instead of the title. * Optional id for the stage, used for identification in the checklist. Will be used in the stage list as well instead of the title.
@@ -49,5 +52,8 @@ export interface Stage {
* *
* By default, it returns `true`, meaning the stage is always shown. * By default, it returns `true`, meaning the stage is always shown.
*/ */
shouldShow?: (project: Project) => boolean shouldShow?: (
project: Labrinth.Projects.v2.Project,
projectV3?: Labrinth.Projects.v3.Project,
) => boolean
} }

View File

@@ -1,4 +1,4 @@
import type { Project } from '@modrinth/utils' import type { Labrinth } from '@modrinth/api-client'
import type { import type {
Action, Action,
@@ -210,11 +210,14 @@ export function getVisibleInputs(
export function expandVariables( export function expandVariables(
template: string, template: string,
project: Project, project: Labrinth.Projects.v2.Project,
projectV3: Labrinth.Projects.v3.Project,
variables?: Record<string, string>, variables?: Record<string, string>,
): string { ): string {
if (!variables) { variables ??= {
variables = flattenProjectVariables(project) ...flattenStaticVariables(),
...flattenProjectVariables(project),
...flattenProjectV3Variables(projectV3),
} }
return Object.entries(variables).reduce((result, [key, value]) => { return Object.entries(variables).reduce((result, [key, value]) => {
@@ -234,7 +237,30 @@ export function arrayOrNone(arr: string[]): string {
return arr.length > 0 ? arr.join(', ') : 'None' return arr.length > 0 ? arr.join(', ') : 'None'
} }
export function flattenProjectVariables(project: Project): Record<string, string> { export function flattenStaticVariables(): Record<string, string> {
const vars: Record<string, string> = {}
vars[`RULES`] = `[Modrinth's Content Rules](https://modrinth.com/legal/rules)`
vars[`TOS`] = `[Terms of Use](https://modrinth.com/legal/terms)`
vars[`COPYRIGHT_POLICY`] = `[Copyright Policy](https://modrinth.com/legal/copyright)`
vars[`SUPPORT`] =
`please visit the [Modrinth Help Center](https://support.modrinth.com/) and click the blue bubble to contact support.`
vars[`MODPACK_PERMISSIONS_GUIDE`] =
`our guide to [Obtaining Modpack Permissions](https://support.modrinth.com/en/articles/8797527-obtaining-modpack-permissions)`
vars[`MODPACKS_ON_MODRINTH`] =
`[Modpacks on Modrinth](https://support.modrinth.com/en/articles/8802250-modpacks-on-modrinth)`
vars[`ADVANCED_MARKDOWN`] =
`[Markdown Formatting Guide](https://support.modrinth.com/en/articles/8801962-advanced-markdown-formatting)`
vars[`LICENSING_GUIDE`] =
`our guide to [Licensing your Mods](https://modrinth.com/news/article/licensing-guide)`
vars[`NEW_ENVIRONMENTS_LINK`] = `https://modrinth.com/news/article/new-environments`
return vars
}
export function flattenProjectVariables(
project: Labrinth.Projects.v2.Project,
): Record<string, string> {
const vars: Record<string, string> = {} const vars: Record<string, string> = {}
vars['PROJECT_ID'] = project.id vars['PROJECT_ID'] = project.id
@@ -299,22 +325,6 @@ export function flattenProjectVariables(project: Project): Record<string, string
vars[`PROJECT_GALLERY_${index}_FEATURED`] = image.featured.toString() vars[`PROJECT_GALLERY_${index}_FEATURED`] = image.featured.toString()
}) })
// Static time saving stuff
vars[`RULES`] = `[Modrinth's Content Rules](https://modrinth.com/legal/rules)`
vars[`TOS`] = `[Terms of Use](https://modrinth.com/legal/terms)`
vars[`COPYRIGHT_POLICY`] = `[Copyright Policy](https://modrinth.com/legal/copyright)`
vars[`SUPPORT`] =
`please visit the [Modrinth Help Center](https://support.modrinth.com/) and click the blue bubble to contact support.`
vars[`MODPACK_PERMISSIONS_GUIDE`] =
`our guide to [Obtaining Modpack Permissions](https://support.modrinth.com/en/articles/8797527-obtaining-modpack-permissions)`
vars[`MODPACKS_ON_MODRINTH`] =
`[Modpacks on Modrinth](https://support.modrinth.com/en/articles/8802250-modpacks-on-modrinth)`
vars[`ADVANCED_MARKDOWN`] =
`[Markdown Formatting Guide](https://support.modrinth.com/en/articles/8801962-advanced-markdown-formatting)`
vars[`LICENSING_GUIDE`] =
`our guide to [Licensing your Mods](https://modrinth.com/news/article/licensing-guide)`
vars[`NEW_ENVIRONMENTS_LINK`] = `https://modrinth.com/news/article/new-environments`
// Navigation related variables // Navigation related variables
vars[`PROJECT_PERMANENT_LINK`] = `https://modrinth.com/project/${project.id}` vars[`PROJECT_PERMANENT_LINK`] = `https://modrinth.com/project/${project.id}`
vars[`PROJECT_SETTINGS_LINK`] = `https://modrinth.com/project/${project.id}/settings` vars[`PROJECT_SETTINGS_LINK`] = `https://modrinth.com/project/${project.id}/settings`
@@ -322,6 +332,7 @@ export function flattenProjectVariables(project: Project): Record<string, string
vars[`PROJECT_TITLE_FLINK`] = `[Name](https://modrinth.com/project/${project.id}/settings)` vars[`PROJECT_TITLE_FLINK`] = `[Name](https://modrinth.com/project/${project.id}/settings)`
vars[`PROJECT_SLUG_FLINK`] = `[URL](https://modrinth.com/project/${project.id}/settings)` vars[`PROJECT_SLUG_FLINK`] = `[URL](https://modrinth.com/project/${project.id}/settings)`
vars[`PROJECT_SUMMARY_FLINK`] = `[Summary](https://modrinth.com/project/${project.id}/settings)` vars[`PROJECT_SUMMARY_FLINK`] = `[Summary](https://modrinth.com/project/${project.id}/settings)`
// Depreciated
vars[`PROJECT_ENVIRONMENT_FLINK`] = vars[`PROJECT_ENVIRONMENT_FLINK`] =
`[Environment Information](https://modrinth.com/project/${project.id}/settings/environment)` `[Environment Information](https://modrinth.com/project/${project.id}/settings/environment)`
vars[`PROJECT_TAGS_LINK`] = `https://modrinth.com/project/${project.id}/settings/tags` vars[`PROJECT_TAGS_LINK`] = `https://modrinth.com/project/${project.id}/settings/tags`
@@ -330,18 +341,40 @@ export function flattenProjectVariables(project: Project): Record<string, string
`https://modrinth.com/project/${project.id}/settings/description` `https://modrinth.com/project/${project.id}/settings/description`
vars[`PROJECT_DESCRIPTION_FLINK`] = vars[`PROJECT_DESCRIPTION_FLINK`] =
`[Description](https://modrinth.com/project/${project.id}/settings/description)` `[Description](https://modrinth.com/project/${project.id}/settings/description)`
vars[`PROJECT_LICENSE_LINK`] = `https://modrinth.com/project/${project.id}/license` vars[`PROJECT_LICENSE_LINK`] = `https://modrinth.com/project/${project.id}/settings/license`
vars[`PROJECT_LICENSE_FLINK`] = `[License](https://modrinth.com/project/${project.id}/license)` vars[`PROJECT_LICENSE_FLINK`] =
`[License](https://modrinth.com/project/${project.id}/settings/license)`
vars[`PROJECT_LINKS_LINK`] = `https://modrinth.com/project/${project.id}/settings/links` vars[`PROJECT_LINKS_LINK`] = `https://modrinth.com/project/${project.id}/settings/links`
vars[`PROJECT_LINKS_FLINK`] = vars[`PROJECT_LINKS_FLINK`] =
`[External Links](https://modrinth.com/project/${project.id}/settings/links)` `[External Links](https://modrinth.com/project/${project.id}/settings/links)`
vars[`PROJECT_GALLERY_LINK`] = `https://modrinth.com/project/${project.id}/gallery` vars[`PROJECT_GALLERY_LINK`] = `https://modrinth.com/project/${project.id}/gallery`
vars[`PROJECT_GALLERY_FLINK`] = `[Gallery](https://modrinth.com/project/${project.id}/gallery)` vars[`PROJECT_GALLERY_FLINK`] =
`[Gallery](https://modrinth.com/project/${project.id}/settings/gallery)`
vars[`PROJECT_VERSIONS_LINK`] = `https://modrinth.com/project/${project.id}/versions` vars[`PROJECT_VERSIONS_LINK`] = `https://modrinth.com/project/${project.id}/versions`
vars[`PROJECT_VERSIONS_FLINK`] = `[Versions](https://modrinth.com/project/${project.id}/versions)` vars[`PROJECT_VERSIONS_FLINK`] =
`[Versions](https://modrinth.com/project/${project.id}/settings/versions)`
vars[`PROJECT_MODERATION_LINK`] = `https://modrinth.com/project/${project.id}/moderation` vars[`PROJECT_MODERATION_LINK`] = `https://modrinth.com/project/${project.id}/moderation`
vars[`PROJECT_MODERATION_FLINK`] = vars[`PROJECT_MODERATION_FLINK`] =
`[moderation tab](https://modrinth.com/project/${project.id}/moderation)` `[moderation tab](https://modrinth.com/project/${project.id}/moderation)`
return vars return vars
} }
export function flattenProjectV3Variables(
projectV3: Labrinth.Projects.v3.Project,
): Record<string, string> {
const vars: Record<string, string> = {}
const environment = projectV3.environment ?? []
vars['PROJECT_V3_ENVIRONMENT_COUNT'] = environment.length.toString()
vars['PROJECT_V3_ALL_ENVIRONMENTS'] = environment.join(', ')
environment.forEach((env, index) => {
vars[`PROJECT_V3_ENVIRONMENT_${index}`] = env
})
vars['PROJECT_V3_REVIEW_STATUS'] = projectV3.side_types_migration_review_status
vars['PROJECT_V3_TYPES'] = projectV3.project_types.join(', ')
return vars
}