Skip to content

fix: corrected rendering of workspace-level labels, members, and states in project view #2966

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Dec 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions web/components/issues/issue-layouts/kanban/properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@ export const KanBanProperties: React.FC<IKanBanProperties> = observer((props) =>
<IssuePropertyState
projectId={issue?.project_detail?.id || null}
value={issue?.state || null}
defaultOptions={issue?.state_detail ? [issue.state_detail] : []}
onChange={handleState}
disabled={isReadOnly}
hideDropdownArrow
Expand All @@ -110,6 +111,7 @@ export const KanBanProperties: React.FC<IKanBanProperties> = observer((props) =>
<IssuePropertyLabels
projectId={issue?.project_detail?.id || null}
value={issue?.labels || null}
defaultOptions={issue?.label_details ? issue.label_details : []}
onChange={handleLabel}
disabled={isReadOnly}
hideDropdownArrow
Expand Down Expand Up @@ -141,6 +143,7 @@ export const KanBanProperties: React.FC<IKanBanProperties> = observer((props) =>
<IssuePropertyAssignee
projectId={issue?.project_detail?.id || null}
value={issue?.assignees || null}
defaultOptions={issue?.assignee_details ? issue.assignee_details : []}
hideDropdownArrow
onChange={handleAssignee}
disabled={isReadOnly}
Expand Down
3 changes: 3 additions & 0 deletions web/components/issues/issue-layouts/list/properties.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ export const ListProperties: FC<IListProperties> = observer((props) => {
<IssuePropertyState
projectId={issue?.project_detail?.id || null}
value={issue?.state || null}
defaultOptions={issue?.state_detail ? [issue.state_detail] : []}
hideDropdownArrow
onChange={handleState}
disabled={isReadonly}
Expand All @@ -81,6 +82,7 @@ export const ListProperties: FC<IListProperties> = observer((props) => {
<IssuePropertyLabels
projectId={issue?.project_detail?.id || null}
value={issue?.labels || null}
defaultOptions={issue?.label_details ? issue.label_details : []}
onChange={handleLabel}
disabled={isReadonly}
hideDropdownArrow
Expand All @@ -92,6 +94,7 @@ export const ListProperties: FC<IListProperties> = observer((props) => {
<IssuePropertyAssignee
projectId={issue?.project_detail?.id || null}
value={issue?.assignees || null}
defaultOptions={issue?.assignee_details ? issue.assignee_details : []}
hideDropdownArrow
onChange={handleAssignee}
disabled={isReadonly}
Expand Down
30 changes: 14 additions & 16 deletions web/components/issues/issue-layouts/properties/assignee.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@ import { Check, ChevronDown, Search, User2 } from "lucide-react";
import { Avatar, AvatarGroup, Tooltip } from "@plane/ui";
// types
import { Placement } from "@popperjs/core";
import { IProjectMember } from "types";

export interface IIssuePropertyAssignee {
projectId: string | null;
value: string[] | string;
defaultOptions?: any;
onChange: (data: string[]) => void;
disabled?: boolean;
hideDropdownArrow?: boolean;
Expand All @@ -27,6 +29,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
const {
projectId,
value,
defaultOptions = [],
onChange,
disabled = false,
hideDropdownArrow = false,
Expand All @@ -40,8 +43,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
// store
const {
workspace: workspaceStore,
project: projectStore,
workspaceMember: { workspaceMembers, fetchWorkspaceMembers },
projectMember: { projectMembers: _projectMembers, fetchProjectMembers },
} = useMobxStore();
const workspaceSlug = workspaceStore?.workspaceSlug;
// states
Expand All @@ -50,20 +52,16 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const [isLoading, setIsLoading] = useState<Boolean>(false);

// const fetchProjectMembers = () => {
// setIsLoading(true);
// if (workspaceSlug && projectId)
// workspaceSlug &&
// projectId &&
// projectStore.fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false));
// };

const getWorkspaceMembers = () => {
setIsLoading(true);
if (workspaceSlug) workspaceSlug && fetchWorkspaceMembers(workspaceSlug).then(() => setIsLoading(false));
if (workspaceSlug && projectId) fetchProjectMembers(workspaceSlug, projectId).then(() => setIsLoading(false));
};

const options = (workspaceMembers ?? [])?.map((member) => ({
const updatedDefaultOptions: IProjectMember[] =
defaultOptions.map((member: any) => ({ member: { ...member } })) ?? [];
const projectMembers = _projectMembers ?? updatedDefaultOptions;

const options = projectMembers?.map((member) => ({
value: member.member.id,
query: member.member.display_name,
content: (
Expand All @@ -82,7 +80,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(

// if multiple assignees
if (Array.isArray(value)) {
const assignees = workspaceMembers?.filter((m) => value.includes(m.member.id));
const assignees = projectMembers?.filter((m) => value.includes(m.member.id));

if (!assignees || assignees.length === 0) return "No Assignee";

Expand All @@ -93,7 +91,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
}

// if single assignee
const assignee = workspaceMembers?.find((m) => m.member.id === value)?.member;
const assignee = projectMembers?.find((m) => m.member.id === value)?.member;

if (!assignee) return "No Assignee";

Expand All @@ -107,7 +105,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
{value && value.length > 0 && Array.isArray(value) ? (
<AvatarGroup showTooltip={false}>
{value.map((assigneeId) => {
const member = workspaceMembers?.find((m) => m.member.id === assigneeId)?.member;
const member = projectMembers?.find((m) => m.member.id === assigneeId)?.member;
if (!member) return null;
return <Avatar key={member.id} name={member.display_name} src={member.avatar} />;
})}
Expand Down Expand Up @@ -149,7 +147,7 @@ export const IssuePropertyAssignee: React.FC<IIssuePropertyAssignee> = observer(
className={`flex items-center justify-between gap-1 w-full text-xs ${
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
onClick={() => !workspaceMembers && getWorkspaceMembers()}
onClick={() => !projectMembers && getWorkspaceMembers()}
>
{label}
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
Expand Down
22 changes: 15 additions & 7 deletions web/components/issues/issue-layouts/properties/labels.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@ import { Check, ChevronDown, Search } from "lucide-react";
// types
import { Placement } from "@popperjs/core";
import { RootStore } from "store/root";
import { IIssueLabel } from "types";

export interface IIssuePropertyLabels {
projectId: string | null;
value: string[];
defaultOptions?: any;
onChange: (data: string[]) => void;
disabled?: boolean;
hideDropdownArrow?: boolean;
Expand All @@ -29,6 +31,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
const {
projectId,
value,
defaultOptions = [],
onChange,
disabled,
hideDropdownArrow = false,
Expand All @@ -42,7 +45,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro

const {
workspace: workspaceStore,
projectLabel: { fetchProjectLabels, projectLabels },
projectLabel: { fetchProjectLabels, labels },
}: RootStore = useMobxStore();
const workspaceSlug = workspaceStore?.workspaceSlug;

Expand All @@ -59,7 +62,11 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro

if (!value) return null;

const options = (projectLabels ? projectLabels : []).map((label) => ({
let projectLabels: IIssueLabel[] = defaultOptions;
const storeLabels = projectId && labels ? labels[projectId] : [];
if (storeLabels && storeLabels.length > 0) projectLabels = storeLabels;

const options = projectLabels.map((label) => ({
value: label.id,
query: label.name,
content: (
Expand Down Expand Up @@ -95,7 +102,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
{value.length > 0 ? (
value.length <= maxRender ? (
<>
{(projectLabels ? projectLabels : [])
{projectLabels
?.filter((l) => value.includes(l.id))
.map((label) => (
<Tooltip position="top" tooltipHeading="Labels" tooltipContent={label.name ?? ""}>
Expand Down Expand Up @@ -123,7 +130,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
<Tooltip
position="top"
tooltipHeading="Labels"
tooltipContent={(projectLabels ? projectLabels : [])
tooltipContent={projectLabels
?.filter((l) => value.includes(l.id))
.map((l) => l.name)
.join(", ")}
Expand Down Expand Up @@ -167,7 +174,7 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
? "cursor-pointer"
: "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
onClick={() => !projectLabels && fetchLabels()}
onClick={() => !storeLabels && fetchLabels()}
>
{label}
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
Expand Down Expand Up @@ -200,8 +207,9 @@ export const IssuePropertyLabels: React.FC<IIssuePropertyLabels> = observer((pro
key={option.value}
value={option.value}
className={({ selected }) =>
`flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 hover:bg-custom-background-80
${selected ? "text-custom-text-100" : "text-custom-text-200"}`
`flex items-center justify-between gap-2 cursor-pointer select-none truncate rounded px-1 py-1.5 hover:bg-custom-background-80 ${
selected ? "text-custom-text-100" : "text-custom-text-200"
}`
}
>
{({ selected }) => (
Expand Down
11 changes: 6 additions & 5 deletions web/components/issues/issue-layouts/properties/state.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { RootStore } from "store/root";
export interface IIssuePropertyState {
projectId: string | null;
value: any | string | null;
defaultOptions?: any;
onChange: (state: IState) => void;
disabled?: boolean;
hideDropdownArrow?: boolean;
Expand All @@ -30,6 +31,7 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
const {
projectId,
value,
defaultOptions = [],
onChange,
disabled,
hideDropdownArrow = false,
Expand All @@ -47,10 +49,9 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
const [isLoading, setIsLoading] = useState<Boolean>(false);

const projectStates: IState[] = [];
const projectStatesByGroup = projectStateStore.groupedProjectStates;
if (projectStatesByGroup)
for (const group in projectStatesByGroup) projectStates.push(...projectStatesByGroup[group]);
let projectStates: IState[] = defaultOptions;
const storeStates = projectId ? projectStateStore.states[projectId] : [];
if (storeStates && storeStates.length > 0) projectStates = storeStates;

const fetchProjectStates = () => {
setIsLoading(true);
Expand Down Expand Up @@ -120,7 +121,7 @@ export const IssuePropertyState: React.FC<IIssuePropertyState> = observer((props
className={`flex items-center justify-between h-5 gap-1 w-full text-xs px-2.5 py-1 rounded border-[0.5px] border-custom-border-300 ${
disabled ? "cursor-not-allowed text-custom-text-200" : "cursor-pointer hover:bg-custom-background-80"
} ${buttonClassName}`}
onClick={() => !projectStatesByGroup && fetchProjectStates()}
onClick={() => !storeStates && fetchProjectStates()}
>
{label}
{!hideDropdownArrow && !disabled && <ChevronDown className="h-3 w-3" aria-hidden="true" />}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ export const SpreadsheetAssigneeColumn: React.FC<Props> = ({ issue, members, onC
<IssuePropertyAssignee
projectId={issue.project_detail?.id ?? null}
value={issue.assignees}
defaultOptions={issue?.assignee_details ? issue.assignee_details : []}
onChange={(data) => onChange({ assignees: data })}
className="h-full w-full"
buttonClassName="!shadow-none !border-0 h-full w-full px-2.5 py-1 "
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const SpreadsheetLabelColumn: React.FC<Props> = (props) => {
<IssuePropertyLabels
projectId={issue.project_detail?.id ?? null}
value={issue.labels}
defaultOptions={issue?.label_details ? issue.label_details : []}
onChange={(data) => onChange({ labels: data })}
className="h-full w-full"
buttonClassName="px-2.5 h-full"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const SpreadsheetStateColumn: React.FC<Props> = (props) => {
<IssuePropertyState
projectId={issue.project_detail?.id ?? null}
value={issue.state_detail.id}
defaultOptions={issue?.state_detail ? [issue.state_detail] : []}
onChange={(data) => onChange({ state: data.id, state_detail: data })}
className="h-full w-full"
buttonClassName="!shadow-none !border-0 h-full w-full"
Expand Down