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