fix: toggle

This commit is contained in:
Calum H. (IMB11)
2026-08-31 17:53:19 +01:00
parent fc4b626915
commit 5e342fe509
5 changed files with 64 additions and 31 deletions
@@ -54,10 +54,6 @@ const messages = defineMessages({
id: 'content.card.frozen',
defaultMessage: 'This project is locked to its current version until unfrozen.',
},
useEnabledForControls: {
id: 'content.card.use-enabled-for-controls',
defaultMessage: 'Use the Enabled for controls to enable or disable this content.',
},
})
interface Props {
@@ -141,16 +137,8 @@ const versionNumberRef = ref<HTMLElement | null>(null)
const fileNameRef = ref<HTMLElement | null>(null)
const isDisabled = computed(() => props.disabled || props.installing)
const isToggleIndeterminate = computed(
() => props.enabledFor !== undefined && props.enabledFor.server !== props.enabledFor.player,
)
const isToggleDisabled = computed(
() => isDisabled.value || props.toggleDisabled || isToggleIndeterminate.value,
)
const isToggleDisabled = computed(() => isDisabled.value || props.toggleDisabled)
const toggleTooltip = computed(() => {
if (isToggleIndeterminate.value) {
return formatMessage(messages.useEnabledForControls)
}
if (!isToggleDisabled.value) return undefined
return props.toggleDisabledTooltip ?? props.disabledTooltip ?? undefined
})
@@ -186,7 +174,8 @@ const installTooltip = computed(() => {
'gap-3': inline,
'justify-between': !enabledFor,
'opacity-50 grayscale': disabled && !installing,
'opacity-50': installing || (enabledFor && isEnabledForDisabled && !disabled),
'opacity-50':
installing || (enabledFor && (isEnabledForDisabled || enabled === false) && !disabled),
}"
>
<div
@@ -444,7 +433,6 @@ const installTooltip = computed(() => {
v-tooltip="toggleTooltip"
:model-value="enabled"
:disabled="isToggleDisabled"
:indeterminate="isToggleIndeterminate"
:aria-label="project.title"
class="my-auto"
@update:model-value="(val) => emit('update:enabled', val as boolean)"
@@ -24,7 +24,8 @@ const messages = defineMessages({
},
enabledForDescription: {
id: 'content.enabled-for.description',
defaultMessage: 'Choose where this content is enabled. Turn both off to disable it.',
defaultMessage:
'Choose where this content is enabled. Use the Actions toggle to enable or disable it entirely.',
},
})
@@ -750,7 +750,7 @@ async function confirmDisable() {
if (itemsToDisable.length === 1) {
const item = itemsToDisable[0]
const id = getItemId(item)
if (!item.enabledFor) markChanging(id)
markChanging(id)
try {
if (ctx.bulkDisableItems) {
await ctx.bulkDisableItems(itemsToDisable)
@@ -758,7 +758,7 @@ async function confirmDisable() {
await ctx.toggleEnabled?.(item)
}
} finally {
if (!item.enabledFor) unmarkChanging(id)
unmarkChanging(id)
}
return
}
@@ -777,11 +777,11 @@ async function handleToggleEnabledById(id: string, _value: boolean) {
await promptDisableItems([item])
return
}
if (!item.enabledFor) markChanging(id)
markChanging(id)
try {
await ctx.toggleEnabled(item)
} finally {
if (!item.enabledFor) unmarkChanging(id)
unmarkChanging(id)
}
}
@@ -64,6 +64,10 @@ const messages = defineMessages({
id: 'hosting.content.failed-to-remove',
defaultMessage: 'Failed to remove content',
},
failedToToggle: {
id: 'hosting.content.failed-to-toggle',
defaultMessage: 'Failed to enable or disable {name}',
},
failedToSetEnabledFor: {
id: 'hosting.content.failed-to-set-enabled-for',
defaultMessage: 'Failed to change where {name} is enabled',
@@ -622,6 +626,53 @@ const deleteMutation = useMutation({
},
})
const toggleEnabledMutation = useMutation({
mutationFn: async ({ addon, enabled }: { addon: Archon.Content.v1.Addon; enabled: boolean }) => {
const request: Archon.Content.v1.RemoveAddonRequest = {
filename: addon.filename,
kind: addon.kind,
}
if (enabled) {
await client.archon.content_v1.enableAddon(serverId, worldId.value!, request)
} else {
await client.archon.content_v1.disableAddon(serverId, worldId.value!, request)
}
},
onMutate: async ({ addon, enabled }) => {
const targetQueryKey = getAddonQueryKey(addon)
await queryClient.cancelQueries({ queryKey: targetQueryKey })
const previousData = queryClient.getQueryData<Archon.Content.v1.Addons>(targetQueryKey)
queryClient.setQueryData(targetQueryKey, (oldData: Archon.Content.v1.Addons | undefined) => {
if (!oldData) return oldData
return {
...oldData,
addons: (oldData.addons ?? []).map((candidate) =>
candidate.filename === addon.filename && candidate.kind === addon.kind
? { ...candidate, disabled: !enabled }
: candidate,
),
}
})
return { previousData, targetQueryKey }
},
onError: (error, { addon }, context) => {
if (context?.previousData) {
queryClient.setQueryData(context.targetQueryKey, context.previousData)
}
addNotification({
type: 'error',
title: formatMessage(messages.failedToToggle, {
name: friendlyAddonName(addon),
}),
text: error instanceof Error ? error.message : undefined,
})
},
onSettled: () => {
void queryClient.invalidateQueries({ queryKey: queryKey.value })
void queryClient.invalidateQueries({ queryKey: modpackContentQueryKey.value })
},
})
type SetEnabledForVariables = {
addon: Archon.Content.v1.Addon
sides: ContentSide[]
@@ -733,15 +784,10 @@ async function handleSetEnabledFor(item: ContentItem, side: ContentSide, enabled
}
async function handleToggleEnabled(item: ContentItem) {
if (contentActionDisabled.value || !item.enabledFor) return
if (item.enabledFor.server !== item.enabledFor.player) return
if (contentActionDisabled.value) return
const addon = getAddonForItem(item)
if (!addon) return
await setEnabledForMutation.mutateAsync({
addon,
sides: ['server', 'player'],
enabled: !item.enabledFor.server,
})
await toggleEnabledMutation.mutateAsync({ addon, enabled: addon.disabled })
}
async function handleModpackSetEnabledFor(item: ContentItem, side: ContentSide, enabled: boolean) {
@@ -1000,7 +1046,7 @@ function addonToContentItem(addon: AddonWithUiState): ContentItem {
id: addon.id ?? addon.filename,
external: !addon.project_id,
source_kind: addon.from_modpack ? 'modrinth_modpack' : undefined,
enabled: serverEnabled || playerEnabled,
enabled: !addon.disabled,
enabledFor: {
server: serverEnabled,
player: playerEnabled,
@@ -1320,8 +1366,6 @@ provideContentManager({
contentTypeLabel: type,
toggleEnabled: handleToggleEnabled,
setEnabledFor: handleSetEnabledFor,
canToggleItem: (item) =>
item.enabledFor !== undefined && item.enabledFor.server === item.enabledFor.player,
deleteItem: handleDeleteItem,
bulkDeleteItems: handleBulkDelete,
refresh: async () => {
+1 -1
View File
@@ -491,7 +491,7 @@ export const commonMessages = defineMessages({
clientRetainedWarning: {
id: 'label.client-retained-warning',
defaultMessage:
'This is a client-side mod that was installed as a dependency and may cause issues when starting your server',
'This client-side mod was also installed on the server because another mod depends on it',
},
clientDependsWarning: {
id: 'label.client-depends-warning',