From fad00d43467a3957f66fdb0e09d771049246b5a1 Mon Sep 17 00:00:00 2001 From: Oisin Coveney <oisin@metabase.com> Date: Wed, 12 Jun 2024 17:18:15 +0300 Subject: [PATCH] Convert Badge and CollectionBadge (#43997) --- .../src/metabase-types/entities/common.ts | 9 ++- .../src/metabase/components/Badge/Badge.jsx | 61 ------------------- .../src/metabase/components/Badge/Badge.tsx | 54 ++++++++++++++++ .../src/metabase/components/Badge/index.jsx | 1 - .../src/metabase/components/Badge/index.tsx | 1 + .../CollectionBreadcrumbs.tsx | 7 +-- .../QuestionLineage/QuestionLineage.tsx | 2 +- .../HeaderBreadcrumbs.styled.tsx | 2 +- ...ollectionBadge.jsx => CollectionBadge.tsx} | 48 ++++++++++----- 9 files changed, 98 insertions(+), 87 deletions(-) delete mode 100644 frontend/src/metabase/components/Badge/Badge.jsx create mode 100644 frontend/src/metabase/components/Badge/Badge.tsx delete mode 100644 frontend/src/metabase/components/Badge/index.jsx create mode 100644 frontend/src/metabase/components/Badge/index.tsx rename frontend/src/metabase/questions/components/{CollectionBadge.jsx => CollectionBadge.tsx} (53%) diff --git a/frontend/src/metabase-types/entities/common.ts b/frontend/src/metabase-types/entities/common.ts index 5725596971d..18fa5f6a747 100644 --- a/frontend/src/metabase-types/entities/common.ts +++ b/frontend/src/metabase-types/entities/common.ts @@ -1,9 +1,14 @@ -import type { IconName } from "metabase/ui"; +import type { IconProps } from "metabase/ui"; import type { Collection } from "metabase-types/api"; export type WrappedEntity<Entity> = { getName: () => string; - getIcon: () => { name: IconName }; + getIcon: () => IconProps; getColor: () => string; getCollection: () => Collection; + getUrl: () => string; + setArchived: (isArchived: boolean) => void; + setCollection: (collection: Collection) => void; + setCollectionPreview: (isEnabled: boolean) => void; + setPinned: (isPinned: boolean) => void; } & Entity; diff --git a/frontend/src/metabase/components/Badge/Badge.jsx b/frontend/src/metabase/components/Badge/Badge.jsx deleted file mode 100644 index 804a2666794..00000000000 --- a/frontend/src/metabase/components/Badge/Badge.jsx +++ /dev/null @@ -1,61 +0,0 @@ -import PropTypes from "prop-types"; - -import CS from "metabase/css/core/index.css"; - -import { BadgeIcon, BadgeText, MaybeLink } from "./Badge.styled"; - -const iconProp = PropTypes.oneOfType([PropTypes.string, PropTypes.object]); - -const propTypes = { - to: PropTypes.string, - icon: iconProp, - inactiveColor: PropTypes.string, - activeColor: PropTypes.string, - isSingleLine: PropTypes.bool, - onClick: PropTypes.func, - children: PropTypes.node, -}; - -const DEFAULT_ICON_SIZE = 16; - -function getIconProps(iconProp) { - if (!iconProp) { - return; - } - const props = typeof iconProp === "string" ? { name: iconProp } : iconProp; - if (!props.size && !props.width && !props.height) { - props.size = DEFAULT_ICON_SIZE; - } - return props; -} - -function Badge({ - icon, - inactiveColor = "text-medium", - activeColor = "brand", - isSingleLine, - children, - ...props -}) { - return ( - <MaybeLink - inactiveColor={inactiveColor} - activeColor={activeColor} - isSingleLine={isSingleLine} - {...props} - > - {icon && <BadgeIcon {...getIconProps(icon)} hasMargin={!!children} />} - {children && ( - <BadgeText className={CS.textWrap} isSingleLine={isSingleLine}> - {children} - </BadgeText> - )} - </MaybeLink> - ); -} - -Badge.propTypes = propTypes; - -export { MaybeLink }; - -export default Badge; diff --git a/frontend/src/metabase/components/Badge/Badge.tsx b/frontend/src/metabase/components/Badge/Badge.tsx new file mode 100644 index 00000000000..9e6eced0d88 --- /dev/null +++ b/frontend/src/metabase/components/Badge/Badge.tsx @@ -0,0 +1,54 @@ +import type { PropsWithChildren } from "react"; + +import CS from "metabase/css/core/index.css"; +import type { IconName, IconProps } from "metabase/ui"; + +import { BadgeIcon, BadgeText, MaybeLink } from "./Badge.styled"; + +const DEFAULT_ICON_SIZE = 16; + +function getIconProps(iconProp: IconName | IconProps) { + const props: IconProps = + typeof iconProp === "string" ? { name: iconProp } : iconProp; + if (!props.size) { + props.size = DEFAULT_ICON_SIZE; + } + return props; +} + +type BadgeProps = PropsWithChildren<{ + to?: string; + onClick?: () => void; + icon?: IconName | IconProps; + inactiveColor?: string; + activeColor?: string; + isSingleLine?: boolean; + className?: string; +}>; + +export const Badge = ({ + to, + icon, + inactiveColor = "text-medium", + activeColor = "brand", + isSingleLine = false, + onClick, + children, + ...props +}: BadgeProps) => ( + <MaybeLink + inactiveColor={inactiveColor} + activeColor={activeColor} + isSingleLine={isSingleLine} + to={to} + onClick={onClick} + {...props} + > + {icon && <BadgeIcon {...getIconProps(icon)} hasMargin={!!children} />} + {children && ( + <BadgeText className={CS.textWrap} isSingleLine={isSingleLine}> + {children} + </BadgeText> + )} + </MaybeLink> +); diff --git a/frontend/src/metabase/components/Badge/index.jsx b/frontend/src/metabase/components/Badge/index.jsx deleted file mode 100644 index b9501403bb1..00000000000 --- a/frontend/src/metabase/components/Badge/index.jsx +++ /dev/null @@ -1 +0,0 @@ -export { default } from "./Badge"; diff --git a/frontend/src/metabase/components/Badge/index.tsx b/frontend/src/metabase/components/Badge/index.tsx new file mode 100644 index 00000000000..5c7042709a7 --- /dev/null +++ b/frontend/src/metabase/components/Badge/index.tsx @@ -0,0 +1 @@ +export { Badge } from "./Badge"; diff --git a/frontend/src/metabase/nav/components/CollectionBreadcrumbs/CollectionBreadcrumbs.tsx b/frontend/src/metabase/nav/components/CollectionBreadcrumbs/CollectionBreadcrumbs.tsx index b7b7ac966b1..b32d6bbc4a1 100644 --- a/frontend/src/metabase/nav/components/CollectionBreadcrumbs/CollectionBreadcrumbs.tsx +++ b/frontend/src/metabase/nav/components/CollectionBreadcrumbs/CollectionBreadcrumbs.tsx @@ -1,7 +1,7 @@ import { Fragment } from "react"; import { useToggle } from "metabase/hooks/use-toggle"; -import CollectionBadge from "metabase/questions/components/CollectionBadge"; +import { CollectionBadge } from "metabase/questions/components/CollectionBadge"; import type { Collection, CollectionEssentials, @@ -42,9 +42,8 @@ export const CollectionBreadcrumbs = ({ <> <CollectionBadge collectionId={parts[0].id} - inactiveColor="text-medium" isSingleLine - onClick={onClick ? () => onClick(parts[0]) : undefined} + onClick={onClick ? () => onClick(collection) : undefined} /> <PathSeparator>/</PathSeparator> <ExpandButton @@ -61,7 +60,6 @@ export const CollectionBreadcrumbs = ({ <Fragment key={collection.id}> <CollectionBadge collectionId={collection.id} - inactiveColor="text-medium" isSingleLine onClick={onClick ? () => onClick(collection) : undefined} /> @@ -75,7 +73,6 @@ export const CollectionBreadcrumbs = ({ {content} <CollectionBadge collectionId={collection.id} - inactiveColor="text-medium" isSingleLine onClick={onClick ? () => onClick(collection) : undefined} /> diff --git a/frontend/src/metabase/nav/components/QuestionLineage/QuestionLineage.tsx b/frontend/src/metabase/nav/components/QuestionLineage/QuestionLineage.tsx index afc3445313a..e649eabb30e 100644 --- a/frontend/src/metabase/nav/components/QuestionLineage/QuestionLineage.tsx +++ b/frontend/src/metabase/nav/components/QuestionLineage/QuestionLineage.tsx @@ -1,6 +1,6 @@ import { t } from "ttag"; -import Badge from "metabase/components/Badge"; +import { Badge } from "metabase/components/Badge"; import Link from "metabase/core/components/Link/Link"; import CS from "metabase/css/core/index.css"; import type { IconName } from "metabase/ui"; diff --git a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderBreadcrumbs/HeaderBreadcrumbs.styled.tsx b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderBreadcrumbs/HeaderBreadcrumbs.styled.tsx index 9d2319655db..0a4aed141db 100644 --- a/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderBreadcrumbs/HeaderBreadcrumbs.styled.tsx +++ b/frontend/src/metabase/query_builder/components/view/ViewHeader/components/HeaderBreadcrumbs/HeaderBreadcrumbs.styled.tsx @@ -2,7 +2,7 @@ import { css } from "@emotion/react"; import styled from "@emotion/styled"; import PropTypes from "prop-types"; -import Badge from "metabase/components/Badge"; +import { Badge } from "metabase/components/Badge"; export const HeaderBadge = styled(Badge)` .Icon { diff --git a/frontend/src/metabase/questions/components/CollectionBadge.jsx b/frontend/src/metabase/questions/components/CollectionBadge.tsx similarity index 53% rename from frontend/src/metabase/questions/components/CollectionBadge.jsx rename to frontend/src/metabase/questions/components/CollectionBadge.tsx index 6a421c2dce5..20c35bdde05 100644 --- a/frontend/src/metabase/questions/components/CollectionBadge.jsx +++ b/frontend/src/metabase/questions/components/CollectionBadge.tsx @@ -1,15 +1,14 @@ -import PropTypes from "prop-types"; +import type { ComponentType, PropsWithChildren } from "react"; -import Badge from "metabase/components/Badge"; +import { Badge } from "metabase/components/Badge"; import Collection from "metabase/entities/collections"; import { PLUGIN_COLLECTIONS } from "metabase/plugins"; - -const propTypes = { - className: PropTypes.string, - collection: PropTypes.object, - isSingleLine: PropTypes.bool, - onClick: PropTypes.func, -}; +import type { + Collection as CollectionType, + CollectionId, +} from "metabase-types/api"; +import type { WrappedEntity } from "metabase-types/entities"; +import type { State } from "metabase-types/store"; const IRREGULAR_ICON_WIDTH = 16; const IRREGULAR_ICON_PROPS = { @@ -20,7 +19,19 @@ const IRREGULAR_ICON_PROPS = { targetOffsetX: IRREGULAR_ICON_WIDTH, }; -function CollectionBadge({ className, collection, isSingleLine, onClick }) { +type CollectionBadgeProps = { + className?: string; + collection: WrappedEntity<CollectionType>; + isSingleLine?: boolean; + onClick?: () => void; +}; + +const CollectionBadgeInner = ({ + className, + collection, + isSingleLine, + onClick, +}: CollectionBadgeProps) => { if (!collection) { return null; } @@ -44,13 +55,18 @@ function CollectionBadge({ className, collection, isSingleLine, onClick }) { {collection.getName()} </Badge> ); -} - -CollectionBadge.propTypes = propTypes; +}; -export default Collection.load({ - id: (state, props) => props.collectionId || "root", +export const CollectionBadge = Collection.load({ + id: (state: State, props: { collectionId?: CollectionId }) => + props.collectionId || "root", wrapped: true, loadingAndErrorWrapper: false, properties: ["name", "authority_level"], -})(CollectionBadge); +})(CollectionBadgeInner) as ComponentType< + PropsWithChildren< + { + collectionId?: CollectionId; + } & Omit<CollectionBadgeProps, "collection"> + > +>; -- GitLab