Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
241c4bf
add environment to version page metadata card
tdgao Dec 22, 2025
3cbd96b
remove environment migration warnings
tdgao Dec 22, 2025
5123f90
show settings/environments in nav only for staff
tdgao Dec 22, 2025
b2c470c
use v2 versions route due to regressions
tdgao Dec 22, 2025
13131f7
add modpack incorrect loaders migration
tdgao Dec 22, 2025
edd5903
remove modpack migration step
tdgao Dec 23, 2025
624e792
remove unused var
tdgao Dec 23, 2025
158357a
run pnpm intl:extract
tdgao Dec 23, 2025
c406f6c
componentize environment migration page
tdgao Dec 23, 2025
ea1b387
rename environment selector
tdgao Dec 23, 2025
18a3351
rename environment selector pt2
tdgao Dec 23, 2025
d19a192
add migration modal to admonition
tdgao Dec 23, 2025
7407e81
hide environments in settings and show message
tdgao Dec 23, 2025
6fd3589
show environment in project versions table
tdgao Dec 24, 2025
486b19d
pnpm fix
tdgao Dec 24, 2025
b522c48
Merge branch 'main' into truman/versions-environments-updates
tdgao Dec 24, 2025
7918b90
pnpm fix on ui package
tdgao Dec 24, 2025
2a5be6b
intl:extract
tdgao Dec 24, 2025
94b99ce
fix: .value
IMB11 Dec 24, 2025
2269147
lower case file
tdgao Dec 24, 2025
24c2368
add icon to environment tags and use i18n
tdgao Dec 24, 2025
31a0800
Update apps/frontend/src/pages/[type]/[id].vue
tdgao Dec 24, 2025
39937f7
open migration modal from warning icon in project dashboard
tdgao Dec 24, 2025
22539d7
fix settings side nav icon
tdgao Dec 24, 2025
c5aa7d0
use useRoute composable
tdgao Dec 24, 2025
9ff1701
pnpm fix
tdgao Dec 24, 2025
519c599
intl:extract
tdgao Dec 24, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -155,8 +155,9 @@

<script lang="ts" setup>
import { EditIcon } from '@modrinth/assets'
import { ButtonStyled, Chips, TagItem } from '@modrinth/ui'
import { ButtonStyled, Chips, ENVIRONMENTS_COPY, TagItem } from '@modrinth/ui'
import { formatCategory } from '@modrinth/utils'
import { defineMessages, useVIntl } from '@vintl/vintl'

import { useGeneratedState } from '~/composables/generated'
import { injectManageVersionContext } from '~/providers/version/manage-version-modal'
Expand Down Expand Up @@ -215,61 +216,51 @@ const usingDetectedLoaders = computed(() => {
return loadersMatch
})

const { formatMessage } = useVIntl()

const noEnvironmentMessage = defineMessages({
title: {
id: 'version.environment.none.title',
defaultMessage: 'No environment set',
},
description: {
id: 'version.environment.none.description',
defaultMessage: 'The environment for this version has not been specified.',
},
})

const unknownEnvironmentMessage = defineMessages({
title: {
id: 'version.environment.unknown.title',
defaultMessage: 'Unknown environment',
},
description: {
id: 'version.environment.unknown.description',
defaultMessage: 'The environment: "{environment}" is not recognized.',
},
})

const environmentCopy = computed(() => {
const emptyMessage = {
title: 'No environment set',
description: 'The environment for this version has not been specified.',
if (!draftVersion.value.environment) {
return {
title: formatMessage(noEnvironmentMessage.title),
description: formatMessage(noEnvironmentMessage.description),
}
}
if (!draftVersion.value.environment) return emptyMessage

const envCopy: Record<string, { title: string; description: string }> = {
client_only: {
title: 'Client-side only',
description: 'All functionality is done client-side and is compatible with vanilla servers.',
},
server_only: {
title: 'Server-side only',
description: 'All functionality is done server-side and is compatible with vanilla clients.',
},
singleplayer_only: {
title: 'Singleplayer only',
description: 'Only functions in Singleplayer or when not connected to a Multiplayer server.',
},
dedicated_server_only: {
title: 'Server-side only',
description: 'All functionality is done server-side and is compatible with vanilla clients.',
},
client_and_server: {
title: 'Client and server',
description: 'Has some functionality on both the client and server, even if only partially.',
},
client_only_server_optional: {
title: 'Client and server',
description: 'Has some functionality on both the client and server, even if only partially.',
},
server_only_client_optional: {
title: 'Client and server',
description: 'Has some functionality on both the client and server, even if only partially.',
},
client_or_server: {
title: 'Client and server',
description: 'Has some functionality on both the client and server, even if only partially.',
},
client_or_server_prefers_both: {
title: 'Client and server',
description: 'Has some functionality on both the client and server, even if only partially.',
},
unknown: {
title: 'Unknown environment',
description: 'The environment for this version could not be determined.',
},
const envCopy = ENVIRONMENTS_COPY[draftVersion.value.environment]
if (envCopy) {
return {
title: formatMessage(envCopy.title),
description: formatMessage(envCopy.description),
}
}

return (
envCopy[draftVersion.value.environment] || {
title: 'Unknown environment',
description: `The environment: "${draftVersion.value.environment}" is not recognized.`,
}
)
return {
title: formatMessage(unknownEnvironmentMessage.title),
description: formatMessage(unknownEnvironmentMessage.description, {
environment: draftVersion.value.environment,
}),
}
})
</script>
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<template>
<div class="sm:w-[512px]">
<ProjectSettingsEnvSelector v-model="draftVersion.environment" />
<EnvironmentSelector v-model="draftVersion.environment" />
</div>
</template>

<script lang="ts" setup>
import { ProjectSettingsEnvSelector } from '@modrinth/ui'
import { EnvironmentSelector } from '@modrinth/ui'

import { injectManageVersionContext } from '~/providers/version/manage-version-modal'

Expand Down
44 changes: 13 additions & 31 deletions apps/frontend/src/locales/en-US/index.json
Original file line number Diff line number Diff line change
Expand Up @@ -2127,7 +2127,7 @@
"message": "Learn more about this change"
},
"project.environment.migration.message": {
"message": "We've just overhauled the Environments system on Modrinth and new options are now available. Please visit your project's settings and verify that the metadata is correct."
"message": "We've just overhauled the Environments system on Modrinth and new options are now available. Please verify that the metadata is correct."
},
"project.environment.migration.review-button": {
"message": "Review environment settings"
Expand Down Expand Up @@ -2174,36 +2174,6 @@
"project.notification.updated.title": {
"message": "Project updated"
},
"project.settings.environment.notice.missing-env.description": {
"message": "Your project is missing environment metadata, please select the appropriate option below."
},
"project.settings.environment.notice.missing-env.title": {
"message": "Please select an environment for your project"
},
"project.settings.environment.notice.multiple-environments.description": {
"message": "Different versions of your project have different environments selected, so you can't edit them globally at this time."
},
"project.settings.environment.notice.multiple-environments.title": {
"message": "Your project has multiple environments"
},
"project.settings.environment.notice.review-options.description": {
"message": "We've just overhauled the Environments system on Modrinth and new options are now available. Please ensure the correct option is selected below and then click 'Verify' when you're done!"
},
"project.settings.environment.notice.review-options.title": {
"message": "Please review the options below"
},
"project.settings.environment.notice.wrong-project-type.description": {
"message": "Only mod or modpack projects can have environment metadata."
},
"project.settings.environment.notice.wrong-project-type.title": {
"message": "This project type does not support environment metadata"
},
"project.settings.environment.verification.verify-button": {
"message": "Verify"
},
"project.settings.environment.verification.verify-text": {
"message": "Verify that this project's environment is set correctly."
},
"project.settings.general.name.description": {
"message": "Avoid prefixes, suffixes, parentheticals, or added descriptions—just the project's actual name."
},
Expand Down Expand Up @@ -2959,5 +2929,17 @@
},
"ui.latest-news-row.view-all": {
"message": "View all news"
},
"version.environment.none.description": {
"message": "The environment for this version has not been specified."
},
"version.environment.none.title": {
"message": "No environment set"
},
"version.environment.unknown.description": {
"message": "The environment: \"{environment}\" is not recognized."
},
"version.environment.unknown.title": {
"message": "Unknown environment"
}
}
40 changes: 33 additions & 7 deletions apps/frontend/src/pages/[type]/[id].vue
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,16 @@
<NuxtPage
v-model:project="project"
v-model:project-v3="projectV3"
v-model:versions="versions"
v-model:members="members"
v-model:all-members="allMembers"
v-model:dependencies="dependencies"
v-model:organization="organization"
:versions="
versions.map((v) => ({
...v,
environment: versionsV3?.find((v3) => v3.id === v.id)?.environment,
}))
"
:current-member="currentMember"
:patch-project="patchProject"
:patch-icon="patchIcon"
Expand Down Expand Up @@ -778,9 +783,9 @@
{{ formatMessage(messages.environmentMigrationLink) }}
</nuxt-link>
<ButtonStyled v-if="hasEditDetailsPermission" color="orange">
<nuxt-link :to="`/project/${project.id}/settings/environment`" class="mt-3 w-fit">
<button class="mt-3 w-fit" @click="() => projectEnvironmentModal.show()">
<SettingsIcon /> {{ formatMessage(messages.reviewEnvironmentSettings) }}
</nuxt-link>
</button>
</ButtonStyled>
</Admonition>
<MessageBanner v-if="project.status === 'archived'" message-type="warning" class="my-4">
Expand Down Expand Up @@ -935,6 +940,10 @@
@toggle-collapsed="collapsedModerationChecklist = !collapsedModerationChecklist"
/>
</div>

<template v-if="hasEditDetailsPermission">
<ProjectEnvironmentModal ref="projectEnvironmentModal" />
</template>
</template>

