Link directly to mojira.dev filtered issue list
Some checks failed
Deploy to GitHub Pages / build (push) Has been cancelled
Deploy to GitHub Pages / deploy (push) Has been cancelled

This commit is contained in:
Misode
2026-02-24 21:57:35 +01:00
parent 9540a46e78
commit c2b5529a60
8 changed files with 101 additions and 147 deletions

View File

@@ -1,15 +0,0 @@
import type { Bugfix } from '../../services/DataFetcher.js'
import { Badge } from '../Badge.jsx'
import { Card } from '../Card.jsx'
interface Props {
fix: Bugfix
}
export function Issue({ fix }: Props) {
return <Card overlay={fix.id} link={`https://mojira.dev/${fix.id}`}>
<div class="changelog-content">{fix.summary}</div>
<div class="badges-list">
{fix.categories.map(c => <Badge label={c} />)}
</div>
</Card>
}

View File

@@ -1,22 +0,0 @@
import { useLocale } from '../../contexts/Locale.jsx'
import { useAsync } from '../../hooks/useAsync.js'
import { fetchBugfixes } from '../../services/DataFetcher.js'
import { Issue } from './Issue.jsx'
interface Props {
version: string
}
export function IssueList({ version }: Props) {
const { locale } = useLocale()
const { value: issues, loading } = useAsync(() => fetchBugfixes(version), [version])
return <div class="card-column">
{issues === undefined || loading ? <>
<span class="note">{locale('loading')}</span>
</> : issues.length === 0 ? <>
<span class="note">{locale('versions.fixes.no_results')}</span>
</> : <>
{issues?.map(issue => <Issue key={issue.id} fix={issue} />)}
</>}
</div>
}

View File

