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/',
byId: (uuid: string) => `organization/${uuid}/`,
members: {
list: (uuid: string) => `organization/${uuid}/members/`,
remove: (uuid: string, userUuid: string) =>
`organization/${uuid}/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}/`,
list: (organizationUuid: string) => `organization/${organizationUuid}/members/`,
remove: (organizationUuid: string, userUuid: string) =>
`organization/${organizationUuid}/member/${userUuid}/remove/`,
},
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/`,
},
invites: {
list: (organizationUuid: string) => `invite/?organization_uuid=${organizationUuid}`,
create: (organizationUuid: string, maxUses: number) =>
`invite/?organization_uuid=${organizationUuid}&max_uses=${maxUses}`,
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: {
@ -144,6 +146,7 @@ export const API = {
list: () => 'onboarding-session/',
byId: (uuid: string) => `onboarding-session/${uuid}/`,
interact: (uuid: string) => `onboarding-session/${uuid}/interact/`,
askKa: (uuid: string) => `onboarding-session/${uuid}/ask-ka/`,
history: (uuid: string) => `onboarding-session/${uuid}/history/`,
complete: (uuid: string) => `onboarding-session/${uuid}/complete/`,
},

View file

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

View file

@ -103,7 +103,7 @@ const fetchMembers = async () => {
const fetchInvites = async () => {
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
} catch (error) {
console.error('Failed to fetch invites:', error)
@ -112,7 +112,7 @@ const fetchInvites = async () => {
const fetchRoles = async () => {
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[]
} catch (error) {
console.error('Failed to fetch Roles:', error)
@ -142,7 +142,7 @@ const createRole = async () => {
creatingRole.value = true
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')
roleModalVisible.value = false
resetRoleForm()
@ -169,7 +169,7 @@ const deleteRole = async (role: Role) => {
onOk: async () => {
deletingRoleUuid.value = role.uuid
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')
await fetchRoles()
} catch (error) {
@ -189,7 +189,7 @@ const deleteRole = async (role: Role) => {
const createInvite = async () => {
try {
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
inviteModalVisible.value = true
@ -200,19 +200,59 @@ const createInvite = async () => {
}
}
const copyInviteUrl = () => {
window.navigator.clipboard.writeText(newInviteUrl.value)
message.success('Invite URL copied to clipboard')
const fallbackCopyText = (text: string): boolean => {
const textarea = document.createElement('textarea')
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) => {
window.navigator.clipboard.writeText(url)
const copyToClipboard = async (text: string): Promise<boolean> => {
const safeText = String(text || '').trim()
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) => {
try {
await apiClient.delete(API.organization.invites.revoke(organizationUuid, inviteUuid))
await apiClient.delete(API.invites.revoke(organizationUuid, inviteUuid))
message.success('Invite revoked')
fetchInvites()
} catch (error) {
@ -280,7 +320,7 @@ onMounted(async () => {
<Tabs>
<Tabs.TabPane key="details" tab="Details">
<div class="section">
<Typography.Title :level="4" style="color: #ffffff !important">
<Typography.Title :level="4" style="color: #1f2937 !important">
Description
</Typography.Title>
<div v-if="!editingDescription">
@ -308,7 +348,7 @@ onMounted(async () => {
<Tabs.TabPane key="members" tab="Members">
<div class="section">
<div class="section-header">
<Typography.Title :level="4" style="color: #ffffff !important">
<Typography.Title :level="4" style="color: #1f2937 !important">
Members ({{ filteredMembers.length }})
</Typography.Title>
<Input
@ -359,7 +399,7 @@ onMounted(async () => {
<Tabs.TabPane key="invites" tab="Invites">
<div class="section">
<div class="section-header">
<Typography.Title :level="4" style="color: #ffffff !important">
<Typography.Title :level="4" style="color: #1f2937 !important">
Invite Tokens
</Typography.Title>
<Space>
@ -412,7 +452,7 @@ onMounted(async () => {
<Tabs.TabPane key="Roles" tab="Roles">
<div class="section">
<div class="section-header">
<Typography.Title :level="4" style="color: #ffffff !important">
<Typography.Title :level="4" style="color: #1f2937 !important">
Roles ({{ filteredRoles.length }})
</Typography.Title>
<Space>
@ -549,30 +589,30 @@ onMounted(async () => {
:deep(.ant-tabs-tab),
:deep(.ant-input-number),
:deep(.ant-input-number-input) {
color: #e5e7eb !important;
color: #1f2937 !important;
}
:deep(.ant-typography-secondary) {
color: #cbd5e1 !important;
color: #6b7280 !important;
}
:deep(.ant-input-number) {
background: #111827;
border-color: #334155;
background: #ffffff;
border-color: #d0d8e2;
}
:deep(.search-input) {
background: #1f2937 !important;
border-color: #475569 !important;
color: #f8fafc !important;
background: #ffffff !important;
border-color: #d0d8e2 !important;
color: #1f2937 !important;
}
:deep(.search-input::placeholder) {
color: #cbd5e1 !important;
color: #6b7280 !important;
}
:deep(.search-input::selection) {
background: #475569 !important;
color: #f8fafc !important;
background: #dbeafe !important;
color: #1f2937 !important;
}
</style>