Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@ import { useState } from 'react'
import { useTranslationStore } from '@utils/viewUtils'
import { defaultTo } from 'lodash-es'

import { Drawer, FormSeparator, Icon, StyledLink } from '@harnessio/ui/components'
import { StyledLink } from '@harnessio/ui/components'
import {
DelegateSelectionTypes,
DelegateSelectorForm,
DelegateSelectorDrawer,
DelegateSelectorFormFields,
DelegateSelectorInput
} from '@harnessio/ui/views'

import mockDelegatesList from './mock-delegates-list.json'
import { getMatchedDelegatesCount, isDelegateSelected } from './utils'

const delegatesData = mockDelegatesList.map(delegate => ({
groupId: delegate.groupId,
Expand Down Expand Up @@ -42,46 +41,6 @@ const mockTagsList = [
const renderSelectedValue = (type: DelegateSelectionTypes | null, tags: string[]) =>
type === DelegateSelectionTypes.TAGS ? tags.join(', ') : type === DelegateSelectionTypes.ANY ? 'any delegate' : null

/* ---------- DRAWER COMPONENT -------------- */
interface DrawerProps {
open: boolean
setOpen: (open: boolean) => void
preSelectedTags: string[]
onSubmit: (data: DelegateSelectorFormFields) => void
disableAnyDelegate?: boolean
}

const DelegateSelectorDrawer = ({ open, setOpen, preSelectedTags, onSubmit, disableAnyDelegate }: DrawerProps) => (
<Drawer.Root open={open} onOpenChange={setOpen} direction="right">
<Drawer.Content className="w-1/2">
<Drawer.Header>
<Drawer.Title className="text-cn-foreground-1 mb-2 text-xl">Delegate selector</Drawer.Title>
<FormSeparator className="w-full" />
<div className="flex">
Haven&apos;t installed a delegate yet?
<StyledLink className="flex flex-row items-center ml-1" variant="accent" to="#">
Install delegate <Icon name="attachment-link" className="ml-1" size={12} />
</StyledLink>
</div>
<Drawer.Close onClick={() => setOpen(false)} />
</Drawer.Header>

<DelegateSelectorForm
delegates={delegatesData}
tagsList={mockTagsList}
useTranslationStore={useTranslationStore}
isLoading={false}
onFormSubmit={onSubmit}
onBack={() => setOpen(false)}
isDelegateSelected={isDelegateSelected}
getMatchedDelegatesCount={getMatchedDelegatesCount}
preSelectedTags={preSelectedTags}
disableAnyDelegate={disableAnyDelegate}
/>
</Drawer.Content>
</Drawer.Root>
)

/* ---------- MAIN COMPONENT -------------------------- */
export const DelegateSelector = () => {
/* ---- FIRST (ANY allowed) ---- */
Expand Down Expand Up @@ -109,17 +68,25 @@ export const DelegateSelector = () => {
return (
<div className="p-5">
<DelegateSelectorInput
placeholder={<StyledLink to="#"> select a delegate</StyledLink>}
placeholder={<StyledLink to="#">select a delegate</StyledLink>}
value={renderSelectedValue(typeA, tagsA)}
label="Delegate selector"
onClick={() => setOpenA(true)}
onEdit={() => setOpenA(true)}
onClear={() => setTagsA([])}
renderValue={tag => tag}
className="max-w-xs mb-8"
className="mb-8 max-w-xs"
/>

<DelegateSelectorDrawer open={openA} setOpen={setOpenA} preSelectedTags={tagsA} onSubmit={handleSubmitA} />
<DelegateSelectorDrawer
open={openA}
setOpen={setOpenA}
preSelectedTags={tagsA}
onSubmit={handleSubmitA}
tagsList={mockTagsList}
delegatesData={delegatesData}
useTranslationStore={useTranslationStore}
/>

<div className="pt-10">
<DelegateSelectorInput
Expand All @@ -130,14 +97,17 @@ export const DelegateSelector = () => {
onEdit={() => setOpenB(true)}
onClear={() => setTagsB([])}
renderValue={tag => tag}
className="max-w-xs mb-8"
className="mb-8 max-w-xs"
/>

<DelegateSelectorDrawer
open={openB}
setOpen={setOpenB}
preSelectedTags={tagsB}
onSubmit={handleSubmitB}
tagsList={mockTagsList}
delegatesData={delegatesData}
useTranslationStore={useTranslationStore}
disableAnyDelegate
/>
</div>
Expand Down
18 changes: 0 additions & 18 deletions apps/design-system/src/subjects/views/delegates/utils.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,6 @@
import { DelegateItem } from '@harnessio/ui/views'

export const isDelegateSelected = (delegateSelectors: string[], tags: string[] = []) => {
if (!tags?.length) {
return false
}
return tags?.some(tag => delegateSelectors.includes(tag))
}

export const getMatchedDelegatesCount = (delegates: DelegateItem[] = [], tags: string[] = []): number => {
if (!delegates.length || !tags.length) {
return 0
}

const tagSet = new Set(tags)

return delegates.reduce<number>((count, delegate) => {
const implicit = delegate.groupImplicitSelectors ?? []
const custom = delegate.groupCustomSelectors ?? []
const delegateTags = [...implicit, ...custom]
const matches = delegateTags.some(tag => tagSet.has(tag))
return matches ? count + 1 : count
}, 0)
}
24 changes: 16 additions & 8 deletions packages/ui/src/components/drawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ const DrawerContent = React.forwardRef<
<DrawerPrimitive.Content
ref={ref}
className={cn(
'bg-cn-background-2 fixed inset-y-0 p-4 right-0 z-50 w-1/4 border-l border-cn-borders-3',
'bg-cn-background-2 fixed flex flex-col inset-y-0 right-0 z-50 w-1/4 border-l border-cn-borders-3',
className
)}
{...props}
Expand All @@ -89,24 +89,31 @@ const DrawerContent = React.forwardRef<
DrawerContent.displayName = 'DrawerContent'

const DrawerHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn('grid gap-1.5 text-center sm:text-left', className)} {...props} />
<div
className={cn('grid gap-1.5 text-center px-6 py-5 sm:text-left border-b border-cn-borders-3', className)}
{...props}
/>
)
DrawerHeader.displayName = 'DrawerHeader'

const DrawerInner = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn('flex flex-col grow gap-4 pt-5 overflow-auto', className)} {...props} />
)
DrawerInner.displayName = 'DrawerInner'

const DrawerFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
<div className={cn('mt-auto flex flex-col gap-2 border-t border-cn-borders-3', className)} {...props} />
<div
className={cn('mt-auto sticky bottom-0 flex flex-col gap-2 border-t border-cn-borders-3', className)}
{...props}
/>
)
DrawerFooter.displayName = 'DrawerFooter'

const DrawerTitle = React.forwardRef<
React.ElementRef<typeof DrawerPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DrawerPrimitive.Title>
>(({ className, ...props }, ref) => (
<DrawerPrimitive.Title
ref={ref}
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
{...props}
/>
<DrawerPrimitive.Title ref={ref} className={cn('text-xl font-semibold leading-6', className)} {...props} />
))
DrawerTitle.displayName = DrawerPrimitive.Title.displayName

Expand All @@ -127,6 +134,7 @@ const Drawer = {
Close: DrawerClose,
Content: DrawerContent,
Header: DrawerHeader,
Inner: DrawerInner,
Footer: DrawerFooter,
Title: DrawerTitle,
Description: DrawerDescription
Expand Down
3 changes: 3 additions & 0 deletions packages/ui/src/components/stacked-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ interface ListItemProps extends React.ComponentProps<'div'>, VariantProps<typeof
isLast?: boolean
isHeader?: boolean
disableHover?: boolean
endIcon?: React.ReactNode
}

interface ListFieldProps extends Omit<React.ComponentProps<'div'>, 'title'>, VariantProps<typeof listFieldVariants> {
Expand Down Expand Up @@ -92,6 +93,7 @@ const ListItem = ({
isLast,
isHeader,
disableHover = false,
endIcon,
...props
}: ListItemProps) => {
const Comp = asChild ? Slot : ('div' as any)
Expand All @@ -111,6 +113,7 @@ const ListItem = ({
{thumbnail && <div className="mr-2 flex items-center">{thumbnail}</div>}
<Slottable>{children}</Slottable>
{actions && <div className="ml-2 flex items-center">{actions}</div>}
{endIcon && <>{endIcon}</>}
<Icon name="chevron-right" className="hidden" />
</Comp>
)
Expand Down
5 changes: 4 additions & 1 deletion packages/ui/src/views/components/RadioSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,16 @@ interface RadioSelectProps<T extends string> {
onValueChange: (value: T) => void
id?: string
className?: string
endIcon?: React.ReactNode
}

export const RadioSelect = <T extends string>({
options,
value,
onValueChange,
id,
className
className,
endIcon
}: RadioSelectProps<T>) => {
return (
<RadioGroup value={value} onValueChange={onValueChange as (value: string) => void} id={id} className={className}>
Expand All @@ -48,6 +50,7 @@ export const RadioSelect = <T extends string>({
isLast
disableHover
onClick={() => !option.disabled && onValueChange(option.value)}
endIcon={value === option.value ? endIcon : undefined}
>
<StackedList.Field
title={option.title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export function DelegateConnectivityList({

return (
<Table.Root
className={isLoading ? '[mask-image:linear-gradient(to_bottom,black_30%,transparent_100%)]' : ''}
className={isLoading ? '[mask-image:linear-gradient(to_bottom,black_30%,transparent_100%)]' : 'min-h-24'}
variant="asStackedList"
>
<Table.Header>
Expand Down Expand Up @@ -85,11 +85,11 @@ export function DelegateConnectivityList({
</Badge>
))}
</Table.Cell>
<Table.Cell className="min-w-8 text-right">
<Table.Cell className="min-w-8 text-right align-middle">
{isDelegateSelected(
[...defaultTo(groupImplicitSelectors, []), ...defaultTo(groupCustomSelectors, [])],
selectedTags || []
) && <Icon name="tick" size={12} className="text-icons-success" />}
) && <Icon name="tick" size={12} className="text-icons-success mx-auto" />}
</Table.Cell>
</Table.Row>
)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Drawer, Icon, StyledLink } from '@/components'
import { DelegateSelectorForm, DelegateSelectorFormFields, TranslationStore } from '@/views'

import { DelegateItem } from '../types'
import { getMatchedDelegatesCount, isDelegateSelected } from '../utils'

interface DrawerProps {
open: boolean
setOpen: (open: boolean) => void
preSelectedTags: string[]
tagsList: string[]
onSubmit: (data: DelegateSelectorFormFields) => void
useTranslationStore: () => TranslationStore
delegatesData: DelegateItem[]
disableAnyDelegate?: boolean
}

const DelegateSelectorDrawer = ({
open,
setOpen,
preSelectedTags,
tagsList,
onSubmit,
useTranslationStore,
disableAnyDelegate,
delegatesData
}: DrawerProps) => (
<Drawer.Root open={open} onOpenChange={setOpen} direction="right">
<Drawer.Content className="w-1/2">
<Drawer.Header>
<Drawer.Title>Delegate selector</Drawer.Title>
</Drawer.Header>

<Drawer.Inner>
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can set default paddings in Drawer.Inner, so you don't need to apply padding to each child component individually

<div className="flex px-6">
Haven&apos;t installed a delegate yet?
<StyledLink className="ml-1 flex flex-row items-center" variant="accent" to="#">
Install delegate <Icon name="attachment-link" className="ml-1" size={12} />
</StyledLink>
</div>

<DelegateSelectorForm
delegates={delegatesData}
tagsList={tagsList}
useTranslationStore={useTranslationStore}
isLoading={false}
onFormSubmit={onSubmit}
onBack={() => setOpen(false)}
isDelegateSelected={isDelegateSelected}
getMatchedDelegatesCount={getMatchedDelegatesCount}
preSelectedTags={preSelectedTags}
disableAnyDelegate={disableAnyDelegate}
FooterWrapper={Drawer.Footer}
/>
</Drawer.Inner>
</Drawer.Content>
</Drawer.Root>
)

export { DelegateSelectorDrawer }
Loading