diff --git a/Cargo.lock b/Cargo.lock
index 459048aa57..7bb6313426 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -437,6 +437,23 @@ dependencies = [
"windows-sys 0.60.2",
]
+[[package]]
+name = "antlr4rust"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "093d520274bfff7278d776f7ea12981a0a0a6f96db90964658e0f38fc6e9a6a6"
+dependencies = [
+ "better_any",
+ "bit-set 0.8.0",
+ "byteorder",
+ "lazy_static",
+ "murmur3",
+ "once_cell",
+ "parking_lot",
+ "typed-arena",
+ "uuid 1.23.3",
+]
+
[[package]]
name = "anyhow"
version = "1.0.100"
@@ -1421,10 +1438,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b08e33815c87d8cadcddb1e74ac307368a3751fbe40c961538afa21a1899f21c"
dependencies = [
"base64 0.21.7",
- "pastey",
+ "pastey 0.1.1",
"serde",
]
+[[package]]
+name = "better_any"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4372b9543397a4b86050cc5e7ee36953edf4bac9518e8a774c2da694977fb6e4"
+
[[package]]
name = "bindgen"
version = "0.72.1"
@@ -1451,7 +1474,16 @@ version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1"
dependencies = [
- "bit-vec",
+ "bit-vec 0.6.3",
+]
+
+[[package]]
+name = "bit-set"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3"
+dependencies = [
+ "bit-vec 0.8.0",
]
[[package]]
@@ -1460,6 +1492,12 @@ version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb"
+[[package]]
+name = "bit-vec"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7"
+
[[package]]
name = "bit_field"
version = "0.10.3"
@@ -1889,6 +1927,23 @@ dependencies = [
"shlex",
]
+[[package]]
+name = "cel"
+version = "0.14.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6ed39583e427bf41d93c28c7f27c943a93bcb8697220ff3575fd53a9e13f3814"
+dependencies = [
+ "antlr4rust",
+ "base64 0.22.1",
+ "lazy_static",
+ "nom 7.1.3",
+ "pastey 0.2.3",
+ "regex",
+ "serde",
+ "serde_json",
+ "thiserror 1.0.69",
+]
+
[[package]]
name = "censor"
version = "0.3.0"
@@ -3530,7 +3585,7 @@ version = "0.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "531e46835a22af56d1e3b66f04844bed63158bc094a628bec1d321d9b4c44bf2"
dependencies = [
- "bit-set",
+ "bit-set 0.5.3",
"regex-automata",
"regex-syntax",
]
@@ -5483,6 +5538,7 @@ dependencies = [
"base64 0.22.1",
"bitflags 2.9.4",
"bytes",
+ "cel",
"censor",
"chrono",
"chumsky",
@@ -6170,6 +6226,15 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb585ade2549a017db2e35978b77c319214fa4b37cede841e27954dd6e8f3ca8"
+[[package]]
+name = "murmur3"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a198f9589efc03f544388dfc4a19fe8af4323662b62f598b8dcfdac62c14771c"
+dependencies = [
+ "byteorder",
+]
+
[[package]]
name = "mutually_exclusive_features"
version = "0.1.0"
@@ -7192,6 +7257,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "35fb2e5f958ec131621fdd531e9fc186ed768cbe395337403ae56c17a74c68ec"
+[[package]]
+name = "pastey"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2ee67f1008b1ba2321834326597b8e186293b049a023cdef258527550b9935b4"
+
[[package]]
name = "path-util"
version = "0.0.0"
@@ -11863,6 +11934,12 @@ dependencies = [
"utf-8",
]
+[[package]]
+name = "typed-arena"
+version = "2.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
+
[[package]]
name = "typed-path"
version = "0.12.0"
diff --git a/Cargo.toml b/Cargo.toml
index 1377c4b047..99b0c562a5 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -55,6 +55,7 @@ bitflags = "2.9.4"
bon = "3.9.3"
bytemuck = "1.24.0"
bytes = "1.10.1"
+cel = { version = "0.14.0", default-features = false, features = ["json", "regex"] }
censor = "0.3.0"
chardetng = "0.1.17"
chrono = "0.4.42"
diff --git a/apps/frontend/src/components/ui/moderation/GlobalDetailLocalTraceCard.vue b/apps/frontend/src/components/ui/moderation/GlobalDetailLocalTraceCard.vue
index 4a368d2d77..62f2e8dfe8 100644
--- a/apps/frontend/src/components/ui/moderation/GlobalDetailLocalTraceCard.vue
+++ b/apps/frontend/src/components/ui/moderation/GlobalDetailLocalTraceCard.vue
@@ -5,14 +5,8 @@
{{ trace.project_name }}
-
- {{ trace.version_number }}
-
- {{ decodeTracePath(trace.file_name) }}
-
-
- {{ decodeTracePath(trace.jar) }}
-
+
+
@@ -31,9 +25,11 @@
diff --git a/apps/frontend/src/components/ui/moderation/GlobalDetailTracesList.vue b/apps/frontend/src/components/ui/moderation/GlobalDetailTracesList.vue
index 1803ee2b73..dff82aaa5d 100644
--- a/apps/frontend/src/components/ui/moderation/GlobalDetailTracesList.vue
+++ b/apps/frontend/src/components/ui/moderation/GlobalDetailTracesList.vue
@@ -64,7 +64,7 @@
Path
- {{ decodeTracePath(getLatestLocalTrace(trace)?.file_path ?? '') }}
+
@@ -132,6 +132,7 @@ import {
} from '@modrinth/ui'
import GlobalDetailLocalTraceCard from '~/components/ui/moderation/GlobalDetailLocalTraceCard.vue'
+import IssueDetailPath from '~/components/ui/moderation/IssueDetailPath.vue'
const client = injectModrinthClient()
const { addNotification } = injectNotificationManager()
@@ -164,24 +165,19 @@ function getLatestLocalTrace(trace: Labrinth.TechReview.Internal.GlobalIssueDeta
return trace.local_traces.at(-1)
}
-function decodeTracePath(path: string): string {
- try {
- return decodeURIComponent(path)
- } catch {
- return path
- }
-}
-
function getSeverityBadgeColor(
severity: Labrinth.TechReview.Internal.DelphiSeverity | undefined,
): string {
switch (severity) {
+ case 'malware':
case 'severe':
return 'border-red/60 bg-highlight-red text-red'
case 'high':
return 'border-orange/60 bg-highlight-orange text-orange'
case 'medium':
return 'border-green/60 bg-highlight-green text-green'
+ case 'hidden':
+ return 'border-divider bg-surface-2 text-secondary'
case 'low':
default:
return 'border-blue/60 bg-highlight-blue text-blue'
diff --git a/apps/frontend/src/components/ui/moderation/IssueDetailPath.vue b/apps/frontend/src/components/ui/moderation/IssueDetailPath.vue
new file mode 100644
index 0000000000..6289a9cd56
--- /dev/null
+++ b/apps/frontend/src/components/ui/moderation/IssueDetailPath.vue
@@ -0,0 +1,74 @@
+
+
+
+
+
+ {{ formatSegment(segment) }}
+
+
+
+
+
+
diff --git a/apps/frontend/src/components/ui/moderation/tech-review/TechRevFileDetailTab.vue b/apps/frontend/src/components/ui/moderation/tech-review/TechRevFileDetailTab.vue
index 7c4d154f51..2bc3879a58 100644
--- a/apps/frontend/src/components/ui/moderation/tech-review/TechRevFileDetailTab.vue
+++ b/apps/frontend/src/components/ui/moderation/tech-review/TechRevFileDetailTab.vue
@@ -3,20 +3,28 @@ import type { Labrinth } from '@modrinth/api-client'
import {
CheckIcon,
ChevronDownIcon,
- ChevronRightIcon,
+ ClipboardCopyIcon,
CopyIcon,
LoaderCircleIcon,
} from '@modrinth/assets'
-import { Collapsible, IconButton, injectNotificationManager, Toggle } from '@modrinth/ui'
+import {
+ Button,
+ Collapsible,
+ IconButton,
+ injectModrinthClient,
+ injectNotificationManager,
+ Toggle,
+} from '@modrinth/ui'
import { capitalizeString, highlightCodeLines } from '@modrinth/utils'
import { computed, nextTick, reactive, ref, watch } from 'vue'
+import IssueDetailPath from '~/components/ui/moderation/IssueDetailPath.vue'
+
import {
canUpdateGlobalDetail,
getFileDetailCount,
getSeverityBadgeColor,
severityOrder,
- truncateMiddle,
verdictToDecision,
} from './helpers'
import TechRevVerdictButtons from './TechRevVerdictButtons.vue'
@@ -37,6 +45,7 @@ const emit = defineEmits<{
}>()
const { addNotification } = injectNotificationManager()
+const client = injectModrinthClient()
const {
updatingDetails,
updatingGlobalDetailKeys,
@@ -57,6 +66,8 @@ const isBatchUpdating = ref(false)
const expandedClasses = reactive>(new Set())
const autoExpandedFileIds = reactive>(new Set())
const showCopyFeedback = reactive