mirror of
https://github.com/makeplane/plane.git
synced 2026-09-02 03:59:00 +02:00
fix: address Button migration review on web call sites
Use IconButton for icon-only controls and AnchorButton for link-styled actions. Add accessible names on render anchors, un-nest link+button pairs, restore compact header labels, and pass through empty-state variant/icon props.
This commit is contained in:
@@ -9,6 +9,7 @@ import { Shapes } from "lucide-react";
|
||||
// plane imports
|
||||
import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@makeplane/propel/components/button";
|
||||
import { IconButton } from "@makeplane/propel/components/icon-button";
|
||||
import { HomeIcon } from "@plane/propel/icons";
|
||||
import { Breadcrumbs, Header } from "@plane/ui";
|
||||
// components
|
||||
@@ -37,7 +38,7 @@ export const WorkspaceDashboardHeader = observer(function WorkspaceDashboardHead
|
||||
</div>
|
||||
</Header.LeftItem>
|
||||
<Header.RightItem>
|
||||
<span className="my-auto mb-0">
|
||||
<span className="my-auto mb-0 hidden md:inline-flex">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
@@ -47,6 +48,15 @@ export const WorkspaceDashboardHeader = observer(function WorkspaceDashboardHead
|
||||
label={t("home.manage_widgets")}
|
||||
/>
|
||||
</span>
|
||||
<span className="my-auto mb-0 md:hidden">
|
||||
<IconButton
|
||||
variant="secondary"
|
||||
size="md"
|
||||
aria-label={t("home.manage_widgets")}
|
||||
icon={<Shapes />}
|
||||
onClick={() => toggleWidgetSettings(true)}
|
||||
/>
|
||||
</span>
|
||||
</Header.RightItem>
|
||||
</Header>
|
||||
</>
|
||||
|
||||
@@ -19,7 +19,7 @@ import { ProfileIssuesFilter } from "@/components/profile/profile-issues-filter"
|
||||
// hooks
|
||||
import { useAppTheme } from "@/hooks/store/use-app-theme";
|
||||
import { useUser, useUserPermissions } from "@/hooks/store/user";
|
||||
import { Button } from "@makeplane/propel/elements/button";
|
||||
import { IconButton } from "@makeplane/propel/components/icon-button";
|
||||
|
||||
type TUserProfileHeader = {
|
||||
userProjectsData: IUserProfileProjectSegregation | undefined;
|
||||
@@ -96,9 +96,13 @@ export const UserProfileHeader = observer(function UserProfileHeader(props: TUse
|
||||
))}
|
||||
</CustomMenu>
|
||||
<div className="shrink-0 md:hidden">
|
||||
<Button variant="ghost" size="md" stretch="auto" onClick={() => toggleProfileSidebar()}>
|
||||
<PanelRight className={!profileSidebarCollapsed ? "text-accent-primary" : "text-secondary"} />
|
||||
</Button>
|
||||
<IconButton
|
||||
variant="ghost"
|
||||
size="md"
|
||||
aria-label="Toggle profile sidebar"
|
||||
icon={<PanelRight className={!profileSidebarCollapsed ? "text-accent-primary" : "text-secondary"} />}
|
||||
onClick={() => toggleProfileSidebar()}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</Header.RightItem>
|
||||
|
||||
@@ -60,15 +60,30 @@ export const CyclesListHeader = observer(function CyclesListHeader() {
|
||||
{canUserCreateCycle && currentProjectDetails ? (
|
||||
<Header.RightItem>
|
||||
<CyclesViewHeader projectId={currentProjectDetails.id} />
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("project_cycles.add_cycle")}
|
||||
onClick={() => {
|
||||
toggleCreateCycleModal(true);
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<span className="block sm:hidden">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("add")}
|
||||
onClick={() => {
|
||||
toggleCreateCycleModal(true);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
<span className="hidden sm:block">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("project_cycles.add_cycle")}
|
||||
onClick={() => {
|
||||
toggleCreateCycleModal(true);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</>
|
||||
</Header.RightItem>
|
||||
) : (
|
||||
<></>
|
||||
|
||||
@@ -65,15 +65,30 @@ export const ModulesListHeader = observer(function ModulesListHeader() {
|
||||
<Header.RightItem>
|
||||
<ModuleViewHeader />
|
||||
{canUserCreateModule ? (
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("project_module.add_module")}
|
||||
onClick={() => {
|
||||
toggleCreateModuleModal(true);
|
||||
}}
|
||||
/>
|
||||
<>
|
||||
<span className="block sm:hidden">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("add")}
|
||||
onClick={() => {
|
||||
toggleCreateModuleModal(true);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
<span className="hidden sm:block">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("project_module.add_module")}
|
||||
onClick={() => {
|
||||
toggleCreateModuleModal(true);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
</>
|
||||
) : (
|
||||
<></>
|
||||
)}
|
||||
|
||||
@@ -99,7 +99,12 @@ const CreateWorkspacePage = observer(function CreateWorkspacePage() {
|
||||
stretch="auto"
|
||||
label={t("workspace_creation.errors.creation_disabled.request_button")}
|
||||
nativeButton={false}
|
||||
render={<a href={getMailtoHref()} />}
|
||||
render={
|
||||
<a
|
||||
href={getMailtoHref()}
|
||||
aria-label={t("workspace_creation.errors.creation_disabled.request_button")}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { Controller, useForm } from "react-hook-form";
|
||||
// icons
|
||||
import { CircleCheck } from "lucide-react";
|
||||
// plane imports
|
||||
import { AnchorButton } from "@makeplane/propel/components/anchor-button";
|
||||
import { Button } from "@makeplane/propel/components/button";
|
||||
import { Field } from "@makeplane/propel/components/field";
|
||||
import { Input, InputGroup } from "@makeplane/propel/components/input";
|
||||
@@ -133,10 +134,9 @@ export const ForgotPasswordForm = observer(function ForgotPasswordForm() {
|
||||
disabled={!isValid}
|
||||
loading={isSubmitting || resendTimerCode > 0}
|
||||
/>
|
||||
<Button
|
||||
variant="ghost"
|
||||
<AnchorButton
|
||||
variant="primary"
|
||||
size="md"
|
||||
stretch="full"
|
||||
label={t("auth.common.back_to_sign_in")}
|
||||
nativeButton={false}
|
||||
render={<Link href="/" />}
|
||||
|
||||
@@ -98,7 +98,9 @@ export const WorkspaceActiveCyclesUpgrade = observer(function WorkspaceActiveCyc
|
||||
label={t("upgrade")}
|
||||
icon={<ProIcon className="h-3.5 w-3.5 text-on-color" />}
|
||||
nativeButton={false}
|
||||
render={<a href={MARKETING_PRICING_PAGE_LINK} target="_blank" rel="noreferrer" />}
|
||||
render={
|
||||
<a href={MARKETING_PRICING_PAGE_LINK} target="_blank" rel="noreferrer" aria-label={t("upgrade")} />
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<span className="absolute top-0 left-0">
|
||||
|
||||
@@ -57,6 +57,7 @@ export function NewEmptyState({ title, description, image, primaryButton, disabl
|
||||
onClick={primaryButton.onClick}
|
||||
disabled={disabled}
|
||||
label={primaryButton.text}
|
||||
icon={primaryButton.icon}
|
||||
/>
|
||||
<div
|
||||
onMouseEnter={handleMouseEnter}
|
||||
|
||||
@@ -42,20 +42,20 @@ const sizeClasses = {
|
||||
function CustomButton({
|
||||
config,
|
||||
variant,
|
||||
size,
|
||||
}: {
|
||||
config: ButtonConfig;
|
||||
variant: "primary" | "secondary";
|
||||
size: EmptyStateSize;
|
||||
}) {
|
||||
const icon = config.prependIcon ?? config.appendIcon;
|
||||
return (
|
||||
<Button
|
||||
variant="primary"
|
||||
variant={variant}
|
||||
size="sm"
|
||||
stretch="auto"
|
||||
label={config.text}
|
||||
icon={config.appendIcon}
|
||||
iconPosition="end"
|
||||
icon={icon}
|
||||
iconPosition={config.prependIcon ? "start" : "end"}
|
||||
onClick={config.onClick}
|
||||
disabled={config.disabled}
|
||||
/>
|
||||
|
||||
@@ -65,9 +65,21 @@ export function SingleExport({ service, refreshing }: Props) {
|
||||
<>
|
||||
{service.status == "completed" && (
|
||||
<div>
|
||||
<a target="_blank" href={service?.url} rel="noopener noreferrer">
|
||||
<Button variant="primary" size="sm" stretch="full" label={isLoading ? "Downloading..." : "Download"} />
|
||||
</a>
|
||||
<Button
|
||||
variant="primary"
|
||||
size="sm"
|
||||
stretch="full"
|
||||
label={isLoading ? "Downloading..." : "Download"}
|
||||
nativeButton={false}
|
||||
render={
|
||||
<a
|
||||
target="_blank"
|
||||
href={service?.url}
|
||||
rel="noopener noreferrer"
|
||||
aria-label={isLoading ? "Downloading..." : "Download"}
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -63,7 +63,9 @@ export function ProductUpdatesFooter() {
|
||||
label={t("powered_by_plane_pages")}
|
||||
icon={<PlaneLogo className="h-4 w-auto text-primary" />}
|
||||
nativeButton={false}
|
||||
render={<a href="https://plane.so/pages" target="_blank" rel="noreferrer" />}
|
||||
render={
|
||||
<a href="https://plane.so/pages" target="_blank" rel="noreferrer" aria-label={t("powered_by_plane_pages")} />
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -369,15 +369,24 @@ export const InboxIssueActionsHeader = observer(function InboxIssueActionsHeader
|
||||
icon={<LinkIcon className="h-2.5 w-2.5" />}
|
||||
onClick={() => handleCopyIssueLink(workItemLink)}
|
||||
/>
|
||||
<ControlLink href={workItemLink} onClick={() => router.push(workItemLink)} target="_self">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("inbox_issue.actions.open")}
|
||||
icon={<NewTabIcon className="h-2.5 w-2.5" />}
|
||||
/>
|
||||
</ControlLink>
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={t("inbox_issue.actions.open")}
|
||||
icon={<NewTabIcon className="h-2.5 w-2.5" />}
|
||||
nativeButton={false}
|
||||
render={
|
||||
<ControlLink
|
||||
href={workItemLink}
|
||||
onClick={() => router.push(workItemLink)}
|
||||
target="_self"
|
||||
aria-label={t("inbox_issue.actions.open")}
|
||||
>
|
||||
{""}
|
||||
</ControlLink>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
|
||||
@@ -45,9 +45,16 @@ export function InstanceNotReady() {
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<a href={GOD_MODE_URL} className="w-72">
|
||||
<Button variant="primary" size="lg" stretch="full" label="Get started" />
|
||||
</a>
|
||||
<span className="w-72">
|
||||
<Button
|
||||
variant="primary"
|
||||
size="lg"
|
||||
stretch="full"
|
||||
label="Get started"
|
||||
nativeButton={false}
|
||||
render={<a href={GOD_MODE_URL} aria-label="Get started" />}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -29,7 +29,14 @@ export function BulkOperationsUpgradeBanner(props: Props) {
|
||||
stretch="auto"
|
||||
label="Upgrade to One"
|
||||
nativeButton={false}
|
||||
render={<a href={MARKETING_PLANE_ONE_PAGE_LINK} target="_blank" rel="noopener noreferrer" />}
|
||||
render={
|
||||
<a
|
||||
href={MARKETING_PLANE_ONE_PAGE_LINK}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
aria-label="Upgrade to One"
|
||||
/>
|
||||
}
|
||||
/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -11,6 +11,7 @@ import { usePopper } from "react-popper";
|
||||
import { Popover, Transition } from "@headlessui/react";
|
||||
// ui
|
||||
import { Button } from "@makeplane/propel/components/button";
|
||||
import { IconButton } from "@makeplane/propel/components/icon-button";
|
||||
|
||||
type Props = {
|
||||
children: React.ReactNode;
|
||||
@@ -46,7 +47,7 @@ export function FiltersDropdown(props: Props) {
|
||||
|
||||
return (
|
||||
<Popover as="div">
|
||||
{({ open }) => (
|
||||
{() => (
|
||||
<>
|
||||
<Popover.Button as={React.Fragment}>
|
||||
{menuButton ? (
|
||||
@@ -70,14 +71,25 @@ export function FiltersDropdown(props: Props) {
|
||||
)}
|
||||
</div>
|
||||
<div className="flex @4xl:hidden">
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={typeof title === "string" ? title : "Filters"}
|
||||
disabled={disabled}
|
||||
tabIndex={tabIndex}
|
||||
/>
|
||||
{miniIcon ? (
|
||||
<IconButton
|
||||
variant="secondary"
|
||||
size="md"
|
||||
aria-label={typeof title === "string" ? title : "Filters"}
|
||||
icon={miniIcon}
|
||||
disabled={disabled}
|
||||
tabIndex={tabIndex}
|
||||
/>
|
||||
) : (
|
||||
<Button
|
||||
variant="secondary"
|
||||
size="md"
|
||||
stretch="auto"
|
||||
label={typeof title === "string" ? title : "Filters"}
|
||||
disabled={disabled}
|
||||
tabIndex={tabIndex}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -78,7 +78,7 @@ export const TalkToSalesCard = observer(function TalkToSalesCard(props: TalkToSa
|
||||
stretch="full"
|
||||
label="Talk to Sales"
|
||||
nativeButton={false}
|
||||
render={<a href={href} target="_blank" rel="noreferrer" />}
|
||||
render={<a href={href} target="_blank" rel="noreferrer" aria-label="Talk to Sales" />}
|
||||
/>
|
||||
</span>
|
||||
{isTrialAllowed && !isSelfHosted && (
|
||||
|
||||
@@ -112,7 +112,7 @@ export function Invitations(props: Props) {
|
||||
<p className="mx-3 flex-shrink-0 text-center text-13 text-placeholder">or</p>
|
||||
<hr className="w-full border-strong" />
|
||||
</div>
|
||||
<span className="w-full bg-surface-2 text-14">
|
||||
<span className="flex w-full items-center bg-surface-2 text-14">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="lg"
|
||||
|
||||
@@ -146,7 +146,7 @@ export const RoleSetupStep = observer(function RoleSetupStep({ handleStepChange
|
||||
{/* Action Buttons */}
|
||||
<div className="space-y-3">
|
||||
<Button variant="primary" size="lg" stretch="full" label="Continue" type="submit" disabled={isButtonDisabled} />
|
||||
<span className="w-full text-tertiary">
|
||||
<span className="flex w-full [&_button]:text-tertiary">
|
||||
<Button variant="ghost" size="lg" stretch="full" label="Skip" onClick={handleSkip} />
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -353,19 +353,17 @@ export const ProjectCard = observer(function ProjectCard(props: Props) {
|
||||
))}
|
||||
{!isMemberOfProject && (
|
||||
<div className="flex items-center">
|
||||
<span className="!p-0 font-semibold">
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
stretch="auto"
|
||||
label="Join"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setJoinProjectModal(true);
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
stretch="auto"
|
||||
label="Join"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
setJoinProjectModal(true);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useTranslation } from "@plane/i18n";
|
||||
import { Button } from "@makeplane/propel/components/button";
|
||||
import type { IWebhook } from "@plane/types";
|
||||
// types
|
||||
import { WebhookSecretKey } from "./form";
|
||||
import { WebhookSecretKey } from "./form/secret-key";
|
||||
|
||||
type Props = {
|
||||
handleClose: () => void;
|
||||
|
||||
Reference in New Issue
Block a user