@@ -4,11 +4,11 @@ import { useLocale } from '../../contexts/index.js'
import { useAsync } from '../../hooks/useAsync.js'
import { useSearchParam } from '../../hooks/useSearchParam.js'
import type { VersionMeta } from '../../services/index.js'
import { fetchChangelogs, getArticleLink } from '../../services/index.js'
import { fetchChangelogs } from '../../services/index.js'
import { Octicon } from '../Octicon.js'
import { ChangelogList, IssueList, VersionDiff, VersionMetaData } from './index.js'
import { ChangelogList, VersionDiff, VersionMetaData } from './index.js'
const Tabs = ['changelog', 'diff', 'fixes']
const Tabs = ['changelog', 'diff']
const WIKI_PAGE_PREFIX = 'https://minecraft.wiki/w/Java_Edition_'
interface Props {
@@ -31,6 +31,7 @@ export function VersionDetail({ id, version }: Props) {
changes?.filter(c => c.version === id || (c.group === id && !c.tags.includes('obsolete'))),
[id, changes])
const fixesLink = version && getFixesLink(version.id)
const articleLink = version && getArticleLink(version.id)
const wikiPageLink = version && WIKI_PAGE_PREFIX + version.name
@@ -55,6 +56,10 @@ export function VersionDetail({ id, version }: Props) {
{Tabs.map(t => <Link key={t} class={tab === t ? 'selected' : ''} href={`/versions/?id=${id}&tab=${t}`}>
{locale(`versions.${t}`)}
</Link>)}
<a href={fixesLink} target="_blank">
{locale('versions.fixes')}
{Octicon.link_external}
</a>
{articleLink && <a href={articleLink} target="_blank">
{locale('versions.article')}
{Octicon.link_external}
@@ -67,7 +72,6 @@ export function VersionDetail({ id, version }: Props) {
<div class="version-tab">
{tab === 'changelog' && <ChangelogList changes={filteredChangelogs} defaultOrder="asc" />}
{tab === 'diff' && <VersionDiff version={id} />}
{tab === 'fixes' && <IssueList version={id} />}
</div>
</div>
</>
@@ -76,3 +80,96 @@ export function VersionDetail({ id, version }: Props) {
export function releaseDate(version: VersionMeta) {
return new Date(version.release_time).toLocaleDateString(undefined, { day: 'numeric', month: 'short', year: 'numeric' })
}
const FIXES_PREFIX = 'https://mojira.dev/?project=MC&resolution=Fixed&fix_version='
function getFixesLink(version: string) {
let match
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-snapshot-(\d+)$/)) && match[1] && match[2]) {
return FIXES_PREFIX + encodeURIComponent(`${match[1]} Snapshot ${match[2]}`)
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-pre(\d+)$/)) && match[1] && match[2]) {
return FIXES_PREFIX + encodeURIComponent(`${match[1]} Pre-Release ${match[2]}`)
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-rc(\d+)$/)) && match[1]) {
return FIXES_PREFIX + encodeURIComponent(`${match[1]} Release Candidate ${match[2]}`)
}
return FIXES_PREFIX + encodeURIComponent(version)
}
const ARTICLE_PREFIX = 'https://www.minecraft.net/article/'
const ARTICLE_OVERRIDES = new Map(Object.entries({
'1.16-pre2': 'minecraft-1-16-pre-release-1',
'1.16-pre4': 'minecraft-1-16-pre-release-3',
'1.16-pre5': 'minecraft-1-16-pre-release-3',
'1.16-pre7': 'minecraft-1-16-pre-release-6',
'1.16-pre8': 'minecraft-1-16-pre-release-6',
'1.16-rc1': 'minecraft-1-16-release-candidate',
'1.16': 'nether-update-java',
'1.16.2-pre3': 'minecraft-1-16-2-pre-release-2',
'1.16.2-rc1': 'minecraft-1-16-2-pre-release-2',
'1.16.2-rc2': 'minecraft-1-16-2-pre-release-2',
'1.17-pre3': 'minecraft-1-17-pre-release-2',
'1.17-pre4': 'minecraft-1-17-pre-release-2',
'1.17-pre5': 'minecraft-1-17-pre-release-2',
'1.17.1-pre3': 'minecraft-1-17-1-pre-release-2',
'1.17-rc2': 'minecraft-1-17-release-candidate-1',
'1.17': 'caves---cliffs--part-i-out-today-java',
'1.17.1-rc2': 'minecraft-1-17-1-release-candidate-1',
'1.18-pre3': 'minecraft-1-18-pre-release-2',
'1.18-pre4': 'minecraft-1-18-pre-release-2',
'1.18-pre5': 'minecraft-1-18-pre-release-2',
'1.18-pre7': 'minecraft-1-18-pre-release-6',
'1.18-pre8': 'minecraft-1-18-pre-release-6',
'1.18-rc2': 'minecraft-1-18-release-candidate-1',
'1.18-rc3': 'minecraft-1-18-release-candidate-1',
'1.18-rc4': 'minecraft-1-18-release-candidate-1',
'1.18': 'caves---cliffs--part-ii-out-today-java',
'1.18.1-rc2': 'minecraft-1-18-1-release-candidate-1',
'1.18.1-rc3': 'minecraft-1-18-1-release-candidate-1',
'1.18.2-pre3': 'minecraft-1-18-2-pre-release-2',
'1.18.2-pre5': 'minecraft-1-18-2-pre-release-4',
'1.19-pre3': 'minecraft-1-19-pre-release-2',
'1.19-pre5': 'minecraft-1-19-pre-release-4',
'1.19-rc2': 'minecraft-1-19-release-candidate-1',
'1.19': 'the-wild-update-out-today-java',
'1.19.1-pre4': 'minecraft-1-19-1-pre-release-3',
'1.19.2-rc2': 'minecraft-1-19-2-release-candidate-1',
'1.19.3-pre2': 'minecraft-1-19-3-pre-release-1',
'1.19.3-rc2': 'minecraft-1-19-3-release-candidate-1',
'1.19.4-pre3': 'minecraft-1-19-4-pre-release-2',
'1.19.4-rc2': 'minecraft-1-19-4-release-candidate-1',
'1.20-pre3': 'minecraft-1-20-pre-release-2',
'1.20-pre4': 'minecraft-1-20-pre-release-2',
'1.20-pre6': 'minecraft-1-20-pre-release-5',
'1.20': 'trails-tales-update-out-today-java',
'1.20.1': 'minecraft--java-edition-1-20-1',
'1.20.2-pre2': 'minecraft-1-20-2-pre-release-1',
'23w43b': 'minecraft-snapshot-23w43b',
'24w03b': 'minecraft-snapshot-24w03b',
'24w05b': 'minecraft-snapshot-24w05b',
}))
function getArticleLink(version: string): string | undefined {
const override = ARTICLE_OVERRIDES.get(version)
if (override) {
return ARTICLE_PREFIX + override
}
let match
if ((match = version.match(/^(\d\dw\d\d)[a-z]$/)) && match[1]) {
return ARTICLE_PREFIX + 'minecraft-snapshot-' + match[1] + 'a'
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-snapshot-(\d+)$/)) && match[1] && match[2]) {
return ARTICLE_PREFIX + 'minecraft-' + match[1].replaceAll('.', '-') + '-snapshot-' + match[2]
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-pre(\d+)$/)) && match[1] && match[2]) {
return ARTICLE_PREFIX + 'minecraft-' + match[1].replaceAll('.', '-') + '-pre-release-' + match[2]
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-rc(\d+)$/)) && match[1]) {
return ARTICLE_PREFIX + 'minecraft-' + match[1].replaceAll('.', '-') + '-release-candidate-' + match[2]
}
if (version.match(/^\d+\.\d+(\.\d+)?$/)) {
return ARTICLE_PREFIX + 'minecraft-java-edition-' + version.replaceAll('.', '-')
}
return undefined
}

