mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: bug fixes and ui/ux enhancements (#2036)
This commit is contained in:
parent
8a95a41100
commit
74bf9062b4
@ -22,8 +22,6 @@ const shortcuts = [
|
|||||||
{ keys: "↓", description: "Move down" },
|
{ keys: "↓", description: "Move down" },
|
||||||
{ keys: "←", description: "Move left" },
|
{ keys: "←", description: "Move left" },
|
||||||
{ keys: "→", description: "Move right" },
|
{ keys: "→", description: "Move right" },
|
||||||
{ keys: "Enter", description: "Select" },
|
|
||||||
{ keys: "Esc", description: "Close" },
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -353,6 +353,28 @@ const activityDetails: {
|
|||||||
.
|
.
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
else if (activity.verb === "updated")
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
updated the{" "}
|
||||||
|
<a
|
||||||
|
href={`${activity.old_value}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="font-medium text-custom-text-100 inline-flex items-center gap-1 hover:underline"
|
||||||
|
>
|
||||||
|
link
|
||||||
|
<Icon iconName="launch" className="!text-xs" />
|
||||||
|
</a>
|
||||||
|
{showIssue && (
|
||||||
|
<>
|
||||||
|
{" "}
|
||||||
|
from <IssueLink activity={activity} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
.
|
||||||
|
</>
|
||||||
|
);
|
||||||
else
|
else
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
@ -158,7 +158,7 @@ export const IssuesFilterView: React.FC = () => {
|
|||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
View
|
Display
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
|
|
||||||
|
@ -40,9 +40,15 @@ type Props = {
|
|||||||
label: string | React.ReactNode;
|
label: string | React.ReactNode;
|
||||||
value: string | null;
|
value: string | null;
|
||||||
onChange: (data: string) => void;
|
onChange: (data: string) => void;
|
||||||
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ImagePickerPopover: React.FC<Props> = ({ label, value, onChange }) => {
|
export const ImagePickerPopover: React.FC<Props> = ({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
disabled = false,
|
||||||
|
}) => {
|
||||||
const ref = useRef<HTMLDivElement>(null);
|
const ref = useRef<HTMLDivElement>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -117,6 +123,7 @@ export const ImagePickerPopover: React.FC<Props> = ({ label, value, onChange })
|
|||||||
<Popover.Button
|
<Popover.Button
|
||||||
className="rounded-md border border-custom-border-300 bg-custom-background-100 px-2 py-1 text-xs text-custom-text-200 hover:text-custom-text-100"
|
className="rounded-md border border-custom-border-300 bg-custom-background-100 px-2 py-1 text-xs text-custom-text-200 hover:text-custom-text-100"
|
||||||
onClick={() => setIsOpen((prev) => !prev)}
|
onClick={() => setIsOpen((prev) => !prev)}
|
||||||
|
disabled={disabled}
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
|
@ -29,6 +29,7 @@ type Props = {
|
|||||||
isCollapsed: boolean;
|
isCollapsed: boolean;
|
||||||
setIsCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
|
setIsCollapsed: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
disableUserActions: boolean;
|
disableUserActions: boolean;
|
||||||
|
disableAddIssue: boolean;
|
||||||
viewProps: IIssueViewProps;
|
viewProps: IIssueViewProps;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -39,6 +40,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
isCollapsed,
|
isCollapsed,
|
||||||
setIsCollapsed,
|
setIsCollapsed,
|
||||||
disableUserActions,
|
disableUserActions,
|
||||||
|
disableAddIssue,
|
||||||
viewProps,
|
viewProps,
|
||||||
}) => {
|
}) => {
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
@ -181,7 +183,7 @@ export const BoardHeader: React.FC<Props> = ({
|
|||||||
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" />
|
<Icon iconName="open_in_full" className="text-base font-medium text-custom-text-900" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
{!disableUserActions && selectedGroup !== "created_by" && (
|
{!disableAddIssue && !disableUserActions && selectedGroup !== "created_by" && (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="grid h-7 w-7 place-items-center rounded p-1 text-custom-text-200 outline-none duration-300 hover:bg-custom-background-80"
|
className="grid h-7 w-7 place-items-center rounded p-1 text-custom-text-200 outline-none duration-300 hover:bg-custom-background-80"
|
||||||
|
@ -53,6 +53,8 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { cycleId, moduleId } = router.query;
|
const { cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
|
const isSubscribedIssues = router.pathname.includes("subscribed");
|
||||||
|
|
||||||
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
||||||
|
|
||||||
// Check if it has at least 4 tickets since it is enough to accommodate the Calendar height
|
// Check if it has at least 4 tickets since it is enough to accommodate the Calendar height
|
||||||
@ -70,6 +72,7 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
isCollapsed={isCollapsed}
|
isCollapsed={isCollapsed}
|
||||||
setIsCollapsed={setIsCollapsed}
|
setIsCollapsed={setIsCollapsed}
|
||||||
disableUserActions={disableUserActions}
|
disableUserActions={disableUserActions}
|
||||||
|
disableAddIssue={isSubscribedIssues}
|
||||||
viewProps={viewProps}
|
viewProps={viewProps}
|
||||||
/>
|
/>
|
||||||
{isCollapsed && (
|
{isCollapsed && (
|
||||||
@ -150,41 +153,41 @@ export const SingleBoard: React.FC<Props> = ({
|
|||||||
</div>
|
</div>
|
||||||
{selectedGroup !== "created_by" && (
|
{selectedGroup !== "created_by" && (
|
||||||
<div>
|
<div>
|
||||||
{type === "issue" ? (
|
{type === "issue"
|
||||||
<button
|
? !isSubscribedIssues && (
|
||||||
type="button"
|
<button
|
||||||
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
|
type="button"
|
||||||
onClick={addIssueToGroup}
|
className="flex items-center gap-2 font-medium text-custom-primary outline-none p-1"
|
||||||
>
|
onClick={addIssueToGroup}
|
||||||
<PlusIcon className="h-4 w-4" />
|
>
|
||||||
Add Issue
|
<PlusIcon className="h-4 w-4" />
|
||||||
</button>
|
Add Issue
|
||||||
) : (
|
</button>
|
||||||
!disableUserActions && (
|
)
|
||||||
<CustomMenu
|
: !disableUserActions && (
|
||||||
customButton={
|
<CustomMenu
|
||||||
<button
|
customButton={
|
||||||
type="button"
|
<button
|
||||||
className="flex items-center gap-2 font-medium text-custom-primary outline-none whitespace-nowrap"
|
type="button"
|
||||||
>
|
className="flex items-center gap-2 font-medium text-custom-primary outline-none whitespace-nowrap"
|
||||||
<PlusIcon className="h-4 w-4" />
|
>
|
||||||
Add Issue
|
<PlusIcon className="h-4 w-4" />
|
||||||
</button>
|
Add Issue
|
||||||
}
|
</button>
|
||||||
position="left"
|
}
|
||||||
noBorder
|
position="left"
|
||||||
>
|
noBorder
|
||||||
<CustomMenu.MenuItem onClick={addIssueToGroup}>
|
>
|
||||||
Create new
|
<CustomMenu.MenuItem onClick={addIssueToGroup}>
|
||||||
</CustomMenu.MenuItem>
|
Create new
|
||||||
{openIssuesListModal && (
|
|
||||||
<CustomMenu.MenuItem onClick={openIssuesListModal}>
|
|
||||||
Add an existing issue
|
|
||||||
</CustomMenu.MenuItem>
|
</CustomMenu.MenuItem>
|
||||||
)}
|
{openIssuesListModal && (
|
||||||
</CustomMenu>
|
<CustomMenu.MenuItem onClick={openIssuesListModal}>
|
||||||
)
|
Add an existing issue
|
||||||
)}
|
</CustomMenu.MenuItem>
|
||||||
|
)}
|
||||||
|
</CustomMenu>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
@ -350,7 +350,7 @@ export const SingleBoardIssue: React.FC<Props> = ({
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{properties.labels && issue.labels.length > 0 && (
|
{properties.labels && issue.labels.length > 0 && (
|
||||||
<ViewIssueLabel issue={issue} maxRender={2} />
|
<ViewIssueLabel labelDetails={issue.label_details} maxRender={2} />
|
||||||
)}
|
)}
|
||||||
{properties.assignee && (
|
{properties.assignee && (
|
||||||
<ViewAssigneeSelect
|
<ViewAssigneeSelect
|
||||||
|
@ -36,9 +36,21 @@ import { LayerDiagonalIcon } from "components/icons";
|
|||||||
import { copyTextToClipboard } from "helpers/string.helper";
|
import { copyTextToClipboard } from "helpers/string.helper";
|
||||||
import { handleIssuesMutation } from "constants/issue";
|
import { handleIssuesMutation } from "constants/issue";
|
||||||
// types
|
// types
|
||||||
import { ICurrentUserResponse, IIssue, IIssueViewProps, ISubIssueResponse, UserAuth } from "types";
|
import {
|
||||||
|
ICurrentUserResponse,
|
||||||
|
IIssue,
|
||||||
|
IIssueViewProps,
|
||||||
|
ISubIssueResponse,
|
||||||
|
IUserProfileProjectSegregation,
|
||||||
|
UserAuth,
|
||||||
|
} from "types";
|
||||||
// fetch-keys
|
// fetch-keys
|
||||||
import { CYCLE_DETAILS, MODULE_DETAILS, SUB_ISSUES } from "constants/fetch-keys";
|
import {
|
||||||
|
CYCLE_DETAILS,
|
||||||
|
MODULE_DETAILS,
|
||||||
|
SUB_ISSUES,
|
||||||
|
USER_PROFILE_PROJECT_SEGREGATION,
|
||||||
|
} from "constants/fetch-keys";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
type?: string;
|
type?: string;
|
||||||
@ -74,7 +86,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
const [contextMenuPosition, setContextMenuPosition] = useState<React.MouseEvent | null>(null);
|
const [contextMenuPosition, setContextMenuPosition] = useState<React.MouseEvent | null>(null);
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId, userId } = router.query;
|
||||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
const isArchivedIssues = router.pathname.includes("archived-issues");
|
||||||
|
|
||||||
const { setToastAlert } = useToast();
|
const { setToastAlert } = useToast();
|
||||||
@ -126,6 +138,11 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
.then(() => {
|
.then(() => {
|
||||||
mutateIssues();
|
mutateIssues();
|
||||||
|
|
||||||
|
if (userId)
|
||||||
|
mutate<IUserProfileProjectSegregation>(
|
||||||
|
USER_PROFILE_PROJECT_SEGREGATION(workspaceSlug.toString(), userId.toString())
|
||||||
|
);
|
||||||
|
|
||||||
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
|
if (cycleId) mutate(CYCLE_DETAILS(cycleId as string));
|
||||||
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
|
if (moduleId) mutate(MODULE_DETAILS(moduleId as string));
|
||||||
});
|
});
|
||||||
@ -134,6 +151,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
workspaceSlug,
|
workspaceSlug,
|
||||||
cycleId,
|
cycleId,
|
||||||
moduleId,
|
moduleId,
|
||||||
|
userId,
|
||||||
groupTitle,
|
groupTitle,
|
||||||
index,
|
index,
|
||||||
selectedGroup,
|
selectedGroup,
|
||||||
@ -261,7 +279,7 @@ export const SingleListIssue: React.FC<Props> = ({
|
|||||||
isNotAllowed={isNotAllowed}
|
isNotAllowed={isNotAllowed}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{properties.labels && <ViewIssueLabel issue={issue} maxRender={3} />}
|
{properties.labels && <ViewIssueLabel labelDetails={issue.label_details} maxRender={3} />}
|
||||||
{properties.assignee && (
|
{properties.assignee && (
|
||||||
<ViewAssigneeSelect
|
<ViewAssigneeSelect
|
||||||
issue={issue}
|
issue={issue}
|
||||||
|
@ -60,6 +60,7 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
const { workspaceSlug, projectId, cycleId, moduleId } = router.query;
|
||||||
|
|
||||||
const isArchivedIssues = router.pathname.includes("archived-issues");
|
const isArchivedIssues = router.pathname.includes("archived-issues");
|
||||||
|
const isSubscribedIssues = router.pathname.includes("subscribed");
|
||||||
|
|
||||||
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
const type = cycleId ? "cycle" : moduleId ? "module" : "issue";
|
||||||
|
|
||||||
@ -180,13 +181,15 @@ export const SingleList: React.FC<Props> = ({
|
|||||||
{isArchivedIssues ? (
|
{isArchivedIssues ? (
|
||||||
""
|
""
|
||||||
) : type === "issue" ? (
|
) : type === "issue" ? (
|
||||||
<button
|
!isSubscribedIssues && (
|
||||||
type="button"
|
<button
|
||||||
className="p-1 text-custom-text-200 hover:bg-custom-background-80"
|
type="button"
|
||||||
onClick={addIssueToGroup}
|
className="p-1 text-custom-text-200 hover:bg-custom-background-80"
|
||||||
>
|
onClick={addIssueToGroup}
|
||||||
<PlusIcon className="h-4 w-4" />
|
>
|
||||||
</button>
|
<PlusIcon className="h-4 w-4" />
|
||||||
|
</button>
|
||||||
|
)
|
||||||
) : disableUserActions ? (
|
) : disableUserActions ? (
|
||||||
""
|
""
|
||||||
) : (
|
) : (
|
||||||
|
@ -323,7 +323,7 @@ export const SingleSpreadsheetIssue: React.FC<Props> = ({
|
|||||||
)}
|
)}
|
||||||
{properties.labels && (
|
{properties.labels && (
|
||||||
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-200">
|
<div className="flex items-center text-xs text-custom-text-200 text-center p-2 group-hover:bg-custom-background-80 border-custom-border-200">
|
||||||
<ViewIssueLabel issue={issue} maxRender={1} />
|
<ViewIssueLabel labelDetails={issue.label_details} maxRender={1} />
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
|
@ -31,6 +31,8 @@ import {
|
|||||||
CompletedStateIcon,
|
CompletedStateIcon,
|
||||||
} from "components/icons";
|
} from "components/icons";
|
||||||
import { StarIcon } from "@heroicons/react/24/outline";
|
import { StarIcon } from "@heroicons/react/24/outline";
|
||||||
|
// components
|
||||||
|
import { ViewIssueLabel } from "components/issues";
|
||||||
// helpers
|
// helpers
|
||||||
import {
|
import {
|
||||||
getDateRangeStatus,
|
getDateRangeStatus,
|
||||||
@ -441,7 +443,10 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
issues.map((issue) => (
|
issues.map((issue) => (
|
||||||
<div
|
<div
|
||||||
key={issue.id}
|
key={issue.id}
|
||||||
className="flex flex-wrap rounded-md items-center justify-between gap-2 border border-custom-border-200 bg-custom-background-90 px-3 py-1.5"
|
onClick={() =>
|
||||||
|
router.push(`/${workspaceSlug}/projects/${projectId}/issues/${issue.id}`)
|
||||||
|
}
|
||||||
|
className="flex flex-wrap cursor-pointer rounded-md items-center justify-between gap-2 border border-custom-border-200 bg-custom-background-90 px-3 py-1.5"
|
||||||
>
|
>
|
||||||
<div className="flex flex-col gap-1">
|
<div className="flex flex-col gap-1">
|
||||||
<div>
|
<div>
|
||||||
@ -474,27 +479,7 @@ export const ActiveCycleDetails: React.FC = () => {
|
|||||||
>
|
>
|
||||||
{getPriorityIcon(issue.priority, "text-sm")}
|
{getPriorityIcon(issue.priority, "text-sm")}
|
||||||
</div>
|
</div>
|
||||||
{issue.label_details.length > 0 ? (
|
<ViewIssueLabel labelDetails={issue.label_details} maxRender={2} />
|
||||||
<div className="flex flex-wrap gap-1">
|
|
||||||
{issue.label_details.map((label) => (
|
|
||||||
<span
|
|
||||||
key={label.id}
|
|
||||||
className="group flex items-center gap-1 rounded-2xl border border-custom-border-200 px-2 py-0.5 text-xs text-custom-text-200"
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
className="h-1.5 w-1.5 rounded-full"
|
|
||||||
style={{
|
|
||||||
backgroundColor:
|
|
||||||
label?.color && label.color !== "" ? label.color : "#000",
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
{label.name}
|
|
||||||
</span>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
<div className={`flex items-center gap-2 text-custom-text-200`}>
|
<div className={`flex items-center gap-2 text-custom-text-200`}>
|
||||||
{issue.assignees &&
|
{issue.assignees &&
|
||||||
issue.assignees.length > 0 &&
|
issue.assignees.length > 0 &&
|
||||||
|
@ -23,7 +23,13 @@ const tabOptions = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorChange }) => {
|
const EmojiIconPicker: React.FC<Props> = ({
|
||||||
|
label,
|
||||||
|
value,
|
||||||
|
onChange,
|
||||||
|
onIconColorChange,
|
||||||
|
disabled = false,
|
||||||
|
}) => {
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
const [isOpen, setIsOpen] = useState(false);
|
||||||
const [openColorPicker, setOpenColorPicker] = useState(false);
|
const [openColorPicker, setOpenColorPicker] = useState(false);
|
||||||
const [activeColor, setActiveColor] = useState<string>("rgb(var(--color-text-200))");
|
const [activeColor, setActiveColor] = useState<string>("rgb(var(--color-text-200))");
|
||||||
@ -40,7 +46,11 @@ const EmojiIconPicker: React.FC<Props> = ({ label, value, onChange, onIconColorC
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Popover className="relative z-[1]">
|
<Popover className="relative z-[1]">
|
||||||
<Popover.Button onClick={() => setIsOpen((prev) => !prev)} className="outline-none">
|
<Popover.Button
|
||||||
|
onClick={() => setIsOpen((prev) => !prev)}
|
||||||
|
className="outline-none"
|
||||||
|
disabled={disabled}
|
||||||
|
>
|
||||||
{label}
|
{label}
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
<Transition
|
<Transition
|
||||||
|
@ -10,4 +10,5 @@ export type Props = {
|
|||||||
}
|
}
|
||||||
) => void;
|
) => void;
|
||||||
onIconColorChange?: (data: any) => void;
|
onIconColorChange?: (data: any) => void;
|
||||||
|
disabled?: boolean;
|
||||||
};
|
};
|
||||||
|
@ -33,16 +33,16 @@ type Props = {
|
|||||||
isOpen: boolean;
|
isOpen: boolean;
|
||||||
handleClose: () => void;
|
handleClose: () => void;
|
||||||
data: IIssue | null;
|
data: IIssue | null;
|
||||||
onSubmit?: () => Promise<void>;
|
|
||||||
user: ICurrentUserResponse | undefined;
|
user: ICurrentUserResponse | undefined;
|
||||||
|
onSubmit?: () => Promise<void>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const DeleteIssueModal: React.FC<Props> = ({
|
export const DeleteIssueModal: React.FC<Props> = ({
|
||||||
isOpen,
|
isOpen,
|
||||||
handleClose,
|
handleClose,
|
||||||
data,
|
data,
|
||||||
onSubmit,
|
|
||||||
user,
|
user,
|
||||||
|
onSubmit,
|
||||||
}) => {
|
}) => {
|
||||||
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
const [isDeleteLoading, setIsDeleteLoading] = useState(false);
|
||||||
|
|
||||||
@ -138,6 +138,7 @@ export const DeleteIssueModal: React.FC<Props> = ({
|
|||||||
console.log(error);
|
console.log(error);
|
||||||
setIsDeleteLoading(false);
|
setIsDeleteLoading(false);
|
||||||
});
|
});
|
||||||
|
if (onSubmit) await onSubmit();
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleArchivedIssueDeletion = async () => {
|
const handleArchivedIssueDeletion = async () => {
|
||||||
|
@ -6,16 +6,16 @@ import { Tooltip } from "components/ui";
|
|||||||
import { IIssue } from "types";
|
import { IIssue } from "types";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
issue: IIssue;
|
labelDetails: any[];
|
||||||
maxRender?: number;
|
maxRender?: number;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ViewIssueLabel: React.FC<Props> = ({ issue, maxRender = 1 }) => (
|
export const ViewIssueLabel: React.FC<Props> = ({ labelDetails, maxRender = 1 }) => (
|
||||||
<>
|
<>
|
||||||
{issue.label_details.length > 0 ? (
|
{labelDetails.length > 0 ? (
|
||||||
issue.label_details.length <= maxRender ? (
|
labelDetails.length <= maxRender ? (
|
||||||
<>
|
<>
|
||||||
{issue.label_details.map((label, index) => (
|
{labelDetails.map((label) => (
|
||||||
<div
|
<div
|
||||||
key={label.id}
|
key={label.id}
|
||||||
className="flex cursor-default items-center flex-shrink-0 rounded-md border border-custom-border-300 px-2.5 py-1 text-xs shadow-sm"
|
className="flex cursor-default items-center flex-shrink-0 rounded-md border border-custom-border-300 px-2.5 py-1 text-xs shadow-sm"
|
||||||
@ -39,11 +39,11 @@ export const ViewIssueLabel: React.FC<Props> = ({ issue, maxRender = 1 }) => (
|
|||||||
<Tooltip
|
<Tooltip
|
||||||
position="top"
|
position="top"
|
||||||
tooltipHeading="Labels"
|
tooltipHeading="Labels"
|
||||||
tooltipContent={issue.label_details.map((l) => l.name).join(", ")}
|
tooltipContent={labelDetails.map((l) => l.name).join(", ")}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-1.5 text-custom-text-200">
|
<div className="flex items-center gap-1.5 text-custom-text-200">
|
||||||
<span className="h-2 w-2 flex-shrink-0 rounded-full bg-custom-primary" />
|
<span className="h-2 w-2 flex-shrink-0 rounded-full bg-custom-primary" />
|
||||||
{`${issue.label_details.length} Labels`}
|
{`${labelDetails.length} Labels`}
|
||||||
</div>
|
</div>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
@ -93,7 +93,7 @@ export const CreateUpdateIssueModal: React.FC<IssuesModalProps> = ({
|
|||||||
|
|
||||||
if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string };
|
if (cycleId) prePopulateData = { ...prePopulateData, cycle: cycleId as string };
|
||||||
if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string };
|
if (moduleId) prePopulateData = { ...prePopulateData, module: moduleId as string };
|
||||||
if (router.asPath.includes("my-issues"))
|
if (router.asPath.includes("my-issues") || router.asPath.includes("assigned"))
|
||||||
prePopulateData = {
|
prePopulateData = {
|
||||||
...prePopulateData,
|
...prePopulateData,
|
||||||
assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""],
|
assignees: [...(prePopulateData?.assignees ?? []), user?.id ?? ""],
|
||||||
|
@ -123,7 +123,7 @@ export const MyIssuesViewOptions: React.FC = () => {
|
|||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
View
|
Display
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
|
|
||||||
|
@ -234,6 +234,9 @@ export const MyIssuesView: React.FC<Props> = ({
|
|||||||
isOpen={deleteIssueModal}
|
isOpen={deleteIssueModal}
|
||||||
data={issueToDelete}
|
data={issueToDelete}
|
||||||
user={user}
|
user={user}
|
||||||
|
onSubmit={async () => {
|
||||||
|
mutateMyIssues();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{areFiltersApplied && (
|
{areFiltersApplied && (
|
||||||
<>
|
<>
|
||||||
|
@ -149,7 +149,7 @@ export const ProfileIssuesViewOptions: React.FC = () => {
|
|||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
View
|
Display
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
|
|
||||||
|
@ -248,6 +248,9 @@ export const ProfileIssuesView = () => {
|
|||||||
isOpen={deleteIssueModal}
|
isOpen={deleteIssueModal}
|
||||||
data={issueToDelete}
|
data={issueToDelete}
|
||||||
user={user}
|
user={user}
|
||||||
|
onSubmit={async () => {
|
||||||
|
mutateProfileIssues();
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
{areFiltersApplied && (
|
{areFiltersApplied && (
|
||||||
<>
|
<>
|
||||||
|
@ -6,78 +6,88 @@ import { Loader, Tooltip } from "components/ui";
|
|||||||
import { InformationCircleIcon } from "@heroicons/react/24/outline";
|
import { InformationCircleIcon } from "@heroicons/react/24/outline";
|
||||||
// types
|
// types
|
||||||
import { IUserWorkspaceDashboard } from "types";
|
import { IUserWorkspaceDashboard } from "types";
|
||||||
|
import { useRouter } from "next/router";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
data: IUserWorkspaceDashboard | undefined;
|
data: IUserWorkspaceDashboard | undefined;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const IssuesStats: React.FC<Props> = ({ data }) => (
|
export const IssuesStats: React.FC<Props> = ({ data }) => {
|
||||||
<div className="grid grid-cols-1 rounded-[10px] border border-custom-border-200 bg-custom-background-100 lg:grid-cols-3">
|
const router = useRouter();
|
||||||
<div className="grid grid-cols-1 divide-y divide-custom-border-200 border-b border-custom-border-200 lg:border-r lg:border-b-0">
|
const { workspaceSlug } = router.query;
|
||||||
<div className="flex">
|
return (
|
||||||
<div className="basis-1/2 p-4">
|
<div className="grid grid-cols-1 rounded-[10px] border border-custom-border-200 bg-custom-background-100 lg:grid-cols-3">
|
||||||
<h4 className="text-sm">Issues assigned to you</h4>
|
<div className="grid grid-cols-1 divide-y divide-custom-border-200 border-b border-custom-border-200 lg:border-r lg:border-b-0">
|
||||||
<h5 className="mt-2 text-2xl font-semibold">
|
<div className="flex">
|
||||||
{data ? (
|
<div className="basis-1/2 p-4">
|
||||||
data.assigned_issues_count
|
<h4 className="text-sm">Issues assigned to you</h4>
|
||||||
) : (
|
<h5 className="mt-2 text-2xl font-semibold">
|
||||||
<Loader>
|
{data ? (
|
||||||
<Loader.Item height="25px" width="50%" />
|
<div
|
||||||
</Loader>
|
className="cursor-pointer"
|
||||||
)}
|
onClick={() => router.push(`/${workspaceSlug}/me/my-issues`)}
|
||||||
</h5>
|
>
|
||||||
|
{data.assigned_issues_count}
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Loader>
|
||||||
|
<Loader.Item height="25px" width="50%" />
|
||||||
|
</Loader>
|
||||||
|
)}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div className="basis-1/2 border-l border-custom-border-200 p-4">
|
||||||
|
<h4 className="text-sm">Pending issues</h4>
|
||||||
|
<h5 className="mt-2 text-2xl font-semibold">
|
||||||
|
{data ? (
|
||||||
|
data.pending_issues_count
|
||||||
|
) : (
|
||||||
|
<Loader>
|
||||||
|
<Loader.Item height="25px" width="50%" />
|
||||||
|
</Loader>
|
||||||
|
)}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="basis-1/2 border-l border-custom-border-200 p-4">
|
<div className="flex">
|
||||||
<h4 className="text-sm">Pending issues</h4>
|
<div className="basis-1/2 p-4">
|
||||||
<h5 className="mt-2 text-2xl font-semibold">
|
<h4 className="text-sm">Completed issues</h4>
|
||||||
{data ? (
|
<h5 className="mt-2 text-2xl font-semibold">
|
||||||
data.pending_issues_count
|
{data ? (
|
||||||
) : (
|
data.completed_issues_count
|
||||||
<Loader>
|
) : (
|
||||||
<Loader.Item height="25px" width="50%" />
|
<Loader>
|
||||||
</Loader>
|
<Loader.Item height="25px" width="50%" />
|
||||||
)}
|
</Loader>
|
||||||
</h5>
|
)}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
|
<div className="basis-1/2 border-l border-custom-border-200 p-4">
|
||||||
|
<h4 className="text-sm">Issues due by this week</h4>
|
||||||
|
<h5 className="mt-2 text-2xl font-semibold">
|
||||||
|
{data ? (
|
||||||
|
data.issues_due_week_count
|
||||||
|
) : (
|
||||||
|
<Loader>
|
||||||
|
<Loader.Item height="25px" width="50%" />
|
||||||
|
</Loader>
|
||||||
|
)}
|
||||||
|
</h5>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex">
|
<div className="p-4 lg:col-span-2">
|
||||||
<div className="basis-1/2 p-4">
|
<h3 className="mb-2 font-semibold capitalize flex items-center gap-2">
|
||||||
<h4 className="text-sm">Completed issues</h4>
|
Activity Graph
|
||||||
<h5 className="mt-2 text-2xl font-semibold">
|
<Tooltip
|
||||||
{data ? (
|
tooltipContent="Your profile activity graph is a record of actions you've performed on issues across the workspace."
|
||||||
data.completed_issues_count
|
className="w-72 border border-custom-border-200"
|
||||||
) : (
|
>
|
||||||
<Loader>
|
<InformationCircleIcon className="h-3 w-3" />
|
||||||
<Loader.Item height="25px" width="50%" />
|
</Tooltip>
|
||||||
</Loader>
|
</h3>
|
||||||
)}
|
<ActivityGraph activities={data?.issue_activities} />
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
<div className="basis-1/2 border-l border-custom-border-200 p-4">
|
|
||||||
<h4 className="text-sm">Issues due by this week</h4>
|
|
||||||
<h5 className="mt-2 text-2xl font-semibold">
|
|
||||||
{data ? (
|
|
||||||
data.issues_due_week_count
|
|
||||||
) : (
|
|
||||||
<Loader>
|
|
||||||
<Loader.Item height="25px" width="50%" />
|
|
||||||
</Loader>
|
|
||||||
)}
|
|
||||||
</h5>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="p-4 lg:col-span-2">
|
);
|
||||||
<h3 className="mb-2 font-semibold capitalize flex items-center gap-2">
|
};
|
||||||
Activity Graph
|
|
||||||
<Tooltip
|
|
||||||
tooltipContent="Your profile activity graph is a record of actions you've performed on issues across the workspace."
|
|
||||||
className="w-72 border border-custom-border-200"
|
|
||||||
>
|
|
||||||
<InformationCircleIcon className="h-3 w-3" />
|
|
||||||
</Tooltip>
|
|
||||||
</h3>
|
|
||||||
<ActivityGraph activities={data?.issue_activities} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
|
@ -476,7 +476,7 @@ const SinglePage: NextPage = () => {
|
|||||||
: "text-custom-sidebar-text-200"
|
: "text-custom-sidebar-text-200"
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
View
|
Display
|
||||||
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
<ChevronDownIcon className="h-3 w-3" aria-hidden="true" />
|
||||||
</Popover.Button>
|
</Popover.Button>
|
||||||
|
|
||||||
|
@ -187,7 +187,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
/>
|
/>
|
||||||
<form onSubmit={handleSubmit(onSubmit)} className="p-8">
|
<form onSubmit={handleSubmit(onSubmit)} className="p-8">
|
||||||
<SettingsHeader />
|
<SettingsHeader />
|
||||||
<div className="space-y-8 sm:space-y-12">
|
<div className="space-y-8 sm:space-y-12 opacity-60">
|
||||||
<div className="grid grid-cols-12 items-start gap-4 sm:gap-16">
|
<div className="grid grid-cols-12 items-start gap-4 sm:gap-16">
|
||||||
<div className="col-span-12 sm:col-span-6">
|
<div className="col-span-12 sm:col-span-6">
|
||||||
<h4 className="text-lg font-semibold">Icon & Name</h4>
|
<h4 className="text-lg font-semibold">Icon & Name</h4>
|
||||||
@ -206,6 +206,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
label={value ? renderEmoji(value) : "Icon"}
|
label={value ? renderEmoji(value) : "Icon"}
|
||||||
value={value}
|
value={value}
|
||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
@ -225,6 +226,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
validations={{
|
validations={{
|
||||||
required: "Name is required",
|
required: "Name is required",
|
||||||
}}
|
}}
|
||||||
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Loader>
|
<Loader>
|
||||||
@ -248,6 +250,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
placeholder="Enter project description"
|
placeholder="Enter project description"
|
||||||
validations={{}}
|
validations={{}}
|
||||||
className="min-h-[46px] text-sm"
|
className="min-h-[46px] text-sm"
|
||||||
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Loader className="w-full">
|
<Loader className="w-full">
|
||||||
@ -279,6 +282,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
setValue("cover_image", imageUrl);
|
setValue("cover_image", imageUrl);
|
||||||
}}
|
}}
|
||||||
value={watch("cover_image")}
|
value={watch("cover_image")}
|
||||||
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -319,6 +323,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
message: "Identifier must at most be of 5 characters",
|
message: "Identifier must at most be of 5 characters",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<Loader>
|
<Loader>
|
||||||
@ -343,6 +348,7 @@ const GeneralSettings: NextPage = () => {
|
|||||||
onChange={onChange}
|
onChange={onChange}
|
||||||
label={currentNetwork?.label ?? "Select network"}
|
label={currentNetwork?.label ?? "Select network"}
|
||||||
input
|
input
|
||||||
|
disabled={!isAdmin}
|
||||||
>
|
>
|
||||||
{NETWORK_CHOICES.map((network) => (
|
{NETWORK_CHOICES.map((network) => (
|
||||||
<CustomSelect.Option key={network.key} value={network.key}>
|
<CustomSelect.Option key={network.key} value={network.key}>
|
||||||
@ -359,44 +365,48 @@ const GeneralSettings: NextPage = () => {
|
|||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:text-right">
|
|
||||||
{projectDetails ? (
|
{isAdmin && (
|
||||||
<SecondaryButton type="submit" loading={isSubmitting} disabled={!isAdmin}>
|
<>
|
||||||
{isSubmitting ? "Updating Project..." : "Update Project"}
|
<div className="sm:text-right">
|
||||||
</SecondaryButton>
|
|
||||||
) : (
|
|
||||||
<Loader className="mt-2 w-full">
|
|
||||||
<Loader.Item height="34px" width="100px" />
|
|
||||||
</Loader>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
{memberDetails?.role === 20 && (
|
|
||||||
<div className="grid grid-cols-12 gap-4 sm:gap-16">
|
|
||||||
<div className="col-span-12 sm:col-span-6">
|
|
||||||
<h4 className="text-lg font-semibold">Danger Zone</h4>
|
|
||||||
<p className="text-sm text-custom-text-200">
|
|
||||||
The danger zone of the project delete page is a critical area that requires
|
|
||||||
careful consideration and attention. When deleting a project, all of the data and
|
|
||||||
resources within that project will be permanently removed and cannot be recovered.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className="col-span-12 sm:col-span-6">
|
|
||||||
{projectDetails ? (
|
{projectDetails ? (
|
||||||
<div>
|
<SecondaryButton type="submit" loading={isSubmitting} disabled={!isAdmin}>
|
||||||
<DangerButton
|
{isSubmitting ? "Updating Project..." : "Update Project"}
|
||||||
onClick={() => setSelectedProject(projectDetails.id ?? null)}
|
</SecondaryButton>
|
||||||
outline
|
|
||||||
>
|
|
||||||
Delete Project
|
|
||||||
</DangerButton>
|
|
||||||
</div>
|
|
||||||
) : (
|
) : (
|
||||||
<Loader className="mt-2 w-full">
|
<Loader className="mt-2 w-full">
|
||||||
<Loader.Item height="46px" width="100px" />
|
<Loader.Item height="34px" width="100px" />
|
||||||
</Loader>
|
</Loader>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div className="grid grid-cols-12 gap-4 sm:gap-16">
|
||||||
|
<div className="col-span-12 sm:col-span-6">
|
||||||
|
<h4 className="text-lg font-semibold">Danger Zone</h4>
|
||||||
|
<p className="text-sm text-custom-text-200">
|
||||||
|
The danger zone of the project delete page is a critical area that requires
|
||||||
|
careful consideration and attention. When deleting a project, all of the data
|
||||||
|
and resources within that project will be permanently removed and cannot be
|
||||||
|
recovered.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-12 sm:col-span-6">
|
||||||
|
{projectDetails ? (
|
||||||
|
<div>
|
||||||
|
<DangerButton
|
||||||
|
onClick={() => setSelectedProject(projectDetails.id ?? null)}
|
||||||
|
outline
|
||||||
|
>
|
||||||
|
Delete Project
|
||||||
|
</DangerButton>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<Loader className="mt-2 w-full">
|
||||||
|
<Loader.Item height="46px" width="100px" />
|
||||||
|
</Loader>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
@ -181,7 +181,7 @@ const WorkspaceSettings: NextPage = () => {
|
|||||||
<div className="p-8">
|
<div className="p-8">
|
||||||
<SettingsHeader />
|
<SettingsHeader />
|
||||||
{activeWorkspace ? (
|
{activeWorkspace ? (
|
||||||
<div className="space-y-8 sm:space-y-12">
|
<div className="space-y-8 sm:space-y-12 opacity-60">
|
||||||
<div className="grid grid-cols-12 gap-4 sm:gap-16">
|
<div className="grid grid-cols-12 gap-4 sm:gap-16">
|
||||||
<div className="col-span-12 sm:col-span-6">
|
<div className="col-span-12 sm:col-span-6">
|
||||||
<h4 className="text-lg font-semibold">Logo</h4>
|
<h4 className="text-lg font-semibold">Logo</h4>
|
||||||
@ -191,7 +191,11 @@ const WorkspaceSettings: NextPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="col-span-12 sm:col-span-6">
|
<div className="col-span-12 sm:col-span-6">
|
||||||
<div className="flex items-center gap-4">
|
<div className="flex items-center gap-4">
|
||||||
<button type="button" onClick={() => setIsImageUploadModalOpen(true)}>
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => setIsImageUploadModalOpen(true)}
|
||||||
|
disabled={!isAdmin}
|
||||||
|
>
|
||||||
{watch("logo") && watch("logo") !== null && watch("logo") !== "" ? (
|
{watch("logo") && watch("logo") !== null && watch("logo") !== "" ? (
|
||||||
<div className="relative mx-auto flex h-12 w-12">
|
<div className="relative mx-auto flex h-12 w-12">
|
||||||
<img
|
<img
|
||||||
@ -206,23 +210,25 @@ const WorkspaceSettings: NextPage = () => {
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
<div className="flex gap-4">
|
{isAdmin && (
|
||||||
<SecondaryButton
|
<div className="flex gap-4">
|
||||||
onClick={() => {
|
<SecondaryButton
|
||||||
setIsImageUploadModalOpen(true);
|
onClick={() => {
|
||||||
}}
|
setIsImageUploadModalOpen(true);
|
||||||
>
|
}}
|
||||||
{isImageUploading ? "Uploading..." : "Upload"}
|
|
||||||
</SecondaryButton>
|
|
||||||
{activeWorkspace.logo && activeWorkspace.logo !== "" && (
|
|
||||||
<DangerButton
|
|
||||||
onClick={() => handleDelete(activeWorkspace.logo)}
|
|
||||||
loading={isImageRemoving}
|
|
||||||
>
|
>
|
||||||
{isImageRemoving ? "Removing..." : "Remove"}
|
{isImageUploading ? "Uploading..." : "Upload"}
|
||||||
</DangerButton>
|
</SecondaryButton>
|
||||||
)}
|
{activeWorkspace.logo && activeWorkspace.logo !== "" && (
|
||||||
</div>
|
<DangerButton
|
||||||
|
onClick={() => handleDelete(activeWorkspace.logo)}
|
||||||
|
loading={isImageRemoving}
|
||||||
|
>
|
||||||
|
{isImageRemoving ? "Removing..." : "Remove"}
|
||||||
|
</DangerButton>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -288,6 +294,7 @@ const WorkspaceSettings: NextPage = () => {
|
|||||||
message: "Workspace name should not exceed 80 characters",
|
message: "Workspace name should not exceed 80 characters",
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
|
disabled={!isAdmin}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -309,6 +316,7 @@ const WorkspaceSettings: NextPage = () => {
|
|||||||
}
|
}
|
||||||
width="w-full"
|
width="w-full"
|
||||||
input
|
input
|
||||||
|
disabled={!isAdmin}
|
||||||
>
|
>
|
||||||
{ORGANIZATION_SIZE?.map((item) => (
|
{ORGANIZATION_SIZE?.map((item) => (
|
||||||
<CustomSelect.Option key={item} value={item}>
|
<CustomSelect.Option key={item} value={item}>
|
||||||
@ -320,32 +328,35 @@ const WorkspaceSettings: NextPage = () => {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="sm:text-right">
|
|
||||||
<SecondaryButton
|
{isAdmin && (
|
||||||
onClick={handleSubmit(onSubmit)}
|
<>
|
||||||
loading={isSubmitting}
|
<div className="sm:text-right">
|
||||||
disabled={!isAdmin}
|
<SecondaryButton
|
||||||
>
|
onClick={handleSubmit(onSubmit)}
|
||||||
{isSubmitting ? "Updating..." : "Update Workspace"}
|
loading={isSubmitting}
|
||||||
</SecondaryButton>
|
disabled={!isAdmin}
|
||||||
</div>
|
>
|
||||||
{memberDetails?.role === 20 && (
|
{isSubmitting ? "Updating..." : "Update Workspace"}
|
||||||
<div className="grid grid-cols-12 gap-4 sm:gap-16">
|
</SecondaryButton>
|
||||||
<div className="col-span-12 sm:col-span-6">
|
|
||||||
<h4 className="text-lg font-semibold">Danger Zone</h4>
|
|
||||||
<p className="text-sm text-custom-text-200">
|
|
||||||
The danger zone of the workspace delete page is a critical area that requires
|
|
||||||
careful consideration and attention. When deleting a workspace, all of the data
|
|
||||||
and resources within that workspace will be permanently removed and cannot be
|
|
||||||
recovered.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-12 sm:col-span-6">
|
<div className="grid grid-cols-12 gap-4 sm:gap-16">
|
||||||
<DangerButton onClick={() => setIsOpen(true)} outline>
|
<div className="col-span-12 sm:col-span-6">
|
||||||
Delete the workspace
|
<h4 className="text-lg font-semibold">Danger Zone</h4>
|
||||||
</DangerButton>
|
<p className="text-sm text-custom-text-200">
|
||||||
|
The danger zone of the workspace delete page is a critical area that requires
|
||||||
|
careful consideration and attention. When deleting a workspace, all of the
|
||||||
|
data and resources within that workspace will be permanently removed and
|
||||||
|
cannot be recovered.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className="col-span-12 sm:col-span-6">
|
||||||
|
<DangerButton onClick={() => setIsOpen(true)} outline>
|
||||||
|
Delete the workspace
|
||||||
|
</DangerButton>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
|
Loading…
Reference in New Issue
Block a user