Skip to content

Commit

Permalink
more work on preloading
Browse files Browse the repository at this point in the history
  • Loading branch information
abailly-akamai committed Nov 6, 2024
1 parent 4998735 commit b365c6c
Show file tree
Hide file tree
Showing 6 changed files with 105 additions and 34 deletions.
1 change: 0 additions & 1 deletion packages/manager/src/components/ActionMenu/ActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import * as React from 'react';
import KebabIcon from 'src/assets/icons/kebab.svg';
import { TooltipIcon } from 'src/components/TooltipIcon';
import { convertToKebabCase } from 'src/utilities/convertToKebobCase';

export interface Action {
disabled?: boolean;
id?: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ import { Link } from 'react-router-dom';

import { StyledActionButton } from 'src/components/Button/StyledActionButton';

import { TanstackLink } from '../TanstackLink';

import type { TanstackLinkProps } from '../TanstackLink';
import type { LinkProps as TanStackLinkProps } from '@tanstack/react-router';

interface InlineMenuActionProps {
/** Required action text */
actionText: string;
Expand All @@ -24,6 +29,13 @@ interface InlineMenuActionProps {
loading?: boolean;
/** Optional onClick handler */
onClick?: (e: React.MouseEvent<HTMLElement, MouseEvent>) => void;
/** Optional use the tanstackRouter */
tanstackRouter?: {
linkType: TanstackLinkProps['linkType'];
params?: TanStackLinkProps['params'];
preload?: TanStackLinkProps['preload'];
to: TanStackLinkProps['to'];
};
/** Optional tooltip text for help icon */
tooltip?: string;
/** Optional tooltip event handler for sending analytics */
Expand All @@ -39,32 +51,41 @@ export const InlineMenuAction = (props: InlineMenuActionProps) => {
href,
loading,
onClick,
tanstackRouter,
tooltip,
tooltipAnalyticsEvent,
...rest
} = props;

if (href) {
if (href && !tanstackRouter?.to) {
return (
<StyledLink className={className} to={href}>
<span>{actionText}</span>
</StyledLink>
);
}

return (
<StyledActionButton
// TODO: We need to define what buttonType this will be in the future for now 'secondary' works...
buttonType="primary"
disabled={disabled}
loading={loading}
onClick={onClick}
sx={buttonHeight !== undefined ? { height: buttonHeight } : {}}
tooltipAnalyticsEvent={tooltipAnalyticsEvent}
tooltipText={tooltip}
{...rest}
const commonProps = {
disabled,
loading,
sx: buttonHeight !== undefined ? { height: buttonHeight } : {},
tooltipAnalyticsEvent,
tooltipText: tooltip,
...rest,
};

return tanstackRouter?.to ? (
<TanstackLink
{...tanstackRouter}
{...commonProps}
style={{ paddingLeft: 8, paddingRight: 8 }}
sx={{ mr: 0.5 }}
>
{actionText}
</TanstackLink>
) : (
<StyledActionButton {...commonProps} onClick={onClick}>
{actionText}
</StyledActionButton>
);
};
Expand Down
20 changes: 18 additions & 2 deletions packages/manager/src/components/TanstackLink.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,25 @@ import { TanstackLink } from './TanstackLink';
import type { TanstackLinkProps } from './TanstackLink';
import type { Meta, StoryObj } from '@storybook/react';

export const ButtonPrimary: StoryObj<TanstackLinkProps> = {
export const AsButtonPrimary: StoryObj<TanstackLinkProps> = {
render: () => (
<TanstackLink buttonType="primary" to="/">
<TanstackLink linkType="primary" to="/">
Home
</TanstackLink>
),
};

export const AsButtonSecondary: StoryObj<TanstackLinkProps> = {
render: () => (
<TanstackLink linkType="secondary" to="/">
Home
</TanstackLink>
),
};

export const AsLink: StoryObj<TanstackLinkProps> = {
render: () => (
<TanstackLink linkType="link" to="/">
Home
</TanstackLink>
),
Expand Down
52 changes: 35 additions & 17 deletions packages/manager/src/components/TanstackLink.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,45 @@
import { Link } from '@tanstack/react-router';
import { LinkComponent } from '@tanstack/react-router';
import { createLink } from '@tanstack/react-router';
import * as React from 'react';

import { Button } from 'src/components/Button/Button';
import { omitProps } from 'src/utilities/omittedProps';

import type { LinkProps } from '@tanstack/react-router';
import type { ButtonProps } from 'src/components/Button/Button';
import type { ButtonProps, ButtonType } from 'src/components/Button/Button';

export interface TanstackLinkProps extends LinkProps {
buttonType: NonNullable<ButtonProps['buttonType']>;
export interface TanstackLinkProps
extends Omit<ButtonProps, 'buttonType' | 'href'> {
linkType: 'link' | ButtonType;
tooltipAnalyticsEvent?: (() => void) | undefined;
tooltipText?: string;
}

export const TanstackLink = ({
buttonType,
children,
...linkProps
}: TanstackLinkProps) => {
const LinkComponent = React.forwardRef<HTMLButtonElement, TanstackLinkProps>(
(props, ref) => {
const _props = omitProps(props, ['linkType']);

return <Button component="a" ref={ref} {..._props} />;
}
);

const CreatedLinkComponent = createLink(LinkComponent);

export const TanstackLink: LinkComponent<typeof LinkComponent> = (props) => {
return (
<Link {...linkProps}>
<Button buttonType={buttonType} component="span">
{typeof children === 'function'
? children({ isActive: false, isTransitioning: false })
: children}
</Button>
</Link>
<CreatedLinkComponent
preload="intent"
{...props}
sx={(theme) => ({
...(props.linkType === 'link' && {
'&:hover': {
textDecoration: 'underline',
},
fontFamily: theme.font.normal,
fontSize: '0.875rem',
minWidth: 'initial',
padding: 0,
}),
})}
/>
);
};
19 changes: 18 additions & 1 deletion packages/manager/src/features/Volumes/VolumesActionMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useIsResourceRestricted } from 'src/hooks/useIsResourceRestricted';
import type { Volume } from '@linode/api-v4';
import type { Theme } from '@mui/material/styles';
import type { Action } from 'src/components/ActionMenu/ActionMenu';
import type { VolumeAction } from 'src/routes/volumes';

export interface ActionHandlers {
handleAttach: () => void;
Expand Down Expand Up @@ -43,12 +44,14 @@ export const VolumesActionMenu = (props: Props) => {
id: volume.id,
});

const actions: Action[] = [
const actions: (Action & { action?: VolumeAction })[] = [
{
action: 'details',
onClick: handlers.handleDetails,
title: 'Show Config',
},
{
action: 'edit',
disabled: isVolumeReadOnly,
onClick: handlers.handleEdit,
title: 'Edit',
Expand All @@ -61,6 +64,7 @@ export const VolumesActionMenu = (props: Props) => {
: undefined,
},
{
action: 'resize',
disabled: isVolumeReadOnly,
onClick: handlers.handleResize,
title: 'Resize',
Expand All @@ -73,6 +77,7 @@ export const VolumesActionMenu = (props: Props) => {
: undefined,
},
{
action: 'clone',
disabled: isVolumeReadOnly,
onClick: handlers.handleClone,
title: 'Clone',
Expand All @@ -88,6 +93,7 @@ export const VolumesActionMenu = (props: Props) => {

if (!attached && isVolumesLanding) {
actions.push({
action: 'attach',
disabled: isVolumeReadOnly,
onClick: handlers.handleAttach,
title: 'Attach',
Expand All @@ -101,6 +107,7 @@ export const VolumesActionMenu = (props: Props) => {
});
} else {
actions.push({
action: 'detach',
disabled: isVolumeReadOnly,
onClick: handlers.handleDetach,
title: 'Detach',
Expand All @@ -115,6 +122,7 @@ export const VolumesActionMenu = (props: Props) => {
}

actions.push({
action: 'delete',
disabled: isVolumeReadOnly || attached,
onClick: handlers.handleDelete,
title: 'Delete',
Expand All @@ -138,6 +146,15 @@ export const VolumesActionMenu = (props: Props) => {
inlineActions.map((action) => {
return (
<InlineMenuAction
tanstackRouter={{
linkType: 'link',
params: {
action: action.action,
volumeId: volume.id,
},
preload: 'intent',
to: `/volumes/$volumeId/$action`,
}}
actionText={action.title}
disabled={action.disabled}
key={action.title}
Expand Down
2 changes: 1 addition & 1 deletion packages/manager/src/routes/volumes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const volumeAction = {
upgrade: 'upgrade',
} as const;

type VolumeAction = typeof volumeAction[keyof typeof volumeAction];
export type VolumeAction = typeof volumeAction[keyof typeof volumeAction];

export interface VolumesSearchParams extends TableSearchParams {
query?: string;
Expand Down

0 comments on commit b365c6c

Please sign in to comment.