View File

@@ -1,7 +1,6 @@
export * from '../Badge.jsx'
export * from './ChangelogEntry.js'
export * from './ChangelogList.js'
export * from './IssueList.jsx'
export * from './VersionDetail.js'
export * from './VersionDiff.jsx'
export * from './VersionEntry.js'

View File

@@ -1,77 +0,0 @@
const ARTICLE_PREFIX = 'https://www.minecraft.net/article/'
const ARTICLE_OVERRIDES = new Map(Object.entries({
'1.16-pre2': 'minecraft-1-16-pre-release-1',
'1.16-pre4': 'minecraft-1-16-pre-release-3',
'1.16-pre5': 'minecraft-1-16-pre-release-3',
'1.16-pre7': 'minecraft-1-16-pre-release-6',
'1.16-pre8': 'minecraft-1-16-pre-release-6',
'1.16-rc1': 'minecraft-1-16-release-candidate',
'1.16': 'nether-update-java',
'1.16.2-pre3': 'minecraft-1-16-2-pre-release-2',
'1.16.2-rc1': 'minecraft-1-16-2-pre-release-2',
'1.16.2-rc2': 'minecraft-1-16-2-pre-release-2',
'1.17-pre3': 'minecraft-1-17-pre-release-2',
'1.17-pre4': 'minecraft-1-17-pre-release-2',
'1.17-pre5': 'minecraft-1-17-pre-release-2',
'1.17.1-pre3': 'minecraft-1-17-1-pre-release-2',
'1.17-rc2': 'minecraft-1-17-release-candidate-1',
'1.17': 'caves---cliffs--part-i-out-today-java',
'1.17.1-rc2': 'minecraft-1-17-1-release-candidate-1',
'1.18-pre3': 'minecraft-1-18-pre-release-2',
'1.18-pre4': 'minecraft-1-18-pre-release-2',
'1.18-pre5': 'minecraft-1-18-pre-release-2',
'1.18-pre7': 'minecraft-1-18-pre-release-6',
'1.18-pre8': 'minecraft-1-18-pre-release-6',
'1.18-rc2': 'minecraft-1-18-release-candidate-1',
'1.18-rc3': 'minecraft-1-18-release-candidate-1',
'1.18-rc4': 'minecraft-1-18-release-candidate-1',
'1.18': 'caves---cliffs--part-ii-out-today-java',
'1.18.1-rc2': 'minecraft-1-18-1-release-candidate-1',
'1.18.1-rc3': 'minecraft-1-18-1-release-candidate-1',
'1.18.2-pre3': 'minecraft-1-18-2-pre-release-2',
'1.18.2-pre5': 'minecraft-1-18-2-pre-release-4',
'1.19-pre3': 'minecraft-1-19-pre-release-2',
'1.19-pre5': 'minecraft-1-19-pre-release-4',
'1.19-rc2': 'minecraft-1-19-release-candidate-1',
'1.19': 'the-wild-update-out-today-java',
'1.19.1-pre4': 'minecraft-1-19-1-pre-release-3',
'1.19.2-rc2': 'minecraft-1-19-2-release-candidate-1',
'1.19.3-pre2': 'minecraft-1-19-3-pre-release-1',
'1.19.3-rc2': 'minecraft-1-19-3-release-candidate-1',
'1.19.4-pre3': 'minecraft-1-19-4-pre-release-2',
'1.19.4-rc2': 'minecraft-1-19-4-release-candidate-1',
'1.20-pre3': 'minecraft-1-20-pre-release-2',
'1.20-pre4': 'minecraft-1-20-pre-release-2',
'1.20-pre6': 'minecraft-1-20-pre-release-5',
'1.20': 'trails-tales-update-out-today-java',
'1.20.1': 'minecraft--java-edition-1-20-1',
'1.20.2-pre2': 'minecraft-1-20-2-pre-release-1',
'23w43b': 'minecraft-snapshot-23w43b',
'24w03b': 'minecraft-snapshot-24w03b',
'24w05b': 'minecraft-snapshot-24w05b',
}))
export function getArticleLink(version: string): string | undefined {
const override = ARTICLE_OVERRIDES.get(version)
if (override) {
return ARTICLE_PREFIX + override
}
let match
if ((match = version.match(/^(\d\dw\d\d)[a-z]$/)) && match[1]) {
return ARTICLE_PREFIX + 'minecraft-snapshot-' + match[1] + 'a'
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-snapshot-(\d+)$/)) && match[1] && match[2]) {
return ARTICLE_PREFIX + 'minecraft-' + match[1].replaceAll('.', '-') + '-snapshot-' + match[2]
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-pre(\d+)$/)) && match[1] && match[2]) {
return ARTICLE_PREFIX + 'minecraft-' + match[1].replaceAll('.', '-') + '-pre-release-' + match[2]
}
if ((match = version.match(/^(\d+\.\d+(?:\.\d+)?)-rc(\d+)$/)) && match[1]) {
return ARTICLE_PREFIX + 'minecraft-' + match[1].replaceAll('.', '-') + '-release-candidate-' + match[2]
}
if (version.match(/^\d+\.\d+(\.\d+)?$/)) {
return ARTICLE_PREFIX + 'minecraft-java-edition-' + version.replaceAll('.', '-')
}
return undefined
}

