mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-02 21:27:03 +00:00
154 lines
5.1 KiB
Vue
154 lines
5.1 KiB
Vue
<script lang="ts" setup>
|
|
import { type TeamV3V3Type } from 'nocodb-sdk'
|
|
import type { SelectValue } from 'ant-design-vue/es/select'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
value: RawValueType
|
|
teams?: TeamV3V3Type[]
|
|
existingTeamIds?: string[]
|
|
onChange: (team: RawValueType) => void | Promise<any>
|
|
size?: 'sm' | 'md' | 'lg'
|
|
placement?: 'bottomRight' | 'bottomLeft'
|
|
isMultiSelect?: boolean
|
|
defaultSlotWrapperClass?: string
|
|
}>(),
|
|
{
|
|
description: true,
|
|
size: 'lg',
|
|
placement: 'bottomLeft',
|
|
onChange: () => Promise.resolve(),
|
|
isMultiSelect: false,
|
|
defaultSlotWrapperClass: '',
|
|
},
|
|
)
|
|
|
|
const { value, placement } = toRefs(props)
|
|
|
|
const workspaceStore = useWorkspace()
|
|
|
|
const { teams: teamList } = storeToRefs(workspaceStore)
|
|
|
|
const { t } = useI18n()
|
|
|
|
const isDropdownOpen = ref(false)
|
|
|
|
const newTeam = ref<null | string>(null)
|
|
|
|
function compareValue(_value: string | number, oldValue = value.value): boolean {
|
|
if (props.isMultiSelect) {
|
|
return ((oldValue as MultiSelectRawValueType) || []).includes(_value)
|
|
}
|
|
|
|
return oldValue === _value
|
|
}
|
|
|
|
async function onChangeTeam(val: SelectValue) {
|
|
if (props.isMultiSelect && deepCompare(value.value, val)) return
|
|
if (!props.isMultiSelect && val === value.value) return
|
|
|
|
newTeam.value = val as string
|
|
|
|
await props.onChange?.(props.isMultiSelect ? (val as MultiSelectRawValueType) : (val as string))
|
|
|
|
newTeam.value = null
|
|
}
|
|
|
|
const teamSelectorOptions = computed<NcListItemType[]>(() => {
|
|
return (props.teams || teamList.value || []).map(
|
|
(team): NcListItemType => ({
|
|
...team,
|
|
value: team.id,
|
|
label: team.title,
|
|
description: `${team.members_count || 0} ${t('labels.members')}`,
|
|
icon: team.icon,
|
|
icon_type: team.icon_type,
|
|
ncItemDisabled: props.existingTeamIds?.includes(team.id),
|
|
ncItemTooltip: props.existingTeamIds?.includes(team.id) ? t('objects.teams.alreadyAdded') : '',
|
|
}),
|
|
)
|
|
})
|
|
|
|
const selectedTeams = computed(() => {
|
|
return teamSelectorOptions.value.filter((team) => {
|
|
if (props.isMultiSelect) {
|
|
return team.value && (value.value as MultiSelectRawValueType)?.includes(team.value as string)
|
|
} else {
|
|
return team.value && team.value === (value.value as string)
|
|
}
|
|
}) as NcListItemType[]
|
|
})
|
|
</script>
|
|
|
|
<template>
|
|
<div class="nc-roles-selector relative flex items-center w-full">
|
|
<NcListDropdown
|
|
v-model:visible="isDropdownOpen"
|
|
:default-slot-wrapper-class="`w-full ${size === 'lg' ? '!h-10' : ''} ${defaultSlotWrapperClass}`"
|
|
:placement="placement"
|
|
>
|
|
<div class="w-[calc(100%_-_24px)] flex items-center gap-2">
|
|
<NcRenderVisibleItems v-if="selectedTeams.length" :items="selectedTeams" :icon-width="20" :padding-x="16" class="w-full">
|
|
<template #default="{ visibleItems }">
|
|
<div
|
|
v-for="selectedTeam of visibleItems"
|
|
:key="selectedTeam.value"
|
|
class="flex items-center gap-2 border-1 border-nc-border-gray-medium rounded-xl pr-2 truncate"
|
|
>
|
|
<GeneralTeamIcon :team="selectedTeam" class="!rounded-full" />
|
|
|
|
{{ selectedTeam?.label }}
|
|
</div>
|
|
</template>
|
|
</NcRenderVisibleItems>
|
|
|
|
<span v-if="!selectedTeams.length" class="text-nc-content-gray-muted">
|
|
-{{ isMultiSelect ? t('labels.selectOneOrMoreTeams') : t('labels.selectTeam') }}-
|
|
</span>
|
|
</div>
|
|
<GeneralIcon
|
|
icon="chevronDown"
|
|
class="flex-none h-4 w-4 text-nc-content-gray-muted transition-transform"
|
|
:class="{ 'transform rotate-180': isDropdownOpen }"
|
|
/>
|
|
|
|
<template #overlay="{ onEsc }">
|
|
<NcList
|
|
v-model:open="isDropdownOpen"
|
|
:value="value"
|
|
:list="teamSelectorOptions"
|
|
:item-height="48"
|
|
:is-multi-select="isMultiSelect"
|
|
:close-on-select="!isMultiSelect"
|
|
class="!w-auto"
|
|
:is-locked="!!newTeam"
|
|
:empty-description="
|
|
!teamSelectorOptions.length && existingTeamIds?.length ? $t('objects.teams.noMoreTeamsToAdd') : undefined
|
|
"
|
|
variant="default"
|
|
item-class-name="nc-team-select-dropdown"
|
|
:wrapper-class-name="`!h-auto nc-team-selector-dropdown ${!!newTeam ? '!cursor-wait' : ''}`"
|
|
@update:value="onChangeTeam"
|
|
@escape="onEsc"
|
|
>
|
|
<template #listItem="{ option }">
|
|
<div class="w-full flex items-center gap-2" :class="`nc-team-select-${option.value}`">
|
|
<GeneralTeamInfo :team="option" class="flex-1 max-w-[100%_-_32px]" />
|
|
<NcBadge
|
|
v-if="option.scope === 'org'"
|
|
:border="false"
|
|
color="blue"
|
|
class="text-[10px] leading-[14px] !h-[18px] font-semibold flex-none"
|
|
>
|
|
{{ $t('general.orgBadge') }}
|
|
</NcBadge>
|
|
<GeneralLoader v-if="compareValue(option.value, newTeam)" size="medium" />
|
|
<GeneralIcon v-else-if="!newTeam && compareValue(option.value)" icon="check" class="text-primary h-4 w-4" />
|
|
</div>
|
|
</template>
|
|
</NcList>
|
|
</template>
|
|
</NcListDropdown>
|
|
</div>
|
|
</template>
|