mirror of
https://github.com/nocodb/nocodb.git
synced 2026-04-30 20:26:49 +00:00
Merge branch 'develop' into feat/sort-for-user-management
This commit is contained in:
@@ -5,14 +5,14 @@ import {
|
||||
ProjectRoles,
|
||||
WorkspaceRolesToProjectRoles,
|
||||
extractRolesObj,
|
||||
parseStringDateTime,
|
||||
timeAgo,
|
||||
} from 'nocodb-sdk'
|
||||
import type { Roles, WorkspaceUserRoles } from 'nocodb-sdk'
|
||||
import InfiniteLoading from 'v3-infinite-loading'
|
||||
import { isEeUI, storeToRefs, useUserSorts } from '#imports'
|
||||
|
||||
const basesStore = useBases()
|
||||
const { getProjectUsers, createProjectUser, updateProjectUser, removeProjectUser } = basesStore
|
||||
const { getBaseUsers, createProjectUser, updateProjectUser, removeProjectUser } = basesStore
|
||||
const { activeProjectId } = storeToRefs(basesStore)
|
||||
|
||||
const { orgRoles, baseRoles } = useRoles()
|
||||
@@ -33,7 +33,6 @@ interface Collaborators {
|
||||
const collaborators = ref<Collaborators[]>([])
|
||||
const totalCollaborators = ref(0)
|
||||
const userSearchText = ref('')
|
||||
const currentPage = ref(0)
|
||||
|
||||
const isLoading = ref(false)
|
||||
const isSearching = ref(false)
|
||||
@@ -45,52 +44,32 @@ const sortedCollaborators = computed(() => {
|
||||
|
||||
const loadCollaborators = async () => {
|
||||
try {
|
||||
currentPage.value += 1
|
||||
|
||||
const { users, totalRows } = await getProjectUsers({
|
||||
const { users, totalRows } = await getBaseUsers({
|
||||
baseId: activeProjectId.value!,
|
||||
page: currentPage.value,
|
||||
...(!userSearchText.value ? {} : ({ searchText: userSearchText.value } as any)),
|
||||
limit: 20,
|
||||
force: true,
|
||||
})
|
||||
|
||||
totalCollaborators.value = totalRows
|
||||
collaborators.value = [
|
||||
...collaborators.value,
|
||||
...users.map((user: any) => ({
|
||||
...user,
|
||||
base_roles: user.roles,
|
||||
roles: extractRolesObj(user.main_roles)?.[OrgUserRoles.SUPER_ADMIN]
|
||||
? OrgUserRoles.SUPER_ADMIN
|
||||
: user.roles ??
|
||||
(user.workspace_roles
|
||||
? WorkspaceRolesToProjectRoles[user.workspace_roles as WorkspaceUserRoles] ?? ProjectRoles.NO_ACCESS
|
||||
: ProjectRoles.NO_ACCESS),
|
||||
})),
|
||||
...users
|
||||
.filter((u: any) => !u?.deleted)
|
||||
.map((user: any) => ({
|
||||
...user,
|
||||
base_roles: user.roles,
|
||||
roles: extractRolesObj(user.main_roles)?.[OrgUserRoles.SUPER_ADMIN]
|
||||
? OrgUserRoles.SUPER_ADMIN
|
||||
: user.roles ??
|
||||
(user.workspace_roles
|
||||
? WorkspaceRolesToProjectRoles[user.workspace_roles as WorkspaceUserRoles] ?? ProjectRoles.NO_ACCESS
|
||||
: ProjectRoles.NO_ACCESS),
|
||||
})),
|
||||
]
|
||||
} catch (e: any) {
|
||||
message.error(await extractSdkResponseErrorMsg(e))
|
||||
}
|
||||
}
|
||||
|
||||
const loadListData = async ($state: any) => {
|
||||
const prevUsersCount = collaborators.value?.length || 0
|
||||
if (collaborators.value?.length === totalCollaborators.value) {
|
||||
$state.complete()
|
||||
return
|
||||
}
|
||||
$state.loading()
|
||||
// const oldPagesCount = currentPage.value || 0
|
||||
|
||||
await loadCollaborators()
|
||||
|
||||
if (prevUsersCount === collaborators.value?.length) {
|
||||
$state.complete()
|
||||
return
|
||||
}
|
||||
$state.loaded()
|
||||
}
|
||||
|
||||
const updateCollaborator = async (collab: any, roles: ProjectRoles) => {
|
||||
const currentCollaborator = collaborators.value.find((coll) => coll.id === collab.id)!
|
||||
|
||||
@@ -126,29 +105,6 @@ const updateCollaborator = async (collab: any, roles: ProjectRoles) => {
|
||||
}
|
||||
}
|
||||
|
||||
watchDebounced(
|
||||
userSearchText,
|
||||
async () => {
|
||||
isSearching.value = true
|
||||
|
||||
currentPage.value = 0
|
||||
totalCollaborators.value = 0
|
||||
collaborators.value = []
|
||||
|
||||
try {
|
||||
await loadCollaborators()
|
||||
} catch (e: any) {
|
||||
message.error(await extractSdkResponseErrorMsg(e))
|
||||
} finally {
|
||||
isSearching.value = false
|
||||
}
|
||||
},
|
||||
{
|
||||
debounce: 300,
|
||||
maxWait: 600,
|
||||
},
|
||||
)
|
||||
|
||||
onMounted(async () => {
|
||||
isLoading.value = true
|
||||
try {
|
||||
@@ -168,6 +124,10 @@ onMounted(async () => {
|
||||
isLoading.value = false
|
||||
}
|
||||
})
|
||||
|
||||
const filteredCollaborators = computed(() =>
|
||||
collaborators.value.filter((collab) => collab.email.toLowerCase().includes(userSearchText.value.toLowerCase())),
|
||||
)
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@@ -189,7 +149,7 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-else-if="!collaborators?.length"
|
||||
v-else-if="!filteredCollaborators?.length"
|
||||
class="nc-collaborators-list w-full h-full flex flex-col items-center justify-center mt-36"
|
||||
>
|
||||
<Empty description="$t('title.noMembersFound')" />
|
||||
@@ -203,18 +163,19 @@ onMounted(async () => {
|
||||
</span>
|
||||
<LazyAccountUserMenu :direction="sortDirection.email" field="email" :handle-user-sort="saveOrUpdate" />
|
||||
</div>
|
||||
<div class="text-gray-700 date-joined-grid">{{ $t('title.dateJoined') }}</div>
|
||||
|
||||
<div class="text-gray-700 user-access-grid flex items-center space-x-2">
|
||||
<span>
|
||||
{{ $t('general.access') }}
|
||||
</span>
|
||||
<LazyAccountUserMenu :direction="sortDirection.roles" field="roles" :handle-user-sort="saveOrUpdate" />
|
||||
</div>
|
||||
<div class="text-gray-700 date-joined-grid">{{ $t('title.dateJoined') }}</div>
|
||||
</div>
|
||||
|
||||
<div class="flex flex-col nc-scrollbar-md">
|
||||
<div
|
||||
v-for="(collab, i) of sortedCollaborators"
|
||||
v-for="(collab, i) of filteredCollaborators"
|
||||
:key="i"
|
||||
class="user-row flex flex-row border-b-1 py-1 min-h-14 items-center"
|
||||
>
|
||||
@@ -224,7 +185,6 @@ onMounted(async () => {
|
||||
{{ collab.email }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="date-joined-grid">{{ timeAgo(collab.created_at) }}</div>
|
||||
<div class="user-access-grid">
|
||||
<template v-if="accessibleRoles.includes(collab.roles)">
|
||||
<RolesSelector
|
||||
@@ -243,20 +203,19 @@ onMounted(async () => {
|
||||
<RolesBadge :role="collab.roles" />
|
||||
</template>
|
||||
</div>
|
||||
<div class="date-joined-grid">
|
||||
<NcTooltip class="max-w-full">
|
||||
<template #title>
|
||||
{{ parseStringDateTime(collab.created_at) }}
|
||||
</template>
|
||||
<span>
|
||||
{{ timeAgo(collab.created_at) }}
|
||||
</span>
|
||||
</NcTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<InfiniteLoading v-bind="$attrs" @infinite="loadListData">
|
||||
<template #spinner>
|
||||
<div class="flex flex-row w-full justify-center mt-2">
|
||||
<GeneralLoader />
|
||||
</div>
|
||||
</template>
|
||||
<template #complete>
|
||||
<span></span>
|
||||
</template>
|
||||
</InfiniteLoading>
|
||||
</div>
|
||||
</template>
|
||||
</div>
|
||||
@@ -280,12 +239,11 @@ onMounted(async () => {
|
||||
}
|
||||
|
||||
.date-joined-grid {
|
||||
@apply flex items-start;
|
||||
width: calc(50% - 10rem);
|
||||
@apply w-1/4 flex items-start;
|
||||
}
|
||||
|
||||
.user-access-grid {
|
||||
@apply w-40;
|
||||
@apply w-1/4 flex justify-start;
|
||||
}
|
||||
|
||||
.user-row {
|
||||
|
||||
Reference in New Issue
Block a user