View File

@@ -14,7 +14,6 @@ const mcmetaUrl = 'https://raw.githubusercontent.com/misode/mcmeta'
const mcmetaTarballUrl = 'https://github.com/misode/mcmeta/tarball'
const vanillaMcdocUrl = 'https://raw.githubusercontent.com/SpyglassMC/vanilla-mcdoc'
const changesUrl = 'https://raw.githubusercontent.com/misode/technical-changes'
const fixesUrl = 'https://raw.githubusercontent.com/misode/mcfixes'
const versionDiffUrl = 'https://mcmeta-diff.misode.workers.dev'
const whatsNewUrl = 'https://whats-new.misode.workers.dev'
@@ -309,31 +308,6 @@ export async function fetchChangelogs(): Promise<Change[]> {
}
}
export interface Bugfix {
id: string,
summary: string,
labels: string[],
status: string,
confirmation_status: string,
categories: string[],
priority: string,
fix_versions: string[],
creation_date: string,
resolution_date: string,
updated_date: string,
watches: number,
votes: number,
}
export async function fetchBugfixes(version: string): Promise<Bugfix[]> {
try {
const fixes = await cachedFetch<Bugfix[]>(`${fixesUrl}/main/versions/${version}.json`, { refresh: true })
return fixes
} catch (e) {
throw new Error(`Error occured while fetching bugfixes for version ${version}: ${message(e)}`)
}
}
export interface GitHubCommitFile {
sha: string,
filename: string,

View File

@@ -1,4 +1,3 @@
export * from './Article.js'
export * from './DataFetcher.js'
export * from './Sharing.js'
export * from './Source.js'

View File

@@ -362,7 +362,6 @@
"versions.data_version": "Data version",
"versions.diff": "Mcmeta diff",
"versions.fixes": "Fixed bugs",
"versions.fixes.no_results": "No fixes",
"versions.latest_release": "Latest release",
"versions.latest_snapshot": "Latest snapshot",
"versions.minecraft_versions": "Minecraft Versions",