<script setup>
Expand Down Expand Up @@ -975,6 +984,7 @@ import {
OverflowMenu,
PopoutMenu,
ProjectBackgroundGradient,
ProjectEnvironmentModal,
ProjectHeader,
ProjectSidebarCompatibility,
ProjectSidebarCreators,
Expand All @@ -992,6 +1002,7 @@ import { IntlFormatted } from '@vintl/vintl/components'
import { useLocalStorage } from '@vueuse/core'
import dayjs from 'dayjs'
import { Tooltip } from 'floating-vue'
import { useTemplateRef } from 'vue'

import { navigateTo } from '#app'
import Accordion from '~/components/ui/Accordion.vue'
Expand Down Expand Up @@ -1035,6 +1046,8 @@ const gameVersionFilterInput = ref()

const versionFilter = ref('')

const projectEnvironmentModal = useTemplateRef('projectEnvironmentModal')

const baseId = useId()

const currentGameVersion = computed(() => {
Expand Down Expand Up @@ -1184,7 +1197,7 @@ const messages = defineMessages({
environmentMigrationMessage: {
id: 'project.environment.migration.message',
defaultMessage:
"We've just overhauled the Environments system on Modrinth and new options are now available. Please visit your project's settings and verify that the metadata is correct.",
"We've just overhauled the Environments system on Modrinth and new options are now available. Please verify that the metadata is correct.",
},
environmentMigrationTitle: {
id: 'project.environment.migration.title',
Expand Down Expand Up @@ -1457,21 +1470,25 @@ let project,
resetMembers,
dependencies,
versions,
resetVersions,
versionsV3,
resetVersionsV2,
organization,
resetOrganization,
projectV2Error,
projectV3Error,
membersError,
dependenciesError,
versionsError
versionsError,
versionsV3Error,
resetVersionsV3
try {
;[
{ data: project, error: projectV2Error, refresh: resetProjectV2 },
{ data: projectV3, error: projectV3Error, refresh: resetProjectV3 },
{ data: allMembers, error: membersError, refresh: resetMembers },
{ data: dependencies, error: dependenciesError },
{ data: versions, error: versionsError, refresh: resetVersions },
{ data: versions, error: versionsError, refresh: resetVersionsV2 },
{ data: versionsV3, error: versionsV3Error, refresh: resetVersionsV3 },
{ data: organization, refresh: resetOrganization },
] = await Promise.all([
useAsyncData(`project/${projectId.value}`, () => useBaseFetch(`project/${projectId.value}`), {
Expand Down Expand Up @@ -1513,6 +1530,9 @@ try {
useAsyncData(`project/${projectId.value}/version`, () =>
useBaseFetch(`project/${projectId.value}/version`),
),
useAsyncData(`project/${projectId.value}/version/v3`, () =>
useBaseFetch(`project/${projectId.value}/version`, { apiVersion: 3 }),
),
useAsyncData(`project/${projectId.value}/organization`, () =>
useBaseFetch(`project/${projectId.value}/organization`, { apiVersion: 3 }),
),
Expand Down Expand Up @@ -1553,6 +1573,11 @@ async function resetProject() {
await resetProjectV3()
}

async function resetVersions() {
await resetVersionsV2()
await resetVersionsV3()
}

function handleError(err, project = false) {
if (err.value && err.value.statusCode) {
throw createError({
Expand All @@ -1571,6 +1596,7 @@ handleError(projectV3Error)
handleError(membersError)
handleError(dependenciesError)
handleError(versionsError)
handleError(versionsV3Error)

if (!project.value) {
throw createError({
Expand Down
17 changes: 15 additions & 2 deletions apps/frontend/src/pages/[type]/[id]/settings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
AlignLeftIcon,
BookTextIcon,
ChartIcon,
GlobeIcon,
ImageIcon,
InfoIcon,
LinkIcon,
Expand All @@ -15,7 +16,7 @@ import {
commonProjectSettingsMessages,
injectNotificationManager,
} from '@modrinth/ui'
import type { Project, ProjectV3Partial } from '@modrinth/utils'
import { isStaff, type Project, type ProjectV3Partial } from '@modrinth/utils'
import { useVIntl } from '@vintl/vintl'
import { useLocalStorage, useScroll } from '@vueuse/core'
import { computed } from 'vue'
Expand All @@ -25,7 +26,7 @@ import NavStack from '~/components/ui/NavStack.vue'

const { formatMessage } = useVIntl()

defineProps<{
const props = defineProps<{
currentMember: any
patchProject: any
patchIcon: any
Expand All @@ -47,6 +48,11 @@ const organization = defineModel<any>('organization')

const navItems = computed(() => {
const base = `${project.value.project_type}/${project.value.slug ? project.value.slug : project.value.id}`

const showEnvironment =
projectV3.value.project_types.some((type) => ['mod', 'modpack'].includes(type)) &&
isStaff(props.currentMember.user)

const items = [
{
link: `/${base}/settings`,
Expand Down Expand Up @@ -101,6 +107,13 @@ const navItems = computed(() => {
label: formatMessage(commonProjectSettingsMessages.analytics),
icon: ChartIcon,
},
{ type: 'heading', label: 'moderation', shown: showEnvironment },
{
link: `/${base}/settings/environment`,
label: formatMessage(commonProjectSettingsMessages.environment),
icon: GlobeIcon,
shown: showEnvironment,
},
]
return items.filter(Boolean) as any[]
})
Expand Down
Loading