mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-03 13:07:11 +00:00
152 lines
5.2 KiB
Vue
152 lines
5.2 KiB
Vue
<script lang="ts" setup>
|
|
import { ProjectRoles, RoleColors, RoleIcons, RoleLabels } from 'nocodb-sdk'
|
|
import type { SelectValue } from 'ant-design-vue/es/select'
|
|
import type { IconMapKey } from '#imports'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
role: keyof typeof RoleLabels
|
|
roles: (keyof typeof RoleLabels)[]
|
|
disabledRoles?: (keyof typeof RoleLabels)[]
|
|
disabledRolesTooltip?: Record<keyof typeof RoleLabels, string>
|
|
onRoleChange: (role: keyof typeof RoleLabels) => void | Promise<any>
|
|
border?: boolean
|
|
description?: boolean
|
|
inherit?: string
|
|
size?: 'sm' | 'md' | 'lg'
|
|
showInherit?: boolean
|
|
placement?: 'bottomRight' | 'bottomLeft'
|
|
inheritedRoleIcon?: string
|
|
inheritSource?: 'workspace' | 'team'
|
|
effectiveRole?: string
|
|
}>(),
|
|
{
|
|
border: true,
|
|
description: true,
|
|
size: 'sm',
|
|
showInherit: false,
|
|
placement: 'bottomLeft',
|
|
inheritedRoleIcon: undefined,
|
|
inheritSource: undefined,
|
|
effectiveRole: undefined,
|
|
},
|
|
)
|
|
|
|
const { role, inherit, showInherit, size, placement, description } = toRefs(props)
|
|
|
|
const { t } = useI18n()
|
|
|
|
const { getResponsiveValue } = useGlobal()
|
|
|
|
const isDropdownOpen = ref(false)
|
|
|
|
const newRole = ref<null | keyof typeof RoleLabels>(null)
|
|
|
|
async function onChangeRole(val: SelectValue) {
|
|
if (val === role.value) return
|
|
|
|
newRole.value = val as keyof typeof RoleLabels
|
|
|
|
await props.onRoleChange(val as keyof typeof RoleLabels)
|
|
|
|
newRole.value = null
|
|
}
|
|
|
|
const roleSelectorOptions = computed<NcListItemType[]>(() => {
|
|
return (props.disabledRoles || []).concat(props.roles || []).map((role: keyof typeof RoleLabels): NcListItemType => {
|
|
return {
|
|
value: role,
|
|
label: t(`objects.roleType.${RoleLabels[role]}`),
|
|
description: t(`objects.roleDescription.${role}`),
|
|
icon: RoleIcons[role],
|
|
color: RoleColors[role],
|
|
ncItemDisabled: props.disabledRoles?.includes(role),
|
|
ncItemTooltip: props.disabledRoles?.includes(role) ? props.disabledRolesTooltip?.[role] ?? '' : '',
|
|
}
|
|
})
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="nc-roles-selector relative flex items-center">
|
|
<NcListDropdown
|
|
v-model:visible="isDropdownOpen"
|
|
:default-slot-wrapper="false"
|
|
default-slot-wrapper-class="flex-1 flex items-center gap-3"
|
|
:placement="placement"
|
|
>
|
|
<div class="flex flex-col gap-1 cursor-pointer">
|
|
<RolesBadge data-testid="roles" :border="false" :role="effectiveRole || role" :size="size" clickable class="flex-none" />
|
|
<div
|
|
v-if="showInherit && role === ProjectRoles.INHERIT && !!inherit"
|
|
class="flex items-center gap-1 text-xs text-nc-content-gray-muted"
|
|
>
|
|
<GeneralIcon icon="role_inherit" class="h-3 w-3" />
|
|
<span>{{
|
|
inheritSource === 'team' ? $t('tooltip.roleInheritedFromTeam') : $t('tooltip.roleInheritedFromWorkspace')
|
|
}}</span>
|
|
</div>
|
|
</div>
|
|
|
|
<template #overlay="{ onEsc }">
|
|
<NcList
|
|
v-model:open="isDropdownOpen"
|
|
:value="role"
|
|
:list="roleSelectorOptions"
|
|
:item-height="!description ? 48 : 72"
|
|
class="!w-auto max-w-80"
|
|
:class="{
|
|
'min-w-50': !description,
|
|
'min-w-80': description,
|
|
}"
|
|
:is-locked="!!newRole"
|
|
variant="default"
|
|
:focus-search-on-open="getResponsiveValue(false, true)"
|
|
item-class-name="nc-role-select-dropdown !px-3"
|
|
:wrapper-class-name="`!h-auto nc-role-selector-dropdown ${!!newRole ? '!cursor-wait' : ''}`"
|
|
@update:value="onChangeRole"
|
|
@escape="onEsc"
|
|
>
|
|
<template #listItem="{ option }">
|
|
<div class="w-full flex flex-col rounded-md" :class="[`nc-role-select-${option.value}`]">
|
|
<div class="w-full flex items-center justify-between">
|
|
<div class="flex items-center gap-2">
|
|
<GeneralIcon
|
|
:icon="(option.icon as IconMapKey)"
|
|
class="flex-none h-4 w-4"
|
|
:class="roleColorsMapping[option.color]?.content ?? 'text-nc-content-brand-hover'"
|
|
/>
|
|
<span
|
|
class="text-captionDropdownDefault"
|
|
:class="[
|
|
roleColorsMapping[option.color]?.content ?? 'text-nc-content-brand-hover',
|
|
{
|
|
'!font-semibold': !description,
|
|
},
|
|
]"
|
|
>
|
|
{{ option.label }}
|
|
</span>
|
|
</div>
|
|
<GeneralLoader v-if="option.value === newRole" size="medium" />
|
|
<GeneralIcon v-else-if="!newRole && option.value === role" icon="check" class="text-nc-content-brand h-4 w-4" />
|
|
</div>
|
|
<div
|
|
v-if="description"
|
|
class="text-bodySm !font-light ml-6"
|
|
:class="
|
|
option.value === ProjectRoles.INHERIT
|
|
? 'text-nc-content-gray-muted dark:text-nc-content-gray-light'
|
|
: 'text-nc-content-gray-muted'
|
|
"
|
|
>
|
|
{{ option.description }}
|
|
</div>
|
|
</div>
|
|
</template>
|
|
</NcList>
|
|
</template>
|
|
</NcListDropdown>
|
|
</div>
|
|
</template>
|