fix sidebar settings for interfaces

This commit is contained in:
Nate Kelley 2025-03-13 14:57:00 -06:00
parent 4fa7e92a38
commit 3ecdf641d3
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
13 changed files with 66 additions and 36 deletions

View File

@ -1,8 +1,8 @@
export enum VerificationStatus { export enum VerificationStatus {
NOT_REQUESTED = 'NOT REQUESTED', NOT_REQUESTED = 'notRequested',
REQUESTED = 'REQUESTED', REQUESTED = 'requested',
IN_REVIEW = 'IN REVIEW', IN_REVIEW = 'inReview',
VERIFIED = 'VERIFIED', VERIFIED = 'verified',
BACKLOGGED = 'BACKLOGGED', BACKLOGGED = 'backlogged',
NOT_VERIFIED = 'NOT VERIFIED' NOT_VERIFIED = 'notVerified'
} }

View File

@ -5,6 +5,7 @@ import { useMemoizedFn } from '@/hooks';
import { Button } from '@/components/ui/buttons'; import { Button } from '@/components/ui/buttons';
import { cn } from '@/lib/classMerge'; import { cn } from '@/lib/classMerge';
import { Star } from '@/components/ui/icons'; import { Star } from '@/components/ui/icons';
import { Star as StarFilled } from '@/components/ui/icons/NucleoIconFilled';
import { cva } from 'class-variance-authority'; import { cva } from 'class-variance-authority';
import { import {
useAddUserFavorite, useAddUserFavorite,
@ -62,7 +63,7 @@ export const FavoriteStar: React.FC<{
return ( return (
<AppTooltip title={tooltipText} key={tooltipText}> <AppTooltip title={tooltipText} key={tooltipText}>
<Button <Button
className={cn(className, 'flex')} className={cn('flex transition-none', isFavorited && 'opacity-100!', className)}
onClick={onFavoriteClick} onClick={onFavoriteClick}
variant="ghost" variant="ghost"
prefix={ prefix={
@ -73,7 +74,7 @@ export const FavoriteStar: React.FC<{
isFavorited isFavorited
}) })
)}> )}>
<Star /> {isFavorited ? <StarFilled /> : <Star />}
</div> </div>
} }
/> />

View File

@ -26,17 +26,15 @@ export const StatusBadgeIndicator: React.FC<{
const isNotVerified = const isNotVerified =
status === VerificationStatus.NOT_VERIFIED || VerificationStatus.NOT_REQUESTED; status === VerificationStatus.NOT_VERIFIED || VerificationStatus.NOT_REQUESTED;
const sharedClass = cn(`flex items-center justify-center rounded-full`, colorClasses); const sharedClass = cn(`flex items-center justify-center rounded-full`, colorClasses);
const _size = isNotVerified ? size : 16;
return ( return (
<AppTooltip title={showTooltip ? tooltipText : ''}> <AppTooltip title={showTooltip ? tooltipText : ''}>
<div <div
className={`rounded-full ${className} ${sharedClass} ${isNotVerified ? '' : ''}`} className={`rounded-full ${className} ${sharedClass} ${isNotVerified ? '' : ''}`}
style={{ style={{
width: _size, width: size,
height: _size height: size
}}> }}>
<Icon size={_size} /> <Icon size={size} />
</div> </div>
</AppTooltip> </AppTooltip>
); );
@ -54,6 +52,7 @@ const statusRecordIcon: Record<VerificationStatus, React.FC<any>> = {
}; };
const getIcon = (status: BusterMetricListItem['status']) => { const getIcon = (status: BusterMetricListItem['status']) => {
console.log(status, statusRecordIcon);
return statusRecordIcon[status] || (() => <React.Fragment />); return statusRecordIcon[status] || (() => <React.Fragment />);
}; };

View File

