feat: move switch version inline like update btn for content tab (#5631)
* fix: switch version inline same as update btn * fix: lint
This commit is contained in:
@@ -86,9 +86,6 @@
|
|||||||
"app.instance.mods.successfully-uploaded": {
|
"app.instance.mods.successfully-uploaded": {
|
||||||
"message": "Successfully uploaded"
|
"message": "Successfully uploaded"
|
||||||
},
|
},
|
||||||
"app.instance.mods.switch-version": {
|
|
||||||
"message": "Switch version"
|
|
||||||
},
|
|
||||||
"app.instance.mods.unknown-version": {
|
"app.instance.mods.unknown-version": {
|
||||||
"message": "Unknown"
|
"message": "Unknown"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -63,7 +63,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Labrinth } from '@modrinth/api-client'
|
import type { Labrinth } from '@modrinth/api-client'
|
||||||
import { ArrowLeftRightIcon, ClipboardCopyIcon, FolderOpenIcon } from '@modrinth/assets'
|
import { ClipboardCopyIcon, FolderOpenIcon } from '@modrinth/assets'
|
||||||
import {
|
import {
|
||||||
ConfirmModpackUpdateModal,
|
ConfirmModpackUpdateModal,
|
||||||
type ContentItem,
|
type ContentItem,
|
||||||
@@ -165,10 +165,6 @@ const messages = defineMessages({
|
|||||||
id: 'app.instance.mods.copy-link',
|
id: 'app.instance.mods.copy-link',
|
||||||
defaultMessage: 'Copy link',
|
defaultMessage: 'Copy link',
|
||||||
},
|
},
|
||||||
switchVersion: {
|
|
||||||
id: 'app.instance.mods.switch-version',
|
|
||||||
defaultMessage: 'Switch version',
|
|
||||||
},
|
|
||||||
})
|
})
|
||||||
|
|
||||||
let savedModalState: ModpackContentModalState | null = null
|
let savedModalState: ModpackContentModalState | null = null
|
||||||
@@ -386,7 +382,7 @@ async function switchProjectVersion(mod: ContentItem, version: Labrinth.Versions
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function handleUpdate(id: string) {
|
async function handleUpdate(id: string) {
|
||||||
const item = projects.value.find((p) => p.file_name === id)
|
const item = projects.value.find((p) => p.id === id)
|
||||||
if (!item?.has_update || !item.project?.id || !item.version?.id) return
|
if (!item?.has_update || !item.project?.id || !item.version?.id) return
|
||||||
|
|
||||||
debug('handleUpdate triggered', {
|
debug('handleUpdate triggered', {
|
||||||
@@ -663,14 +659,6 @@ async function handleShareItems(
|
|||||||
function getOverflowOptions(item: ContentItem): OverflowMenuOption[] {
|
function getOverflowOptions(item: ContentItem): OverflowMenuOption[] {
|
||||||
const options: OverflowMenuOption[] = []
|
const options: OverflowMenuOption[] = []
|
||||||
|
|
||||||
if (item.project?.id && item.version?.id && !item.has_update) {
|
|
||||||
options.push({
|
|
||||||
id: formatMessage(messages.switchVersion),
|
|
||||||
icon: ArrowLeftRightIcon,
|
|
||||||
action: () => handleSwitchVersion(item),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
options.push({
|
options.push({
|
||||||
id: formatMessage(messages.showFile),
|
id: formatMessage(messages.showFile),
|
||||||
icon: FolderOpenIcon,
|
icon: FolderOpenIcon,
|
||||||
@@ -837,6 +825,7 @@ provideContentManager({
|
|||||||
viewModpackContent: handleModpackContent,
|
viewModpackContent: handleModpackContent,
|
||||||
unlinkModpack: unpairProfile,
|
unlinkModpack: unpairProfile,
|
||||||
openSettings: props.openSettings,
|
openSettings: props.openSettings,
|
||||||
|
switchVersion: handleSwitchVersion,
|
||||||
getOverflowOptions,
|
getOverflowOptions,
|
||||||
showContentHint,
|
showContentHint,
|
||||||
dismissContentHint,
|
dismissContentHint,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import {
|
import {
|
||||||
|
ArrowLeftRightIcon,
|
||||||
DownloadIcon,
|
DownloadIcon,
|
||||||
MoreVerticalIcon,
|
MoreVerticalIcon,
|
||||||
SpinnerIcon,
|
SpinnerIcon,
|
||||||
@@ -67,11 +68,15 @@ const emit = defineEmits<{
|
|||||||
'update:enabled': [value: boolean]
|
'update:enabled': [value: boolean]
|
||||||
delete: [event: MouseEvent]
|
delete: [event: MouseEvent]
|
||||||
update: []
|
update: []
|
||||||
|
switchVersion: []
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
const hasDeleteListener = computed(() => typeof instance?.vnode.props?.onDelete === 'function')
|
const hasDeleteListener = computed(() => typeof instance?.vnode.props?.onDelete === 'function')
|
||||||
const hasUpdateListener = computed(() => typeof instance?.vnode.props?.onUpdate === 'function')
|
const hasUpdateListener = computed(() => typeof instance?.vnode.props?.onUpdate === 'function')
|
||||||
|
const hasSwitchVersionListener = computed(
|
||||||
|
() => typeof instance?.vnode.props?.onSwitchVersion === 'function',
|
||||||
|
)
|
||||||
|
|
||||||
const versionNumberRef = ref<HTMLElement | null>(null)
|
const versionNumberRef = ref<HTMLElement | null>(null)
|
||||||
const fileNameRef = ref<HTMLElement | null>(null)
|
const fileNameRef = ref<HTMLElement | null>(null)
|
||||||
@@ -232,8 +237,11 @@ const deleteHovered = ref(false)
|
|||||||
>
|
>
|
||||||
<slot name="additionalButtonsLeft" />
|
<slot name="additionalButtonsLeft" />
|
||||||
|
|
||||||
<!-- Fixed width container to reserve space for update button -->
|
<!-- Fixed width container to reserve space for update/switch version button -->
|
||||||
<div v-if="hasUpdateListener" class="flex w-8 items-center justify-center">
|
<div
|
||||||
|
v-if="hasUpdateListener || hasSwitchVersionListener"
|
||||||
|
class="flex w-8 items-center justify-center"
|
||||||
|
>
|
||||||
<ButtonStyled
|
<ButtonStyled
|
||||||
v-if="hasUpdate"
|
v-if="hasUpdate"
|
||||||
circular
|
circular
|
||||||
@@ -250,6 +258,15 @@ const deleteHovered = ref(false)
|
|||||||
<DownloadIcon class="size-5" />
|
<DownloadIcon class="size-5" />
|
||||||
</button>
|
</button>
|
||||||
</ButtonStyled>
|
</ButtonStyled>
|
||||||
|
<ButtonStyled v-else-if="hasSwitchVersionListener && version" circular type="transparent">
|
||||||
|
<button
|
||||||
|
v-tooltip="formatMessage(commonMessages.switchVersionButton)"
|
||||||
|
:disabled="disabled"
|
||||||
|
@click="emit('switchVersion')"
|
||||||
|
>
|
||||||
|
<ArrowLeftRightIcon class="size-5" />
|
||||||
|
</button>
|
||||||
|
</ButtonStyled>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Toggle
|
<Toggle
|
||||||
|
|||||||
@@ -49,6 +49,7 @@ const emit = defineEmits<{
|
|||||||
'update:enabled': [id: string, value: boolean]
|
'update:enabled': [id: string, value: boolean]
|
||||||
delete: [id: string, event: MouseEvent]
|
delete: [id: string, event: MouseEvent]
|
||||||
update: [id: string]
|
update: [id: string]
|
||||||
|
switchVersion: [id: string]
|
||||||
sort: [column: ContentCardTableSortColumn, direction: ContentCardTableSortDirection]
|
sort: [column: ContentCardTableSortColumn, direction: ContentCardTableSortDirection]
|
||||||
}>()
|
}>()
|
||||||
|
|
||||||
@@ -56,6 +57,9 @@ const emit = defineEmits<{
|
|||||||
const instance = getCurrentInstance()
|
const instance = getCurrentInstance()
|
||||||
const hasDeleteListener = computed(() => typeof instance?.vnode.props?.onDelete === 'function')
|
const hasDeleteListener = computed(() => typeof instance?.vnode.props?.onDelete === 'function')
|
||||||
const hasUpdateListener = computed(() => typeof instance?.vnode.props?.onUpdate === 'function')
|
const hasUpdateListener = computed(() => typeof instance?.vnode.props?.onUpdate === 'function')
|
||||||
|
const hasSwitchVersionListener = computed(
|
||||||
|
() => typeof instance?.vnode.props?.onSwitchVersion === 'function',
|
||||||
|
)
|
||||||
const hasEnabledListener = computed(
|
const hasEnabledListener = computed(
|
||||||
() => typeof instance?.vnode.props?.['onUpdate:enabled'] === 'function',
|
() => typeof instance?.vnode.props?.['onUpdate:enabled'] === 'function',
|
||||||
)
|
)
|
||||||
@@ -65,6 +69,7 @@ const hasAnyActions = computed(() => {
|
|||||||
const hasListeners =
|
const hasListeners =
|
||||||
(hasDeleteListener.value && !props.hideDelete) ||
|
(hasDeleteListener.value && !props.hideDelete) ||
|
||||||
hasUpdateListener.value ||
|
hasUpdateListener.value ||
|
||||||
|
hasSwitchVersionListener.value ||
|
||||||
hasEnabledListener.value
|
hasEnabledListener.value
|
||||||
|
|
||||||
// Check if any items have overflow options or updates
|
// Check if any items have overflow options or updates
|
||||||
@@ -294,6 +299,7 @@ function handleSort(column: ContentCardTableSortColumn) {
|
|||||||
@update:enabled="(val) => emit('update:enabled', item.id, val)"
|
@update:enabled="(val) => emit('update:enabled', item.id, val)"
|
||||||
@delete="(e: MouseEvent) => emit('delete', item.id, e)"
|
@delete="(e: MouseEvent) => emit('delete', item.id, e)"
|
||||||
@update="emit('update', item.id)"
|
@update="emit('update', item.id)"
|
||||||
|
@switch-version="emit('switchVersion', item.id)"
|
||||||
>
|
>
|
||||||
<template #additionalButtonsLeft>
|
<template #additionalButtonsLeft>
|
||||||
<slot name="itemButtonsLeft" :item="item" :index="visibleRange.start + idx" />
|
<slot name="itemButtonsLeft" :item="item" :index="visibleRange.start + idx" />
|
||||||
@@ -342,6 +348,7 @@ function handleSort(column: ContentCardTableSortColumn) {
|
|||||||
@update:enabled="(val) => emit('update:enabled', item.id, val)"
|
@update:enabled="(val) => emit('update:enabled', item.id, val)"
|
||||||
@delete="(e: MouseEvent) => emit('delete', item.id, e)"
|
@delete="(e: MouseEvent) => emit('delete', item.id, e)"
|
||||||
@update="emit('update', item.id)"
|
@update="emit('update', item.id)"
|
||||||
|
@switch-version="emit('switchVersion', item.id)"
|
||||||
>
|
>
|
||||||
<template #additionalButtonsLeft>
|
<template #additionalButtonsLeft>
|
||||||
<slot name="itemButtonsLeft" :item="item" :index="index" />
|
<slot name="itemButtonsLeft" :item="item" :index="index" />
|
||||||
|
|||||||
@@ -407,6 +407,13 @@ function handleUpdateById(id: string) {
|
|||||||
ctx.updateItem?.(id)
|
ctx.updateItem?.(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleSwitchVersionById(id: string) {
|
||||||
|
const item = ctx.items.value.find((i) => i.id === id)
|
||||||
|
if (item) {
|
||||||
|
ctx.switchVersion?.(item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Bulk updating
|
// Bulk updating
|
||||||
const confirmBulkUpdateModal = ref<InstanceType<typeof ConfirmBulkUpdateModal>>()
|
const confirmBulkUpdateModal = ref<InstanceType<typeof ConfirmBulkUpdateModal>>()
|
||||||
const pendingBulkUpdateItems = ref<ContentItem[]>([])
|
const pendingBulkUpdateItems = ref<ContentItem[]>([])
|
||||||
@@ -705,6 +712,7 @@ const confirmUnlinkModal = ref<InstanceType<typeof ConfirmUnlinkModal>>()
|
|||||||
@update:enabled="handleToggleEnabledById"
|
@update:enabled="handleToggleEnabledById"
|
||||||
@delete="handleDeleteById"
|
@delete="handleDeleteById"
|
||||||
@update="handleUpdateById"
|
@update="handleUpdateById"
|
||||||
|
@switch-version="handleSwitchVersionById"
|
||||||
>
|
>
|
||||||
<template #empty>
|
<template #empty>
|
||||||
<span>{{ formatMessage(messages.noContentFound) }}</span>
|
<span>{{ formatMessage(messages.noContentFound) }}</span>
|
||||||
|
|||||||
@@ -78,6 +78,9 @@ export interface ContentManagerContext {
|
|||||||
unlinkModpack?: () => void
|
unlinkModpack?: () => void
|
||||||
openSettings?: () => void
|
openSettings?: () => void
|
||||||
|
|
||||||
|
// Switch version (optional)
|
||||||
|
switchVersion?: (item: ContentItem) => void
|
||||||
|
|
||||||
// Per-item overflow menu (optional)
|
// Per-item overflow menu (optional)
|
||||||
getOverflowOptions?: (item: ContentItem) => OverflowMenuOption[]
|
getOverflowOptions?: (item: ContentItem) => OverflowMenuOption[]
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Archon, Labrinth } from '@modrinth/api-client'
|
import type { Archon, Labrinth } from '@modrinth/api-client'
|
||||||
import { ArrowLeftRightIcon, ClipboardCopyIcon } from '@modrinth/assets'
|
import { ClipboardCopyIcon } from '@modrinth/assets'
|
||||||
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
||||||
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
|
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
|
||||||
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
|
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
|
||||||
@@ -78,10 +78,6 @@ const messages = defineMessages({
|
|||||||
id: 'hosting.content.failed-to-bulk-update',
|
id: 'hosting.content.failed-to-bulk-update',
|
||||||
defaultMessage: 'Failed to update content',
|
defaultMessage: 'Failed to update content',
|
||||||
},
|
},
|
||||||
switchVersion: {
|
|
||||||
id: 'hosting.content.switch-version',
|
|
||||||
defaultMessage: 'Switch version',
|
|
||||||
},
|
|
||||||
copyLink: {
|
copyLink: {
|
||||||
id: 'hosting.content.copy-link',
|
id: 'hosting.content.copy-link',
|
||||||
defaultMessage: 'Copy link',
|
defaultMessage: 'Copy link',
|
||||||
@@ -823,15 +819,7 @@ function handleModpackUpdateCancel() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getOverflowOptions(item: ContentItem) {
|
function getOverflowOptions(item: ContentItem) {
|
||||||
const options: { id: string; icon?: typeof ArrowLeftRightIcon; action: () => void }[] = []
|
const options: { id: string; icon?: typeof ClipboardCopyIcon; action: () => void }[] = []
|
||||||
|
|
||||||
if (item.project?.id && item.version?.id && !item.has_update) {
|
|
||||||
options.push({
|
|
||||||
id: formatMessage(messages.switchVersion),
|
|
||||||
icon: ArrowLeftRightIcon,
|
|
||||||
action: () => handleSwitchVersion(item),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if (item.project?.slug) {
|
if (item.project?.slug) {
|
||||||
options.push({
|
options.push({
|
||||||
@@ -894,6 +882,7 @@ provideContentManager({
|
|||||||
viewModpackContent: handleViewModpackContent,
|
viewModpackContent: handleViewModpackContent,
|
||||||
unlinkModpack: handleModpackUnlink,
|
unlinkModpack: handleModpackUnlink,
|
||||||
openSettings: () => router.push(`/hosting/manage/${serverId}/options/loader`),
|
openSettings: () => router.push(`/hosting/manage/${serverId}/options/loader`),
|
||||||
|
switchVersion: handleSwitchVersion,
|
||||||
getOverflowOptions,
|
getOverflowOptions,
|
||||||
mapToTableItem: (item) => {
|
mapToTableItem: (item) => {
|
||||||
const projectType = item.project_type ?? type.value
|
const projectType = item.project_type ?? type.value
|
||||||
|
|||||||
@@ -554,9 +554,6 @@
|
|||||||
"hosting.content.failed-to-upload": {
|
"hosting.content.failed-to-upload": {
|
||||||
"defaultMessage": "Failed to upload file"
|
"defaultMessage": "Failed to upload file"
|
||||||
},
|
},
|
||||||
"hosting.content.switch-version": {
|
|
||||||
"defaultMessage": "Switch version"
|
|
||||||
},
|
|
||||||
"hosting.specs.burst": {
|
"hosting.specs.burst": {
|
||||||
"defaultMessage": "Bursts up to {cpus} CPUs"
|
"defaultMessage": "Bursts up to {cpus} CPUs"
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user