mirror of
https://github.com/jxxghp/MoviePilot-Frontend.git
synced 2026-09-10 02:06:44 +08:00
fix: separate auto-update and dev tracking settings for clarity by jxxghp
This commit is contained in:
@@ -2651,6 +2651,10 @@ export interface SystemUpdateItemStatus {
|
|||||||
|
|
||||||
/** 后端主程序与站点资源后台更新状态机快照。 */
|
/** 后端主程序与站点资源后台更新状态机快照。 */
|
||||||
export interface SystemUpdateStatus {
|
export interface SystemUpdateStatus {
|
||||||
|
/** 当前自动检查开关;由后端实时返回,避免旧缓存继续触发提醒。 */
|
||||||
|
auto_update?: boolean
|
||||||
|
/** 站点资源单独控制自动检查和提醒。 */
|
||||||
|
auto_update_resource?: boolean
|
||||||
state: SystemUpdateState
|
state: SystemUpdateState
|
||||||
current_version: string
|
current_version: string
|
||||||
version?: string | null
|
version?: string | null
|
||||||
|
|||||||
@@ -70,6 +70,9 @@ const updateItems = computed<SystemUpdateItemStatus[]>(() => {
|
|||||||
|
|
||||||
const visibleItems = computed(() =>
|
const visibleItems = computed(() =>
|
||||||
updateItems.value.filter(item => {
|
updateItems.value.filter(item => {
|
||||||
|
// 关闭自动检查后隐藏版本提醒,手动发起的下载、安装和失败反馈仍可见。
|
||||||
|
const enabled = item.type === 'resources' ? status.value?.auto_update_resource : status.value?.auto_update
|
||||||
|
if (['available', 'ready'].includes(item.state) && enabled !== true) return false
|
||||||
if (!['available', 'downloading', 'ready', 'installing', 'failed'].includes(item.state)) return false
|
if (!['available', 'downloading', 'ready', 'installing', 'failed'].includes(item.state)) return false
|
||||||
return !['available', 'ready'].includes(item.state) || !isCurrentVersionSuppressed(item)
|
return !['available', 'ready'].includes(item.state) || !isCurrentVersionSuppressed(item)
|
||||||
}),
|
}),
|
||||||
|
|||||||
@@ -57,6 +57,8 @@ vi.mock('vue-i18n', async importOriginal => ({
|
|||||||
}))
|
}))
|
||||||
|
|
||||||
const availableStatus: SystemUpdateStatus = {
|
const availableStatus: SystemUpdateStatus = {
|
||||||
|
auto_update: true,
|
||||||
|
auto_update_resource: true,
|
||||||
state: 'available',
|
state: 'available',
|
||||||
current_version: 'v3.0.0',
|
current_version: 'v3.0.0',
|
||||||
version: 'v3.1.0',
|
version: 'v3.1.0',
|
||||||
@@ -77,6 +79,43 @@ describe('SystemUpdatePrompt', () => {
|
|||||||
mocks.footerDockHeight!.value = null
|
mocks.footerDockHeight!.value = null
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it.each(['available', 'ready'] as const)(
|
||||||
|
'hides cached %s reminders when automatic checks are disabled',
|
||||||
|
async state => {
|
||||||
|
mocks.updateStatus!.value = { ...availableStatus, state, auto_update: false }
|
||||||
|
await renderWithProviders(SystemUpdatePrompt, { props: { enabled: true } })
|
||||||
|
expect(document.querySelector('.system-update-prompt')).not.toBeInTheDocument()
|
||||||
|
|
||||||
|
mocks.updateStatus!.value = { ...availableStatus, state, auto_update: true }
|
||||||
|
await waitFor(() => expect(document.querySelector('.system-update-prompt')).toBeInTheDocument())
|
||||||
|
mocks.updateStatus!.value = { ...availableStatus, state, auto_update: false }
|
||||||
|
await waitFor(() => expect(document.querySelector('.system-update-prompt')).not.toBeInTheDocument())
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
it('keeps manually started download progress visible with automatic checks disabled', async () => {
|
||||||
|
mocks.updateStatus!.value = { ...availableStatus, state: 'downloading', auto_update: false, progress: 25 }
|
||||||
|
await renderWithProviders(SystemUpdatePrompt, { props: { enabled: true } })
|
||||||
|
expect(screen.getByText('25%')).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
|
||||||
|
it('shows only resource reminders when only automatic resource updates are enabled', async () => {
|
||||||
|
mocks.updateStatus!.value = {
|
||||||
|
...availableStatus,
|
||||||
|
auto_update: false,
|
||||||
|
auto_update_resource: true,
|
||||||
|
updates: [
|
||||||
|
{ ...availableStatus, type: 'application' },
|
||||||
|
{ ...availableStatus, type: 'resources', auth_version: '3.1.0' },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
await renderWithProviders(SystemUpdatePrompt, { props: { enabled: true } })
|
||||||
|
expect(screen.queryByText('systemUpdate.applicationAvailableTitle')).not.toBeInTheDocument()
|
||||||
|
expect(screen.getByText('systemUpdate.resourcesAvailableTitle')).toBeInTheDocument()
|
||||||
|
mocks.updateStatus!.value = { ...mocks.updateStatus!.value, auto_update_resource: false }
|
||||||
|
await waitFor(() => expect(document.querySelector('.system-update-prompt')).not.toBeInTheDocument())
|
||||||
|
})
|
||||||
|
|
||||||
it('asks an administrator to start the background download', async () => {
|
it('asks an administrator to start the background download', async () => {
|
||||||
mocks.post.mockResolvedValue({
|
mocks.post.mockResolvedValue({
|
||||||
...availableStatus,
|
...availableStatus,
|
||||||
|
|||||||
@@ -2989,6 +2989,9 @@ export default {
|
|||||||
imageProxyAllowedPrivateRangeAdd: 'Add CIDR, e.g.: 198.18.0.0/15',
|
imageProxyAllowedPrivateRangeAdd: 'Add CIDR, e.g.: 198.18.0.0/15',
|
||||||
proxyHost: 'Proxy Server',
|
proxyHost: 'Proxy Server',
|
||||||
proxyHostHint: 'Set proxy server address, support: http(s), socks5, socks5h, etc.',
|
proxyHostHint: 'Set proxy server address, support: http(s), socks5, socks5h, etc.',
|
||||||
|
moviePilotAutoUpdate: 'Automatically check for updates',
|
||||||
|
moviePilotAutoUpdateHint:
|
||||||
|
'Check for application updates every 6 hours and show reminders; confirm downloads and installation manually',
|
||||||
moviePilotDevUpdate: 'Track Dev builds',
|
moviePilotDevUpdate: 'Track Dev builds',
|
||||||
moviePilotDevUpdateHint: 'Update to the latest code on the current v3 development branch at every restart',
|
moviePilotDevUpdateHint: 'Update to the latest code on the current v3 development branch at every restart',
|
||||||
autoUpdateResource: 'Auto Update Resource',
|
autoUpdateResource: 'Auto Update Resource',
|
||||||
|
|||||||
@@ -2924,6 +2924,8 @@ export default {
|
|||||||
imageProxyAllowedPrivateRangeAdd: '添加 CIDR,如:198.18.0.0/15',
|
imageProxyAllowedPrivateRangeAdd: '添加 CIDR,如:198.18.0.0/15',
|
||||||
proxyHost: '代理服务器',
|
proxyHost: '代理服务器',
|
||||||
proxyHostHint: '设置代理服务器地址,支持:http(s)、socks5、socks5h 等协议',
|
proxyHostHint: '设置代理服务器地址,支持:http(s)、socks5、socks5h 等协议',
|
||||||
|
moviePilotAutoUpdate: '自动检查版本更新',
|
||||||
|
moviePilotAutoUpdateHint: '每 6 小时检查主程序版本更新并提示,下载和安装需手动确认',
|
||||||
moviePilotDevUpdate: '跟踪 Dev 开发版',
|
moviePilotDevUpdate: '跟踪 Dev 开发版',
|
||||||
moviePilotDevUpdateHint: '每次重启时更新到当前 v3 开发分支的最新代码',
|
moviePilotDevUpdateHint: '每次重启时更新到当前 v3 开发分支的最新代码',
|
||||||
autoUpdateResource: '自动更新站点资源',
|
autoUpdateResource: '自动更新站点资源',
|
||||||
|
|||||||
@@ -2897,6 +2897,8 @@ export default {
|
|||||||
imageProxyAllowedPrivateRangeAdd: '添加 CIDR,如:198.18.0.0/15',
|
imageProxyAllowedPrivateRangeAdd: '添加 CIDR,如:198.18.0.0/15',
|
||||||
proxyHost: '代理服務器',
|
proxyHost: '代理服務器',
|
||||||
proxyHostHint: '設置代理服務器地址,支持:http(s)、socks5、socks5h 等協議',
|
proxyHostHint: '設置代理服務器地址,支持:http(s)、socks5、socks5h 等協議',
|
||||||
|
moviePilotAutoUpdate: '自動檢查版本更新',
|
||||||
|
moviePilotAutoUpdateHint: '每 6 小時檢查主程式版本更新並提示,下載和安裝需手動確認',
|
||||||
moviePilotDevUpdate: '追蹤 Dev 開發版',
|
moviePilotDevUpdate: '追蹤 Dev 開發版',
|
||||||
moviePilotDevUpdateHint: '每次重新啟動時更新到目前 v3 開發分支的最新程式碼',
|
moviePilotDevUpdateHint: '每次重新啟動時更新到目前 v3 開發分支的最新程式碼',
|
||||||
autoUpdateResource: '自動更新站點資源',
|
autoUpdateResource: '自動更新站點資源',
|
||||||
|
|||||||
@@ -99,6 +99,7 @@ const SystemSettings = ref<any>({
|
|||||||
DB_WAL_ENABLE: false,
|
DB_WAL_ENABLE: false,
|
||||||
AUTO_UPDATE_RESOURCE: true,
|
AUTO_UPDATE_RESOURCE: true,
|
||||||
MOVIEPILOT_AUTO_UPDATE: false,
|
MOVIEPILOT_AUTO_UPDATE: false,
|
||||||
|
MOVIEPILOT_UPDATE_DEV: false,
|
||||||
DATA_CLEANUP_ENABLE: false,
|
DATA_CLEANUP_ENABLE: false,
|
||||||
DATA_CLEANUP_MESSAGE_DAYS: 90,
|
DATA_CLEANUP_MESSAGE_DAYS: 90,
|
||||||
DATA_CLEANUP_DOWNLOAD_HISTORY_DAYS: 180,
|
DATA_CLEANUP_DOWNLOAD_HISTORY_DAYS: 180,
|
||||||
@@ -1117,13 +1118,6 @@ function onMediaServerChange(mediaserver: MediaServerConf, name: string) {
|
|||||||
if (index !== -1) mediaServers.value[index] = mediaserver
|
if (index !== -1) mediaServers.value[index] = mediaserver
|
||||||
}
|
}
|
||||||
|
|
||||||
const moviePilotDevUpdate = computed({
|
|
||||||
get: () => SystemSettings.value.Advanced.MOVIEPILOT_AUTO_UPDATE === 'dev',
|
|
||||||
set: enabled => {
|
|
||||||
SystemSettings.value.Advanced.MOVIEPILOT_AUTO_UPDATE = enabled ? 'dev' : 'false'
|
|
||||||
},
|
|
||||||
})
|
|
||||||
|
|
||||||
// Fanart语言多选处理
|
// Fanart语言多选处理
|
||||||
const fanartLanguageSelection = computed({
|
const fanartLanguageSelection = computed({
|
||||||
get: () => {
|
get: () => {
|
||||||
@@ -2131,7 +2125,15 @@ watch(currentLlmSnapshotKey, (snapshotKey, previousSnapshotKey) => {
|
|||||||
</VCol>
|
</VCol>
|
||||||
<VCol cols="12" md="6">
|
<VCol cols="12" md="6">
|
||||||
<VSwitch
|
<VSwitch
|
||||||
v-model="moviePilotDevUpdate"
|
v-model="SystemSettings.Advanced.MOVIEPILOT_AUTO_UPDATE"
|
||||||
|
:label="t('setting.system.moviePilotAutoUpdate')"
|
||||||
|
:hint="t('setting.system.moviePilotAutoUpdateHint')"
|
||||||
|
persistent-hint
|
||||||
|
/>
|
||||||
|
</VCol>
|
||||||
|
<VCol cols="12" md="6">
|
||||||
|
<VSwitch
|
||||||
|
v-model="SystemSettings.Advanced.MOVIEPILOT_UPDATE_DEV"
|
||||||
:label="t('setting.system.moviePilotDevUpdate')"
|
:label="t('setting.system.moviePilotDevUpdate')"
|
||||||
:hint="t('setting.system.moviePilotDevUpdateHint')"
|
:hint="t('setting.system.moviePilotDevUpdateHint')"
|
||||||
persistent-hint
|
persistent-hint
|
||||||
|
|||||||
@@ -1006,7 +1006,30 @@ describe('AccountSettingSystem', () => {
|
|||||||
expect(mocks.toastSuccess).toHaveBeenCalledWith('高级设置保存成功')
|
expect(mocks.toastSuccess).toHaveBeenCalledWith('高级设置保存成功')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('round-trips all advanced system switches and enables only the Dev update mode', async () => {
|
it.each([
|
||||||
|
[false, false],
|
||||||
|
[false, true],
|
||||||
|
[true, false],
|
||||||
|
[true, true],
|
||||||
|
])('loads and saves independent update switches (%s, %s)', async (autoUpdate, updateDev) => {
|
||||||
|
systemEnv.MOVIEPILOT_AUTO_UPDATE = autoUpdate
|
||||||
|
systemEnv.MOVIEPILOT_UPDATE_DEV = updateDev
|
||||||
|
await renderSettings()
|
||||||
|
const dialog = await openAdvancedTab('系统')
|
||||||
|
const autoSwitch = dialog.getByLabelText('自动检查版本更新')
|
||||||
|
const devSwitch = dialog.getByLabelText('跟踪 Dev 开发版')
|
||||||
|
expect((autoSwitch as HTMLInputElement).checked).toBe(autoUpdate)
|
||||||
|
expect((devSwitch as HTMLInputElement).checked).toBe(updateDev)
|
||||||
|
await fireEvent.click(autoSwitch)
|
||||||
|
expect((devSwitch as HTMLInputElement).checked).toBe(updateDev)
|
||||||
|
await fireEvent.click(dialog.getByRole('button', { name: '保存' }))
|
||||||
|
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument())
|
||||||
|
expect(findPost('system/env')?.[1]).toEqual(
|
||||||
|
expect.objectContaining({ MOVIEPILOT_AUTO_UPDATE: !autoUpdate, MOVIEPILOT_UPDATE_DEV: updateDev }),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('round-trips all advanced system switches with independent boolean update settings', async () => {
|
||||||
await renderSettings()
|
await renderSettings()
|
||||||
const dialog = await openAdvancedTab('系统')
|
const dialog = await openAdvancedTab('系统')
|
||||||
for (const label of [
|
for (const label of [
|
||||||
@@ -1018,6 +1041,7 @@ describe('AccountSettingSystem', () => {
|
|||||||
'分享工作流数据',
|
'分享工作流数据',
|
||||||
'大内存模式',
|
'大内存模式',
|
||||||
'数据库WAL模式',
|
'数据库WAL模式',
|
||||||
|
'自动检查版本更新',
|
||||||
'跟踪 Dev 开发版',
|
'跟踪 Dev 开发版',
|
||||||
'自动更新站点资源',
|
'自动更新站点资源',
|
||||||
]) {
|
]) {
|
||||||
@@ -1033,7 +1057,8 @@ describe('AccountSettingSystem', () => {
|
|||||||
BIG_MEMORY_MODE: true,
|
BIG_MEMORY_MODE: true,
|
||||||
DB_WAL_ENABLE: true,
|
DB_WAL_ENABLE: true,
|
||||||
GLOBAL_IMAGE_CACHE: true,
|
GLOBAL_IMAGE_CACHE: true,
|
||||||
MOVIEPILOT_AUTO_UPDATE: 'dev',
|
MOVIEPILOT_AUTO_UPDATE: true,
|
||||||
|
MOVIEPILOT_UPDATE_DEV: true,
|
||||||
PLUGIN_STATISTIC_SHARE: false,
|
PLUGIN_STATISTIC_SHARE: false,
|
||||||
SUBSCRIBE_STATISTIC_SHARE: false,
|
SUBSCRIBE_STATISTIC_SHARE: false,
|
||||||
USAGE_STATISTIC_SHARE: false,
|
USAGE_STATISTIC_SHARE: false,
|
||||||
|
|||||||
Reference in New Issue
Block a user