Browse Source

Merge pull request #9293 from nocodb/nc-feat/user-mgmt-followup

Nc feat/user mgmt followup
pull/9300/head
Pranav C 4 months ago committed by GitHub
parent
commit
5e35237d4f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 24
      packages/nc-gui/components/cell/User.vue
  2. 10
      packages/nc-gui/components/general/UserIcon.vue
  3. 23
      packages/nc-gui/components/workspace/CollaboratorsList.vue
  4. 9
      packages/nc-gui/store/base.ts

24
packages/nc-gui/components/cell/User.vue

@ -32,8 +32,12 @@ const activeCell = inject(ActiveCellInj, ref(false))
const basesStore = useBases() const basesStore = useBases()
const baseStore = useBase()
const { basesUser } = storeToRefs(basesStore) const { basesUser } = storeToRefs(basesStore)
const { idUserMap } = storeToRefs(baseStore)
const baseUsers = computed(() => (meta.value.base_id ? basesUser.value.get(meta.value.base_id) || [] : [])) const baseUsers = computed(() => (meta.value.base_id ? basesUser.value.get(meta.value.base_id) || [] : []))
// use both ActiveCellInj or EditModeInj to determine the active state // use both ActiveCellInj or EditModeInj to determine the active state
@ -303,6 +307,11 @@ const filterOption = (input: string, option: any) => {
return searchVal.toLowerCase().includes(input.toLowerCase()) return searchVal.toLowerCase().includes(input.toLowerCase())
} }
} }
// check if user is part of the base
const isCollaborator = (userIdOrEmail) => {
return !idUserMap.value?.[userIdOrEmail]?.deleted
}
</script> </script>
<template> <template>
@ -347,6 +356,7 @@ const filterOption = (input: string, option: any) => {
:name="op.display_name?.trim() ? op.display_name?.trim() : ''" :name="op.display_name?.trim() ? op.display_name?.trim() : ''"
:email="op.email" :email="op.email"
class="!text-[0.65rem]" class="!text-[0.65rem]"
:disabled="!isCollaborator(op.id)"
/> />
</div> </div>
<NcTooltip class="truncate max-w-full" show-on-truncate-only> <NcTooltip class="truncate max-w-full" show-on-truncate-only>
@ -360,6 +370,9 @@ const filterOption = (input: string, option: any) => {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
display: 'inline', display: 'inline',
}" }"
:class="{
'text-gray-600': !isCollaborator(op.id || op.email),
}"
> >
{{ op.display_name?.trim() || op.email }} {{ op.display_name?.trim() || op.email }}
</span> </span>
@ -408,6 +421,7 @@ const filterOption = (input: string, option: any) => {
> >
<div class="flex-none"> <div class="flex-none">
<GeneralUserIcon <GeneralUserIcon
:disabled="!isCollaborator(selectedOpt.value)"
size="auto" size="auto"
:name="!selectedOpt.label?.includes('@') ? selectedOpt.label.trim() : ''" :name="!selectedOpt.label?.includes('@') ? selectedOpt.label.trim() : ''"
:email="selectedOpt.label" :email="selectedOpt.label"
@ -425,6 +439,9 @@ const filterOption = (input: string, option: any) => {
whiteSpace: 'nowrap', whiteSpace: 'nowrap',
display: 'inline', display: 'inline',
}" }"
:class="{
'text-gray-600': !isCollaborator(selectedOpt.value),
}"
> >
{{ selectedOpt.label }} {{ selectedOpt.label }}
</span> </span>
@ -540,10 +557,17 @@ const filterOption = (input: string, option: any) => {
:name="!label?.includes('@') ? label.trim() : ''" :name="!label?.includes('@') ? label.trim() : ''"
:email="label" :email="label"
class="!text-[0.65rem]" class="!text-[0.65rem]"
:disabled="!isCollaborator(val)"
/> />
</div> </div>
<span
:class="{
'text-gray-600': !isCollaborator(val),
}"
>
{{ label }} {{ label }}
</span> </span>
</span>
</a-tag> </a-tag>
</template> </template>
</a-select> </a-select>

10
packages/nc-gui/components/general/UserIcon.vue

