Modrinth/helpers/projects.js
Prospector 1d9fe0c03d
Add new links card and feature flag system for incremental dev. (#1714)
* Add new links card and feature flag system for incremental dev.

* Switch to env variable for dev flags

* Add members card

* fix order of creators card

* Fix owner icon color and bring org owner to top of list

* lint + other fixes

* Revamp feature flag system, add flag config page

* Add button to flags page in dev mode

* fix env overrides

* make typescript happy with the refs
2024-06-11 19:46:07 -07:00

253 lines
7.2 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

export const getProjectTypeForUrl = (type, categories) => {
return getProjectTypeForUrlShorthand(type, categories)
}
export const getProjectTypeForUrlShorthand = (type, categories, overrideTags) => {
const tags = overrideTags ?? useTags().value
if (type === 'mod') {
const isMod = categories.some((category) => {
return tags.loaderData.modLoaders.includes(category)
})
const isPlugin = categories.some((category) => {
return tags.loaderData.allPluginLoaders.includes(category)
})
const isDataPack = categories.some((category) => {
return tags.loaderData.dataPackLoaders.includes(category)
})
if (isDataPack) {
return 'datapack'
} else if (isPlugin) {
return 'plugin'
} else if (isMod) {
return 'mod'
} else {
return 'mod'
}
} else {
return type
}
}
export const getProjectLink = (project) => {
return `/${getProjectTypeForUrl(project.project_type, project.loaders)}/${
project.slug ? project.slug : project.id
}`
}
export const getVersionLink = (project, version) => {
if (version) {
return getProjectLink(project) + '/version/' + version.id
} else {
return getProjectLink(project)
}
}
export const isApproved = (project) => {
return project && APPROVED_PROJECT_STATUSES.includes(project.status)
}
export const isListed = (project) => {
return project && LISTED_PROJECT_STATUSES.includes(project.status)
}
export const isUnlisted = (project) => {
return project && UNLISTED_PROJECT_STATUSES.includes(project.status)
}
export const isPrivate = (project) => {
return project && PRIVATE_PROJECT_STATUSES.includes(project.status)
}
export const isRejected = (project) => {
return project && REJECTED_PROJECT_STATUSES.includes(project.status)
}
export const isUnderReview = (project) => {
return project && UNDER_REVIEW_PROJECT_STATUSES.includes(project.status)
}
export const isDraft = (project) => {
return project && DRAFT_PROJECT_STATUSES.includes(project.status)
}
export const APPROVED_PROJECT_STATUSES = ['approved', 'archived', 'unlisted', 'private']
export const LISTED_PROJECT_STATUSES = ['approved', 'archived']
export const UNLISTED_PROJECT_STATUSES = ['unlisted', 'withheld']
export const PRIVATE_PROJECT_STATUSES = ['private', 'rejected', 'processing']
export const REJECTED_PROJECT_STATUSES = ['rejected', 'withheld']
export const UNDER_REVIEW_PROJECT_STATUSES = ['processing']
export const DRAFT_PROJECT_STATUSES = ['draft']
export function getVersionsToDisplay(project, overrideTags) {
const tags = overrideTags ?? useTags().value
const projectVersions = project.game_versions.slice()
const allVersions = tags.gameVersions.slice()
const allSnapshots = allVersions.filter((version) => version.version_type === 'snapshot')
const allReleases = allVersions.filter((version) => version.version_type === 'release')
const allLegacy = allVersions.filter(
(version) => version.version_type !== 'snapshot' && version.version_type !== 'release'
)
{
const indices = allVersions.reduce((map, gameVersion, index) => {
map[gameVersion.version] = index
return map
}, {})
projectVersions.sort((a, b) => indices[a] - indices[b])
}
const releaseVersions = projectVersions.filter((projVer) =>
allReleases.some((gameVer) => gameVer.version === projVer)
)
const latestReleaseVersionDate = Date.parse(
allReleases.find((version) => version.version === releaseVersions[0])?.date
)
const latestSnapshot = projectVersions.find((projVer) =>
allSnapshots.some(
(gameVer) =>
gameVer.version === projVer &&
(!latestReleaseVersionDate || latestReleaseVersionDate < Date.parse(gameVer.date))
)
)
const allReleasesGrouped = groupVersions(
allReleases.map((release) => release.version),
false
)
const projectVersionsGrouped = groupVersions(releaseVersions, true)
const releaseVersionsAsRanges = projectVersionsGrouped.map(({ major, minor }) => {
if (minor.length === 1) {
return formatVersion(major, minor[0])
}
if (
allReleasesGrouped
.find((x) => x.major === major)
.minor.every((value, index) => value === minor[index])
) {
return `${major}.x`
}
return `${formatVersion(major, minor[0])}${formatVersion(major, minor[minor.length - 1])}`
})
const legacyVersionsAsRanges = groupConsecutiveIndices(
projectVersions.filter((projVer) => allLegacy.some((gameVer) => gameVer.version === projVer)),
allLegacy
)
let output = [...legacyVersionsAsRanges]
// show all snapshots if there's no release versions
if (releaseVersionsAsRanges.length === 0) {
const snapshotVersionsAsRanges = groupConsecutiveIndices(
projectVersions.filter((projVer) =>
allSnapshots.some((gameVer) => gameVer.version === projVer)
),
allSnapshots
)
output = [...snapshotVersionsAsRanges, ...output]
} else {
output = [...releaseVersionsAsRanges, ...output]
}
if (latestSnapshot) {
output = [latestSnapshot, ...output]
}
return output
}
const mcVersionRegex = /^([0-9]+.[0-9]+)(.[0-9]+)?$/
function groupVersions(versions, consecutive = false) {
return versions
.slice()
.reverse()
.reduce((ranges, version) => {
const matchesVersion = version.match(mcVersionRegex)
if (matchesVersion) {
const majorVersion = matchesVersion[1]
const minorVersion = matchesVersion[2]
const minorNumeric = minorVersion ? parseInt(minorVersion.replace('.', '')) : 0
let prevInRange
if (
(prevInRange = ranges.find(
(x) => x.major === majorVersion && (!consecutive || x.minor.at(-1) === minorNumeric - 1)
))
) {
prevInRange.minor.push(minorNumeric)
return ranges
}
return [...ranges, { major: majorVersion, minor: [minorNumeric] }]
}
return ranges
}, [])
.reverse()
}
function groupConsecutiveIndices(versions, referenceList) {
if (!versions || versions.length === 0) {
return []
}
const referenceMap = new Map()
referenceList.forEach((item, index) => {
referenceMap.set(item.version, index)
})
const sortedList = versions.slice().sort((a, b) => referenceMap.get(a) - referenceMap.get(b))
const ranges = []
let start = sortedList[0]
let previous = sortedList[0]
for (let i = 1; i < sortedList.length; i++) {
const current = sortedList[i]
if (referenceMap.get(current) !== referenceMap.get(previous) + 1) {
ranges.push(validateRange(`${previous}${start}`))
start = current
}
previous = current
}
ranges.push(validateRange(`${previous}${start}`))
return ranges
}
function validateRange(range) {
switch (range) {
case 'rd-132211b1.8.1':
return 'All legacy versions'
case 'a1.0.4b1.8.1':
return 'All alpha and beta versions'
case 'a1.0.4a1.2.6':
return 'All alpha versions'
case 'b1.0b1.8.1':
return 'All beta versions'
case 'rd-132211inf20100618':
return 'All pre-alpha versions'
}
const splitRange = range.split('')
if (splitRange && splitRange[0] === splitRange[1]) {
return splitRange[0]
}
return range
}
function formatVersion(major, minor) {
return minor === 0 ? major : `${major}.${minor}`
}