feat: rebuild frontend with react
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
import http from './http'
|
||||
import type { CurrentUser, LoginResponse } from '../types'
|
||||
|
||||
export function login(username: string, password: string) {
|
||||
return http.post<LoginResponse>('/auth/login', { username, password })
|
||||
}
|
||||
|
||||
export function getMe() {
|
||||
return http.get<CurrentUser>('/auth/me')
|
||||
}
|
||||
|
||||
export function changePassword(currentPassword: string, newPassword: string) {
|
||||
return http.post<{ message: string; passwordChangeRequired: boolean }>('/auth/change-password', {
|
||||
currentPassword,
|
||||
newPassword,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
import http from './http'
|
||||
import type { BatchCommandResponse, Connection, ConnectionCreateRequest } from '../types'
|
||||
|
||||
export function listConnections() {
|
||||
return http.get<Connection[]>('/connections')
|
||||
}
|
||||
|
||||
export function createConnection(payload: ConnectionCreateRequest) {
|
||||
return http.post<Connection>('/connections', payload)
|
||||
}
|
||||
|
||||
export function updateConnection(id: number, payload: ConnectionCreateRequest) {
|
||||
return http.put<Connection>(`/connections/${id}`, payload)
|
||||
}
|
||||
|
||||
export function deleteConnection(id: number) {
|
||||
return http.delete<{ message: string }>(`/connections/${id}`)
|
||||
}
|
||||
|
||||
export function executeBatchCommand(connectionIds: number[], command: string) {
|
||||
return http.post<BatchCommandResponse>('/connections/batch-command', { connectionIds, command })
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import axios from 'axios'
|
||||
|
||||
const http = axios.create({
|
||||
baseURL: '/api',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
},
|
||||
})
|
||||
|
||||
http.interceptors.request.use((config) => {
|
||||
const token = localStorage.getItem('token')
|
||||
if (token) {
|
||||
config.headers.Authorization = `Bearer ${token}`
|
||||
}
|
||||
if (typeof FormData !== 'undefined' && config.data instanceof FormData) {
|
||||
const headers = config.headers as Record<string, string> | undefined
|
||||
if (headers) {
|
||||
delete headers['Content-Type']
|
||||
delete headers['content-type']
|
||||
}
|
||||
}
|
||||
return config
|
||||
})
|
||||
|
||||
http.interceptors.response.use(
|
||||
(response) => response,
|
||||
(error) => {
|
||||
if (error.response?.status === 401) {
|
||||
localStorage.removeItem('token')
|
||||
}
|
||||
return Promise.reject(error)
|
||||
},
|
||||
)
|
||||
|
||||
export default http
|
||||
@@ -0,0 +1,6 @@
|
||||
import http from './http'
|
||||
import type { MonitorMetrics } from '../types'
|
||||
|
||||
export function getMetrics(connectionId: number) {
|
||||
return http.get<MonitorMetrics>(`/monitor/${connectionId}`)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import http from './http'
|
||||
import type { SessionTreeLayoutPayload } from '../types'
|
||||
|
||||
export function getSessionTree() {
|
||||
return http.get<SessionTreeLayoutPayload>('/session-tree')
|
||||
}
|
||||
|
||||
export function saveSessionTree(payload: SessionTreeLayoutPayload) {
|
||||
return http.put<SessionTreeLayoutPayload>('/session-tree', payload)
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
import http from './http'
|
||||
import type { RemoteTransferTask, SftpFileInfo, UploadTask } from '../types'
|
||||
|
||||
export function getPwd(connectionId: number) {
|
||||
return http.get<{ path: string }>('/sftp/pwd', { params: { connectionId } })
|
||||
}
|
||||
|
||||
export function listFiles(connectionId: number, path: string) {
|
||||
return http.get<SftpFileInfo[]>('/sftp/list', { params: { connectionId, path: path || '.' } })
|
||||
}
|
||||
|
||||
export async function downloadFile(connectionId: number, path: string, downloadName?: string) {
|
||||
const token = localStorage.getItem('token')
|
||||
const params = new URLSearchParams({ connectionId: String(connectionId), path })
|
||||
const response = await fetch(`/api/sftp/download?${params.toString()}`, {
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : {},
|
||||
})
|
||||
if (!response.ok) throw new Error('Download failed')
|
||||
const blob = await response.blob()
|
||||
const url = URL.createObjectURL(blob)
|
||||
const link = document.createElement('a')
|
||||
link.href = url
|
||||
link.download = downloadName || path.split('/').pop() || 'download'
|
||||
document.body.appendChild(link)
|
||||
link.click()
|
||||
document.body.removeChild(link)
|
||||
URL.revokeObjectURL(url)
|
||||
}
|
||||
|
||||
export function uploadFile(connectionId: number, path: string, file: File) {
|
||||
const form = new FormData()
|
||||
form.append('file', file, file.name)
|
||||
return http.post<{ taskId: string; message: string }>('/sftp/upload', form, {
|
||||
params: { connectionId, path },
|
||||
})
|
||||
}
|
||||
|
||||
export function subscribeUploadProgress(taskId: string, onProgress: (task: UploadTask) => void) {
|
||||
const token = localStorage.getItem('token')
|
||||
const source = new EventSource(
|
||||
`/api/sftp/upload/tasks/${encodeURIComponent(taskId)}/progress?token=${encodeURIComponent(token || '')}`,
|
||||
)
|
||||
source.addEventListener('progress', (event) => {
|
||||
onProgress(JSON.parse((event as MessageEvent).data))
|
||||
})
|
||||
source.addEventListener('error', () => {
|
||||
source.close()
|
||||
})
|
||||
return () => source.close()
|
||||
}
|
||||
|
||||
export function createDir(connectionId: number, path: string) {
|
||||
return http.post('/sftp/mkdir', null, { params: { connectionId, path } })
|
||||
}
|
||||
|
||||
export function renameFile(connectionId: number, oldPath: string, newPath: string) {
|
||||
return http.post('/sftp/rename', null, { params: { connectionId, oldPath, newPath } })
|
||||
}
|
||||
|
||||
export function deleteFile(connectionId: number, path: string, directory: boolean) {
|
||||
return http.delete('/sftp/delete', { params: { connectionId, path, directory } })
|
||||
}
|
||||
|
||||
export function createRemoteTransferTask(
|
||||
sourceConnectionId: number,
|
||||
sourcePath: string,
|
||||
targetConnectionId: number,
|
||||
targetPath: string,
|
||||
) {
|
||||
return http.post<RemoteTransferTask>('/sftp/transfer-remote/tasks', null, {
|
||||
params: { sourceConnectionId, sourcePath, targetConnectionId, targetPath },
|
||||
})
|
||||
}
|
||||
|
||||
export function subscribeRemoteTransferProgress(taskId: string, onProgress: (task: RemoteTransferTask) => void) {
|
||||
const token = localStorage.getItem('token')
|
||||
const source = new EventSource(
|
||||
`/api/sftp/transfer-remote/tasks/${encodeURIComponent(taskId)}/progress?token=${encodeURIComponent(token || '')}`,
|
||||
)
|
||||
source.addEventListener('progress', (event) => {
|
||||
onProgress(JSON.parse((event as MessageEvent).data))
|
||||
})
|
||||
source.addEventListener('error', () => {
|
||||
source.close()
|
||||
})
|
||||
return () => source.close()
|
||||
}
|
||||
|
||||
export function cancelRemoteTransferTask(taskId: string) {
|
||||
return http.delete(`/sftp/transfer-remote/tasks/${encodeURIComponent(taskId)}`)
|
||||
}
|
||||
Reference in New Issue
Block a user