forked from github/plane
chore: updating the theme using MobX from command k (#1879)
* chore: updating the theme using mobx from command k * feat: Showing the project published status in the app header * dev: updated validation and redirection the project publish modal and added redirection on the app header
This commit is contained in:
parent
5b6b43fb83
commit
65295f6c6f
@ -9,12 +9,18 @@ import userService from "services/user.service";
|
||||
import useUser from "hooks/use-user";
|
||||
// helper
|
||||
import { unsetCustomCssVariables } from "helpers/theme.helper";
|
||||
// mobx react lite
|
||||
import { observer } from "mobx-react-lite";
|
||||
// mobx store
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
|
||||
type Props = {
|
||||
setIsPaletteOpen: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
|
||||
export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
export const ChangeInterfaceTheme: React.FC<Props> = observer(({ setIsPaletteOpen }) => {
|
||||
const store: any = useMobxStore();
|
||||
|
||||
const [mounted, setMounted] = useState(false);
|
||||
|
||||
const { setTheme } = useTheme();
|
||||
@ -23,29 +29,11 @@ export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
|
||||
const updateUserTheme = (newTheme: string) => {
|
||||
if (!user) return;
|
||||
|
||||
unsetCustomCssVariables();
|
||||
|
||||
setTheme(newTheme);
|
||||
|
||||
mutateUser((prevData: any) => {
|
||||
if (!prevData) return prevData;
|
||||
|
||||
return {
|
||||
...prevData,
|
||||
theme: {
|
||||
...prevData?.theme,
|
||||
theme: newTheme,
|
||||
},
|
||||
};
|
||||
}, false);
|
||||
|
||||
userService.updateUser({
|
||||
theme: {
|
||||
...user.theme,
|
||||
theme: newTheme,
|
||||
},
|
||||
});
|
||||
return store.user
|
||||
.updateCurrentUserSettings({ theme: { ...user.theme, theme: newTheme } })
|
||||
.then((response: any) => response)
|
||||
.catch((error: any) => error);
|
||||
};
|
||||
|
||||
// useEffect only runs on the client, so now we can safely show the UI
|
||||
@ -74,4 +62,4 @@ export const ChangeInterfaceTheme: React.FC<Props> = ({ setIsPaletteOpen }) => {
|
||||
))}
|
||||
</>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
@ -14,6 +14,9 @@ import { observer } from "mobx-react-lite";
|
||||
import { useMobxStore } from "lib/mobx/store-provider";
|
||||
import { RootStore } from "store/root";
|
||||
import { IProjectPublishSettingsViews } from "store/project-publish";
|
||||
// hooks
|
||||
import useToast from "hooks/use-toast";
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
|
||||
type Props = {
|
||||
// user: ICurrentUserResponse | undefined;
|
||||
@ -25,7 +28,7 @@ const defaultValues: Partial<any> = {
|
||||
reactions: false,
|
||||
votes: false,
|
||||
inbox: null,
|
||||
views: [],
|
||||
views: ["list", "kanban"],
|
||||
};
|
||||
|
||||
const viewOptions = [
|
||||
@ -40,6 +43,17 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
const store: RootStore = useMobxStore();
|
||||
const { projectPublish } = store;
|
||||
|
||||
const { projectDetails, mutateProjectDetails } = useProjectDetails();
|
||||
|
||||
const { setToastAlert } = useToast();
|
||||
const handleToastAlert = (title: string, type: string, message: string) => {
|
||||
setToastAlert({
|
||||
title: title || "Title",
|
||||
type: "error" || "warning",
|
||||
message: message || "Message",
|
||||
});
|
||||
};
|
||||
|
||||
const { NEXT_PUBLIC_DEPLOY_URL } = process.env;
|
||||
const plane_deploy_url = NEXT_PUBLIC_DEPLOY_URL
|
||||
? NEXT_PUBLIC_DEPLOY_URL
|
||||
@ -111,32 +125,41 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
}, [workspaceSlug, projectPublish, projectPublish.projectPublishModal]);
|
||||
|
||||
const onSettingsPublish = async (formData: any) => {
|
||||
const payload = {
|
||||
comments: formData.comments || false,
|
||||
reactions: formData.reactions || false,
|
||||
votes: formData.votes || false,
|
||||
inbox: formData.inbox || null,
|
||||
views: {
|
||||
list: formData.views.includes("list") || false,
|
||||
kanban: formData.views.includes("kanban") || false,
|
||||
calendar: formData.views.includes("calendar") || false,
|
||||
gantt: formData.views.includes("gantt") || false,
|
||||
spreadsheet: formData.views.includes("spreadsheet") || false,
|
||||
},
|
||||
};
|
||||
if (formData.views && formData.views.length > 0) {
|
||||
const payload = {
|
||||
comments: formData.comments || false,
|
||||
reactions: formData.reactions || false,
|
||||
votes: formData.votes || false,
|
||||
inbox: formData.inbox || null,
|
||||
views: {
|
||||
list: formData.views.includes("list") || false,
|
||||
kanban: formData.views.includes("kanban") || false,
|
||||
calendar: formData.views.includes("calendar") || false,
|
||||
gantt: formData.views.includes("gantt") || false,
|
||||
spreadsheet: formData.views.includes("spreadsheet") || false,
|
||||
},
|
||||
};
|
||||
|
||||
return projectPublish
|
||||
.createProjectSettingsAsync(
|
||||
workspaceSlug as string,
|
||||
projectPublish.project_id as string,
|
||||
payload,
|
||||
null
|
||||
)
|
||||
.then((response) => response)
|
||||
.catch((error) => {
|
||||
console.error("error", error);
|
||||
return error;
|
||||
});
|
||||
const _workspaceSlug = workspaceSlug;
|
||||
const _projectId = projectPublish.project_id;
|
||||
|
||||
return projectPublish
|
||||
.createProjectSettingsAsync(_workspaceSlug as string, _projectId as string, payload, null)
|
||||
.then((response) => {
|
||||
mutateProjectDetails();
|
||||
handleClose();
|
||||
console.log("_projectId", _projectId);
|
||||
if (_projectId)
|
||||
window.open(`${plane_deploy_url}/${_workspaceSlug}/${_projectId}`, "_blank");
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error("error", error);
|
||||
return error;
|
||||
});
|
||||
} else {
|
||||
handleToastAlert("Missing fields", "warning", "Please select at least one view to publish");
|
||||
}
|
||||
};
|
||||
|
||||
const onSettingsUpdate = async (key: string, value: any) => {
|
||||
@ -171,7 +194,10 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
payload,
|
||||
null
|
||||
)
|
||||
.then((response) => response)
|
||||
.then((response) => {
|
||||
mutateProjectDetails();
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
console.log("error", error);
|
||||
return error;
|
||||
@ -187,7 +213,9 @@ export const PublishProjectModal: React.FC<Props> = observer(() => {
|
||||
null
|
||||
)
|
||||
.then((response) => {
|
||||
mutateProjectDetails();
|
||||
reset({ ...defaultValues });
|
||||
handleClose();
|
||||
return response;
|
||||
})
|
||||
.catch((error) => {
|
||||
|
@ -1,5 +1,12 @@
|
||||
// next imports
|
||||
import { useRouter } from "next/router";
|
||||
import Link from "next/link";
|
||||
// icons
|
||||
import { Bars3Icon } from "@heroicons/react/24/outline";
|
||||
// ui components
|
||||
import { Tooltip } from "components/ui";
|
||||
// hooks
|
||||
import useProjectDetails from "hooks/use-project-details";
|
||||
|
||||
type Props = {
|
||||
breadcrumbs?: JSX.Element;
|
||||
@ -9,27 +16,61 @@ type Props = {
|
||||
noHeader: boolean;
|
||||
};
|
||||
|
||||
const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar, noHeader }) => (
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 px-5 py-4 ${
|
||||
noHeader ? "md:hidden" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => setToggleSidebar((prevData) => !prevData)}
|
||||
>
|
||||
<Bars3Icon className="h-5 w-5" />
|
||||
</button>
|
||||
const { NEXT_PUBLIC_DEPLOY_URL } = process.env;
|
||||
const plane_deploy_url = NEXT_PUBLIC_DEPLOY_URL ? NEXT_PUBLIC_DEPLOY_URL : "http://localhost:3001";
|
||||
|
||||
const Header: React.FC<Props> = ({ breadcrumbs, left, right, setToggleSidebar, noHeader }) => {
|
||||
const { projectDetails } = useProjectDetails();
|
||||
|
||||
const router = useRouter();
|
||||
const { workspaceSlug, projectId } = router.query;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`relative flex w-full flex-shrink-0 flex-row z-10 items-center justify-between gap-x-2 gap-y-4 border-b border-custom-border-200 bg-custom-sidebar-background-100 px-5 py-4 ${
|
||||
noHeader ? "md:hidden" : ""
|
||||
}`}
|
||||
>
|
||||
<div className="flex items-center gap-2 flex-grow w-full whitespace-nowrap overflow-ellipsis">
|
||||
<div className="block md:hidden">
|
||||
<button
|
||||
type="button"
|
||||
className="grid h-8 w-8 place-items-center rounded border border-custom-border-200"
|
||||
onClick={() => setToggleSidebar((prevData) => !prevData)}
|
||||
>
|
||||
<Bars3Icon className="h-5 w-5" />
|
||||
</button>
|
||||
</div>
|
||||
<div>{breadcrumbs}</div>
|
||||
|
||||
{projectDetails && projectDetails?.is_deployed && (
|
||||
<Link href={`${plane_deploy_url}/${workspaceSlug}/${projectId}`}>
|
||||
<a target="_blank" rel="noreferrer">
|
||||
<Tooltip
|
||||
tooltipContent="This project is public, and live on web."
|
||||
position="bottom-left"
|
||||
>
|
||||
<div className="transition-all flex-shrink-0 bg-custom-primary-100/20 text-custom-primary-100 p-1 rounded overflow-hidden relative flex items-center gap-1 cursor-pointer group">
|
||||
<div className="w-[14px] h-[14px] flex justify-center items-center">
|
||||
<span className="material-symbols-rounded text-[14px]">
|
||||
radio_button_checked
|
||||
</span>
|
||||
</div>
|
||||
<div className="text-xs font-medium">Public</div>
|
||||
<div className="w-[14px] h-[14px] hidden group-hover:flex justify-center items-center">
|
||||
<span className="material-symbols-rounded text-[14px]">open_in_new</span>
|
||||
</div>
|
||||
</div>
|
||||
</Tooltip>
|
||||
</a>
|
||||
</Link>
|
||||
)}
|
||||
|
||||
<div className="flex-shrink-0">{left}</div>
|
||||
</div>
|
||||
{breadcrumbs}
|
||||
<div className="flex-shrink-0">{left}</div>
|
||||
<div className="flex-shrink-0">{right}</div>
|
||||
</div>
|
||||
<div className="flex-shrink-0">{right}</div>
|
||||
</div>
|
||||
);
|
||||
);
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
@ -259,15 +259,13 @@ class ProjectPublishStore implements IProjectPublishStore {
|
||||
user
|
||||
);
|
||||
|
||||
if (response) {
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = "not-initialized";
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
runInAction(() => {
|
||||
this.projectPublishSettings = "not-initialized";
|
||||
this.loader = false;
|
||||
this.error = null;
|
||||
});
|
||||
|
||||
return response;
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
this.loader = false;
|
||||
this.error = error;
|
||||
|
1
apps/app/types/projects.d.ts
vendored
1
apps/app/types/projects.d.ts
vendored
@ -57,6 +57,7 @@ export interface IProject {
|
||||
updated_by: string;
|
||||
workspace: IWorkspace | string;
|
||||
workspace_detail: IWorkspaceLite;
|
||||
is_deployed: boolean;
|
||||
}
|
||||
|
||||
export interface IProjectLite {
|
||||
|
Loading…
Reference in New Issue
Block a user