feat(05-07): cloud connections Pinia store + API client functions
- Create useCloudConnectionsStore with connections/loading/error refs - fetchConnections, disconnect(id), disconnectAll() actions - Append listCloudConnections, disconnectCloud, connectWebDav, updateDefaultStorage to api/client.js - Add vitest test script to package.json - 4 unit tests passing (W4 — CLAUDE.md)
This commit is contained in:
@@ -5,7 +5,8 @@
|
|||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"preview": "vite preview"
|
"preview": "vite preview",
|
||||||
|
"test": "vitest run"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"pinia": "^2.1.0",
|
"pinia": "^2.1.0",
|
||||||
|
|||||||
@@ -364,3 +364,29 @@ export function adminListAuditLog({ start, end, user_id, event_type, page = 1, p
|
|||||||
export function getDocumentContentUrl(docId) {
|
export function getDocumentContentUrl(docId) {
|
||||||
return `/api/documents/${docId}/content`
|
return `/api/documents/${docId}/content`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── Cloud Storage ─────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
export function listCloudConnections() {
|
||||||
|
return request('/api/cloud/connections')
|
||||||
|
}
|
||||||
|
|
||||||
|
export function disconnectCloud(id) {
|
||||||
|
return request(`/api/cloud/connections/${id}`, { method: 'DELETE' })
|
||||||
|
}
|
||||||
|
|
||||||
|
export function connectWebDav(provider, serverUrl, username, password) {
|
||||||
|
return request('/api/cloud/connections/webdav', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ provider, server_url: serverUrl, username, password }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function updateDefaultStorage(backend) {
|
||||||
|
return request('/api/users/me/default-storage', {
|
||||||
|
method: 'PATCH',
|
||||||
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
body: JSON.stringify({ backend }),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
import { describe, it, expect, vi, beforeEach } from 'vitest'
|
||||||
|
import { setActivePinia, createPinia } from 'pinia'
|
||||||
|
|
||||||
|
// Mock api/client.js — no real HTTP calls in unit tests (CLAUDE.md W4)
|
||||||
|
vi.mock('../../api/client.js', () => ({
|
||||||
|
listCloudConnections: vi.fn(),
|
||||||
|
disconnectCloud: vi.fn(),
|
||||||
|
connectWebDav: vi.fn(),
|
||||||
|
updateDefaultStorage: vi.fn(),
|
||||||
|
}))
|
||||||
|
|
||||||
|
import { useCloudConnectionsStore } from '../cloudConnections.js'
|
||||||
|
import * as api from '../../api/client.js'
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
setActivePinia(createPinia())
|
||||||
|
vi.clearAllMocks()
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('useCloudConnectionsStore', () => {
|
||||||
|
it('fetchConnections sets connections from API response', async () => {
|
||||||
|
api.listCloudConnections.mockResolvedValue({
|
||||||
|
items: [{ id: '1', provider: 'google_drive', status: 'ACTIVE' }],
|
||||||
|
})
|
||||||
|
const store = useCloudConnectionsStore()
|
||||||
|
await store.fetchConnections()
|
||||||
|
expect(store.connections).toHaveLength(1)
|
||||||
|
expect(store.connections[0].provider).toBe('google_drive')
|
||||||
|
expect(store.loading).toBe(false)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('fetchConnections sets error on API failure', async () => {
|
||||||
|
api.listCloudConnections.mockRejectedValue(new Error('Network error'))
|
||||||
|
const store = useCloudConnectionsStore()
|
||||||
|
await store.fetchConnections()
|
||||||
|
expect(store.error).toBeTruthy()
|
||||||
|
expect(store.connections).toHaveLength(0)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disconnect removes connection from state after API call', async () => {
|
||||||
|
api.disconnectCloud.mockResolvedValue(null)
|
||||||
|
const store = useCloudConnectionsStore()
|
||||||
|
store.connections = [{ id: 'conn-1', provider: 'google_drive', status: 'ACTIVE' }]
|
||||||
|
await store.disconnect('conn-1')
|
||||||
|
expect(store.connections).toHaveLength(0)
|
||||||
|
expect(api.disconnectCloud).toHaveBeenCalledWith('conn-1')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('disconnectAll clears all connections', async () => {
|
||||||
|
api.disconnectCloud.mockResolvedValue(null)
|
||||||
|
const store = useCloudConnectionsStore()
|
||||||
|
store.connections = [
|
||||||
|
{ id: 'a', provider: 'google_drive', status: 'ACTIVE' },
|
||||||
|
{ id: 'b', provider: 'onedrive', status: 'ACTIVE' },
|
||||||
|
]
|
||||||
|
await store.disconnectAll()
|
||||||
|
expect(store.connections).toHaveLength(0)
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { ref } from 'vue'
|
||||||
|
import * as api from '../api/client.js'
|
||||||
|
|
||||||
|
export const useCloudConnectionsStore = defineStore('cloudConnections', () => {
|
||||||
|
const connections = ref([])
|
||||||
|
const loading = ref(false)
|
||||||
|
const error = ref(null)
|
||||||
|
|
||||||
|
async function fetchConnections() {
|
||||||
|
loading.value = true
|
||||||
|
error.value = null
|
||||||
|
try {
|
||||||
|
const data = await api.listCloudConnections()
|
||||||
|
connections.value = data.items ?? []
|
||||||
|
} catch (e) {
|
||||||
|
error.value = e.message || 'Failed to load cloud connections'
|
||||||
|
} finally {
|
||||||
|
loading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disconnect(id) {
|
||||||
|
try {
|
||||||
|
await api.disconnectCloud(id)
|
||||||
|
connections.value = connections.value.filter(c => c.id !== id)
|
||||||
|
} catch (e) {
|
||||||
|
throw e
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function disconnectAll() {
|
||||||
|
const ids = connections.value.map(c => c.id)
|
||||||
|
for (const id of ids) await disconnect(id)
|
||||||
|
connections.value = []
|
||||||
|
}
|
||||||
|
|
||||||
|
return { connections, loading, error, fetchConnections, disconnect, disconnectAll }
|
||||||
|
})
|
||||||
Reference in New Issue
Block a user