refactor: migrate web Tag to @makeplane/propel Pill

Replace @plane/ui Tag in apps/web with Propel PillButton for dismissible chips.
Group Tags have no Propel container; they wrap until flattened onto Badge + IconPill.
This commit is contained in:
anmolsinghbhatia
2026-08-28 16:41:17 +05:30
parent 3478d4fac4
commit accde008b8
12 changed files with 107 additions and 85 deletions

View File

@@ -8,9 +8,9 @@ import { observer } from "mobx-react";
// plane imports
import { EUserPermissions, EUserPermissionsLevel } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { PillButton } from "@makeplane/propel/components/pill";
import { CloseIcon } from "@plane/propel/icons";
import type { TCycleFilters } from "@plane/types";
import { Tag } from "@plane/ui";
import { replaceUnderscoreIfSnakeCase } from "@plane/utils";
// hooks
import { useUserPermissions } from "@/hooks/store/user";
@@ -50,7 +50,10 @@ export const CycleAppliedFiltersList = observer(function CycleAppliedFiltersList
if (Array.isArray(value) && value.length === 0) return;
return (
<Tag key={filterKey}>
<div
key={filterKey}
className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary"
>
<span className="text-11 text-tertiary">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
<div className="flex flex-wrap items-center gap-1">
{filterKey === "status" && (
@@ -77,16 +80,18 @@ export const CycleAppliedFiltersList = observer(function CycleAppliedFiltersList
</button>
)}
</div>
</Tag>
</div>
);
})}
{isEditingAllowed && (
<button type="button" onClick={handleClearAllFilters}>
<Tag>
{t("common.clear_all")}
<CloseIcon height={12} width={12} strokeWidth={2} />
</Tag>
</button>
<PillButton
type="button"
size="md"
variant="outline"
label={t("common.clear_all")}
endIcon={<CloseIcon height={12} width={12} strokeWidth={2} />}
onClick={handleClearAllFilters}
/>
)}
</div>
);

View File

