АРХ - МЕЖПРОЕКТНАЯ КОММУНИКАЦИЯ: миграция searchable select-пикеров на общий канон

This commit is contained in:
DCCONSTRUCTIONS
2026-04-22 13:48:28 +03:00
parent a49e18d0e5
commit 8fa5de24eb
13 changed files with 127 additions and 59 deletions
@@ -11,8 +11,8 @@ import { Calendar } from "lucide-react";
// plane package imports
import { ANALYTICS_DURATION_FILTER_OPTIONS } from "@plane/constants";
import { useTranslation } from "@plane/i18n";
import { CustomSearchSelect } from "@plane/ui";
// types
import { SelectionDropdown } from "@/components/common/selection-dropdown";
import type { TDropdownProps } from "@/components/dropdowns/types";
type Props = TDropdownProps & {
@@ -31,25 +31,21 @@ function DurationDropdown({ placeholder = "Duration", onChange, value }: Props)
useTranslation();
const options = ANALYTICS_DURATION_FILTER_OPTIONS.map((option) => ({
value: option.value,
query: option.name,
content: (
<div className="flex max-w-[300px] items-center gap-2">
<span className="flex-grow truncate">{option.name}</span>
</div>
),
key: option.value,
title: option.name,
isChecked: value === option.value,
onClick: () => onChange(option.value),
}));
return (
<CustomSearchSelect
value={value ? [value] : []}
onChange={onChange}
<SelectionDropdown
options={options}
label={
menuButton={
<div className="flex items-center gap-2 p-1">
<Calendar className="h-4 w-4" />
{value ? ANALYTICS_DURATION_FILTER_OPTIONS.find((opt) => opt.value === value)?.name : placeholder}
</div>
}
menuButtonWrapperClassName="flex items-center rounded-full border-0 outline-none"
/>
);
}
@@ -9,7 +9,7 @@ import { observer } from "mobx-react";
import { getButtonStyling } from "@plane/propel/button";
import { Logo } from "@plane/propel/emoji-icon-picker";
import { ChevronDownIcon, ProjectIcon } from "@plane/propel/icons";
import { CustomSearchSelect } from "@plane/ui";
import { SearchSelectionDropdown } from "@plane/ui";
import { cn } from "@plane/utils";
// hooks
import { useProject } from "@/hooks/store/use-project";
@@ -44,12 +44,12 @@ export const ProjectSelect = observer(function ProjectSelect(props: Props) {
});
return (
<CustomSearchSelect
<SearchSelectionDropdown
value={value ?? []}
onChange={(val: string[]) => onChange(val)}
options={options}
className="border-none p-0"
customButton={
menuButton={
<div className={cn(getButtonStyling("secondary", "lg"), "gap-2")}>
<ProjectIcon className="h-4 w-4" />
{value && value.length > 3
@@ -63,7 +63,7 @@ export const ProjectSelect = observer(function ProjectSelect(props: Props) {
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</div>
}
customButtonClassName="border-none p-0 bg-transparent hover:bg-transparent w-auto h-auto"
menuButtonWrapperClassName="h-auto w-auto border-none bg-transparent p-0 hover:bg-transparent"
multiple
/>
);
@@ -13,7 +13,7 @@ import { PROJECT_AUTOMATION_MONTHS, EUserPermissions, EUserPermissionsLevel, EIc
import { useTranslation } from "@plane/i18n";
import { StateGroupIcon, StatePropertyIcon } from "@plane/propel/icons";
import type { IProject } from "@plane/types";
import { CustomSelect, CustomSearchSelect, ToggleSwitch, Loader } from "@plane/ui";
import { CustomSelect, Loader, SearchSelectionDropdown, ToggleSwitch } from "@plane/ui";
import { SelectMonthModal } from "@/components/automation";
import { SettingsControlItem } from "@/components/settings/control-item";
// hooks
@@ -151,7 +151,7 @@ export const AutoCloseAutomation = observer(function AutoCloseAutomation(props:
{t("project_settings.automations.auto-close.auto_close_status")}
</div>
<div className="w-1/2">
<CustomSearchSelect
<SearchSelectionDropdown
value={currentProjectDetails?.default_state ?? defaultState}
label={
<div className="flex items-center gap-2">
@@ -21,7 +21,7 @@ import { TOAST_TYPE, setToast } from "@plane/propel/toast";
// import { Tooltip } from "@plane/propel/tooltip";
// import { EIssuesStoreType } from "@plane/types";
import type { TWorkItemFilterExpression } from "@plane/types";
import { CustomSearchSelect, CustomSelect } from "@plane/ui";
import { CustomSelect, SearchSelectionDropdown } from "@plane/ui";
// import { WorkspaceLevelWorkItemFiltersHOC } from "@/components/work-item-filters/filters-hoc/workspace-level";
// import { WorkItemFiltersRow } from "@/components/work-item-filters/filters-row";
import { useProject } from "@/hooks/store/use-project";
@@ -155,7 +155,7 @@ export const ExportForm = observer(function ExportForm(props: Props) {
name="project"
disabled={!isMember && (!hasProjects || !canPerformAnyCreateAction)}
render={({ field: { value, onChange } }) => (
<CustomSearchSelect
<SearchSelectionDropdown
value={value ?? []}
onChange={(val: string[]) => onChange(val)}
options={options}
@@ -14,7 +14,7 @@ import { Button } from "@plane/propel/button";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import type { IUser, IImporterService } from "@plane/types";
// ui
import { Checkbox, CustomSearchSelect, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { Checkbox, EModalPosition, EModalWidth, ModalCore, SearchSelectionDropdown } from "@plane/ui";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useUser } from "@/hooks/store/user";
@@ -122,7 +122,7 @@ export const Exporter = observer(function Exporter(props: Props) {
</span>
</div>
<div>
<CustomSearchSelect
<SearchSelectionDropdown
value={value ?? []}
onChange={(val: string[]) => onChange(val)}
options={options}
@@ -6,7 +6,7 @@
import { observer } from "mobx-react";
// plane imports
import { CustomSearchSelect } from "@plane/ui";
import { SearchSelectionDropdown } from "@plane/ui";
import { cn } from "@plane/utils";
// hooks
import useTimezone from "@/hooks/use-timezone";
@@ -39,7 +39,7 @@ export const TimezoneSelect = observer(function TimezoneSelect(props: TTimezoneS
return (
<div>
<CustomSearchSelect
<SearchSelectionDropdown
value={value}
label={value && selectedValue ? selectedValue(value) : label}
options={isDisabled || disabled ? [] : timezones}
@@ -10,7 +10,7 @@ import useSWRInfinite from "swr/infinite";
import type { IWorkspaceIntegration } from "@plane/types";
// services
// ui
import { CustomSearchSelect } from "@plane/ui";
import { SearchSelectionDropdown } from "@plane/ui";
// helpers
import { truncateText } from "@plane/utils";
import { ProjectService } from "@/services/project";
@@ -62,7 +62,7 @@ export function SelectRepository(props: Props) {
if (userRepositories.length < 1) return null;
return (
<CustomSearchSelect
<SearchSelectionDropdown
value={value}
options={options}
onChange={(val: string) => {
@@ -9,7 +9,7 @@ import { observer } from "mobx-react";
// plane imports
import { ProjectIcon } from "@plane/propel/icons";
import type { ICustomSearchSelectOption } from "@plane/types";
import { CustomSearchSelect } from "@plane/ui";
import { SearchSelectionDropdown } from "@plane/ui";
// hooks
import { useProject } from "@/hooks/store/use-project";
import { useUserPermissions } from "@/hooks/store/user";
@@ -100,13 +100,13 @@ export const ProjectHeader = observer(function ProjectHeader(props: TProjectHead
if (!currentProjectDetails) return null;
return (
<CustomSearchSelect
<SearchSelectionDropdown
options={switcherOptions}
value={currentProjectDetails.id}
onChange={handleProjectChange}
customButton={currentProjectDetails ? <ProjectHeaderButton project={currentProjectDetails} /> : null}
menuButton={currentProjectDetails ? <ProjectHeaderButton project={currentProjectDetails} /> : null}
className="h-full rounded"
customButtonClassName="group flex items-center gap-0.5 rounded-sm hover:bg-surface-2 outline-none cursor-pointer h-full"
menuButtonWrapperClassName="group flex h-full cursor-pointer items-center gap-0.5 rounded-sm outline-none hover:bg-surface-2"
/>
);
});
@@ -11,7 +11,7 @@ import { Ban } from "lucide-react";
import { useTranslation } from "@plane/i18n";
import { EUserProjectRoles } from "@plane/types";
// plane ui
import { Avatar, CustomSearchSelect } from "@plane/ui";
import { Avatar, SearchSelectionDropdown } from "@plane/ui";
// helpers
import { getFileURL } from "@plane/utils";
// hooks
@@ -62,7 +62,7 @@ export const MemberSelect = observer(function MemberSelect(props: Props) {
const selectedOption = projectId ? getProjectMemberDetails(value, projectId.toString()) : null;
return (
<CustomSearchSelect
<SearchSelectionDropdown
value={value}
label={
<div className="flex h-3.5 items-center gap-2">
@@ -13,7 +13,7 @@ import { useTranslation } from "@plane/i18n";
import { Button } from "@plane/propel/button";
import { PlusIcon, CloseIcon, ChevronDownIcon } from "@plane/propel/icons";
import { TOAST_TYPE, setToast } from "@plane/propel/toast";
import { Avatar, CustomSelect, CustomSearchSelect, EModalPosition, EModalWidth, ModalCore } from "@plane/ui";
import { Avatar, CustomSelect, EModalPosition, EModalWidth, ModalCore, SearchSelectionDropdown } from "@plane/ui";
// helpers
import { getFileURL } from "@plane/utils";
// hooks
@@ -193,10 +193,10 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
render={({ field: { value, onChange } }) => {
const selectedMember = getWorkspaceMemberDetails(value);
return (
<CustomSearchSelect
<SearchSelectionDropdown
value={value}
customButton={
<button className="shadow-sm flex w-full items-center justify-between gap-1 rounded-md border border-subtle px-3 py-2 text-left text-13 text-secondary duration-300 hover:bg-layer-1 hover:text-primary focus:outline-none">
menuButton={
<>
{value && value !== "" ? (
<div className="flex items-center gap-2">
<Avatar
@@ -211,8 +211,9 @@ export const SendProjectInvitationModal = observer(function SendProjectInvitatio
</div>
)}
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
</button>
</>
}
menuButtonWrapperClassName="shadow-sm flex w-full items-center justify-between gap-1 rounded-md border border-subtle px-3 py-2 text-left text-13 text-secondary duration-300 hover:bg-layer-1 hover:text-primary focus:outline-none"
onChange={(val: string) => {
onChange(val);
// Update the role to the workspace role when member ID changes