[WEB-3514] improvement: workflow UI (#2713)

* improvement: workflow and reviewer icon padding and styles

* improvement: disable reviewer collapsible if no reviewers are available.
* minor UI improvements

* improvement: workflow tree message
This commit is contained in:
Prateek Shourya
2025-03-12 12:38:56 +05:30
committed by GitHub
parent 49e28ff9ff
commit a015fde11e
7 changed files with 34 additions and 22 deletions

View File

@@ -120,7 +120,9 @@ export const HeaderGroupByCard = observer((props: IHeaderGroupByCard) => {
>
<div className="inline-block line-clamp-1 truncate font-medium text-custom-text-100">{title}</div>
<div className="pl-2 text-sm font-medium text-custom-text-300">{count || 0}</div>
<WorkFlowGroupTree groupBy={groupBy} groupId={groupID} />
<div className="px-2.5">
<WorkFlowGroupTree groupBy={groupBy} groupId={groupID} />
</div>
</div>
{!disableIssueCreation &&

View File

@@ -20,7 +20,7 @@ export const StateItemContent = observer((props: StateItemContentProps) => {
return (
<div className="flex flex-col w-full gap-1.5 p-2">
<div className={cn("flex flex-col gap-3 px-3", transitionIds.length > 0 && "py-2")}>
<div className={cn("flex flex-col gap-4 px-3", transitionIds.length > 0 && "py-2")}>
{transitionIds.map((transitionId) => (
<StateTransitionItem
key={transitionId}

View File

@@ -28,8 +28,8 @@ export const StateTransitionApprovers = observer((props: Props) => {
return (
<>
<hr className="border-t-[1px] border-custom-border-200 border-dashed h-[1] w-full pb-2" />
<div className="flex flex-col pb-2 gap-1">
<hr className="border-t-[1px] border-custom-border-200 border-dashed h-[1] w-full pb-2 mt-1.5" />
<div className="flex flex-col pt-1 pb-2 gap-1">
<span className="flex items-center gap-1 text-xs text-custom-text-300 font-medium">
{t("workflows.workflow_states.state_changes.movers.label")}
<Tooltip tooltipContent={t("workflows.workflow_states.state_changes.movers.tooltip")} position="right">
@@ -38,7 +38,7 @@ export const StateTransitionApprovers = observer((props: Props) => {
</span>
</Tooltip>
</span>
<div className="flex p-3 rounded-md border border-custom-border-100 w-full gap-2 items-center">
<div className="flex p-3 my-1 rounded-md border border-custom-border-100 w-full gap-2 items-center">
<AppliedMembersFilters
editable
handleRemove={(value) =>

View File

@@ -38,6 +38,7 @@ export const StateTransitionItem = observer((props: StateTransitionItemProps) =>
} = useProjectState();
// derived state
const stateTransition = getTransitionById(parentStateId, transitionId);
const areApproversAvailable = stateTransition.approvers && stateTransition.approvers.length > 0;
if (!stateTransition) return <></>;
@@ -47,6 +48,11 @@ export const StateTransitionItem = observer((props: StateTransitionItemProps) =>
stateTransition.transition_state_id
);
const handleToggle = () => {
if (!areApproversAvailable) return;
setIsOpen((prevState) => !prevState);
};
const handleTransitionStateChange = async (val: string) => {
try {
await changeStateTransition(workspaceSlug, projectId, parentStateId, transitionId, val);
@@ -101,9 +107,11 @@ export const StateTransitionItem = observer((props: StateTransitionItemProps) =>
/>
<Collapsible
isOpen={isOpen}
onToggle={() => setIsOpen((prevState) => !prevState)}
onToggle={handleToggle}
className="w-full"
buttonClassName="flex w-full items-center justify-between"
buttonClassName={cn("flex w-full items-center justify-between", {
"cursor-not-allowed": !areApproversAvailable,
})}
title={
<div className="flex w-full items-center">
<div className="flex w-full items-center justify-start gap-1 py-1">
@@ -126,7 +134,7 @@ export const StateTransitionItem = observer((props: StateTransitionItemProps) =>
dropdownArrow
/>
</div>
{stateTransition.approvers && stateTransition.approvers.length > 0 && (
{areApproversAvailable && (
<div className="flex gap-1 text-custom-text-400 items-center">
<ApproverIcon strokeWidth={2} className="flex-shrink-0 size-3.5 text-custom-text-300" />
<span className="text-xs font-medium">
@@ -167,7 +175,8 @@ export const StateTransitionItem = observer((props: StateTransitionItemProps) =>
<ChevronDown
strokeWidth={2}
className={cn("transition-all size-4 text-custom-text-400 hover:text-custom-text-300", {
"rotate-180 text-custom-text-200": isOpen,
"rotate-180 text-custom-text-200": isOpen && areApproversAvailable,
"text-custom-text-400 hover:text-custom-text-400": !areApproversAvailable,
})}
/>
</div>
@@ -176,11 +185,13 @@ export const StateTransitionItem = observer((props: StateTransitionItemProps) =>
</div>
}
>
<StateTransitionApprovers
parentStateId={parentStateId}
stateTransition={stateTransition}
handleApproversUpdate={handleApproversUpdate}
/>
{areApproversAvailable && (
<StateTransitionApprovers
parentStateId={parentStateId}
stateTransition={stateTransition}
handleApproversUpdate={handleApproversUpdate}
/>
)}
</Collapsible>
</div>
);

View File

@@ -29,7 +29,7 @@ export const WorkFlowEnabledMessage = observer((props: Props) => {
<span className="text-xs font-medium">{t("workflows.workflow_enabled.label")}</span>
</div>
<div className="pl-4">
<WorkflowTree parentStateId={parentStateId} showCurrentUserName={false} />
<WorkflowTree parentStateId={parentStateId} />
</div>
</div>
);

View File

@@ -45,14 +45,14 @@ export const WorkFlowGroupTree = observer((props: Props) => {
"flex h-[20px] w-[20px] flex-shrink-0 items-center justify-center overflow-hidden rounded transition-all",
{
"bg-[#00A0CC]/15": isTransitionEnabledForUser,
"hover:bg-custom-background-80": !isTransitionEnabledForUser,
"bg-custom-background-80 hover:bg-custom-background-80": !isTransitionEnabledForUser,
}
)}
>
{isTransitionEnabledForUser ? (
<ApproverIcon width={14} strokeWidth={2} className="text-[#00A0CC]" />
) : (
<WorkflowIcon width={14} strokeWidth={2} />
<WorkflowIcon width={14} strokeWidth={2} className="text-custom-text-200" />
)}
</div>
</Tooltip>

View File

@@ -9,11 +9,10 @@ import { StatePill } from "./state-pill";
type Props = {
parentStateId: string;
showCurrentUserName?: boolean;
};
export const WorkflowTree = observer((props: Props) => {
const { parentStateId, showCurrentUserName = true } = props;
const { parentStateId } = props;
// plane hooks
const { t } = useTranslation();
// store hooks
@@ -24,7 +23,7 @@ export const WorkflowTree = observer((props: Props) => {
const currentStateTransitionMap = stateTransitionMap[parentStateId];
const getUserName = (moverId: string) => {
if (!showCurrentUserName && moverId === user?.id) return t("common.you");
if (moverId === user?.id) return t("common.you");
return getUserDetails(moverId)?.display_name;
};
@@ -46,15 +45,15 @@ export const WorkflowTree = observer((props: Props) => {
return 0;
});
// Order approvers such that current user is first, followed by other approvers
// Order approvers such that current user is last
const getOrderedApprovers = useCallback(
(approvers: string[]) => {
const currentUserIndex = approvers.indexOf(user?.id ?? "");
if (currentUserIndex !== -1) {
return [
approvers[currentUserIndex],
...approvers.slice(0, currentUserIndex),
...approvers.slice(currentUserIndex + 1),
approvers[currentUserIndex],
];
}
return approvers;