Flattened api structure
This commit is contained in:
parent
8c1bbd7f6c
commit
1c0551a809
3 changed files with 90 additions and 47 deletions
|
|
@ -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/`,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
message.success('Copied to clipboard')
|
||||
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>
|
||||
|
|
|
|||
Loading…
Reference in a new issue