feat(hosts): move host management into the Hosts application
Hosts becomes a built-in application opened from the Apps menu, with Hosts and Agent packages tabs. The remote capability switch keeps using remoteProjectsEnabled and moves to the application settings, so Main-side gating and saved values are unchanged. Saved navigation gains the new entry at the end, unpinned. Settings drops the SSH hosts category and the Remote projects tab. The host list collapses to one-line summaries with status badges, versions show as a table, and application settings switches align to the right edge.
This commit is contained in:
@@ -282,7 +282,7 @@ describe('ApplicationSettingsStore', () => {
|
||||
const settings = await store.get()
|
||||
expect(settings.warnings).toBeUndefined()
|
||||
expect(settings.magicNotesEnabled).toBe(false)
|
||||
expect(settings.applicationNavigation).toEqual({ order: [...expected, 'device-sharing'], pinned: { 'magic-notes': false, heartbeat: true, 'local-inference': false } })
|
||||
expect(settings.applicationNavigation).toEqual({ order: [...expected, 'device-sharing', 'remote-hosts'], pinned: { 'magic-notes': false, heartbeat: true, 'local-inference': false, 'remote-hosts': false } })
|
||||
expect(applicationSettingsSchema.parse(settings)).toEqual(settings)
|
||||
await store.update({ checkUpdatesOnStartup: false })
|
||||
expect(JSON.parse(await readFile(filePath, 'utf8')).applicationNavigation).toEqual(settings.applicationNavigation)
|
||||
@@ -292,8 +292,8 @@ describe('ApplicationSettingsStore', () => {
|
||||
it('validates full-order writes, persists and publishes them, and rejects partial writes without mutation', async () => {
|
||||
const { store, filePath } = await createStore()
|
||||
const applicationNavigation = {
|
||||
order: ['local-inference', 'heartbeat', 'magic-notes', 'knowledge', 'device-sharing'],
|
||||
pinned: { 'magic-notes': false, heartbeat: true, 'local-inference': false },
|
||||
order: ['local-inference', 'heartbeat', 'magic-notes', 'knowledge', 'remote-hosts', 'device-sharing'],
|
||||
pinned: { 'magic-notes': false, heartbeat: true, 'local-inference': false, 'remote-hosts': true },
|
||||
}
|
||||
const changed = vi.fn()
|
||||
store.onChanged(changed)
|
||||
@@ -337,11 +337,27 @@ describe('ApplicationSettingsStore', () => {
|
||||
pinned: { 'magic-notes': false, 'local-inference': pinned }
|
||||
}
|
||||
await writeFile(filePath, JSON.stringify({ ...defaultApplicationSettings, applicationNavigation, version: 11, lastSeenReleaseNotesVersion: null }), 'utf8')
|
||||
const normalized = { ...applicationNavigation, pinned: { ...applicationNavigation.pinned, heartbeat: true }, order: ['knowledge', 'heartbeat', 'local-inference', 'magic-notes', 'device-sharing'] }
|
||||
const normalized = { ...applicationNavigation, pinned: { ...applicationNavigation.pinned, heartbeat: true, 'remote-hosts': false }, order: ['knowledge', 'heartbeat', 'local-inference', 'magic-notes', 'device-sharing', 'remote-hosts'] }
|
||||
expect((await store.get()).applicationNavigation).toEqual(normalized)
|
||||
await store.update({ checkUpdatesOnStartup: false })
|
||||
expect((await createApplicationSettingsStore(filePath).get()).applicationNavigation).toEqual(normalized)
|
||||
})
|
||||
it.each([true, false])('adds Hosts after a saved full order and keeps remote projects %s', async (remoteProjectsEnabled) => {
|
||||
const { filePath, store } = await createStore()
|
||||
const applicationNavigation = {
|
||||
order: ['device-sharing', 'local-inference', 'heartbeat', 'magic-notes', 'knowledge'],
|
||||
pinned: { 'magic-notes': false, heartbeat: false, 'local-inference': true }
|
||||
}
|
||||
await writeFile(filePath, JSON.stringify({ ...defaultApplicationSettings, remoteProjectsEnabled, applicationNavigation, version: 12, lastSeenReleaseNotesVersion: null }), 'utf8')
|
||||
const expected = { order: [...applicationNavigation.order, 'remote-hosts'], pinned: { ...applicationNavigation.pinned, 'remote-hosts': false } }
|
||||
const migrated = await store.get()
|
||||
expect(migrated.warnings).toBeUndefined()
|
||||
expect(migrated.remoteProjectsEnabled).toBe(remoteProjectsEnabled)
|
||||
expect(migrated.applicationNavigation).toEqual(expected)
|
||||
expect(applicationSettingsSchema.parse(migrated)).toEqual(migrated)
|
||||
await store.update({ checkUpdatesOnStartup: false })
|
||||
expect(await createApplicationSettingsStore(filePath).get()).toMatchObject({ remoteProjectsEnabled, applicationNavigation: expected })
|
||||
})
|
||||
it('migrates released settings without replacing explicit false values or comment choices', async () => {
|
||||
const { filePath, store } = await createStore()
|
||||
const legacy: Record<string, unknown> = { ...defaultApplicationSettings, version: 11, lastSeenReleaseNotesVersion: null, magicNotesEnabled: false, magicNotesShowIncompleteTodoCount: false, magicNoteCommentMode: 'after-save-manual', magicNoteCommentFormat: 'structured' }
|
||||
|
||||
Reference in New Issue
Block a user