@ -1,8 +1,8 @@
import type { Meta, StoryObj } from '@storybook/react'; import type { Meta, StoryObj } from '@storybook/react';
import { SidebarPrimary } from './SidebarPrimary'; import { SidebarPrimary } from './SidebarPrimary';
import { BusterRoutes, createBusterRoute } from '@/routes'; import { BusterRoutes, createBusterRoute } from '../../../routes';
import { ShareAssetType } from '@/api/asset_interfaces/share/shareInterfaces'; import { ShareAssetType } from '../../../api/asset_interfaces/share';
import React from 'react';
const meta: Meta<typeof SidebarPrimary> = { const meta: Meta<typeof SidebarPrimary> = {
title: 'Features/Sidebars/SidebarPrimary', title: 'Features/Sidebars/SidebarPrimary',
component: SidebarPrimary, component: SidebarPrimary,

View File

@ -18,9 +18,14 @@ import { SupportModal } from '../modal/SupportModal';
import { InvitePeopleModal } from '../modal/InvitePeopleModal'; import { InvitePeopleModal } from '../modal/InvitePeopleModal';
import { useMemoizedFn } from '@/hooks'; import { useMemoizedFn } from '@/hooks';
import { SidebarUserFooter } from './SidebarUserFooter/SidebarUserFooter'; import { SidebarUserFooter } from './SidebarUserFooter/SidebarUserFooter';
import { useGetUserFavorites, useUpdateUserFavorites } from '@/api/buster_rest'; import {
useDeleteUserFavorite,
useGetUserFavorites,
useUpdateUserFavorites
} from '@/api/buster_rest';
const topItems: ISidebarList = { const topItems: ISidebarList = {
id: 'top-items',
items: [ items: [
{ {
label: 'Home', label: 'Home',
@ -39,6 +44,7 @@ const topItems: ISidebarList = {
const yourStuff: ISidebarGroup = { const yourStuff: ISidebarGroup = {
label: 'Your stuff', label: 'Your stuff',
id: 'your-stuff',
items: [ items: [
{ {
label: 'Metrics', label: 'Metrics',
@ -63,6 +69,7 @@ const yourStuff: ISidebarGroup = {
const adminTools: ISidebarGroup = { const adminTools: ISidebarGroup = {
label: 'Admin tools', label: 'Admin tools',
id: 'admin-tools',
items: [ items: [
{ {
label: 'Logs', label: 'Logs',
@ -90,6 +97,7 @@ const tryGroup = (
onClickLeaveFeedback: () => void onClickLeaveFeedback: () => void
): ISidebarGroup => ({ ): ISidebarGroup => ({
label: 'Try', label: 'Try',
id: 'try',
items: [ items: [
{ {
label: 'Invite people', label: 'Invite people',
@ -115,6 +123,7 @@ export const SidebarPrimary = React.memo(() => {
const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal); const onToggleInviteModal = useAppLayoutContextSelector((s) => s.onToggleInviteModal);
const [openSupportModal, setOpenSupportModal] = useState(false); const [openSupportModal, setOpenSupportModal] = useState(false);
const { mutateAsync: updateUserFavorites } = useUpdateUserFavorites(); const { mutateAsync: updateUserFavorites } = useUpdateUserFavorites();
const { mutateAsync: deleteUserFavorite } = useDeleteUserFavorite();
const onFavoritesReorder = useMemoizedFn((itemIds: string[]) => { const onFavoritesReorder = useMemoizedFn((itemIds: string[]) => {
updateUserFavorites(itemIds); updateUserFavorites(itemIds);
@ -130,7 +139,7 @@ export const SidebarPrimary = React.memo(() => {
items.push(yourStuff); items.push(yourStuff);
if (favorites && favorites.length > 0) { if (favorites && favorites.length > 0) {
items.push(favoritesDropdown(favorites, onFavoritesReorder)); items.push(favoritesDropdown(favorites, { deleteUserFavorite, onFavoritesReorder }));
} }
items.push(tryGroup(onToggleInviteModal, () => setOpenSupportModal(true))); items.push(tryGroup(onToggleInviteModal, () => setOpenSupportModal(true)));
@ -213,12 +222,19 @@ GlobalModals.displayName = 'GlobalModals';
const favoritesDropdown = ( const favoritesDropdown = (
favorites: BusterUserFavorite[], favorites: BusterUserFavorite[],
onItemsReorder: (itemIds: string[]) => void {
onFavoritesReorder,
deleteUserFavorite
}: {
onFavoritesReorder: (itemIds: string[]) => void;
deleteUserFavorite: (itemId: string) => void;
}
): ISidebarGroup => { ): ISidebarGroup => {
return { return {
label: 'Favorites', label: 'Favorites',
id: 'favorites',
isSortable: true, isSortable: true,
onItemsReorder, onItemsReorder: onFavoritesReorder,
items: favorites.map((favorite) => { items: favorites.map((favorite) => {
const Icon = assetTypeToIcon(favorite.asset_type); const Icon = assetTypeToIcon(favorite.asset_type);
const route = assetTypeToRoute(favorite.asset_type, favorite.id); const route = assetTypeToRoute(favorite.asset_type, favorite.id);
@ -226,7 +242,8 @@ const favoritesDropdown = (
label: favorite.name, label: favorite.name,
icon: <Icon />, icon: <Icon />,
route, route,
id: route id: route,
onRemove: () => deleteUserFavorite(favorite.id)
}; };
}) })
}; };

View File

@ -1,5 +1,6 @@
import type { Meta, StoryObj } from '@storybook/react'; import type { Meta, StoryObj } from '@storybook/react';
import { SidebarSettings } from './SidebarSettings'; import { SidebarSettings } from './SidebarSettings';
import React from 'react';
const meta: Meta<typeof SidebarSettings> = { const meta: Meta<typeof SidebarSettings> = {
title: 'Features/Sidebars/SidebarSettings', title: 'Features/Sidebars/SidebarSettings',

View File

@ -12,6 +12,7 @@ import { SidebarUserFooter } from './SidebarUserFooter/SidebarUserFooter';
const accountItems: ISidebarGroup = { const accountItems: ISidebarGroup = {
label: 'Account', label: 'Account',
variant: 'icon', variant: 'icon',
id: 'account',
icon: <CircleUser />, icon: <CircleUser />,
items: [ items: [
{ {
@ -25,6 +26,7 @@ const accountItems: ISidebarGroup = {
const workspaceItems: ISidebarGroup = { const workspaceItems: ISidebarGroup = {
label: 'Workspace', label: 'Workspace',
variant: 'icon', variant: 'icon',
id: 'workspace',
icon: <ApartmentBuilding />, icon: <ApartmentBuilding />,
items: [ items: [
{ {
@ -38,6 +40,7 @@ const workspaceItems: ISidebarGroup = {
const permissionAndSecurityItems: ISidebarGroup = { const permissionAndSecurityItems: ISidebarGroup = {
label: 'Permission & Security', label: 'Permission & Security',
variant: 'icon', variant: 'icon',
id: 'permission-and-security',
icon: <LockCircle />, icon: <LockCircle />,
items: [ items: [
{ {

View File

@ -2,21 +2,16 @@ import React from 'react';
import { ISidebarGroup, ISidebarList, SidebarProps } from './interfaces'; import { ISidebarGroup, ISidebarList, SidebarProps } from './interfaces';
import { SidebarCollapsible } from './SidebarCollapsible'; import { SidebarCollapsible } from './SidebarCollapsible';
import { SidebarItem } from './SidebarItem'; import { SidebarItem } from './SidebarItem';
import { useMemoizedFn } from '@/hooks';
export const Sidebar: React.FC<SidebarProps> = React.memo( export const Sidebar: React.FC<SidebarProps> = React.memo(
({ header, content, footer, activeItem }) => { ({ header, content, footer, activeItem }) => {
const onItemsReorder = useMemoizedFn((ids: string[], contentIndex: number) => {
console.log('onItemsReorder', ids);
});
return ( return (
<div className="flex h-full flex-col overflow-hidden px-3.5 pt-4.5"> <div className="flex h-full flex-col overflow-hidden px-3.5 pt-4.5">
<div className="flex flex-col space-y-4.5 overflow-hidden"> <div className="flex flex-col space-y-4.5 overflow-hidden">
<div className="mb-5"> {header}</div> <div className="mb-5"> {header}</div>
<div className="flex flex-grow flex-col space-y-4.5 overflow-y-auto pb-3"> <div className="flex flex-grow flex-col space-y-4.5 overflow-y-auto pb-3">
{content.map((item, index) => ( {content.map((item) => (
<ContentSelector key={index} content={item} activeItem={activeItem} /> <ContentSelector key={item.id} content={item} activeItem={activeItem} />
))} ))}
</div> </div>
</div> </div>

View File

@ -1,6 +1,6 @@
'use client'; 'use client';
import React from 'react'; import React, { useEffect } from 'react';
import { import {
Collapsible, Collapsible,
CollapsibleContent, CollapsibleContent,
@ -118,7 +118,11 @@ export const SidebarCollapsible: React.FC<
const [draggingId, setDraggingId] = React.useState<string | null>(null); const [draggingId, setDraggingId] = React.useState<string | null>(null);
const sensors = useSensors( const sensors = useSensors(
useSensor(PointerSensor), useSensor(PointerSensor, {
activationConstraint: {
distance: 2
}
}),
useSensor(KeyboardSensor, { useSensor(KeyboardSensor, {
coordinateGetter: sortableKeyboardCoordinates coordinateGetter: sortableKeyboardCoordinates
}) })
@ -145,6 +149,10 @@ export const SidebarCollapsible: React.FC<
const draggingItem = draggingId ? sortedItems.find((item) => item.id === draggingId) : null; const draggingItem = draggingId ? sortedItems.find((item) => item.id === draggingId) : null;
useEffect(() => {
setSortedItems(items);
}, [items]);
return ( return (
<Collapsible open={isOpen} onOpenChange={setIsOpen} className="space-y-0.5"> <Collapsible open={isOpen} onOpenChange={setIsOpen} className="space-y-0.5">
{variant === 'collapsible' && ( {variant === 'collapsible' && (

View File

@ -1,8 +1,8 @@
import type { Meta, StoryObj } from '@storybook/react'; import type { Meta, StoryObj } from '@storybook/react';
import { SidebarItem } from './SidebarItem'; import { SidebarItem } from './SidebarItem';
import { HouseModern } from '@/components/ui/icons'; import { HouseModern } from '../icons/NucleoIconOutlined';
import { BusterRoutes } from '@/routes'; import { BusterRoutes } from '../../../routes';
import React from 'react';
const meta: Meta<typeof SidebarItem> = { const meta: Meta<typeof SidebarItem> = {
title: 'UI/Sidebar/SidebarItem', title: 'UI/Sidebar/SidebarItem',
component: SidebarItem, component: SidebarItem,

View File

@ -83,7 +83,7 @@ export const SidebarItem: React.FC<
href={route || ''} href={route || ''}
className={cn(itemVariants({ active, disabled, variant }), className)} className={cn(itemVariants({ active, disabled, variant }), className)}
onClick={onClick}> onClick={onClick}>
<div className="flex items-center gap-2"> <div className="flex items-center gap-2 overflow-hidden">
<span <span
className={cn('text-icon-size! text-icon-color', { className={cn('text-icon-size! text-icon-color', {
'text-text-disabled': disabled, 'text-text-disabled': disabled,
@ -99,7 +99,11 @@ export const SidebarItem: React.FC<
variant="ghost" variant="ghost"
size={'small'} size={'small'}
prefix={<Xmark />} prefix={<Xmark />}
onClick={onRemove}></Button> onClick={(e) => {
e.stopPropagation();
e.preventDefault();
onRemove();
}}></Button>
)} )}
</ItemNode> </ItemNode>
); );

View File

@ -14,6 +14,7 @@ export interface ISidebarItem {
export interface ISidebarGroup { export interface ISidebarGroup {
label: string; label: string;
icon?: React.ReactNode; icon?: React.ReactNode;
id: string;
items: ISidebarItem[]; items: ISidebarItem[];
variant?: 'collapsible' | 'icon'; //default is collapsible variant?: 'collapsible' | 'icon'; //default is collapsible
defaultOpen?: boolean; //will default to true defaultOpen?: boolean; //will default to true
@ -23,6 +24,7 @@ export interface ISidebarGroup {
export interface ISidebarList { export interface ISidebarList {
items: ISidebarItem[]; items: ISidebarItem[];
id: string;
} }
type SidebarContent = ISidebarGroup | ISidebarList; type SidebarContent = ISidebarGroup | ISidebarList;

View File

@ -13,7 +13,7 @@ const TooltipTrigger = TooltipPrimitive.Trigger;
const TooltipContent = React.forwardRef< const TooltipContent = React.forwardRef<
React.ElementRef<typeof TooltipPrimitive.Content>, React.ElementRef<typeof TooltipPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
>(({ className, sideOffset = 6, ...props }, ref) => ( >(({ className, sideOffset = 4, ...props }, ref) => (
<TooltipPrimitive.Content <TooltipPrimitive.Content
ref={ref} ref={ref}
sideOffset={sideOffset} sideOffset={sideOffset}