@@ -8,11 +8,7 @@ import { observer } from "mobx-react";
import { PAST_DURATION_FILTER_OPTIONS } from "@plane/constants";
import { CloseIcon } from "@plane/propel/icons";
import type { TInboxIssueFilterDateKeys } from "@plane/types";
// helpers
import { Tag } from "@plane/ui";
import { renderFormattedDate } from "@plane/utils";
// constants
// hooks
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
type InboxIssueAppliedFiltersDate = {
@@ -45,7 +41,7 @@ export const InboxIssueAppliedFiltersDate = observer(function InboxIssueAppliedF
if (filteredValues.length === 0) return <></>;
return (
<Tag>
<div className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary">
<div className="text-11 text-secondary">{label}</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@@ -69,6 +65,6 @@ export const InboxIssueAppliedFiltersDate = observer(function InboxIssueAppliedF
>
<CloseIcon className={`h-3 w-3`} />
</div>
</Tag>
</div>
);
});

View File

@@ -7,7 +7,6 @@
import { observer } from "mobx-react";
// hooks
import { CloseIcon } from "@plane/propel/icons";
import { Tag } from "@plane/ui";
import { useLabel } from "@/hooks/store/use-label";
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
@@ -30,7 +29,7 @@ export const InboxIssueAppliedFiltersLabel = observer(function InboxIssueApplied
if (filteredValues.length === 0) return <></>;
return (
<Tag>
<div className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary">
<div className="text-11 text-secondary">Label</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@@ -57,6 +56,6 @@ export const InboxIssueAppliedFiltersLabel = observer(function InboxIssueApplied
>
<CloseIcon className={`h-3 w-3`} />
</div>
</Tag>
</div>
);
});

View File

@@ -10,7 +10,7 @@ import { observer } from "mobx-react";
import { CloseIcon } from "@plane/propel/icons";
import type { TInboxIssueFilterMemberKeys } from "@plane/types";
// plane ui
import { Avatar, Tag } from "@plane/ui";
import { Avatar } from "@plane/ui";
// helpers
import { getFileURL } from "@plane/utils";
// hooks
@@ -40,7 +40,7 @@ export const InboxIssueAppliedFiltersMember = observer(function InboxIssueApplie
if (filteredValues.length === 0) return <></>;
return (
<Tag>
<div className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary">
<div className="text-11 text-secondary">{label}</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@@ -72,6 +72,6 @@ export const InboxIssueAppliedFiltersMember = observer(function InboxIssueApplie
>
<CloseIcon className={`h-3 w-3`} />
</div>
</Tag>
</div>
);
});

View File

@@ -9,7 +9,6 @@ import { ISSUE_PRIORITIES } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { PriorityIcon, CloseIcon } from "@plane/propel/icons";
import type { TIssuePriorities } from "@plane/types";
import { Tag } from "@plane/ui";
// hooks
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
@@ -29,7 +28,7 @@ export const InboxIssueAppliedFiltersPriority = observer(function InboxIssueAppl
if (filteredValues.length === 0) return <></>;
return (
<Tag>
<div className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary">
<div className="text-11 text-secondary">{t("common.priority")}</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@@ -56,6 +55,6 @@ export const InboxIssueAppliedFiltersPriority = observer(function InboxIssueAppl
>
<CloseIcon className={`h-3 w-3`} />
</div>
</Tag>
</div>
);
});

View File

@@ -7,7 +7,6 @@
import { observer } from "mobx-react";
import { EIconSize } from "@plane/constants";
import { StateGroupIcon, CloseIcon } from "@plane/propel/icons";
import { Tag } from "@plane/ui";
// hooks
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
import { useProjectState } from "@/hooks/store/use-project-state";
@@ -27,7 +26,7 @@ export const InboxIssueAppliedFiltersState = observer(function InboxIssueApplied
if (filteredValues.length === 0) return <></>;
return (
<Tag>
<div className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary">
<div className="text-11 text-secondary">State</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@@ -54,6 +53,6 @@ export const InboxIssueAppliedFiltersState = observer(function InboxIssueApplied
>
<CloseIcon className={`h-3 w-3`} />
</div>
</Tag>
</div>
);
});

View File

@@ -9,9 +9,6 @@ import { INBOX_STATUS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { CloseIcon } from "@plane/propel/icons";
import type { TInboxIssueStatus } from "@plane/types";
// constants
import { Tag } from "@plane/ui";
// hooks
import { useProjectInbox } from "@/hooks/store/use-project-inbox";
import { InboxStatusIcon } from "../../inbox-status-icon";
@@ -28,7 +25,7 @@ export const InboxIssueAppliedFiltersStatus = observer(function InboxIssueApplie
if (filteredValues.length === 0) return <></>;
return (
<Tag>
<div className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary">
<div className="text-11 text-secondary">Status</div>
{filteredValues.map((value) => {
const optionDetail = currentOptionDetail(value);
@@ -50,6 +47,6 @@ export const InboxIssueAppliedFiltersStatus = observer(function InboxIssueApplie
</div>
);
})}
</Tag>
</div>
);
});

View File

@@ -5,10 +5,11 @@
*/
import { useTranslation } from "@plane/i18n";
import { PillButton } from "@makeplane/propel/components/pill";
import { CloseIcon } from "@plane/propel/icons";
import type { TModuleDisplayFilters, TModuleFilters } from "@plane/types";
// components
import { Header, EHeaderVariant, Tag } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
import { replaceUnderscoreIfSnakeCase } from "@plane/utils";
import { AppliedDateFilters, AppliedMembersFilters, AppliedStatusFilters } from "@/components/modules";
// helpers
@@ -54,7 +55,10 @@ export function ModuleAppliedFiltersList(props: Props) {
if (Array.isArray(value) && value.length === 0) return;
return (
<Tag key={filterKey}>
<div
key={filterKey}
className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary"
>
<div className="flex flex-wrap items-center gap-1.5">
<span className="text-11 text-tertiary">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{filterKey === "status" && (
@@ -88,7 +92,7 @@ export function ModuleAppliedFiltersList(props: Props) {
</button>
)}
</div>
</Tag>
</div>
);
})}
{!isArchived && isFavoriteFilterApplied && (
@@ -119,12 +123,14 @@ export function ModuleAppliedFiltersList(props: Props) {
</div>
)}
{isEditingAllowed && (
<button type="button" onClick={handleClearAllFilters}>
<Tag>
{t("common.clear_all")}
<CloseIcon height={12} width={12} strokeWidth={2} />
</Tag>
</button>
<PillButton
type="button"
size="md"
variant="outline"
label={t("common.clear_all")}
endIcon={<CloseIcon height={12} width={12} strokeWidth={2} />}
onClick={handleClearAllFilters}
/>
)}
</div>
</Header>

View File

@@ -5,10 +5,10 @@
*/
import { useTranslation } from "@plane/i18n";
import { PillButton } from "@makeplane/propel/components/pill";
import { CloseIcon } from "@plane/propel/icons";
// plane imports
import type { TPageFilterProps } from "@plane/types";
import { Tag } from "@plane/ui";
import { replaceUnderscoreIfSnakeCase } from "@plane/utils";
// components
import { AppliedDateFilters } from "@/components/common/applied-filters/date";
@@ -42,7 +42,10 @@ export function PageAppliedFiltersList(props: Props) {
if (Array.isArray(value) && value.length === 0) return;
return (
<Tag key={filterKey}>
<div
key={filterKey}
className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary"
>
<div className="flex flex-wrap items-center gap-1.5">
<span className="text-11 text-tertiary">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{DATE_FILTERS.includes(filterKey) && (
@@ -69,16 +72,18 @@ export function PageAppliedFiltersList(props: Props) {
</button>
)}
</div>
</Tag>
</div>
);
})}
{isEditingAllowed && (
<button type="button" onClick={handleClearAllFilters}>
<Tag>
{t("common.clear_all")}
<CloseIcon height={12} strokeWidth={2} />
</Tag>
</button>
<PillButton
type="button"
size="md"
variant="outline"
label={t("common.clear_all")}
endIcon={<CloseIcon height={12} strokeWidth={2} />}
onClick={handleClearAllFilters}
/>
)}
</div>
);

