Consolidated api list to nested structure, moved types to separate files

This commit is contained in:
Viswamedha Nalabotu 2026-02-27 12:26:51 +00:00
parent 5ffdb8ba27
commit 529ab95a91
15 changed files with 245 additions and 176 deletions

View file

@ -40,8 +40,12 @@ class ApiClient {
} }
} }
processUrl(endpoint: string): string {
return `${apiEndpoint}${endpoint}`
}
get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> { get<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return this.client.get<T>(url, this.withCsrf(config)) return this.client.get<T>(this.processUrl(url), this.withCsrf(config))
} }
post<T = unknown>( post<T = unknown>(
@ -49,7 +53,7 @@ class ApiClient {
data?: unknown, data?: unknown,
config?: AxiosRequestConfig, config?: AxiosRequestConfig,
): Promise<AxiosResponse<T>> { ): Promise<AxiosResponse<T>> {
return this.client.post<T>(url, data, this.withCsrf(config)) return this.client.post<T>(this.processUrl(url), data, this.withCsrf(config))
} }
put<T = unknown>( put<T = unknown>(
@ -57,7 +61,7 @@ class ApiClient {
data?: unknown, data?: unknown,
config?: AxiosRequestConfig, config?: AxiosRequestConfig,
): Promise<AxiosResponse<T>> { ): Promise<AxiosResponse<T>> {
return this.client.put<T>(url, data, this.withCsrf(config)) return this.client.put<T>(this.processUrl(url), data, this.withCsrf(config))
} }
patch<T = unknown>( patch<T = unknown>(
@ -65,64 +69,89 @@ class ApiClient {
data?: unknown, data?: unknown,
config?: AxiosRequestConfig, config?: AxiosRequestConfig,
): Promise<AxiosResponse<T>> { ): Promise<AxiosResponse<T>> {
return this.client.patch<T>(url, data, this.withCsrf(config)) return this.client.patch<T>(this.processUrl(url), data, this.withCsrf(config))
} }
delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> { delete<T = unknown>(url: string, config?: AxiosRequestConfig): Promise<AxiosResponse<T>> {
return this.client.delete<T>(url, this.withCsrf(config)) return this.client.delete<T>(this.processUrl(url), this.withCsrf(config))
} }
} }
export const apiEndpoint = '/api/';
export const API = { export const API = {
me: () => '/api/user/me/', auth: {
login: () => '/api/user/login/', me: () => 'user/me/',
logout: () => '/api/user/logout/', login: () => 'user/login/',
session: () => '/api/user/session/', logout: () => 'user/logout/',
signup: () => '/api/user/signup/', session: () => 'user/session/',
changePassword: () => '/api/user/change_password/', signup: () => 'user/signup/',
changePassword: () => 'user/change_password/',
},
organizations: () => '/api/organization/', organization: {
organization: (uuid: string) => `/api/organization/${uuid}/`, list: () => 'organization/',
organizationMembers: (uuid: string) => `/api/organization/${uuid}/members/`, byId: (uuid: string) => `organization/${uuid}/`,
organizationMemberRemove: (uuid: string, userId: number) => members: {
`/api/organization/${uuid}/member/${userId}/remove/`, list: (uuid: string) => `organization/${uuid}/members/`,
remove: (uuid: string, userId: number) =>
`organization/${uuid}/member/${userId}/remove/`,
},
invites: {
list: (uuid: string) => `organization/${uuid}/invite/`,
create: (uuid: string, maxUses: number) =>
`organization/${uuid}/create-invite/?max_uses=${maxUses}`,
revoke: (uuid: string, inviteUuid: string) =>
`organization/${uuid}/revoke-invite/${inviteUuid}/`,
join: (token: string) => `organization/join/${token}/`,
},
leave: (uuid: string) => `organization/${uuid}/leave/`,
roles: {
list: (uuid: string) => `organization/${uuid}/role/`,
mine: () => 'organization/role/mine/',
remove: (orgUuid: string, roleUuid: string) =>
`organization/${orgUuid}/role/${roleUuid}/`,
join: (orgUuid: string, roleUuid: string) =>
`organization/${orgUuid}/role/${roleUuid}/join/`,
},
},
organizationInvites: (uuid: string) => `/api/organization/${uuid}/invite/`, knowledge: {
organizationCreateInvite: (uuid: string, max_uses: number) => trainingFiles: {
`/api/organization/${uuid}/create-invite/?max_uses=${max_uses}`, list: () => 'training-file/',
organizationRevokeInvite: (uuid: string, inviteUuid: string) => byId: (uuid: string) => `training-file/${uuid}/`,
`/api/organization/${uuid}/revoke-invite/${inviteUuid}/`, },
organizationJoin: (token: string) => `/api/organization/join/${token}/`, roleRagDocuments: {
organizationLeave: (uuid: string) => `/api/organization/${uuid}/leave/`, list: () => 'role-rag-document/',
byId: (uuid: string) => `role-rag-document/${uuid}/`,
},
},
organizationRoles: (uuid: string) => `/api/organization/${uuid}/role/`, agents: {
organizationRolesMine: () => '/api/organization/role/mine/', configs: {
organizationRoleDelete: (orgUuid: string, roleUuid: string) => list: () => 'agent-config/',
`/api/organization/${orgUuid}/role/${roleUuid}/`, byId: (uuid: string) => `agent-config/${uuid}/`,
organizationRoleJoin: (orgUuid: string, roleUuid: string) => },
`/api/organization/${orgUuid}/role/${roleUuid}/join/`, },
trainingFiles: () => `/api/training-file/`, onboarding: {
trainingFile: (uuid: string) => `/api/training-file/${uuid}/`, flows: {
organizationTrainingFiles: () => `/api/training-file/`, list: () => 'onboarding-flow/',
organizationTrainingFile: (uuid: string) => `/api/training-file/${uuid}/`, byId: (uuid: string) => `onboarding-flow/${uuid}/`,
roleRagDocuments: () => `/api/role-rag-document/`, startSession: (uuid: string) => `onboarding-flow/${uuid}/start-session/`,
roleRagDocument: (uuid: string) => `/api/role-rag-document/${uuid}/`, },
sessions: {
agentConfigs: () => '/api/agent-config/', list: () => 'onboarding-session/',
agentConfig: (uuid: string) => `/api/agent-config/${uuid}/`, byId: (uuid: string) => `onboarding-session/${uuid}/`,
interact: (uuid: string) => `onboarding-session/${uuid}/interact/`,
onboardingFlows: () => '/api/onboarding-flow/', history: (uuid: string) => `onboarding-session/${uuid}/history/`,
onboardingFlow: (uuid: string) => `/api/onboarding-flow/${uuid}/`, complete: (uuid: string) => `onboarding-session/${uuid}/complete/`,
onboardingFlowStartSession: (uuid: string) => `/api/onboarding-flow/${uuid}/start-session/`, },
logs: {
onboardingSessions: () => '/api/onboarding-session/', list: () => 'agent-interaction-log/',
onboardingSession: (uuid: string) => `/api/onboarding-session/${uuid}/`, byId: (uuid: string) => `agent-interaction-log/${uuid}/`,
onboardingSessionInteract: (uuid: string) => `/api/onboarding-session/${uuid}/interact/`, },
onboardingSessionHistory: (uuid: string) => `/api/onboarding-session/${uuid}/history/`, },
onboardingSessionComplete: (uuid: string) => `/api/onboarding-session/${uuid}/complete/`,
interactionLogs: () => '/api/agent-interaction-log/',
interactionLog: (uuid: string) => `/api/agent-interaction-log/${uuid}/`,
} }
export const apiClient = new ApiClient() export const apiClient = new ApiClient()
export { isAxiosError } from 'axios' export { isAxiosError } from 'axios'

View file

@ -1,20 +1,20 @@
import { defineStore } from 'pinia' import { defineStore } from 'pinia'
import { ref } from 'vue' import { ref } from 'vue'
import type { AgentEvent } from '../types/agent' import type {
AgentEvent,
AgentExecutionStatus,
AgentSocketEventPayload,
AgentStartPayload,
} from '../types/agent'
export const useAgentStore = defineStore('agent', () => { export const useAgentStore = defineStore('agent', () => {
const isConnected = ref(false) const isConnected = ref(false)
const executionStatus = ref<'idle' | 'running' | 'completed' | 'failed'>('idle') const executionStatus = ref<AgentExecutionStatus>('idle')
const eventLog = ref<AgentEvent[]>([]) const eventLog = ref<AgentEvent[]>([])
const lastExecutionId = ref<string | null>(null) const lastExecutionId = ref<string | null>(null)
const socket = ref<WebSocket | null>(null) const socket = ref<WebSocket | null>(null)
const pushEvent = (evt: { const pushEvent = (evt: AgentSocketEventPayload) => {
type: string
message?: string
content?: unknown
timestamp?: string
}) => {
eventLog.value.unshift({ eventLog.value.unshift({
type: evt.type, type: evt.type,
message: evt.message, message: evt.message,
@ -40,7 +40,7 @@ export const useAgentStore = defineStore('agent', () => {
socket.value.onmessage = (event) => { socket.value.onmessage = (event) => {
try { try {
const payload = JSON.parse(event.data) const payload = JSON.parse(event.data) as AgentSocketEventPayload
const type = payload.type const type = payload.type
if (payload.execution_id) { if (payload.execution_id) {
@ -96,7 +96,7 @@ export const useAgentStore = defineStore('agent', () => {
executionStatus.value = 'idle' executionStatus.value = 'idle'
} }
const startAgent = (data: { query?: string; role_uuid?: string; max_tokens?: number }) => { const startAgent = (data: AgentStartPayload) => {
if (!socket.value || socket.value.readyState !== WebSocket.OPEN) return if (!socket.value || socket.value.readyState !== WebSocket.OPEN) return
executionStatus.value = 'running' executionStatus.value = 'running'

View file

@ -63,9 +63,9 @@ export const useUserStore = defineStore('user', () => {
loading.value = true loading.value = true
error.value = null error.value = null
try { try {
const response = await apiClient.get<SessionResponse>(API.session()) const response = await apiClient.get<SessionResponse>(API.auth.session())
if (response.data?.isAuthenticated) { if (response.data?.isAuthenticated) {
const userData = await apiClient.get<User>(API.me()) const userData = await apiClient.get<User>(API.auth.me())
setUser(userData.data) setUser(userData.data)
await fetchJoinedOrganizations() await fetchJoinedOrganizations()
} else { } else {
@ -91,7 +91,7 @@ export const useUserStore = defineStore('user', () => {
const fetchJoinedOrganizations = async () => { const fetchJoinedOrganizations = async () => {
if (!user.value) return if (!user.value) return
try { try {
const response = await apiClient.get<Organization[]>(API.organizations()) const response = await apiClient.get<Organization[]>(API.organization.list())
setJoinedOrganizations(response.data) setJoinedOrganizations(response.data)
return response.data return response.data
} catch (err: unknown) { } catch (err: unknown) {
@ -105,7 +105,7 @@ export const useUserStore = defineStore('user', () => {
if (!user.value || !userSelectedOrganization.value) return if (!user.value || !userSelectedOrganization.value) return
try { try {
const response = await apiClient.get<Role[]>( const response = await apiClient.get<Role[]>(
API.organizationRoles(userSelectedOrganization.value.uuid), API.organization.roles.list(userSelectedOrganization.value.uuid),
) )
setJoinedRoles(response.data) setJoinedRoles(response.data)
return response.data return response.data
@ -127,7 +127,7 @@ export const useUserStore = defineStore('user', () => {
const res = await apiClient.post<{ const res = await apiClient.post<{
user: User user: User
message?: string message?: string
}>(API.login(), { email_address: emailAddress, password }) }>(API.auth.login(), { email_address: emailAddress, password })
setUser(res.data?.user ?? null) setUser(res.data?.user ?? null)
return res.data return res.data
} catch (err: unknown) { } catch (err: unknown) {
@ -156,7 +156,7 @@ export const useUserStore = defineStore('user', () => {
loading.value = true loading.value = true
error.value = null error.value = null
try { try {
await apiClient.post(API.signup(), payload) await apiClient.post(API.auth.signup(), payload)
await login(payload.email_address, payload.password) await login(payload.email_address, payload.password)
} catch (err: unknown) { } catch (err: unknown) {
if (isAxiosError(err)) { if (isAxiosError(err)) {
@ -176,7 +176,7 @@ export const useUserStore = defineStore('user', () => {
loading.value = true loading.value = true
error.value = null error.value = null
try { try {
await apiClient.post(API.logout()) await apiClient.post(API.auth.logout())
} catch (err: unknown) { } catch (err: unknown) {
if (isAxiosError(err)) { if (isAxiosError(err)) {
error.value = err.response?.data?.detail || err.response?.data?.error || err.message error.value = err.response?.data?.detail || err.response?.data?.error || err.message

View file

@ -1,3 +1,44 @@
import type { UuidNameRef } from './common'
export type AgentType = 'curriculum' | 'knowledge' | 'assessment' | 'monitor' | string
export type AgentExecutionStatus = 'idle' | 'running' | 'completed' | 'failed'
export interface LLMConfig {
model_id?: string
[key: string]: unknown
}
export interface AgentConfig {
uuid: string
name: string
agent_type: AgentType
llm_config: LLMConfig
organization: string | UuidNameRef
description?: string
[key: string]: unknown
}
export type AgentStartPayload = {
query?: string
role_uuid?: string
max_tokens?: number
}
export type AgentSocketEventPayload = {
type: string
message?: string
thought?: string
content?: unknown
timestamp?: string
execution_id?: string
}
export type AgentRunResult = {
response?: string
[key: string]: unknown
}
export type AgentEvent = { export type AgentEvent = {
type: string type: string
timestamp: Date timestamp: Date

7
site/src/types/common.ts Normal file
View file

@ -0,0 +1,7 @@
export type MaybePaginated<T> = T[] | { results?: T[] }
export type UuidNameRef = {
uuid?: string
name?: string
[key: string]: unknown
}

View file

@ -1,3 +1,6 @@
import type { Role } from './organization'
import type { UuidNameRef } from './common'
export type OnboardingField = { export type OnboardingField = {
uuid: string uuid: string
key: string key: string
@ -22,7 +25,7 @@ export type OnboardingPage = {
export type OnboardingFlow = { export type OnboardingFlow = {
uuid: string uuid: string
role: string role: string | UuidNameRef
agent?: string | null agent?: string | null
title: string title: string
description?: string description?: string
@ -42,3 +45,39 @@ export type OnboardingSession = {
export type OnboardingFeedback = { export type OnboardingFeedback = {
summary?: string summary?: string
} }
export type OnboardingSessionStatus = 'active' | 'completed' | 'paused'
export type OnboardingSessionSummary = {
uuid: string
status: string
role?: string | UuidNameRef
}
export type OnboardingFlowSummary = {
uuid: string
role?: string | UuidNameRef
}
export type ProgressSessionApi = {
uuid: string
status: OnboardingSessionStatus
role: UuidNameRef
updated_at?: string
state?: Record<string, unknown>
}
export type ProgressFlowApi = {
uuid: string
role: UuidNameRef
title: string
}
export type RoleProgressItem = {
role: Role
latestStatus: string
latestSessionUuid?: string
flowTitle?: string
feedback?: string
loadingFeedback: boolean
}

View file

@ -17,17 +17,22 @@ import { marked } from 'marked'
import DOMPurify from 'dompurify' import DOMPurify from 'dompurify'
import { useAgentStore } from '../stores/agentStore' import { useAgentStore } from '../stores/agentStore'
import { apiClient, isAxiosError, API } from '../router/api' import { apiClient, isAxiosError, API } from '../router/api'
import type { AgentConfig, AgentRunResult } from '../types/agent'
const route = useRoute() const route = useRoute()
const agentStore = useAgentStore() const agentStore = useAgentStore()
const agentId = route.params.id as string const agentId = route.params.id as string
const agent = ref<Record<string, unknown>>({ const agent = ref<AgentConfig>({
id: agentId, id: agentId,
name: 'Loading...', name: 'Loading...',
description: '', description: '',
status: 'idle', status: 'idle',
uuid: agentId,
agent_type: 'knowledge',
llm_config: {},
organization: '',
}) })
const maxTokens = ref<number>(256) const maxTokens = ref<number>(256)
@ -38,7 +43,7 @@ const isConnected = computed(() => agentStore.isConnected ?? false)
const agentResponse = computed(() => { const agentResponse = computed(() => {
const completedEvent = agentStore.eventLog?.find((event) => event.type === 'completed') const completedEvent = agentStore.eventLog?.find((event) => event.type === 'completed')
if (completedEvent?.content && typeof completedEvent.content === 'object') { if (completedEvent?.content && typeof completedEvent.content === 'object') {
const output = completedEvent.content as Record<string, unknown> const output = completedEvent.content as AgentRunResult
return (output.response as string) || null return (output.response as string) || null
} }
@ -58,7 +63,7 @@ const statusColor = (status: string) => {
const fetchAgent = async () => { const fetchAgent = async () => {
try { try {
const response = await apiClient.get<Record<string, unknown>>(API.agentConfig(agentId)) const response = await apiClient.get<AgentConfig>(API.agents.configs.byId(agentId))
agent.value = response.data agent.value = response.data
} catch (error) { } catch (error) {
console.error('Failed to fetch agent:', error) console.error('Failed to fetch agent:', error)

View file

@ -2,37 +2,18 @@
import { ref, onMounted } from 'vue' import { ref, onMounted } from 'vue'
import { List, Typography, Button, Card, Spin, message, Tag, Space } from 'ant-design-vue' import { List, Typography, Button, Card, Spin, message, Tag, Space } from 'ant-design-vue'
import { apiClient, API } from '../router/api' import { apiClient, API } from '../router/api'
import type { MaybePaginated } from '../types/common'
import type { AgentConfig } from '../types/agent'
interface LLMConfig { const agents = ref<AgentConfig[]>([])
model_id?: string
[key: string]: unknown
}
interface OrganizationRef {
uuid?: string
name?: string
[key: string]: unknown
}
interface Agent {
uuid: string
name: string
agent_type: string
llm_config: LLMConfig
organization: string | OrganizationRef
}
const agents = ref<Agent[]>([])
const loading = ref(false) const loading = ref(false)
const loadError = ref(false) const loadError = ref(false)
type MaybePaginated<T> = T[] | { results?: T[] }
const fetchAgents = async () => { const fetchAgents = async () => {
loading.value = true loading.value = true
loadError.value = false loadError.value = false
try { try {
const response = await apiClient.get<MaybePaginated<Agent>>(API.agentConfigs()) const response = await apiClient.get<MaybePaginated<AgentConfig>>(API.agents.configs.list())
const data = response.data const data = response.data
agents.value = Array.isArray(data) ? data : data.results || [] agents.value = Array.isArray(data) ? data : data.results || []

View file

@ -18,7 +18,7 @@ const acceptInvite = async () => {
error.value = null error.value = null
try { try {
const response = await apiClient.post<{ message: string; success: boolean; uuid: string }>( const response = await apiClient.post<{ message: string; success: boolean; uuid: string }>(
API.organizationJoin(token), API.organization.invites.join(token),
) )
message.success(response.data?.message || 'Successfully joined organization') message.success(response.data?.message || 'Successfully joined organization')
accepted.value = true accepted.value = true

View file

@ -19,7 +19,13 @@ import {
} from 'ant-design-vue' } from 'ant-design-vue'
import { apiClient, API } from '../router/api' import { apiClient, API } from '../router/api'
import { useAgentStore } from '../stores/agentStore' import { useAgentStore } from '../stores/agentStore'
import type { OnboardingFlow, OnboardingPage, OnboardingSession } from '../types/onboarding' import type {
OnboardingFlow,
OnboardingPage,
OnboardingSession,
OnboardingSessionSummary,
OnboardingFlowSummary,
} from '../types/onboarding'
import { Marked } from 'marked' import { Marked } from 'marked'
import DOMPurify from 'dompurify' import DOMPurify from 'dompurify'
@ -53,29 +59,18 @@ const renderedBody = computed(() => {
return DOMPurify.sanitize(marked.parse(currentPage.value.body) as string) return DOMPurify.sanitize(marked.parse(currentPage.value.body) as string)
}) })
type SessionSummary = { const getSessionRoleUuid = (sessionData: OnboardingSessionSummary): string | undefined => {
uuid: string
status: string
role?: string | { uuid?: string }
}
type FlowSummary = {
uuid: string
role?: string | { uuid?: string }
}
const getSessionRoleUuid = (sessionData: SessionSummary): string | undefined => {
if (typeof sessionData.role === 'string') return sessionData.role if (typeof sessionData.role === 'string') return sessionData.role
return sessionData.role?.uuid return sessionData.role?.uuid
} }
const getFlowRoleUuid = (flowData: FlowSummary): string | undefined => { const getFlowRoleUuid = (flowData: OnboardingFlowSummary): string | undefined => {
if (typeof flowData.role === 'string') return flowData.role if (typeof flowData.role === 'string') return flowData.role
return flowData.role?.uuid return flowData.role?.uuid
} }
const findCompletedSessionForRole = async (): Promise<SessionSummary | null> => { const findCompletedSessionForRole = async (): Promise<OnboardingSessionSummary | null> => {
const sessionRes = await apiClient.get<SessionSummary[]>(API.onboardingSessions(), { const sessionRes = await apiClient.get<OnboardingSessionSummary[]>(API.onboarding.sessions.list(), {
params: { role: roleId.value }, params: { role: roleId.value },
}) })
return ( return (
@ -90,13 +85,13 @@ const retryGeneration = async () => {
generationHandled.value = false generationHandled.value = false
try { try {
const response = await apiClient.get<OnboardingFlow[]>(API.onboardingFlows(), { const response = await apiClient.get<OnboardingFlow[]>(API.onboarding.flows.list(), {
params: { role: roleId.value }, params: { role: roleId.value },
}) })
if (response.data && response.data.length > 0) { if (response.data && response.data.length > 0) {
for (const flow of response.data) { for (const flow of response.data) {
await apiClient.delete(API.onboardingFlow(flow.uuid)) await apiClient.delete(API.onboarding.flows.byId(flow.uuid))
} }
} }
@ -116,7 +111,7 @@ const resetCurrentFlow = async () => {
deletingFlow.value = true deletingFlow.value = true
try { try {
await apiClient.delete(API.onboardingFlow(flowDetails.value.uuid)) await apiClient.delete(API.onboarding.flows.byId(flowDetails.value.uuid))
flowDetails.value = null flowDetails.value = null
session.value = null session.value = null
@ -141,7 +136,7 @@ const initOnboarding = async () => {
if (loading.value) return if (loading.value) return
loading.value = true loading.value = true
try { try {
const response = await apiClient.get<OnboardingFlow[]>(API.onboardingFlows(), { const response = await apiClient.get<OnboardingFlow[]>(API.onboarding.flows.list(), {
params: { role: roleId.value }, params: { role: roleId.value },
}) })
@ -227,10 +222,10 @@ watch(
) )
const loadFlow = async (flowUuid: string) => { const loadFlow = async (flowUuid: string) => {
const response = await apiClient.get<OnboardingFlow>(API.onboardingFlow(flowUuid)) const response = await apiClient.get<OnboardingFlow>(API.onboarding.flows.byId(flowUuid))
flowDetails.value = response.data flowDetails.value = response.data
const sessionRes = await apiClient.post<OnboardingSession>( const sessionRes = await apiClient.post<OnboardingSession>(
API.onboardingFlowStartSession(flowUuid), API.onboarding.flows.startSession(flowUuid),
) )
session.value = sessionRes.data session.value = sessionRes.data
@ -253,7 +248,7 @@ const hydrateFormState = () => {
const onSubmitPage = async () => { const onSubmitPage = async () => {
if (!currentPage.value || !session.value) return if (!currentPage.value || !session.value) return
try { try {
await apiClient.post(API.onboardingSessionInteract(session.value.uuid), { await apiClient.post(API.onboarding.sessions.interact(session.value.uuid), {
page_uuid: currentPage.value.uuid, page_uuid: currentPage.value.uuid,
responses: formState, responses: formState,
}) })
@ -263,7 +258,7 @@ const onSubmitPage = async () => {
hydrateFormState() hydrateFormState()
window.scrollTo(0, 0) window.scrollTo(0, 0)
} else { } else {
await apiClient.post(API.onboardingSessionComplete(session.value.uuid)) await apiClient.post(API.onboarding.sessions.complete(session.value.uuid))
message.success('Onboarding Finished!') message.success('Onboarding Finished!')
router.push('/organization') router.push('/organization')
} }

View file

@ -48,7 +48,7 @@ const newDescription = ref('')
const fetchOrganization = async () => { const fetchOrganization = async () => {
loading.value = true loading.value = true
try { try {
const response = await apiClient.get<Organization>(API.organization(orgId)) const response = await apiClient.get<Organization>(API.organization.byId(orgId))
organization.value = response.data organization.value = response.data
newDescription.value = response.data.description newDescription.value = response.data.description
} catch (error) { } catch (error) {
@ -61,7 +61,7 @@ const fetchOrganization = async () => {
const fetchMembers = async () => { const fetchMembers = async () => {
try { try {
const response = await apiClient.get<User[]>(API.organizationMembers(orgId)) const response = await apiClient.get<User[]>(API.organization.members.list(orgId))
members.value = response.data members.value = response.data
} catch (error) { } catch (error) {
console.error('Failed to fetch members:', error) console.error('Failed to fetch members:', error)
@ -70,7 +70,7 @@ const fetchMembers = async () => {
const fetchInvites = async () => { const fetchInvites = async () => {
try { try {
const response = await apiClient.get<InviteToken[]>(API.organizationInvites(orgId)) const response = await apiClient.get<InviteToken[]>(API.organization.invites.list(orgId))
invites.value = response.data invites.value = response.data
} catch (error) { } catch (error) {
console.error('Failed to fetch invites:', error) console.error('Failed to fetch invites:', error)
@ -79,7 +79,7 @@ const fetchInvites = async () => {
const fetchRoles = async () => { const fetchRoles = async () => {
try { try {
const response = await apiClient.get<Role[]>(API.organizationRoles(orgId)) const response = await apiClient.get<Role[]>(API.organization.roles.list(orgId))
Roles.value = response.data as unknown as Role[] Roles.value = response.data as unknown as Role[]
} catch (error) { } catch (error) {
console.error('Failed to fetch Roles:', error) console.error('Failed to fetch Roles:', error)
@ -109,7 +109,7 @@ const createRole = async () => {
creatingRole.value = true creatingRole.value = true
try { try {
await apiClient.post(API.organizationRoles(orgId), { name, description }) await apiClient.post(API.organization.roles.list(orgId), { name, description })
message.success('Role created successfully') message.success('Role created successfully')
roleModalVisible.value = false roleModalVisible.value = false
resetRoleForm() resetRoleForm()
@ -136,7 +136,7 @@ const deleteRole = async (role: Role) => {
onOk: async () => { onOk: async () => {
deletingRoleUuid.value = role.uuid deletingRoleUuid.value = role.uuid
try { try {
await apiClient.delete(API.organizationRoleDelete(orgId, role.uuid)) await apiClient.delete(API.organization.roles.remove(orgId, role.uuid))
message.success('Role deleted successfully') message.success('Role deleted successfully')
await fetchRoles() await fetchRoles()
} catch (error) { } catch (error) {
@ -156,7 +156,7 @@ const deleteRole = async (role: Role) => {
const createInvite = async () => { const createInvite = async () => {
try { try {
const response = await apiClient.post<InviteToken>( const response = await apiClient.post<InviteToken>(
API.organizationCreateInvite(orgId, newInviteMaxUses.value), API.organization.invites.create(orgId, newInviteMaxUses.value),
) )
newInviteUrl.value = response.data.invite_url newInviteUrl.value = response.data.invite_url
inviteModalVisible.value = true inviteModalVisible.value = true
@ -179,7 +179,7 @@ const copyUrl = (url: string) => {
const revokeInvite = async (token: string) => { const revokeInvite = async (token: string) => {
try { try {
await apiClient.delete(API.organizationRevokeInvite(orgId, token)) await apiClient.delete(API.organization.invites.revoke(orgId, token))
message.success('Invite revoked') message.success('Invite revoked')
fetchInvites() fetchInvites()
} catch (error) { } catch (error) {
@ -190,7 +190,7 @@ const revokeInvite = async (token: string) => {
const removeMember = async (userId: number) => { const removeMember = async (userId: number) => {
try { try {
await apiClient.post(API.organizationMemberRemove(orgId, userId)) await apiClient.post(API.organization.members.remove(orgId, userId))
message.success('Member removed') message.success('Member removed')
fetchMembers() fetchMembers()
} catch (error) { } catch (error) {
@ -203,7 +203,7 @@ const removeMember = async (userId: number) => {
const saveDescription = async () => { const saveDescription = async () => {
try { try {
await apiClient.patch(API.organization(orgId), { await apiClient.patch(API.organization.byId(orgId), {
description: newDescription.value, description: newDescription.value,
}) })
message.success('Description updated') message.success('Description updated')

View file

@ -45,7 +45,7 @@ const isManager = computed(() => {
const fetchOrganization = async () => { const fetchOrganization = async () => {
loading.value = true loading.value = true
try { try {
const response = await apiClient.get<Organization>(API.organization(orgId)) const response = await apiClient.get<Organization>(API.organization.byId(orgId))
organization.value = response.data organization.value = response.data
} catch (error) { } catch (error) {
console.error('Failed to fetch organization:', error) console.error('Failed to fetch organization:', error)
@ -58,7 +58,7 @@ const fetchOrganization = async () => {
const fetchRoles = async () => { const fetchRoles = async () => {
if (!organization.value?.uuid) return if (!organization.value?.uuid) return
try { try {
const response = await apiClient.get<Role[]>(API.organizationRoles(organization.value.uuid)) const response = await apiClient.get<Role[]>(API.organization.roles.list(organization.value.uuid))
roles.value = response.data roles.value = response.data
} catch (error) { } catch (error) {
console.error('Failed to fetch roles:', error) console.error('Failed to fetch roles:', error)
@ -68,7 +68,7 @@ const fetchRoles = async () => {
const fetchUserRoleMemberships = async () => { const fetchUserRoleMemberships = async () => {
if (!organization.value?.uuid) return if (!organization.value?.uuid) return
try { try {
const response = await apiClient.get<Role[]>(API.organizationRolesMine()) const response = await apiClient.get<Role[]>(API.organization.roles.mine())
const mine = Array.isArray(response.data) ? response.data : [] const mine = Array.isArray(response.data) ? response.data : []
const orgUuid = organization.value.uuid const orgUuid = organization.value.uuid
const joinedRoles = mine.filter((role) => role.organization?.uuid === orgUuid) const joinedRoles = mine.filter((role) => role.organization?.uuid === orgUuid)
@ -87,7 +87,7 @@ const fetchMembers = async () => {
if (!organization.value?.uuid) return if (!organization.value?.uuid) return
try { try {
const response = await apiClient.get<Array<{ user: { id: number }; role: string }>>( const response = await apiClient.get<Array<{ user: { id: number }; role: string }>>(
API.organizationMembers(organization.value.uuid), API.organization.members.list(organization.value.uuid),
) )
members.value = response.data members.value = response.data
} catch (error) { } catch (error) {
@ -114,7 +114,7 @@ const selectRole = async (roleUuid: string) => {
} }
try { try {
await apiClient.post(API.organizationRoleJoin(organization.value.uuid, roleUuid)) await apiClient.post(API.organization.roles.join(organization.value.uuid, roleUuid))
message.success('Successfully joined role') message.success('Successfully joined role')
if (!auth.userJoinedRoles.some((role) => role.uuid === roleUuid)) { if (!auth.userJoinedRoles.some((role) => role.uuid === roleUuid)) {
auth.setJoinedRoles([ auth.setJoinedRoles([
@ -133,7 +133,7 @@ const selectRole = async (roleUuid: string) => {
const fetchTrainingFiles = async () => { const fetchTrainingFiles = async () => {
if (!organization.value?.uuid) return if (!organization.value?.uuid) return
try { try {
const response = await apiClient.get<TrainingFile[]>(API.organizationTrainingFiles()) const response = await apiClient.get<TrainingFile[]>(API.knowledge.trainingFiles.list())
trainingFiles.value = response.data trainingFiles.value = response.data
} catch (error) { } catch (error) {
console.error('Failed to fetch training files:', error) console.error('Failed to fetch training files:', error)
@ -203,7 +203,7 @@ const handleFileUpload = async (file: File, description: string = '') => {
} }
const response = await apiClient.post<TrainingFile>( const response = await apiClient.post<TrainingFile>(
API.organizationTrainingFiles(), API.knowledge.trainingFiles.list(),
formData, formData,
{ {
headers: { headers: {
@ -245,7 +245,7 @@ const deleteFile = async (uuid: string, fileName: string) => {
cancelText: 'Cancel', cancelText: 'Cancel',
onOk: async () => { onOk: async () => {
try { try {
await apiClient.delete(API.organizationTrainingFile(uuid)) await apiClient.delete(API.knowledge.trainingFiles.byId(uuid))
message.success('File deleted successfully') message.success('File deleted successfully')
trainingFiles.value = trainingFiles.value.filter((f) => f.uuid !== uuid) trainingFiles.value = trainingFiles.value.filter((f) => f.uuid !== uuid)
} catch (error) { } catch (error) {

View file

@ -20,7 +20,7 @@ const createOrgForm = ref({
const fetchOrganizations = async () => { const fetchOrganizations = async () => {
loading.value = true loading.value = true
try { try {
const resp = await apiClient.get<Organization[]>(API.organizations()) const resp = await apiClient.get<Organization[]>(API.organization.list())
organizations.value = resp.data || [] organizations.value = resp.data || []
if (organizations.value.length === 1 && !auth.isGeneralManager) { if (organizations.value.length === 1 && !auth.isGeneralManager) {
@ -71,7 +71,7 @@ const handleCreateOrganization = async () => {
creatingOrganization.value = true creatingOrganization.value = true
try { try {
const response = await apiClient.post<Organization>(API.organizations(), { const response = await apiClient.post<Organization>(API.organization.list(), {
name, name,
description, description,
}) })

View file

@ -4,14 +4,7 @@ import { useRoute, useRouter } from 'vue-router'
import { Card, Typography, Button, Spin, Tag, List, message } from 'ant-design-vue' import { Card, Typography, Button, Spin, Tag, List, message } from 'ant-design-vue'
import { apiClient, API } from '../router/api' import { apiClient, API } from '../router/api'
import type { Role } from '../types/organization' import type { Role } from '../types/organization'
import type { ProgressSessionApi } from '../types/onboarding'
type SessionApi = {
uuid: string
status: 'active' | 'completed' | 'paused'
state?: Record<string, unknown>
role: { uuid: string; name: string }
updated_at?: string
}
const route = useRoute() const route = useRoute()
const router = useRouter() const router = useRouter()
@ -20,7 +13,7 @@ const roleId = computed(() => route.params.roleId as string)
const loading = ref(false) const loading = ref(false)
const monitoring = ref(false) const monitoring = ref(false)
const role = ref<Role | null>(null) const role = ref<Role | null>(null)
const sessions = ref<SessionApi[]>([]) const sessions = ref<ProgressSessionApi[]>([])
const feedback = ref<string>('') const feedback = ref<string>('')
const monitorLogs = ref<string[]>([]) const monitorLogs = ref<string[]>([])
@ -93,8 +86,8 @@ const loadData = async () => {
loading.value = true loading.value = true
try { try {
const [rolesRes, sessionsRes] = await Promise.all([ const [rolesRes, sessionsRes] = await Promise.all([
apiClient.get<Role[]>(API.organizationRolesMine()), apiClient.get<Role[]>(API.organization.roles.mine()),
apiClient.get<SessionApi[]>(API.onboardingSessions()), apiClient.get<ProgressSessionApi[]>(API.onboarding.sessions.list()),
]) ])
const roles = Array.isArray(rolesRes.data) ? rolesRes.data : [] const roles = Array.isArray(rolesRes.data) ? rolesRes.data : []

View file

@ -4,28 +4,7 @@ import { useRouter } from 'vue-router'
import { Card, Typography, List, Tag, Button, Spin, message } from 'ant-design-vue' import { Card, Typography, List, Tag, Button, Spin, message } from 'ant-design-vue'
import { apiClient, API } from '../router/api' import { apiClient, API } from '../router/api'
import type { Role } from '../types/organization' import type { Role } from '../types/organization'
import type { ProgressSessionApi, ProgressFlowApi, RoleProgressItem } from '../types/onboarding'
type SessionApi = {
uuid: string
status: 'active' | 'completed' | 'paused'
role: { uuid: string; name: string }
updated_at?: string
}
type FlowApi = {
uuid: string
role: { uuid: string; name: string }
title: string
}
type RoleProgressItem = {
role: Role
latestStatus: string
latestSessionUuid?: string
flowTitle?: string
feedback?: string
loadingFeedback: boolean
}
const router = useRouter() const router = useRouter()
const loading = ref(false) const loading = ref(false)
@ -85,9 +64,9 @@ const loadProgress = async () => {
loading.value = true loading.value = true
try { try {
const [rolesRes, sessionsRes, flowsRes] = await Promise.all([ const [rolesRes, sessionsRes, flowsRes] = await Promise.all([
apiClient.get<Role[]>(API.organizationRolesMine()), apiClient.get<Role[]>(API.organization.roles.mine()),
apiClient.get<SessionApi[]>(API.onboardingSessions()), apiClient.get<ProgressSessionApi[]>(API.onboarding.sessions.list()),
apiClient.get<FlowApi[]>(API.onboardingFlows()), apiClient.get<ProgressFlowApi[]>(API.onboarding.flows.list()),
]) ])
const roles = Array.isArray(rolesRes.data) ? rolesRes.data : [] const roles = Array.isArray(rolesRes.data) ? rolesRes.data : []