diff --git a/frontend/src/components/cloud/CloudCredentialModal.vue b/frontend/src/components/cloud/CloudCredentialModal.vue new file mode 100644 index 0000000..81f85b7 --- /dev/null +++ b/frontend/src/components/cloud/CloudCredentialModal.vue @@ -0,0 +1,195 @@ + + + diff --git a/frontend/src/components/settings/SettingsAiTab.vue b/frontend/src/components/settings/SettingsAiTab.vue new file mode 100644 index 0000000..dcf04f6 --- /dev/null +++ b/frontend/src/components/settings/SettingsAiTab.vue @@ -0,0 +1,9 @@ + diff --git a/frontend/src/components/settings/SettingsCloudTab.vue b/frontend/src/components/settings/SettingsCloudTab.vue new file mode 100644 index 0000000..a2d0cde --- /dev/null +++ b/frontend/src/components/settings/SettingsCloudTab.vue @@ -0,0 +1,260 @@ + + + diff --git a/frontend/src/components/settings/SettingsPreferencesTab.vue b/frontend/src/components/settings/SettingsPreferencesTab.vue new file mode 100644 index 0000000..f7b5f33 --- /dev/null +++ b/frontend/src/components/settings/SettingsPreferencesTab.vue @@ -0,0 +1,65 @@ + + + diff --git a/frontend/src/components/settings/__tests__/SettingsCloudTab.test.js b/frontend/src/components/settings/__tests__/SettingsCloudTab.test.js new file mode 100644 index 0000000..562cac1 --- /dev/null +++ b/frontend/src/components/settings/__tests__/SettingsCloudTab.test.js @@ -0,0 +1,59 @@ +import { describe, it, expect, vi, beforeEach } from 'vitest' +import { mount } from '@vue/test-utils' +import { createPinia, setActivePinia } from 'pinia' + +// Mock store module before importing component (W4 — CLAUDE.md unit test requirement) +vi.mock('../../../stores/cloudConnections.js', () => ({ + useCloudConnectionsStore: () => ({ + connections: [], + loading: false, + error: null, + fetchConnections: vi.fn(), + disconnect: vi.fn(), + disconnectAll: vi.fn(), + }), +})) + +// Mock api/client.js to avoid HTTP calls +vi.mock('../../../api/client.js', () => ({ + connectWebDav: vi.fn(), + listCloudConnections: vi.fn(), + disconnectCloud: vi.fn(), +})) + +import SettingsCloudTab from '../SettingsCloudTab.vue' + +const globalPlugins = { + plugins: [createPinia()], + stubs: { + // Stub CloudCredentialModal to avoid portal/teleport complexity in tests + CloudCredentialModal: { + template: '
', + props: ['show', 'provider'], + }, + }, +} + +beforeEach(() => { + setActivePinia(createPinia()) + vi.clearAllMocks() +}) + +describe('SettingsCloudTab', () => { + it('renders all 4 provider rows', () => { + const wrapper = mount(SettingsCloudTab, { global: globalPlugins }) + expect(wrapper.text()).toContain('Google Drive') + expect(wrapper.text()).toContain('OneDrive') + expect(wrapper.text()).toContain('Nextcloud') + expect(wrapper.text()).toContain('WebDAV') + }) + + it('shows Connect buttons when no connections active', () => { + const wrapper = mount(SettingsCloudTab, { global: globalPlugins }) + const buttons = wrapper.findAll('button') + expect(buttons.length).toBeGreaterThan(0) + // At least some "Connect" buttons should be visible when no connections + const buttonTexts = buttons.map(b => b.text()).join(' ') + expect(buttonTexts).toContain('Connect') + }) +}) diff --git a/frontend/src/views/SettingsView.vue b/frontend/src/views/SettingsView.vue index 4c54837..708082c 100644 --- a/frontend/src/views/SettingsView.vue +++ b/frontend/src/views/SettingsView.vue @@ -1,79 +1,132 @@ diff --git a/frontend/vite.config.js b/frontend/vite.config.js index ebd6662..7d0bf9e 100644 --- a/frontend/vite.config.js +++ b/frontend/vite.config.js @@ -3,6 +3,10 @@ import vue from '@vitejs/plugin-vue' export default defineConfig({ plugins: [vue()], + build: { + // top-level await in main.js requires esnext target + target: 'esnext', + }, server: { host: '0.0.0.0', port: 5173,