Files
supabase/packages/ui-patterns/MultiSelectDeprecated/MultiSelectV2.tsx
Joshen Lim 1127c4ba88 Project Level Permissions (#27347)
* fix: update Permission params

* fix: upgrade check permission hook to support project level role

* fix: usePermissionsLoaded

* fix: Permission params can be undefined

* Scaffold new access management UI

* Add validation

* Update roles view

* Add tooltip

* Add button to apply role to all projects

* Update UI to select projects first instead of roles

* Merge master update UI

* Midway trying to implementation project level perms API

* First pass implementating updating project level permissions

* Add client side validation for assigning/removing roles

* Midway implementing new invites

* Integrate most of the project level permissions functionality

* fix: filter out org-level permissions before checking

* Add relevant UI guards in org level pages for project role POV

* Minor refactors

* Small refactors

* More fixes

* Moar refactors

* More fixes

* More fixes

* Refactor update role logic and smack some test cases on it

* Fixes

* Fix type issue

* Fix type

* more fixes, refactors, adding checks...

* MORE fixes

* Add perms checking for replicas

* Add ButtonTooltip component and use them to prevent repetition of pointer events auto for buttons with tooltips

* Convert all buttons with tooltips to use ButtonTooltip

* refactor

* PRettier

* Small fix

* Remove commented out code in organization-invitation-accept-mutation

* fix: switch to use the platform oauth authorizations routes

* Add perms checking for org audit logs and org oauth apps

* PRettier

* Fix incorrect URL for oauth app flow

* Fix incorrect URL for oauth app flow

* Fix

* Add perms checking for warehouse related UI

* Update roles helper icon

* remove unused lib

* Update package lock... again

* Update package lock... again

* Smalllll update

* Update some checks

* Add gate for project level permissions

* Last fix

* update codegen

* Update warehouse endpoint routes

* Fix

---------

Co-authored-by: phamhieu <phamhieu1998@gmail.com>
Co-authored-by: Alaister Young <a@alaisteryoung.com>
2024-07-01 17:59:54 +08:00

159 lines
5.3 KiB
TypeScript

import { orderBy, without } from 'lodash'
import { Check, ChevronDown } from 'lucide-react'
import { ReactNode, useState } from 'react'
import {
CommandEmpty_Shadcn_,
CommandGroup_Shadcn_,
CommandInput_Shadcn_,
CommandItem_Shadcn_,
CommandList_Shadcn_,
Command_Shadcn_,
PopoverContent_Shadcn_,
PopoverTrigger_Shadcn_,
Popover_Shadcn_,
ScrollArea,
cn,
} from 'ui'
import { BadgeDisabled, BadgeSelected } from './Badges'
interface MultiSelectOption {
id: string | number
value: string
name: string
description?: string
disabled: boolean
}
interface MultiSelectProps {
value: string[]
options: MultiSelectOption[]
placeholder?: string | ReactNode
searchPlaceholder?: string
disabled?: boolean
onChange?(x: string[]): void
}
/**
* @deprecated Use ./multi-select instead
*/
export const MultiSelectV2 = ({
options,
value,
placeholder,
searchPlaceholder = 'Search for option',
disabled = false,
onChange = () => {},
}: MultiSelectProps) => {
const [open, setOpen] = useState(false)
const [selected, setSelected] = useState<string[]>(value || [])
// Selected is `value` if defined, otherwise use local useState
const selectedOptions = value || selected
// Order the options so disabled items are at the beginning
const formattedOptions = orderBy(options, ['disabled'], ['desc'])
const checkIfActive = (option: MultiSelectOption) => {
const isOptionSelected = (selectedOptions || []).find((x) => x === option.value)
return isOptionSelected !== undefined
}
const handleChange = (option: MultiSelectOption) => {
const _selected = selectedOptions
const isActive = checkIfActive(option)
const updatedPayload = isActive
? [...without(_selected, option.value)]
: [..._selected.concat([option.value])]
// Payload must always include disabled options
const compulsoryOptions = options
.filter((option) => option.disabled)
.map((option) => option.name)
const formattedPayload = [...new Set(updatedPayload.concat(compulsoryOptions))]
setSelected(formattedPayload)
onChange(formattedPayload)
}
return (
<div className={disabled ? 'pointer-events-none opacity-50' : ''}>
<Popover_Shadcn_ open={open} onOpenChange={setOpen} modal={false}>
<PopoverTrigger_Shadcn_ asChild>
<div
className={cn(
'relative border border-strong bg-control rounded',
'flex w-full flex-wrap items-start gap-1.5 p-1.5 cursor-pointer',
`${selectedOptions.length === 0 ? 'h-9' : ''}`
)}
onClick={() => setOpen(true)}
>
{selectedOptions.length === 0 && placeholder && (
<div className="px-2 text-sm text-foreground-light h-full flex items-center">
{placeholder}
</div>
)}
{selectedOptions.map((value, idx) => {
const id = `${value}-${idx}`
const option = formattedOptions.find((x) => x.value === value)
const isDisabled = option?.disabled ?? false
if (!option) {
return <></>
} else if (isDisabled) {
return <BadgeDisabled key={id} name={option.name} />
} else {
return (
<BadgeSelected
key={id}
name={option.name}
handleRemove={() => handleChange(option)}
/>
)
}
})}
<div className="absolute inset-y-0 right-0 pl-3 pr-2 flex space-x-1 items-center cursor-pointer ">
<ChevronDown size={16} strokeWidth={2} className="text-foreground-lighter" />
</div>
</div>
</PopoverTrigger_Shadcn_>
<PopoverContent_Shadcn_ className="p-0 w-96 border-strong" side="bottom" align="start">
<Command_Shadcn_>
<CommandInput_Shadcn_ placeholder={searchPlaceholder} />
<CommandList_Shadcn_>
<CommandEmpty_Shadcn_>No options found</CommandEmpty_Shadcn_>
<CommandGroup_Shadcn_>
<ScrollArea className={cn(formattedOptions.length > 7 ? 'h-[210px]' : '')}>
{formattedOptions?.map((option) => {
const active =
selectedOptions &&
selectedOptions.find((selected) => {
return selected === option.value
})
? true
: false
return (
<CommandItem_Shadcn_
key={option.id}
value={option.value}
className="cursor-pointer w-full"
onClick={() => handleChange(option)}
onSelect={() => handleChange(option)}
>
<div className="w-full flex items-center justify-between">
{option.name}
{active && <Check size={14} />}
</div>
</CommandItem_Shadcn_>
)
})}
</ScrollArea>
</CommandGroup_Shadcn_>
</CommandList_Shadcn_>
</Command_Shadcn_>
</PopoverContent_Shadcn_>
</Popover_Shadcn_>
</div>
)
}