View File

@@ -5,11 +5,12 @@
*/
import { useTranslation } from "@plane/i18n";
import { PillButton } from "@makeplane/propel/components/pill";
import { CloseIcon } from "@plane/propel/icons";
// plane imports
import { Tooltip } from "@plane/propel/tooltip";
import type { TProjectAppliedDisplayFilterKeys, TProjectFilters } from "@plane/types";
import { EHeaderVariant, Header, Tag } from "@plane/ui";
import { EHeaderVariant, Header } from "@plane/ui";
import { replaceUnderscoreIfSnakeCase } from "@plane/utils";
// local imports
import { AppliedAccessFilters } from "./access";
@@ -60,7 +61,10 @@ export function ProjectAppliedFiltersList(props: Props) {
if (Array.isArray(value) && value.length === 0) return;
return (
<Tag key={filterKey}>
<div
key={filterKey}
className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary"
>
<span className="text-11 text-tertiary">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{filterKey === "access" && (
<AppliedAccessFilters
@@ -92,27 +96,32 @@ export function ProjectAppliedFiltersList(props: Props) {
<CloseIcon height={12} width={12} strokeWidth={2} />
</button>
)}
</Tag>
</div>
);
})}
{/* Applied display filters */}
{appliedDisplayFilters.length > 0 && (
<Tag key="project_display_filters">
<div
key="project_display_filters"
className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary"
>
<span className="text-11 text-tertiary">{t("common.projects")}</span>
<AppliedProjectDisplayFilters
editable={isEditingAllowed}
values={appliedDisplayFilters}
handleRemove={(key) => handleRemoveDisplayFilter(key)}
/>
</Tag>
</div>
)}
{isEditingAllowed && (
<button type="button" onClick={handleClearAllFilters}>
<Tag>
{t("common.clear_all")}
<CloseIcon height={12} width={12} strokeWidth={2} />
</Tag>
</button>
<PillButton
type="button"
size="md"
variant="outline"
label={t("common.clear_all")}
endIcon={<CloseIcon height={12} width={12} strokeWidth={2} />}
onClick={handleClearAllFilters}
/>
)}
</Header.LeftItem>
<Header.RightItem>

