mirror of
https://github.com/makeplane/plane
synced 2024-06-14 14:31:34 +00:00
chore: global issues ui improvement and bug fixes (#2300)
This commit is contained in:
parent
6cb4b222d0
commit
459999e8c9
@ -82,7 +82,7 @@ export const IssueColumn: React.FC<Props> = ({
|
||||
const isNotAllowed = userAuth.isGuest || userAuth.isViewer;
|
||||
|
||||
return (
|
||||
<div className="group flex items-center w-[28rem] text-sm h-11 sticky top-0 bg-custom-background-100 truncate border-b border-r border-custom-border-200">
|
||||
<div className="group flex items-center w-[28rem] text-sm h-11 sticky top-0 bg-custom-background-100 truncate border-b border-r border-custom-border-100">
|
||||
<div
|
||||
className="flex gap-1.5 px-4 pr-0 py-2.5 items-center w-24"
|
||||
style={issue.parent && nestingLevel !== 0 ? { paddingLeft } : {}}
|
||||
@ -101,7 +101,7 @@ export const IssueColumn: React.FC<Props> = ({
|
||||
onInteraction={(nextOpenState) => setIsOpen(nextOpenState)}
|
||||
content={
|
||||
<div
|
||||
className={`flex flex-col gap-1.5 overflow-y-scroll whitespace-nowrap rounded-md border p-1 text-xs shadow-lg focus:outline-none max-h-44 min-w-full border-custom-border-200 bg-custom-background-90`}
|
||||
className={`flex flex-col gap-1.5 overflow-y-scroll whitespace-nowrap rounded-md border p-1 text-xs shadow-lg focus:outline-none max-h-44 min-w-full border-custom-border-100 bg-custom-background-90`}
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
|
@ -239,7 +239,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
||||
descendingOrder: TIssueOrderByOptions
|
||||
) => (
|
||||
<div className="relative flex flex-col h-max w-full bg-custom-background-100">
|
||||
<div className="flex items-center min-w-[9rem] px-4 py-2.5 text-sm font-medium z-[1] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-200">
|
||||
<div className="flex items-center min-w-[9rem] px-4 py-2.5 text-sm font-medium z-[1] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
||||
<CustomMenu
|
||||
customButtonClassName="!w-full"
|
||||
className="!w-full"
|
||||
@ -491,7 +491,7 @@ export const SpreadsheetView: React.FC<Props> = ({
|
||||
isScrolled ? "shadow-r shadow-custom-shadow-xs" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center text-sm font-medium z-[2] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-200">
|
||||
<div className="flex items-center text-sm font-medium z-[2] h-11 w-full sticky top-0 bg-custom-background-90 border border-l-0 border-custom-border-100">
|
||||
<span className="flex items-center px-4 py-2.5 h-full w-24 flex-shrink-0">
|
||||
ID
|
||||
</span>
|
||||
|
@ -31,7 +31,7 @@ import { IIssue, IWorkspaceIssueFilterOptions } from "types";
|
||||
|
||||
export const WorkspaceViewIssues = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, workspaceViewId } = router.query;
|
||||
const { workspaceSlug, viewId } = router.query;
|
||||
|
||||
const { memberRole } = useProjectMyMembership();
|
||||
const { user } = useUser();
|
||||
@ -189,7 +189,7 @@ export const WorkspaceViewIssues = () => {
|
||||
/>
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
if (workspaceViewId) handleFilters("filters", filters.filters, true);
|
||||
if (viewId) handleFilters("filters", filters.filters, true);
|
||||
else
|
||||
setCreateViewModal({
|
||||
query: filters.filters,
|
||||
@ -197,8 +197,8 @@ export const WorkspaceViewIssues = () => {
|
||||
}}
|
||||
className="flex items-center gap-2 text-sm"
|
||||
>
|
||||
{!workspaceViewId && <PlusIcon className="h-4 w-4" />}
|
||||
{workspaceViewId ? "Update" : "Save"} view
|
||||
{!viewId && <PlusIcon className="h-4 w-4" />}
|
||||
{viewId ? "Update" : "Save"} view
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
{<div className="mt-3 border-t border-custom-border-200" />}
|
||||
|
@ -31,7 +31,7 @@ import { IIssue, IWorkspaceIssueFilterOptions } from "types";
|
||||
|
||||
export const WorkspaceAllIssue = () => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, workspaceViewId } = router.query;
|
||||
const { workspaceSlug, viewId } = router.query;
|
||||
|
||||
const [createViewModal, setCreateViewModal] = useState<any>(null);
|
||||
|
||||
@ -203,7 +203,7 @@ export const WorkspaceAllIssue = () => {
|
||||
/>
|
||||
<PrimaryButton
|
||||
onClick={() => {
|
||||
if (workspaceViewId) handleFilters("filters", filters.filters, true);
|
||||
if (viewId) handleFilters("filters", filters.filters, true);
|
||||
else
|
||||
setCreateViewModal({
|
||||
query: filters.filters,
|
||||
@ -211,8 +211,8 @@ export const WorkspaceAllIssue = () => {
|
||||
}}
|
||||
className="flex items-center gap-2 text-sm"
|
||||
>
|
||||
{!workspaceViewId && <PlusIcon className="h-4 w-4" />}
|
||||
{workspaceViewId ? "Update" : "Save"} view
|
||||
{!viewId && <PlusIcon className="h-4 w-4" />}
|
||||
{viewId ? "Update" : "Save"} view
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
{<div className="mt-3 border-t border-custom-border-200" />}
|
||||
|
@ -91,7 +91,7 @@ export const SingleViewItem: React.FC<Props> = ({
|
||||
const viewRedirectionUrl =
|
||||
viewType === "project"
|
||||
? `/${workspaceSlug}/projects/${projectId}/views/${view.id}`
|
||||
: `/${workspaceSlug}/workspace-views/${view.id}`;
|
||||
: `/${workspaceSlug}/workspace-views/issues?viewId=${view.id}`;
|
||||
|
||||
return (
|
||||
<div className="group hover:bg-custom-background-90 border-b border-custom-border-200">
|
||||
|
@ -34,7 +34,7 @@ const workspaceLinks = (workspaceSlug: string) => [
|
||||
},
|
||||
{
|
||||
Icon: TaskAltOutlined,
|
||||
name: "Issues",
|
||||
name: "All Issues",
|
||||
href: `/${workspaceSlug}/workspace-views/all-issues`,
|
||||
},
|
||||
];
|
||||
|
@ -48,10 +48,12 @@ export const CreateUpdateWorkspaceViewModal: React.FC<Props> = ({
|
||||
};
|
||||
await workspaceService
|
||||
.createView(workspaceSlug as string, payloadData)
|
||||
.then(() => {
|
||||
.then((res) => {
|
||||
mutate(WORKSPACE_VIEWS_LIST(workspaceSlug as string));
|
||||
handleClose();
|
||||
|
||||
router.replace(`/${workspaceSlug}/workspace-views/issues?viewId=${res.id}`);
|
||||
|
||||
setToastAlert({
|
||||
type: "success",
|
||||
title: "Success!",
|
||||
|
@ -17,7 +17,7 @@ type Props = {
|
||||
|
||||
export const WorkspaceViewsNavigation: React.FC<Props> = ({ handleAddView }) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, workspaceViewId } = router.query;
|
||||
const { workspaceSlug, viewId } = router.query;
|
||||
|
||||
const { data: workspaceViews } = useSWR(
|
||||
workspaceSlug ? WORKSPACE_VIEWS_LIST(workspaceSlug.toString()) : null,
|
||||
@ -25,67 +25,80 @@ export const WorkspaceViewsNavigation: React.FC<Props> = ({ handleAddView }) =>
|
||||
);
|
||||
|
||||
const isSelected = (pathName: string) => router.pathname.includes(pathName);
|
||||
React.useEffect(() => {
|
||||
const activeTabElement = document.getElementById("active-tab-global-view");
|
||||
if (activeTabElement) activeTabElement.scrollIntoView({ behavior: "smooth", inline: "center" });
|
||||
}, [viewId, workspaceViews]);
|
||||
|
||||
const tabsList = [
|
||||
{
|
||||
key: "all",
|
||||
label: "All Issues",
|
||||
selected: isSelected("workspace-views/all-issues"),
|
||||
onClick: () => router.push(`/${workspaceSlug}/workspace-views/all-issues`),
|
||||
onClick: () => router.replace(`/${workspaceSlug}/workspace-views/all-issues`),
|
||||
},
|
||||
{
|
||||
key: "assigned",
|
||||
label: "Assigned",
|
||||
selected: isSelected("workspace-views/assigned"),
|
||||
onClick: () => router.push(`/${workspaceSlug}/workspace-views/assigned`),
|
||||
onClick: () => router.replace(`/${workspaceSlug}/workspace-views/assigned`),
|
||||
},
|
||||
{
|
||||
key: "created",
|
||||
label: "Created",
|
||||
selected: isSelected("workspace-views/created"),
|
||||
onClick: () => router.push(`/${workspaceSlug}/workspace-views/created`),
|
||||
onClick: () => router.replace(`/${workspaceSlug}/workspace-views/created`),
|
||||
},
|
||||
{
|
||||
key: "subscribed",
|
||||
label: "Subscribed",
|
||||
selected: isSelected("workspace-views/subscribed"),
|
||||
onClick: () => router.push(`/${workspaceSlug}/workspace-views/subscribed`),
|
||||
onClick: () => router.replace(`/${workspaceSlug}/workspace-views/subscribed`),
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<div className="group flex items-center overflow-x-scroll">
|
||||
<div className="group flex items-center gap-x-1 overflow-x-scroll relative">
|
||||
{tabsList.map((tab) => (
|
||||
<button
|
||||
key={tab.key}
|
||||
type="button"
|
||||
onClick={tab.onClick}
|
||||
className={`border-b-2 min-w-[96px] p-4 text-sm font-medium outline-none whitespace-nowrap ${
|
||||
className={`border-b-2 min-w-min p-3 text-sm font-medium outline-none whitespace-nowrap flex-shrink-0 ${
|
||||
tab.selected
|
||||
? "border-custom-primary-100 text-custom-primary-100"
|
||||
: "border-transparent hover:border-custom-primary-100 hover:text-custom-primary-100"
|
||||
: "border-transparent hover:border-custom-border-200 hover:text-custom-text-400"
|
||||
}`}
|
||||
id={tab.selected ? `active-tab-global-view` : ``}
|
||||
>
|
||||
{tab.label}
|
||||
</button>
|
||||
))}
|
||||
|
||||
{workspaceViews &&
|
||||
workspaceViews.length > 0 &&
|
||||
workspaceViews?.map((view) => (
|
||||
<button
|
||||
className={`border-b-2 min-w-[96px] p-4 text-sm font-medium outline-none whitespace-nowrap ${
|
||||
view.id === workspaceViewId
|
||||
className={`border-b-2 min-w-min p-3 text-sm font-medium outline-none whitespace-nowrap flex-shrink-0 ${
|
||||
view.id === viewId
|
||||
? "border-custom-primary-100 text-custom-primary-100"
|
||||
: "border-transparent hover:border-custom-primary-100 hover:text-custom-primary-100"
|
||||
: "border-transparent hover:border-custom-border-200 hover:text-custom-text-400"
|
||||
}`}
|
||||
onClick={() => router.push(`/${workspaceSlug}/workspace-views/${view.id}`)}
|
||||
id={view.id === viewId ? `active-tab-global-view` : ``}
|
||||
onClick={() =>
|
||||
router.replace(`/${workspaceSlug}/workspace-views/issues?viewId=${view.id}`)
|
||||
}
|
||||
>
|
||||
{view.name}
|
||||
</button>
|
||||
))}
|
||||
|
||||
<button type="button" className="min-w-[96px] " onClick={handleAddView}>
|
||||
<PlusIcon className="h-4 w-4 text-custom-primary-200 hover:text-current" />
|
||||
<button
|
||||
type="button"
|
||||
className="flex items-center justify-center flex-shrink-0 sticky right-0 w-12 py-3 border-transparent bg-custom-background-100 hover:border-custom-border-200 hover:text-custom-text-400"
|
||||
onClick={handleAddView}
|
||||
>
|
||||
<PlusIcon className="h-4 w-4 text-custom-primary-200" />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
|
@ -67,19 +67,19 @@ export const initialState: IWorkspaceGlobalViewProps = {
|
||||
|
||||
const saveViewFilters = async (
|
||||
workspaceSlug: string,
|
||||
workspaceViewId: string,
|
||||
viewId: string,
|
||||
state: IWorkspaceGlobalViewProps
|
||||
) => {
|
||||
await workspaceService.updateView(workspaceSlug, workspaceViewId, {
|
||||
await workspaceService.updateView(workspaceSlug, viewId, {
|
||||
query_data: state,
|
||||
});
|
||||
};
|
||||
|
||||
export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, workspaceViewId } = router.query as {
|
||||
const { workspaceSlug, viewId } = router.query as {
|
||||
workspaceSlug: string;
|
||||
workspaceViewId: string;
|
||||
viewId: string;
|
||||
};
|
||||
|
||||
const [filters, setFilters] = useState<IWorkspaceGlobalViewProps>(initialState);
|
||||
@ -98,7 +98,7 @@ export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||
};
|
||||
setFilters(() => updatedFilterPayload);
|
||||
|
||||
if (saveFiltersToServer) saveViewFilters(workspaceSlug, workspaceViewId, updatedFilterPayload);
|
||||
if (saveFiltersToServer) saveViewFilters(workspaceSlug, viewId, updatedFilterPayload);
|
||||
};
|
||||
|
||||
const computedFilter = (filters: any) => {
|
||||
@ -151,9 +151,9 @@ export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||
};
|
||||
|
||||
const { data: view, isLoading: viewLoading } = useSWR(
|
||||
workspaceSlug && workspaceViewId ? WORKSPACE_VIEW_DETAILS(workspaceViewId.toString()) : null,
|
||||
workspaceSlug && workspaceViewId
|
||||
? () => workspaceService.getViewDetails(workspaceSlug.toString(), workspaceViewId.toString())
|
||||
workspaceSlug && viewId ? WORKSPACE_VIEW_DETAILS(viewId.toString()) : null,
|
||||
workspaceSlug && viewId
|
||||
? () => workspaceService.getViewDetails(workspaceSlug.toString(), viewId.toString())
|
||||
: null
|
||||
);
|
||||
|
||||
@ -162,10 +162,10 @@ export const WorkspaceViewProvider: React.FC<{ children: React.ReactNode }> = ({
|
||||
mutate: mutateViewIssues,
|
||||
isLoading: viewIssueLoading,
|
||||
} = useSWR(
|
||||
workspaceSlug && view && workspaceViewId && filters
|
||||
? WORKSPACE_VIEW_ISSUES(workspaceViewId.toString(), params)
|
||||
workspaceSlug && view && viewId && filters
|
||||
? WORKSPACE_VIEW_ISSUES(viewId.toString(), params)
|
||||
: null,
|
||||
workspaceSlug && view && workspaceViewId
|
||||
workspaceSlug && view && viewId
|
||||
? () =>
|
||||
workspaceService.getViewIssues(
|
||||
workspaceSlug.toString(),
|
||||
|
@ -312,51 +312,52 @@ const WorkspaceSettings: NextPage = () => {
|
||||
</PrimaryButton>
|
||||
</div>
|
||||
</div>
|
||||
{isAdmin && (
|
||||
<Disclosure as="div" className="border-t border-custom-border-400">
|
||||
{({ open }) => (
|
||||
<div className="w-full">
|
||||
<Disclosure.Button
|
||||
as="button"
|
||||
type="button"
|
||||
className="flex items-center justify-between w-full py-4"
|
||||
>
|
||||
<span className="text-xl tracking-tight">Delete Workspace</span>
|
||||
<Icon iconName={open ? "expand_less" : "expand_more"} className="!text-2xl" />
|
||||
</Disclosure.Button>
|
||||
|
||||
<Disclosure as="div" className="border-t border-custom-border-400">
|
||||
{({ open }) => (
|
||||
<div className="w-full">
|
||||
<Disclosure.Button
|
||||
as="button"
|
||||
type="button"
|
||||
className="flex items-center justify-between w-full py-4"
|
||||
>
|
||||
<span className="text-xl tracking-tight">Delete Workspace</span>
|
||||
<Icon iconName={open ? "expand_less" : "expand_more"} className="!text-2xl" />
|
||||
</Disclosure.Button>
|
||||
|
||||
<Transition
|
||||
show={open}
|
||||
enter="transition duration-100 ease-out"
|
||||
enterFrom="transform opacity-0"
|
||||
enterTo="transform opacity-100"
|
||||
leave="transition duration-75 ease-out"
|
||||
leaveFrom="transform opacity-100"
|
||||
leaveTo="transform opacity-0"
|
||||
>
|
||||
<Disclosure.Panel>
|
||||
<div className="flex flex-col gap-8">
|
||||
<span className="text-sm tracking-tight">
|
||||
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.
|
||||
</span>
|
||||
<div>
|
||||
<DangerButton
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="!text-sm"
|
||||
outline
|
||||
>
|
||||
Delete my workspace
|
||||
</DangerButton>
|
||||
<Transition
|
||||
show={open}
|
||||
enter="transition duration-100 ease-out"
|
||||
enterFrom="transform opacity-0"
|
||||
enterTo="transform opacity-100"
|
||||
leave="transition duration-75 ease-out"
|
||||
leaveFrom="transform opacity-100"
|
||||
leaveTo="transform opacity-0"
|
||||
>
|
||||
<Disclosure.Panel>
|
||||
<div className="flex flex-col gap-8">
|
||||
<span className="text-sm tracking-tight">
|
||||
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.
|
||||
</span>
|
||||
<div>
|
||||
<DangerButton
|
||||
onClick={() => setIsOpen(true)}
|
||||
className="!text-sm"
|
||||
outline
|
||||
>
|
||||
Delete my workspace
|
||||
</DangerButton>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Disclosure.Panel>
|
||||
</Transition>
|
||||
</div>
|
||||
)}
|
||||
</Disclosure>
|
||||
</Disclosure.Panel>
|
||||
</Transition>
|
||||
</div>
|
||||
)}
|
||||
</Disclosure>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center justify-center h-full w-full px-4 sm:px-0">
|
||||
|
Loading…
Reference in New Issue
Block a user