chore: global issues ui improvement and bug fixes (#2300)

This commit is contained in:
Anmol Singh Bhatia 2023-09-29 12:36:38 +05:30 committed by GitHub
parent 6cb4b222d0
commit 459999e8c9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 99 additions and 83 deletions

View File

@ -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"

View File

@ -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>

View File

@ -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" />}

View File

@ -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" />}

View File

@ -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">

View File

@ -34,7 +34,7 @@ const workspaceLinks = (workspaceSlug: string) => [
},
{
Icon: TaskAltOutlined,
name: "Issues",
name: "All Issues",
href: `/${workspaceSlug}/workspace-views/all-issues`,
},
];

View File

@ -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!",

View File

@ -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>
);

View File

@ -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(),

View File

@ -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">