forked from github/plane
Merge pull request #5 from makeplane/stage-release
promote existing changes to master
This commit is contained in:
commit
db14e9735e
@ -22,9 +22,9 @@ import { ChevronDownIcon } from "@heroicons/react/24/outline";
|
||||
import type { IState } from "types";
|
||||
type Props = {
|
||||
isOpen: boolean;
|
||||
setIsOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
projectId: string;
|
||||
data?: IState;
|
||||
handleClose: () => void;
|
||||
};
|
||||
|
||||
const defaultValues: Partial<IState> = {
|
||||
@ -33,14 +33,9 @@ const defaultValues: Partial<IState> = {
|
||||
color: "#000000",
|
||||
};
|
||||
|
||||
const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
data,
|
||||
projectId,
|
||||
}) => {
|
||||
const handleClose = () => {
|
||||
setIsOpen(false);
|
||||
const CreateUpdateStateModal: React.FC<Props> = ({ isOpen, data, projectId, handleClose }) => {
|
||||
const onClose = () => {
|
||||
handleClose();
|
||||
const timeout = setTimeout(() => {
|
||||
reset(defaultValues);
|
||||
clearTimeout(timeout);
|
||||
@ -70,12 +65,8 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
await stateService
|
||||
.createState(activeWorkspace.slug, projectId, payload)
|
||||
.then((res) => {
|
||||
mutate<IState[]>(
|
||||
STATE_LIST(projectId),
|
||||
(prevData) => [...(prevData ?? []), res],
|
||||
false
|
||||
);
|
||||
handleClose();
|
||||
mutate<IState[]>(STATE_LIST(projectId), (prevData) => [...(prevData ?? []), res], false);
|
||||
onClose();
|
||||
})
|
||||
.catch((err) => {
|
||||
Object.keys(err).map((key) => {
|
||||
@ -101,7 +92,7 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
},
|
||||
false
|
||||
);
|
||||
handleClose();
|
||||
onClose();
|
||||
})
|
||||
.catch((err) => {
|
||||
Object.keys(err).map((key) => {
|
||||
@ -115,16 +106,15 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
|
||||
useEffect(() => {
|
||||
if (data) {
|
||||
setIsOpen(true);
|
||||
reset(data);
|
||||
} else {
|
||||
reset(defaultValues);
|
||||
}
|
||||
}, [data, setIsOpen, reset]);
|
||||
}, [data, reset]);
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={React.Fragment}>
|
||||
<Dialog as="div" className="relative z-10" onClose={handleClose}>
|
||||
<Dialog as="div" className="relative z-10" onClose={onClose}>
|
||||
<Transition.Child
|
||||
as={React.Fragment}
|
||||
enter="ease-out duration-300"
|
||||
@ -152,10 +142,7 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
<form onSubmit={handleSubmit(onSubmit)}>
|
||||
<div>
|
||||
<div className="mt-3 sm:mt-5">
|
||||
<Dialog.Title
|
||||
as="h3"
|
||||
className="text-lg font-medium leading-6 text-gray-900"
|
||||
>
|
||||
<Dialog.Title as="h3" className="text-lg font-medium leading-6 text-gray-900">
|
||||
{data ? "Update" : "Create"} State
|
||||
</Dialog.Title>
|
||||
<div className="mt-2 space-y-3">
|
||||
@ -188,8 +175,7 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
<span
|
||||
className="w-4 h-4 ml-2 rounded"
|
||||
style={{
|
||||
backgroundColor:
|
||||
watch("color") ?? "green",
|
||||
backgroundColor: watch("color") ?? "green",
|
||||
}}
|
||||
></span>
|
||||
)}
|
||||
@ -214,14 +200,10 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
<Controller
|
||||
name="color"
|
||||
control={control}
|
||||
render={({
|
||||
field: { value, onChange },
|
||||
}) => (
|
||||
render={({ field: { value, onChange } }) => (
|
||||
<TwitterPicker
|
||||
color={value}
|
||||
onChange={(value) =>
|
||||
onChange(value.hex)
|
||||
}
|
||||
onChange={(value) => onChange(value.hex)}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
@ -245,7 +227,7 @@ const CreateUpdateStateModal: React.FC<Props> = ({
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-5 sm:mt-6 sm:grid sm:grid-flow-row-dense sm:grid-cols-2 sm:gap-3">
|
||||
<Button theme="secondary" onClick={handleClose}>
|
||||
<Button theme="secondary" onClick={onClose}>
|
||||
Cancel
|
||||
</Button>
|
||||
<Button type="submit" disabled={isSubmitting}>
|
||||
|
@ -267,7 +267,7 @@ const CreateUpdateIssuesModal: React.FC<Props> = ({
|
||||
<>
|
||||
<CreateUpdateStateModal
|
||||
isOpen={isStateModalOpen}
|
||||
setIsOpen={setIsStateModalOpen}
|
||||
handleClose={() => setIsStateModalOpen(false)}
|
||||
projectId={activeProject?.id}
|
||||
/>
|
||||
<CreateUpdateCycleModal
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FC, CSSProperties, useEffect, useState } from "react";
|
||||
import { FC, CSSProperties } from "react";
|
||||
// next
|
||||
import Script from "next/script";
|
||||
|
||||
export interface IGoogleLoginButton {
|
||||
@ -28,7 +29,7 @@ export const GoogleLoginButton: FC<IGoogleLoginButton> = (props) => {
|
||||
size: "large",
|
||||
logo_alignment: "center",
|
||||
width: document.getElementById("googleSignInButton")?.offsetWidth,
|
||||
text: props.text || "Continue with Google",
|
||||
text: "continue_with",
|
||||
} as GsiButtonConfiguration // customization attributes
|
||||
);
|
||||
window?.google?.accounts.id.prompt(); // also display the One Tap dialog
|
||||
|
@ -504,7 +504,7 @@ const Sidebar: React.FC = () => {
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="px-2 py-2 bg-gray-50 w-full self-baseline">
|
||||
<div className="px-2 py-2 bg-gray-50 w-full self-baseline flex items-center gap-x-2">
|
||||
<button
|
||||
type="button"
|
||||
className={`flex items-center gap-3 px-2 py-2 text-xs font-medium rounded-md text-gray-500 hover:bg-gray-100 hover:text-gray-900 focus:bg-gray-100 focus:text-gray-900 outline-none ${
|
||||
@ -520,6 +520,19 @@ const Sidebar: React.FC = () => {
|
||||
/>
|
||||
</Tooltip>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => {
|
||||
const e = new KeyboardEvent("keydown", {
|
||||
ctrlKey: true,
|
||||
key: "h",
|
||||
});
|
||||
document.dispatchEvent(e);
|
||||
}}
|
||||
title="Help"
|
||||
>
|
||||
<QuestionMarkCircleIcon className="h-4 w-4 text-gray-500" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -27,11 +27,13 @@ class UserService extends APIService {
|
||||
}
|
||||
|
||||
async currentUser(): Promise<any> {
|
||||
if (!this.getAccessToken()) return null;
|
||||
return this.get(USER_ENDPOINT)
|
||||
.then((response) => {
|
||||
return response?.data;
|
||||
})
|
||||
.catch((error) => {
|
||||
this.purgeAccessToken();
|
||||
throw error?.response?.data;
|
||||
});
|
||||
}
|
||||
|
@ -28,9 +28,14 @@ import CreateUpdateStateModal from "components/project/issues/BoardView/state/Cr
|
||||
import { Spinner, Button, Input, TextArea, Select } from "ui";
|
||||
import { Breadcrumbs, BreadcrumbItem } from "ui/Breadcrumbs";
|
||||
// icons
|
||||
import { ChevronDownIcon, CheckIcon, PlusIcon } from "@heroicons/react/24/outline";
|
||||
import {
|
||||
ChevronDownIcon,
|
||||
CheckIcon,
|
||||
PlusIcon,
|
||||
PencilSquareIcon,
|
||||
} from "@heroicons/react/24/outline";
|
||||
// types
|
||||
import type { IProject, IWorkspace, WorkspaceMember } from "types";
|
||||
import type { IProject, IState, IWorkspace, WorkspaceMember } from "types";
|
||||
|
||||
const defaultValues: Partial<IProject> = {
|
||||
name: "",
|
||||
@ -52,6 +57,7 @@ const ProjectSettings: NextPage = () => {
|
||||
});
|
||||
|
||||
const [isCreateStateModalOpen, setIsCreateStateModalOpen] = useState(false);
|
||||
const [selectedState, setSelectedState] = useState<string | undefined>();
|
||||
|
||||
const router = useRouter();
|
||||
|
||||
@ -135,9 +141,13 @@ const ProjectSettings: NextPage = () => {
|
||||
<AdminLayout>
|
||||
<div className="space-y-5">
|
||||
<CreateUpdateStateModal
|
||||
isOpen={isCreateStateModalOpen}
|
||||
setIsOpen={setIsCreateStateModalOpen}
|
||||
isOpen={isCreateStateModalOpen || Boolean(selectedState)}
|
||||
handleClose={() => {
|
||||
setSelectedState(undefined);
|
||||
setIsCreateStateModalOpen(false);
|
||||
}}
|
||||
projectId={projectId as string}
|
||||
data={selectedState ? states?.find((state) => state.id === selectedState) : undefined}
|
||||
/>
|
||||
<Breadcrumbs>
|
||||
<BreadcrumbItem title="Projects" link="/projects" />
|
||||
@ -404,9 +414,10 @@ const ProjectSettings: NextPage = () => {
|
||||
<div className="w-full space-y-5">
|
||||
{states?.map((state) => (
|
||||
<div
|
||||
className="border p-1 px-4 rounded flex items-center gap-x-2"
|
||||
className="border p-1 px-4 rounded flex justify-between items-center"
|
||||
key={state.id}
|
||||
>
|
||||
<div className="flex items-center gap-x-2">
|
||||
<div
|
||||
className="w-3 h-3 rounded-full"
|
||||
style={{
|
||||
@ -415,6 +426,12 @@ const ProjectSettings: NextPage = () => {
|
||||
></div>
|
||||
<h4>{addSpaceIfCamelCase(state.name)}</h4>
|
||||
</div>
|
||||
<div>
|
||||
<button type="button" onClick={() => setSelectedState(state.id)}>
|
||||
<PencilSquareIcon className="h-5 w-5 text-gray-400" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
|
@ -1,10 +1,9 @@
|
||||
import React, { useCallback, useState, useEffect } from "react";
|
||||
// next
|
||||
import type { NextPage } from "next";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/router";
|
||||
import Image from "next/image";
|
||||
// react
|
||||
import React, { useCallback, useState } from "react";
|
||||
// hooks
|
||||
import useUser from "lib/hooks/useUser";
|
||||
// services
|
||||
@ -37,8 +36,10 @@ const SignIn: NextPage = () => {
|
||||
|
||||
const { mutateUser, mutateWorkspaces } = useUser();
|
||||
|
||||
const [githubToken, setGithubToken] = React.useState(undefined);
|
||||
const [loginCallBackURL, setLoginCallBackURL] = React.useState(undefined);
|
||||
const [githubToken, setGithubToken] = useState(undefined);
|
||||
const [loginCallBackURL, setLoginCallBackURL] = useState(undefined);
|
||||
|
||||
const [isGoogleAuthenticationLoading, setIsGoogleAuthenticationLoading] = useState(false);
|
||||
|
||||
const onSignInSuccess = useCallback(
|
||||
async (res: any) => {
|
||||
@ -54,7 +55,7 @@ const SignIn: NextPage = () => {
|
||||
return githubToken;
|
||||
}, [githubToken]);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const {
|
||||
query: { code },
|
||||
} = router;
|
||||
@ -63,7 +64,7 @@ const SignIn: NextPage = () => {
|
||||
}
|
||||
}, [router, githubTokenMemo]);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
if (githubToken) {
|
||||
authenticationService
|
||||
.socialAuth({
|
||||
@ -80,10 +81,12 @@ const SignIn: NextPage = () => {
|
||||
}
|
||||
}, [githubToken, mutateUser, mutateWorkspaces, router, onSignInSuccess]);
|
||||
|
||||
React.useEffect(() => {
|
||||
useEffect(() => {
|
||||
const origin =
|
||||
typeof window !== "undefined" && window.location.origin ? window.location.origin : "";
|
||||
setLoginCallBackURL(`${origin}/signin` as any);
|
||||
|
||||
return () => setIsGoogleAuthenticationLoading(false);
|
||||
}, []);
|
||||
|
||||
return (
|
||||
@ -92,6 +95,11 @@ const SignIn: NextPage = () => {
|
||||
title: "Plane - Sign In",
|
||||
}}
|
||||
>
|
||||
{isGoogleAuthenticationLoading && (
|
||||
<div className="absolute top-0 left-0 w-full h-full bg-white z-50 flex items-center justify-center">
|
||||
<h2 className="text-2xl text-black">Sign in with Google. Please wait...</h2>
|
||||
</div>
|
||||
)}
|
||||
<div className="w-full h-screen flex justify-center items-center bg-gray-50 overflow-auto">
|
||||
<div className="min-h-full w-full flex flex-col justify-center py-12 px-6 lg:px-8">
|
||||
<div className="sm:mx-auto sm:w-full sm:max-w-md">
|
||||
@ -129,6 +137,7 @@ const SignIn: NextPage = () => {
|
||||
</button>
|
||||
<GoogleLoginButton
|
||||
onSuccess={({ clientId, credential }) => {
|
||||
setIsGoogleAuthenticationLoading(true);
|
||||
authenticationService
|
||||
.socialAuth({
|
||||
medium: "google",
|
||||
@ -140,6 +149,7 @@ const SignIn: NextPage = () => {
|
||||
})
|
||||
.catch((err) => {
|
||||
console.log(err);
|
||||
setIsGoogleAuthenticationLoading(false);
|
||||
});
|
||||
}}
|
||||
onFailure={(err) => {
|
||||
|
Loading…
Reference in New Issue
Block a user