Flattened api structure

This commit is contained in:
Viswamedha Nalabotu 2026-03-08 13:19:17 +00:00
parent 8c1bbd7f6c
commit 1c0551a809
3 changed files with 90 additions and 47 deletions

View file

@ -93,27 +93,29 @@ export const API = {
list: () => 'organization/', list: () => 'organization/',
byId: (uuid: string) => `organization/${uuid}/`, byId: (uuid: string) => `organization/${uuid}/`,
members: { members: {
list: (uuid: string) => `organization/${uuid}/members/`, list: (organizationUuid: string) => `organization/${organizationUuid}/members/`,
remove: (uuid: string, userUuid: string) => remove: (organizationUuid: string, userUuid: string) =>
`organization/${uuid}/member/${userUuid}/remove/`, `organization/${organizationUuid}/member/${userUuid}/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: (inviteUuid: string) => `organization/join/${inviteUuid}/`,
}, },
leave: (uuid: string) => `organization/${uuid}/leave/`, leave: (uuid: string) => `organization/${uuid}/leave/`,
roles: { },
list: (uuid: string) => `organization/${uuid}/role/`,
mine: () => 'organization/role/mine/', invites: {
remove: (orgUuid: string, roleUuid: string) => list: (organizationUuid: string) => `invite/?organization_uuid=${organizationUuid}`,
`organization/${orgUuid}/role/${roleUuid}/`, create: (organizationUuid: string, maxUses: number) =>
join: (orgUuid: string, roleUuid: string) => `invite/?organization_uuid=${organizationUuid}&max_uses=${maxUses}`,
`organization/${orgUuid}/role/${roleUuid}/join/`, revoke: (organizationUuid: string, inviteUuid: string) =>
}, `invite/${inviteUuid}/?organization_uuid=${organizationUuid}`,
join: (inviteUuid: string) => `invite/join/?invite_uuid=${inviteUuid}`,
},
roles: {
list: (organizationUuid: string) => `role/?organization_uuid=${organizationUuid}`,
mine: () => 'role/mine/',
remove: (organizationUuid: string, roleUuid: string) =>
`role/${roleUuid}/?organization_uuid=${organizationUuid}`,
join: (organizationUuid: string, roleUuid: string) =>
`role/${roleUuid}/join/?organization_uuid=${organizationUuid}`,
}, },
knowledge: { knowledge: {
@ -144,6 +146,7 @@ export const API = {
list: () => 'onboarding-session/', list: () => 'onboarding-session/',
byId: (uuid: string) => `onboarding-session/${uuid}/`, byId: (uuid: string) => `onboarding-session/${uuid}/`,
interact: (uuid: string) => `onboarding-session/${uuid}/interact/`, interact: (uuid: string) => `onboarding-session/${uuid}/interact/`,
askKa: (uuid: string) => `onboarding-session/${uuid}/ask-ka/`,
history: (uuid: string) => `onboarding-session/${uuid}/history/`, history: (uuid: string) => `onboarding-session/${uuid}/history/`,
complete: (uuid: string) => `onboarding-session/${uuid}/complete/`, complete: (uuid: string) => `onboarding-session/${uuid}/complete/`,
}, },

View file

@ -19,7 +19,7 @@ const acceptInvite = async () => {
error.value = null error.value = null
try { try {
const response = await apiClient.post<{ message?: string; organization?: { uuid?: string } }>( const response = await apiClient.post<{ message?: string; organization?: { uuid?: string } }>(
API.organization.invites.join(inviteUuid), API.invites.join(inviteUuid),
) )
joinedOrganizationUuid.value = response.data?.organization?.uuid || null joinedOrganizationUuid.value = response.data?.organization?.uuid || null
message.success(response.data?.message || 'Successfully joined organization') message.success(response.data?.message || 'Successfully joined organization')
@ -84,7 +84,7 @@ onMounted(() => {
} }
.org-info { .org-info {
background: #1f2937; background: #f8fafc;
border-radius: 8px; border-radius: 8px;
padding: 1.5rem; padding: 1.5rem;
margin: 2rem 0; margin: 2rem 0;

View file

@ -103,7 +103,7 @@ const fetchMembers = async () => {
const fetchInvites = async () => { const fetchInvites = async () => {
try { try {
const response = await apiClient.get<InviteToken[]>(API.organization.invites.list(organizationUuid)) const response = await apiClient.get<InviteToken[]>(API.invites.list(organizationUuid))
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)
@ -112,7 +112,7 @@ const fetchInvites = async () => {
const fetchRoles = async () => { const fetchRoles = async () => {
try { try {
const response = await apiClient.get<Role[]>(API.organization.roles.list(organizationUuid)) const response = await apiClient.get<Role[]>(API.roles.list(organizationUuid))
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)
@ -142,7 +142,7 @@ const createRole = async () => {
creatingRole.value = true creatingRole.value = true
try { try {
await apiClient.post(API.organization.roles.list(organizationUuid), { name, description }) await apiClient.post(API.roles.list(organizationUuid), { name, description })
message.success('Role created successfully') message.success('Role created successfully')
roleModalVisible.value = false roleModalVisible.value = false
resetRoleForm() resetRoleForm()
@ -169,7 +169,7 @@ const deleteRole = async (role: Role) => {
onOk: async () => { onOk: async () => {
deletingRoleUuid.value = role.uuid deletingRoleUuid.value = role.uuid
try { try {
await apiClient.delete(API.organization.roles.remove(organizationUuid, role.uuid)) await apiClient.delete(API.roles.remove(organizationUuid, role.uuid))
message.success('Role deleted successfully') message.success('Role deleted successfully')
await fetchRoles() await fetchRoles()
} catch (error) { } catch (error) {
@ -189,7 +189,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.organization.invites.create(organizationUuid, newInviteMaxUses.value), API.invites.create(organizationUuid, newInviteMaxUses.value),
) )
newInviteUrl.value = response.data.invite_url newInviteUrl.value = response.data.invite_url
inviteModalVisible.value = true inviteModalVisible.value = true
@ -200,19 +200,59 @@ const createInvite = async () => {
} }
} }
const copyInviteUrl = () => { const fallbackCopyText = (text: string): boolean => {
window.navigator.clipboard.writeText(newInviteUrl.value) const textarea = document.createElement('textarea')
message.success('Invite URL copied to clipboard') textarea.value = text
textarea.setAttribute('readonly', 'true')
textarea.style.position = 'fixed'
textarea.style.opacity = '0'
textarea.style.pointerEvents = 'none'
document.body.appendChild(textarea)
textarea.focus()
textarea.select()
const copied = document.execCommand('copy')
document.body.removeChild(textarea)
return copied
} }
const copyUrl = (url: string) => { const copyToClipboard = async (text: string): Promise<boolean> => {
window.navigator.clipboard.writeText(url) const safeText = String(text || '').trim()
message.success('Copied to clipboard') if (!safeText) return false
if (window.isSecureContext && window.navigator.clipboard?.writeText) {
try {
await window.navigator.clipboard.writeText(safeText)
return true
} catch {
// Fall through to legacy copy for restricted browser contexts.
}
}
return fallbackCopyText(safeText)
}
const copyInviteUrl = async () => {
const copied = await copyToClipboard(newInviteUrl.value)
if (copied) {
message.success('Invite URL copied to clipboard')
return
}
message.error('Could not copy invite URL. Please copy it manually.')
}
const copyUrl = async (url: string) => {
const copied = await copyToClipboard(url)
if (copied) {
message.success('Copied to clipboard')
return
}
message.error('Could not copy URL. Please copy it manually.')
} }
const revokeInvite = async (inviteUuid: string) => { const revokeInvite = async (inviteUuid: string) => {
try { try {
await apiClient.delete(API.organization.invites.revoke(organizationUuid, inviteUuid)) await apiClient.delete(API.invites.revoke(organizationUuid, inviteUuid))
message.success('Invite revoked') message.success('Invite revoked')
fetchInvites() fetchInvites()
} catch (error) { } catch (error) {
@ -280,7 +320,7 @@ onMounted(async () => {
<Tabs> <Tabs>
<Tabs.TabPane key="details" tab="Details"> <Tabs.TabPane key="details" tab="Details">
<div class="section"> <div class="section">
<Typography.Title :level="4" style="color: #ffffff !important"> <Typography.Title :level="4" style="color: #1f2937 !important">
Description Description
</Typography.Title> </Typography.Title>
<div v-if="!editingDescription"> <div v-if="!editingDescription">
@ -308,7 +348,7 @@ onMounted(async () => {
<Tabs.TabPane key="members" tab="Members"> <Tabs.TabPane key="members" tab="Members">
<div class="section"> <div class="section">
<div class="section-header"> <div class="section-header">
<Typography.Title :level="4" style="color: #ffffff !important"> <Typography.Title :level="4" style="color: #1f2937 !important">
Members ({{ filteredMembers.length }}) Members ({{ filteredMembers.length }})
</Typography.Title> </Typography.Title>
<Input <Input
@ -359,7 +399,7 @@ onMounted(async () => {
<Tabs.TabPane key="invites" tab="Invites"> <Tabs.TabPane key="invites" tab="Invites">
<div class="section"> <div class="section">
<div class="section-header"> <div class="section-header">
<Typography.Title :level="4" style="color: #ffffff !important"> <Typography.Title :level="4" style="color: #1f2937 !important">
Invite Tokens Invite Tokens
</Typography.Title> </Typography.Title>
<Space> <Space>
@ -412,7 +452,7 @@ onMounted(async () => {
<Tabs.TabPane key="Roles" tab="Roles"> <Tabs.TabPane key="Roles" tab="Roles">
<div class="section"> <div class="section">
<div class="section-header"> <div class="section-header">
<Typography.Title :level="4" style="color: #ffffff !important"> <Typography.Title :level="4" style="color: #1f2937 !important">
Roles ({{ filteredRoles.length }}) Roles ({{ filteredRoles.length }})
</Typography.Title> </Typography.Title>
<Space> <Space>
@ -549,30 +589,30 @@ onMounted(async () => {
:deep(.ant-tabs-tab), :deep(.ant-tabs-tab),
:deep(.ant-input-number), :deep(.ant-input-number),
:deep(.ant-input-number-input) { :deep(.ant-input-number-input) {
color: #e5e7eb !important; color: #1f2937 !important;
} }
:deep(.ant-typography-secondary) { :deep(.ant-typography-secondary) {
color: #cbd5e1 !important; color: #6b7280 !important;
} }
:deep(.ant-input-number) { :deep(.ant-input-number) {
background: #111827; background: #ffffff;
border-color: #334155; border-color: #d0d8e2;
} }
:deep(.search-input) { :deep(.search-input) {
background: #1f2937 !important; background: #ffffff !important;
border-color: #475569 !important; border-color: #d0d8e2 !important;
color: #f8fafc !important; color: #1f2937 !important;
} }
:deep(.search-input::placeholder) { :deep(.search-input::placeholder) {
color: #cbd5e1 !important; color: #6b7280 !important;
} }
:deep(.search-input::selection) { :deep(.search-input::selection) {
background: #475569 !important; background: #dbeafe !important;
color: #f8fafc !important; color: #1f2937 !important;
} }
</style> </style>