From 9798d5553d406304233ba2d212a3994b1b0d0f80 Mon Sep 17 00:00:00 2001
From: Prospector <6166773+Prospector@users.noreply.github.com>
Date: Fri, 3 Apr 2026 13:40:40 -0700
Subject: [PATCH 3/3] begin project page permissions settings
---
apps/frontend/src/composables/featureFlags.ts | 1 +
apps/frontend/src/layouts/default.vue | 13 ++
.../src/pages/[type]/[id]/settings.vue | 10 +
.../[type]/[id]/settings/permissions.vue | 173 ++++++++++++++++++
.../pages/[type]/[id]/settings/versions.vue | 55 ++++++
packages/assets/generated-icons.ts | 2 +
packages/assets/icons/signature.svg | 16 ++
.../ui/src/components/base/Admonition.vue | 5 +-
.../ui/src/components/base/StyledInput.vue | 3 +
packages/ui/src/locales/en-US/index.json | 3 +
packages/ui/src/utils/common-messages.ts | 4 +
11 files changed, 284 insertions(+), 1 deletion(-)
create mode 100644 apps/frontend/src/pages/[type]/[id]/settings/permissions.vue
create mode 100644 packages/assets/icons/signature.svg
diff --git a/apps/frontend/src/composables/featureFlags.ts b/apps/frontend/src/composables/featureFlags.ts
index a1acb5878c..89e1a6151c 100644
--- a/apps/frontend/src/composables/featureFlags.ts
+++ b/apps/frontend/src/composables/featureFlags.ts
@@ -46,6 +46,7 @@ export const DEFAULT_FEATURE_FLAGS = validateValues({
showDiscoverProjectButtons: false,
useV1ContentTabAPI: true,
labrinthApiCanary: false,
+ dismissedExternalProjectsInfo: false,
} as const)
export type FeatureFlag = keyof typeof DEFAULT_FEATURE_FLAGS
diff --git a/apps/frontend/src/layouts/default.vue b/apps/frontend/src/layouts/default.vue
index 6ef59f08c5..5a0776a265 100644
--- a/apps/frontend/src/layouts/default.vue
+++ b/apps/frontend/src/layouts/default.vue
@@ -323,6 +323,11 @@
color: 'orange',
link: '/moderation/reports',
},
+ {
+ id: 'external-projects',
+ color: 'orange',
+ link: '/moderation/external-projects',
+ },
{
divider: true,
},
@@ -377,6 +382,9 @@
{{ formatMessage(messages.reports) }}
+
+ {{ formatMessage(messages.externalProjects) }}
+
{{ formatMessage(messages.lookupByEmail) }}
@@ -705,6 +713,7 @@ import {
DropdownIcon,
FileIcon,
GlassesIcon,
+ GlobeIcon,
HamburgerIcon,
HomeIcon,
IssuesIcon,
@@ -877,6 +886,10 @@ const messages = defineMessages({
id: 'layout.action.reports',
defaultMessage: 'Review reports',
},
+ externalProjects: {
+ id: 'layout.action.external-projects',
+ defaultMessage: 'External projects',
+ },
lookupByEmail: {
id: 'layout.action.lookup-by-email',
defaultMessage: 'Lookup by email',
diff --git a/apps/frontend/src/pages/[type]/[id]/settings.vue b/apps/frontend/src/pages/[type]/[id]/settings.vue
index 9b51e4bb8d..ccb5283955 100644
--- a/apps/frontend/src/pages/[type]/[id]/settings.vue
+++ b/apps/frontend/src/pages/[type]/[id]/settings.vue
@@ -8,6 +8,7 @@ import {
InfoIcon,
LinkIcon,
ServerIcon,
+ SignatureIcon,
TagsIcon,
UsersIcon,
VersionIcon,
@@ -46,6 +47,10 @@ const navItems = computed(() => {
projectV3.value?.project_types?.some((type) => ['mod', 'modpack'].includes(type)) &&
isStaff(currentMember.value?.user)
+ const hasPermissionsPage = computed(() =>
+ projectV3.value?.project_types?.some((type) => ['modpack'].includes(type)),
+ )
+
const items = [
{
link: `/${base}/settings`,
@@ -75,6 +80,11 @@ const navItems = computed(() => {
label: formatMessage(commonProjectSettingsMessages.description),
icon: AlignLeftIcon,
},
+ hasPermissionsPage.value && {
+ link: `/${base}/settings/permissions`,
+ label: formatMessage(commonProjectSettingsMessages.permissions),
+ icon: SignatureIcon,
+ },
!isServerProject.value && {
link: `/${base}/settings/versions`,
label: formatMessage(commonProjectSettingsMessages.versions),
diff --git a/apps/frontend/src/pages/[type]/[id]/settings/permissions.vue b/apps/frontend/src/pages/[type]/[id]/settings/permissions.vue
new file mode 100644
index 0000000000..3588672aff
--- /dev/null
+++ b/apps/frontend/src/pages/[type]/[id]/settings/permissions.vue
@@ -0,0 +1,173 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ currentSortType }}
+
+
+
+
+
+
+
+
+
+
diff --git a/apps/frontend/src/pages/[type]/[id]/settings/versions.vue b/apps/frontend/src/pages/[type]/[id]/settings/versions.vue
index 9f79d39e41..623352b3b3 100644
--- a/apps/frontend/src/pages/[type]/[id]/settings/versions.vue
+++ b/apps/frontend/src/pages/[type]/[id]/settings/versions.vue
@@ -15,6 +15,37 @@
@proceed="deleteVersion()"
/>
+
+
+
+
+
+ {{ formatMessage(messages.withheldVersionsWarningResolve) }}
+
+
+
+
+
['4.0.0'])
+
+const messages = defineMessages({
+ withheldVersionsWarningTitle: {
+ id: 'project.versions.withheld-versions-warning.title',
+ defaultMessage:
+ '{count, plural, one {Version {version_name}} other {Versions}} withheld due to unknown embedded content',
+ },
+ withheldVersionsWarningDescription: {
+ id: 'project.versions.withheld-versions-warning.description',
+ defaultMessage:
+ '{count, plural, one {This version is} other {These versions are}} currently withheld and not publicly listed. Please provide proof that you have permission to redistribute certain files included in the modpack {count, plural, one {version} other {versions}}.',
+ },
+ withheldVersionsWarningResolve: {
+ id: 'project.versions.withheld-versions-warning.resolve-button',
+ defaultMessage: 'Resolve',
+ },
+})
diff --git a/packages/assets/generated-icons.ts b/packages/assets/generated-icons.ts
index 2afa15e0b0..f6a88776bb 100644
--- a/packages/assets/generated-icons.ts
+++ b/packages/assets/generated-icons.ts
@@ -210,6 +210,7 @@ import _ShieldIcon from './icons/shield.svg?component'
import _ShieldAlertIcon from './icons/shield-alert.svg?component'
import _ShieldCheckIcon from './icons/shield-check.svg?component'
import _SignalIcon from './icons/signal.svg?component'
+import _SignatureIcon from './icons/signature.svg?component'
import _SkullIcon from './icons/skull.svg?component'
import _SlashIcon from './icons/slash.svg?component'
import _SortAscIcon from './icons/sort-asc.svg?component'
@@ -598,6 +599,7 @@ export const ShieldIcon = _ShieldIcon
export const ShieldAlertIcon = _ShieldAlertIcon
export const ShieldCheckIcon = _ShieldCheckIcon
export const SignalIcon = _SignalIcon
+export const SignatureIcon = _SignatureIcon
export const SkullIcon = _SkullIcon
export const SlashIcon = _SlashIcon
export const SortAscIcon = _SortAscIcon
diff --git a/packages/assets/icons/signature.svg b/packages/assets/icons/signature.svg
new file mode 100644
index 0000000000..298ef3587f
--- /dev/null
+++ b/packages/assets/icons/signature.svg
@@ -0,0 +1,16 @@
+
+
diff --git a/packages/ui/src/components/base/Admonition.vue b/packages/ui/src/components/base/Admonition.vue
index 90a3178b14..5094289fd0 100644
--- a/packages/ui/src/components/base/Admonition.vue
+++ b/packages/ui/src/components/base/Admonition.vue
@@ -27,7 +27,10 @@
{{ header }}