Sync source to CNB / Sync Git ref (push) Has been cancelled
搬入 game-settings-modal(游戏选项精细编辑,10 文件):设置行编辑器、按键绑定、语言选择与文案表。新增 app-settings-modal provider 与 instance-settings-context 转发,并把 instance-settings 的 closeModal 改为支持关闭回调。SyncSettings 恢复游戏设置入口。补齐 game-options 相关 en-US / zh-CN 文案。
619 lines
21 KiB
Vue
619 lines
21 KiB
Vue
<script setup lang="ts">
|
|
import { EditIcon } from '@modrinth/assets'
|
|
import {
|
|
commonMessages,
|
|
defineMessages,
|
|
IconButton,
|
|
injectNotificationManager,
|
|
Toggle,
|
|
useVIntl,
|
|
} from '@modrinth/ui'
|
|
import { useMutation, useQuery, useQueryClient } from '@tanstack/vue-query'
|
|
import { computed, nextTick, onScopeDispose, ref } from 'vue'
|
|
|
|
import { gameSettingsKeys } from '@/helpers/game-options'
|
|
import {
|
|
type GlobalSyncedOptions,
|
|
isSyncedOptionAvailable,
|
|
set_global_synced_option,
|
|
type SyncedOption,
|
|
} from '@/helpers/instance'
|
|
import {
|
|
canSourceMultiplayerServers,
|
|
gameOptionsSyncSourcesQueryOptions,
|
|
globalSyncedOptionsQueryOptions,
|
|
initializedSyncedOptionsQueryOptions,
|
|
syncedOptionsKeys,
|
|
syncedServersQueryOptions,
|
|
} from '@/helpers/synced-options'
|
|
import { syncedPackKeys, syncedPackQueryOptions } from '@/helpers/synced-packs'
|
|
import { instanceKeys, instanceListQueryOptions } from '@/pages/instance/query-options'
|
|
|
|
import SettingsRow from '../settings/SettingsRow.vue'
|
|
import SettingsSection from '../settings/SettingsSection.vue'
|
|
import CommandHistoryModal from '../settings/instances/command-history-modal.vue'
|
|
import SyncedServersModal from '../settings/instances/servers-modal.vue'
|
|
import SyncedPacksModal from '../settings/instances/SyncedPacksModal.vue'
|
|
import SyncSourceModal from '../settings/instances/SyncSourceModal.vue'
|
|
import GameSettingsModal from '../settings/instances/game-settings-modal/index.vue'
|
|
|
|
const { handleError } = injectNotificationManager()
|
|
const { formatMessage } = useVIntl()
|
|
const queryClient = useQueryClient()
|
|
const syncedPacksModal = ref<InstanceType<typeof SyncedPacksModal>>()
|
|
const commandHistoryModal = ref<InstanceType<typeof CommandHistoryModal>>()
|
|
const syncedServersModal = ref<InstanceType<typeof SyncedServersModal>>()
|
|
const gameSettingsModal = ref<InstanceType<typeof GameSettingsModal> | null>(null)
|
|
|
|
const messages = defineMessages({
|
|
globalOptionsTitle: {
|
|
id: 'app.settings.synced-options.title',
|
|
defaultMessage: 'Options synced across all instances',
|
|
},
|
|
resourcePacks: {
|
|
id: 'app.settings.synced-options.resource-packs',
|
|
defaultMessage: 'Sync resource packs',
|
|
},
|
|
resourcePacksDescription: {
|
|
id: 'app.settings.synced-options.resource-packs.description',
|
|
defaultMessage: 'Use the same resource packs across your instances.',
|
|
},
|
|
dataPacks: { id: 'app.settings.synced-options.data-packs', defaultMessage: 'Sync data packs' },
|
|
dataPacksDescription: {
|
|
id: 'app.settings.synced-options.data-packs.description',
|
|
defaultMessage: 'Use the same datapacks across your instances',
|
|
},
|
|
packsDisabled: {
|
|
id: 'app.settings.synced-options.packs.disabled',
|
|
defaultMessage: 'Enable syncing before editing shared packs.',
|
|
},
|
|
gameSettings: {
|
|
id: 'app.settings.synced-options.game-settings',
|
|
defaultMessage: 'Sync game options',
|
|
},
|
|
gameSettingsDescription: {
|
|
id: 'app.settings.synced-options.game-settings.description',
|
|
defaultMessage: 'Use the same game options across your instances.',
|
|
},
|
|
gameSettingsButton: {
|
|
id: 'app.settings.synced-options.game-settings.button',
|
|
defaultMessage: 'Edit game settings',
|
|
},
|
|
gameSettingsDisabledTooltip: {
|
|
id: 'app.settings.synced-options.game-settings.disabled-tooltip',
|
|
defaultMessage: 'Enable game settings sync before choosing individual settings.',
|
|
},
|
|
noGameOptionsToEdit: {
|
|
id: 'app.settings.synced-options.game-settings.no-options-to-edit',
|
|
defaultMessage: "You haven't got any options yet to edit",
|
|
},
|
|
multiplayerServers: {
|
|
id: 'app.settings.synced-options.multiplayer-servers',
|
|
defaultMessage: 'Sync multiplayer servers',
|
|
},
|
|
multiplayerServersDescription: {
|
|
id: 'app.settings.synced-options.multiplayer-servers.description',
|
|
defaultMessage: 'Use the same multiplayer servers across your instances.',
|
|
},
|
|
commandHistory: {
|
|
id: 'app.settings.synced-options.command-history',
|
|
defaultMessage: 'Sync command history',
|
|
},
|
|
commandHistoryDescription: {
|
|
id: 'app.settings.synced-options.command-history.description',
|
|
defaultMessage: 'Use the same command history across your instances.',
|
|
},
|
|
creativeHotbars: {
|
|
id: 'app.settings.synced-options.creative-hotbars',
|
|
defaultMessage: 'Sync saved creative hotbars',
|
|
},
|
|
creativeHotbarsDescription: {
|
|
id: 'app.settings.synced-options.creative-hotbars.description',
|
|
defaultMessage: 'Use the same saved creative hotbars across your instances.',
|
|
},
|
|
gameSettingsSyncSourceTitle: {
|
|
id: 'app.settings.synced-options.choose-sync-source.game-settings-title',
|
|
defaultMessage: 'Choose game settings source',
|
|
},
|
|
multiplayerServersSyncSourceDescription: {
|
|
id: 'app.settings.synced-options.choose-sync-source.multiplayer-servers-description',
|
|
defaultMessage:
|
|
'Choose which instance to copy your multiplayer servers from. These servers are only used for the initial sync, and you can edit them from any instance afterward.',
|
|
},
|
|
multiplayerServersSyncSourceTitle: {
|
|
id: 'app.settings.synced-options.choose-sync-source.multiplayer-servers-title',
|
|
defaultMessage: 'Choose multiplayer servers source',
|
|
},
|
|
commandHistorySyncSourceDescription: {
|
|
id: 'app.settings.synced-options.choose-sync-source.command-history-description',
|
|
defaultMessage:
|
|
'Choose which instance to copy your command history from. This history is only used for the initial sync, and you can edit it from any instance afterward.',
|
|
},
|
|
commandHistorySyncSourceTitle: {
|
|
id: 'app.settings.synced-options.choose-sync-source.command-history-title',
|
|
defaultMessage: 'Choose command history source',
|
|
},
|
|
creativeHotbarsSyncSourceDescription: {
|
|
id: 'app.settings.synced-options.choose-sync-source.creative-hotbars-description',
|
|
defaultMessage:
|
|
'Choose which instance to copy your saved creative hotbars from. These hotbars are only used for the initial sync, and you can edit them from any instance afterward.',
|
|
},
|
|
creativeHotbarsSyncSourceTitle: {
|
|
id: 'app.settings.synced-options.choose-sync-source.creative-hotbars-title',
|
|
defaultMessage: 'Choose creative hotbars source',
|
|
},
|
|
gameSettingsSyncSourceDescription: {
|
|
id: 'app.settings.synced-options.choose-sync-source.game-settings-description',
|
|
defaultMessage:
|
|
'Choose which instance to copy your game settings from. These settings are only used for the initial sync, and you can edit them from any instance afterward.',
|
|
},
|
|
resourcePacksSyncSourceTitle: {
|
|
id: 'app.settings.synced-options.choose-sync-source.resource-packs-title',
|
|
defaultMessage: 'Choose resource packs source',
|
|
},
|
|
resourcePacksSyncSourceDescription: {
|
|
id: 'app.sync-instances-update.choose-source.resource-packs',
|
|
defaultMessage:
|
|
'Choose which instance to copy your resource packs from. These packs are only used for the initial sync, and you can edit them from any instance afterward.',
|
|
},
|
|
dataPacksSyncSourceTitle: {
|
|
id: 'app.settings.synced-options.choose-sync-source.data-packs-title',
|
|
defaultMessage: 'Choose data packs source',
|
|
},
|
|
dataPacksSyncSourceDescription: {
|
|
id: 'app.sync-instances-update.choose-source.data-packs',
|
|
defaultMessage:
|
|
'Choose which instance to copy your data packs from. These packs are only used for the initial sync, and you can edit them from any instance afterward.',
|
|
},
|
|
noServersSyncedYet: {
|
|
id: 'app.settings.synced-options.multiplayer-servers.none-synced-yet',
|
|
defaultMessage: "You haven't synced any servers yet",
|
|
},
|
|
noResourcePacksSyncedYet: {
|
|
id: 'app.settings.synced-options.resource-packs.none-synced-yet',
|
|
defaultMessage: "You haven't synced any resource packs yet",
|
|
},
|
|
noDataPacksSyncedYet: {
|
|
id: 'app.settings.synced-options.data-packs.none-synced-yet',
|
|
defaultMessage: "You haven't synced any data packs yet",
|
|
},
|
|
noInstancesToEdit: {
|
|
id: 'app.settings.synced-options.edit.no-instances',
|
|
defaultMessage: 'Add an instance before editing synced data.',
|
|
},
|
|
noSyncedDataToEdit: {
|
|
id: 'app.settings.synced-options.edit.no-synced-data',
|
|
defaultMessage: 'Choose a sync source before editing this setting.',
|
|
},
|
|
})
|
|
|
|
const globalRows: Array<{
|
|
option: SyncedOption
|
|
title: keyof typeof messages
|
|
description?: keyof typeof messages
|
|
editable?: 'game-settings' | 'servers' | 'commands' | 'resourcepack' | 'datapack'
|
|
}> = [
|
|
{
|
|
option: 'game_options',
|
|
title: 'gameSettings',
|
|
description: 'gameSettingsDescription',
|
|
editable: 'game-settings',
|
|
},
|
|
{
|
|
option: 'multiplayer_servers',
|
|
title: 'multiplayerServers',
|
|
description: 'multiplayerServersDescription',
|
|
editable: 'servers',
|
|
},
|
|
{
|
|
option: 'resource_packs',
|
|
title: 'resourcePacks',
|
|
description: 'resourcePacksDescription',
|
|
editable: 'resourcepack',
|
|
},
|
|
{
|
|
option: 'data_packs',
|
|
title: 'dataPacks',
|
|
description: 'dataPacksDescription',
|
|
editable: 'datapack',
|
|
},
|
|
{
|
|
option: 'command_history',
|
|
title: 'commandHistory',
|
|
description: 'commandHistoryDescription',
|
|
editable: 'commands',
|
|
},
|
|
{
|
|
option: 'creative_hotbars',
|
|
title: 'creativeHotbars',
|
|
description: 'creativeHotbarsDescription',
|
|
},
|
|
]
|
|
|
|
const availableGlobalRows = globalRows.filter((row) => isSyncedOptionAvailable(row.option))
|
|
|
|
const defaultGlobalOptions: GlobalSyncedOptions = {
|
|
resource_packs: false,
|
|
data_packs: false,
|
|
game_options: false,
|
|
command_history: false,
|
|
multiplayer_servers: false,
|
|
creative_hotbars: false,
|
|
screenshots: false,
|
|
}
|
|
|
|
const globalOptionsQuery = useQuery(globalSyncedOptionsQueryOptions())
|
|
const initializedOptionsQuery = useQuery(initializedSyncedOptionsQueryOptions())
|
|
const gameOptionSourcesQuery = useQuery(gameOptionsSyncSourcesQueryOptions())
|
|
const resourcePacksQuery = useQuery(syncedPackQueryOptions('resourcepack'))
|
|
const dataPacksQuery = useQuery(syncedPackQueryOptions('datapack'))
|
|
const globalOptions = computed(() => globalOptionsQuery.data.value ?? defaultGlobalOptions)
|
|
const initializedOptions = computed(
|
|
() => initializedOptionsQuery.data.value ?? defaultGlobalOptions,
|
|
)
|
|
const gameOptionSources = computed(() => gameOptionSourcesQuery.data.value ?? [])
|
|
const instancesQuery = useQuery(instanceListQueryOptions())
|
|
const instances = computed(() => instancesQuery.data.value ?? [])
|
|
const serversQuery = useQuery(syncedServersQueryOptions())
|
|
const syncedServers = computed(() => serversQuery.data.value ?? [])
|
|
const eligibleGameOptionSourceIds = computed(
|
|
() =>
|
|
new Set(
|
|
gameOptionSources.value.filter((source) => source.eligible).map((source) => source.source_id),
|
|
),
|
|
)
|
|
const hasGameOptionsToEdit = computed(
|
|
() =>
|
|
initializedOptions.value.game_options ||
|
|
instances.value.some(
|
|
(instance) =>
|
|
instance?.synced_options?.game_options &&
|
|
eligibleGameOptionSourceIds.value.has(instance.id),
|
|
),
|
|
)
|
|
const baseOption = ref<SyncedOption | null>(null)
|
|
const baseInstanceId = ref('')
|
|
const baseModal = ref<InstanceType<typeof SyncSourceModal> | null>(null)
|
|
const baseSourcesLoading = computed(() =>
|
|
baseOption.value === null
|
|
? false
|
|
: baseOption.value === 'game_options'
|
|
? gameOptionSourcesQuery.isPending.value
|
|
: instancesQuery.isPending.value,
|
|
)
|
|
const baseSourcesError = computed(() =>
|
|
baseOption.value === 'game_options'
|
|
? gameOptionSourcesQuery.isError.value && !gameOptionSourcesQuery.data.value
|
|
: instancesQuery.isError.value && !instancesQuery.data.value,
|
|
)
|
|
let baseSourceGeneration = 0
|
|
|
|
const baseInstanceTitle = computed(() => {
|
|
switch (baseOption.value) {
|
|
case 'game_options':
|
|
return formatMessage(messages.gameSettingsSyncSourceTitle)
|
|
case 'multiplayer_servers':
|
|
return formatMessage(messages.multiplayerServersSyncSourceTitle)
|
|
case 'command_history':
|
|
return formatMessage(messages.commandHistorySyncSourceTitle)
|
|
case 'creative_hotbars':
|
|
return formatMessage(messages.creativeHotbarsSyncSourceTitle)
|
|
case 'resource_packs':
|
|
return formatMessage(messages.resourcePacksSyncSourceTitle)
|
|
case 'data_packs':
|
|
return formatMessage(messages.dataPacksSyncSourceTitle)
|
|
default:
|
|
return ''
|
|
}
|
|
})
|
|
|
|
const baseInstanceDescription = computed(() => {
|
|
switch (baseOption.value) {
|
|
case 'game_options':
|
|
return formatMessage(messages.gameSettingsSyncSourceDescription)
|
|
case 'multiplayer_servers':
|
|
return formatMessage(messages.multiplayerServersSyncSourceDescription)
|
|
case 'command_history':
|
|
return formatMessage(messages.commandHistorySyncSourceDescription)
|
|
case 'creative_hotbars':
|
|
return formatMessage(messages.creativeHotbarsSyncSourceDescription)
|
|
case 'resource_packs':
|
|
return formatMessage(messages.resourcePacksSyncSourceDescription)
|
|
case 'data_packs':
|
|
return formatMessage(messages.dataPacksSyncSourceDescription)
|
|
default:
|
|
return ''
|
|
}
|
|
})
|
|
|
|
const baseInstances = computed(() =>
|
|
baseOption.value === 'game_options'
|
|
? gameOptionSources.value.map((source) => ({
|
|
id: source.source_id,
|
|
name: source.name,
|
|
icon_path: source.icon_path,
|
|
eligible: source.eligible,
|
|
}))
|
|
: instances.value.map((instance) => ({
|
|
id: instance.id,
|
|
name: instance.name,
|
|
icon_path: instance.icon_path,
|
|
eligible:
|
|
!instance.quarantined &&
|
|
(baseOption.value !== 'multiplayer_servers' || canSourceMultiplayerServers(instance)),
|
|
})),
|
|
)
|
|
|
|
async function invalidateSyncedOptions() {
|
|
await Promise.all([
|
|
queryClient.invalidateQueries({ queryKey: instanceKeys.all }),
|
|
queryClient.invalidateQueries({ queryKey: ['instance-synced-options'] }),
|
|
queryClient.invalidateQueries({ queryKey: syncedOptionsKeys.global }),
|
|
queryClient.invalidateQueries({ queryKey: syncedOptionsKeys.initialized }),
|
|
queryClient.invalidateQueries({ queryKey: syncedOptionsKeys.gameSources }),
|
|
queryClient.invalidateQueries({ queryKey: ['worlds'] }),
|
|
queryClient.invalidateQueries({ queryKey: syncedPackKeys.all }),
|
|
])
|
|
}
|
|
|
|
function emptySyncedContentMessage(row: (typeof globalRows)[number]) {
|
|
if (
|
|
row.editable === 'servers' &&
|
|
(instances.value.length === 0 || syncedServers.value.length === 0)
|
|
) {
|
|
return messages.noServersSyncedYet
|
|
}
|
|
if (row.editable === 'resourcepack' && !resourcePacksQuery.data.value?.length) {
|
|
return messages.noResourcePacksSyncedYet
|
|
}
|
|
if (row.editable === 'datapack' && !dataPacksQuery.data.value?.length) {
|
|
return messages.noDataPacksSyncedYet
|
|
}
|
|
}
|
|
|
|
function canEditGlobalOption(row: (typeof globalRows)[number]): boolean {
|
|
if (!row.editable || !globalOptions.value[row.option]) return false
|
|
if (emptySyncedContentMessage(row)) return false
|
|
if (row.editable === 'resourcepack' || row.editable === 'datapack') return true
|
|
if (row.editable === 'game-settings') return hasGameOptionsToEdit.value
|
|
return instances.value.length > 0 && initializedOptions.value[row.option]
|
|
}
|
|
|
|
function editGlobalOptionTooltip(row: (typeof globalRows)[number]): string {
|
|
const emptyMessage = emptySyncedContentMessage(row)
|
|
if (emptyMessage) return formatMessage(emptyMessage)
|
|
if (row.editable === 'resourcepack' || row.editable === 'datapack') {
|
|
return formatMessage(
|
|
globalOptions.value[row.option] ? commonMessages.editButton : messages.packsDisabled,
|
|
)
|
|
}
|
|
if (row.editable === 'game-settings') {
|
|
if (!hasGameOptionsToEdit.value) return formatMessage(messages.noGameOptionsToEdit)
|
|
if (!globalOptions.value[row.option]) {
|
|
return formatMessage(messages.gameSettingsDisabledTooltip)
|
|
}
|
|
return formatMessage(messages.gameSettingsButton)
|
|
}
|
|
if (instances.value.length === 0) {
|
|
return formatMessage(messages.noInstancesToEdit)
|
|
}
|
|
if (!initializedOptions.value[row.option]) {
|
|
return formatMessage(messages.noSyncedDataToEdit)
|
|
}
|
|
return formatMessage(commonMessages.editButton)
|
|
}
|
|
|
|
type GlobalOptionMutationVariables = {
|
|
option: SyncedOption
|
|
enabled: boolean
|
|
baseInstanceId?: string
|
|
}
|
|
|
|
const globalOptionMutation = useMutation({
|
|
mutationKey: syncedOptionsKeys.set,
|
|
mutationFn: ({ option, enabled, baseInstanceId }: GlobalOptionMutationVariables) =>
|
|
set_global_synced_option(option, enabled, baseInstanceId),
|
|
onError: handleError,
|
|
onSuccess: async (options, { option, enabled }) => {
|
|
queryClient.setQueryData(syncedOptionsKeys.global, options)
|
|
if (option === 'game_options') {
|
|
await queryClient.invalidateQueries({ queryKey: gameSettingsKeys.synced })
|
|
}
|
|
if (enabled && option === 'multiplayer_servers') {
|
|
await queryClient.invalidateQueries({ queryKey: syncedOptionsKeys.servers })
|
|
}
|
|
},
|
|
onSettled: async (_data, _error, { option }) => {
|
|
if (queryClient.isMutating({ mutationKey: syncedOptionsKeys.set }) === 1) {
|
|
if (option === 'resource_packs' || option === 'data_packs') {
|
|
void Promise.all([
|
|
queryClient.invalidateQueries({ queryKey: instanceKeys.all }),
|
|
queryClient.invalidateQueries({ queryKey: ['instance-synced-options'] }),
|
|
queryClient.invalidateQueries({ queryKey: syncedOptionsKeys.global }),
|
|
queryClient.invalidateQueries({ queryKey: syncedOptionsKeys.initialized }),
|
|
queryClient.invalidateQueries({ queryKey: syncedPackKeys.all }),
|
|
])
|
|
return
|
|
}
|
|
await invalidateSyncedOptions()
|
|
}
|
|
},
|
|
})
|
|
|
|
const canToggleGlobalOptions = computed(
|
|
() =>
|
|
!!globalOptionsQuery.data.value &&
|
|
!globalOptionMutation.isPending.value &&
|
|
!baseSourcesLoading.value,
|
|
)
|
|
|
|
async function chooseBaseInstance(option: SyncedOption) {
|
|
const generation = ++baseSourceGeneration
|
|
baseOption.value = option
|
|
baseInstanceId.value = ''
|
|
|
|
try {
|
|
if (option === 'game_options') {
|
|
await queryClient.fetchQuery(gameOptionsSyncSourcesQueryOptions())
|
|
} else {
|
|
await queryClient.fetchQuery({ ...instanceListQueryOptions(), staleTime: 0 })
|
|
}
|
|
} catch (error) {
|
|
if (generation !== baseSourceGeneration) return
|
|
handleError(error)
|
|
baseModal.value?.show()
|
|
return
|
|
}
|
|
|
|
if (generation !== baseSourceGeneration) return
|
|
const eligibleSources = baseInstances.value.filter((source) => source.eligible)
|
|
baseInstanceId.value = eligibleSources[0]?.id ?? ''
|
|
if (eligibleSources.length > 1) {
|
|
baseModal.value?.show()
|
|
return
|
|
}
|
|
|
|
try {
|
|
await globalOptionMutation.mutateAsync({
|
|
option,
|
|
enabled: true,
|
|
baseInstanceId: eligibleSources[0]?.id,
|
|
})
|
|
await nextTick()
|
|
if (!baseModal.value?.hide()) clearBaseSource()
|
|
} catch {
|
|
return
|
|
}
|
|
}
|
|
|
|
function toggleGlobalOption(option: SyncedOption, enabled: boolean) {
|
|
if (!isSyncedOptionAvailable(option) || !canToggleGlobalOptions.value) return
|
|
if (enabled && option !== 'screenshots') {
|
|
void chooseBaseInstance(option)
|
|
return
|
|
}
|
|
globalOptionMutation.mutate({ option, enabled })
|
|
}
|
|
|
|
async function confirmBaseInstance() {
|
|
if (!baseOption.value || !baseInstanceId.value) return
|
|
try {
|
|
await globalOptionMutation.mutateAsync({
|
|
option: baseOption.value,
|
|
enabled: true,
|
|
baseInstanceId: baseInstanceId.value,
|
|
})
|
|
await nextTick()
|
|
baseModal.value?.hide()
|
|
} catch {
|
|
return
|
|
}
|
|
}
|
|
|
|
function editGlobalOption(row: (typeof globalRows)[number]) {
|
|
if (!isSyncedOptionAvailable(row.option)) return
|
|
if (row.editable === 'resourcepack' || row.editable === 'datapack') {
|
|
void syncedPacksModal.value?.show(row.editable)
|
|
} else if (row.editable === 'game-settings') {
|
|
openGameSettings()
|
|
} else if (row.editable === 'commands') {
|
|
void commandHistoryModal.value?.show()
|
|
} else {
|
|
void syncedServersModal.value?.show()
|
|
}
|
|
}
|
|
|
|
function openGameSettings() {
|
|
if (!hasGameOptionsToEdit.value) return
|
|
gameSettingsModal.value?.show()
|
|
}
|
|
|
|
async function handleGameSettingsSaved() {
|
|
await invalidateSyncedOptions()
|
|
}
|
|
|
|
|
|
|
|
function clearBaseSource() {
|
|
baseSourceGeneration++
|
|
baseOption.value = null
|
|
}
|
|
|
|
onScopeDispose(clearBaseSource)
|
|
</script>
|
|
|
|
<template>
|
|
<div class="flex flex-col gap-6">
|
|
<SyncedPacksModal ref="syncedPacksModal" />
|
|
<CommandHistoryModal ref="commandHistoryModal" />
|
|
<SyncedServersModal ref="syncedServersModal" />
|
|
<GameSettingsModal ref="gameSettingsModal" @saved="handleGameSettingsSaved" />
|
|
|
|
<SyncSourceModal
|
|
ref="baseModal"
|
|
v-model="baseInstanceId"
|
|
:title="baseInstanceTitle"
|
|
:description="baseInstanceDescription"
|
|
:sources="baseInstances"
|
|
:loading="baseSourcesLoading"
|
|
:error="baseSourcesError"
|
|
:pending="globalOptionMutation.isPending.value"
|
|
@confirm="confirmBaseInstance"
|
|
@close="clearBaseSource"
|
|
@retry="baseOption && chooseBaseInstance(baseOption)"
|
|
/>
|
|
|
|
<SettingsSection>
|
|
<template #header>
|
|
<h2
|
|
id="settings-target-instance-sync-options"
|
|
tabindex="-1"
|
|
class="m-0 text-lg font-semibold text-[var(--color-text-primary)]"
|
|
>
|
|
{{ formatMessage(messages.globalOptionsTitle) }}
|
|
</h2>
|
|
</template>
|
|
<SettingsRow v-for="row in availableGlobalRows" :key="row.option">
|
|
<template #label>
|
|
<span :id="`settings-target-instance-sync-${row.option}`" tabindex="-1">
|
|
{{ formatMessage(messages[row.title]) }}
|
|
</span>
|
|
</template>
|
|
<template v-if="row.description" #description>
|
|
{{ formatMessage(messages[row.description]) }}
|
|
</template>
|
|
<template #control>
|
|
<span v-if="row.editable" v-tooltip="editGlobalOptionTooltip(row)" class="flex">
|
|
<IconButton
|
|
type="outlined"
|
|
circular
|
|
:disabled="
|
|
!canEditGlobalOption(row) ||
|
|
initializedOptionsQuery.isPending.value ||
|
|
globalOptionMutation.isPending.value
|
|
"
|
|
:label="
|
|
formatMessage(
|
|
row.editable === 'game-settings'
|
|
? messages.gameSettingsButton
|
|
: commonMessages.editButton,
|
|
)
|
|
"
|
|
@click="editGlobalOption(row)"
|
|
>
|
|
<EditIcon aria-hidden="true" />
|
|
</IconButton>
|
|
</span>
|
|
<Toggle
|
|
:id="`global-sync-${row.option}`"
|
|
:model-value="globalOptions[row.option]"
|
|
:disabled="!canToggleGlobalOptions"
|
|
:aria-label="formatMessage(messages[row.title])"
|
|
@update:model-value="(enabled) => toggleGlobalOption(row.option, enabled)"
|
|
/>
|
|
</template>
|
|
</SettingsRow>
|
|
</SettingsSection>
|
|
</div>
|
|
</template>
|