@ -6,11 +6,13 @@ const props = withDefaults(
size?: 'small' | 'medium' | 'base' | 'large' | 'xlarge' | 'auto' size?: 'small' | 'medium' | 'base' | 'large' | 'xlarge' | 'auto'
name?: string name?: string
email?: string email?: string
disabled?: boolean
}>(), }>(),
{ {
size: 'medium', size: 'medium',
name: '', name: '',
email: '', email: '',
disabled: false,
}, },
) )
@ -19,11 +21,19 @@ const { size, email } = toRefs(props)
const displayName = computed(() => props.name?.trim() || '') const displayName = computed(() => props.name?.trim() || '')
const backgroundColor = computed(() => { const backgroundColor = computed(() => {
if (props.disabled) {
return '#bbbbbb'
}
// in comments we need to generate user icon from email // in comments we need to generate user icon from email
return displayName.value ? stringToColor(displayName.value) : email.value ? stringToColor(email.value) : '#FFFFFF' return displayName.value ? stringToColor(displayName.value) : email.value ? stringToColor(email.value) : '#FFFFFF'
}) })
const usernameInitials = computed(() => { const usernameInitials = computed(() => {
if (props.disabled) {
return ''
}
const displayNameSplit = displayName.value?.split(' ').filter((name) => name) ?? [] const displayNameSplit = displayName.value?.split(' ').filter((name) => name) ?? []
if (displayNameSplit.length > 0) { if (displayNameSplit.length > 0) {

23
packages/nc-gui/components/workspace/CollaboratorsList.vue

@ -7,6 +7,8 @@ const props = defineProps<{
const { workspaceRoles } = useRoles() const { workspaceRoles } = useRoles()
const { user } = useGlobal()
const workspaceStore = useWorkspace() const workspaceStore = useWorkspace()
const { removeCollaborator, updateCollaborator: _updateCollaborator, loadWorkspace } = workspaceStore const { removeCollaborator, updateCollaborator: _updateCollaborator, loadWorkspace } = workspaceStore
@ -35,8 +37,6 @@ const isOnlyOneOwner = computed(() => {
return collaborators.value?.filter((collab) => collab.roles === WorkspaceUserRoles.OWNER).length === 1 return collaborators.value?.filter((collab) => collab.roles === WorkspaceUserRoles.OWNER).length === 1
}) })
const { isUIAllowed } = useRoles()
const { t } = useI18n() const { t } = useI18n()
const inviteDlg = ref(false) const inviteDlg = ref(false)
@ -289,25 +289,20 @@ const isDeleteOrUpdateAllowed = (user) => {
<a-menu-divider class="my-1.5" /> <a-menu-divider class="my-1.5" />
</template> </template>
<NcMenuItem <NcTooltip :disabled="!isOnlyOneOwner || record.roles !== WorkspaceUserRoles.OWNER">
v-if="isUIAllowed('transferWorkspaceOwnership')" <template #title>
:disabled="!isDeleteOrUpdateAllowed(record)" Each workspace must have at least one owner. Please assign another user as the Owner before leaving the
data-testid="nc-admin-org-user-assign-admin" workspace. If you are the last member, consider deleting the workspace instead.
@click="updateCollaborator(record, WorkspaceUserRoles.OWNER)" </template>
>
<GeneralIcon :class="{ 'text-gray-800': isDeleteOrUpdateAllowed(record) }" icon="user" />
<span>{{ $t('labels.assignAs') }}</span>
<RolesBadge :border="false" :show-icon="false" role="owner" :disabled="!isDeleteOrUpdateAllowed(record)" />
</NcMenuItem>
<NcMenuItem <NcMenuItem
:disabled="!isDeleteOrUpdateAllowed(record)" :disabled="!isDeleteOrUpdateAllowed(record)"
:class="{ '!text-red-500 !hover:bg-red-50': isDeleteOrUpdateAllowed(record) }" :class="{ '!text-red-500 !hover:bg-red-50': isDeleteOrUpdateAllowed(record) }"
@click="removeCollaborator(record.id, currentWorkspace?.id)" @click="removeCollaborator(record.id, currentWorkspace?.id)"
> >
<MaterialSymbolsDeleteOutlineRounded /> <MaterialSymbolsDeleteOutlineRounded />
Remove user {{ record.id === user.id ? 'Leave workspace' : 'Remove user' }}
</NcMenuItem> </NcMenuItem>
</NcTooltip>
</NcMenu> </NcMenu>
</template> </template>
</NcDropdown> </NcDropdown>

9
packages/nc-gui/store/base.ts

@ -26,6 +26,14 @@ export const useBase = defineStore('baseStore', () => {
const tablesStore = useTablesStore() const tablesStore = useTablesStore()
const idUserMap = computed(() => {
return (basesStore.basesUser.get(baseId.value) || []).reduce((acc, user) => {
acc[user.id] = user
acc[user.email] = user
return acc
}, {} as Record<string, any>)
})
// todo: refactor // todo: refactor
const sharedProject = ref<BaseType>() const sharedProject = ref<BaseType>()
@ -297,6 +305,7 @@ export const useBase = defineStore('baseStore', () => {
baseUrl, baseUrl,
getBaseType, getBaseType,
navigateToProjectPage, navigateToProjectPage,
idUserMap,
} }
}) })

Loading…
Cancel
Save