View File

@@ -5,10 +5,10 @@
*/
import { useTranslation } from "@plane/i18n";
import { PillButton } from "@makeplane/propel/components/pill";
import { CloseIcon } from "@plane/propel/icons";
// plane imports
import type { EViewAccess, TViewFilterProps } from "@plane/types";
import { Tag } from "@plane/ui";
import { replaceUnderscoreIfSnakeCase } from "@plane/utils";
// components
import { AppliedDateFilters } from "@/components/common/applied-filters/date";
@@ -45,7 +45,10 @@ export function ViewAppliedFiltersList(props: Props) {
if (Array.isArray(value) && value.length === 0) return;
return (
<Tag key={filterKey}>
<div
key={filterKey}
className="my-auto flex min-h-9 cursor-pointer flex-wrap items-center gap-1.5 rounded-md border border-subtle p-1.5 text-11 text-tertiary capitalize hover:text-secondary"
>
<span className="text-11 text-tertiary">{replaceUnderscoreIfSnakeCase(filterKey)}</span>
{VIEW_ACCESS_FILTERS.includes(filterKey) && (
<AppliedAccessFilters
@@ -77,16 +80,18 @@ export function ViewAppliedFiltersList(props: Props) {
<CloseIcon height={12} width={12} strokeWidth={2} />
</button>
)}
</Tag>
</div>
);
})}
{isEditingAllowed && (
<button type="button" onClick={handleClearAllFilters}>
<Tag>
{t("common.clear_all")}
<CloseIcon height={12} width={12} strokeWidth={2} />
</Tag>
</button>
<PillButton
type="button"
size="md"
variant="outline"
label={t("common.clear_all")}
endIcon={<CloseIcon height={12} width={12} strokeWidth={2} />}
onClick={handleClearAllFilters}
/>
)}
</div>
);

View File

@@ -8,8 +8,9 @@ import { observer } from "mobx-react";
// plane imports
import { ENotificationFilterType, FILTER_TYPE_OPTIONS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { PillButton } from "@makeplane/propel/components/pill";
import { CloseIcon } from "@plane/propel/icons";
import { Header, EHeaderVariant, Tag } from "@plane/ui";
import { Header, EHeaderVariant } from "@plane/ui";
// hooks
import { useWorkspaceNotifications } from "@/hooks/store/notifications";
@@ -47,24 +48,25 @@ export const AppliedFilters = observer(function AppliedFilters(props: TAppliedFi
const isSelected = filters?.type?.[filter?.value] || false;
if (!isSelected) return <></>;
return (
<Tag
<PillButton
key={filter.value}
className="flex-start flex flex-wrap"
type="button"
size="md"
variant="outline"
label={t(filter.i18n_label)}
endIcon={<CloseIcon className="h-3 w-3" />}
onClick={() => handleFilterTypeChange(filter?.value, !isSelected)}
>
<div className="whitespace-nowrap text-secondary">{t(filter.i18n_label)}</div>
<div className="flex h-4 w-4 items-center justify-center rounded-xs text-secondary transition-all hover:text-primary">
<CloseIcon className="h-3 w-3" />
</div>
</Tag>
/>
);
})}
<button type="button" onClick={handleClearFilters}>
<Tag>
{t("common.clear_all")}
<CloseIcon height={12} width={12} strokeWidth={2} />
</Tag>
</button>
<PillButton
type="button"
size="md"
variant="outline"
label={t("common.clear_all")}
endIcon={<CloseIcon height={12} width={12} strokeWidth={2} />}
onClick={handleClearFilters}
/>
</Header.LeftItem>
</Header>
);