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/',
|
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/',
|
|
||||||
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: {
|
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/`,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
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')
|
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>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue