-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Instance Admin Panel: Configuration Settings (#2800)
* feat: Instance Admin Panel: Configuration Settings * refactor: seprate Google and Github form into independent components. * feat: add admin auth wrapper and access denied page. * style: design updates.
- Loading branch information
1 parent
f44f701
commit b903126
Showing
21 changed files
with
1,144 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,204 @@ | ||
import { FC } from "react"; | ||
import { Controller, useForm } from "react-hook-form"; | ||
// ui | ||
import { Button, Input, ToggleSwitch } from "@plane/ui"; | ||
// types | ||
import { IFormattedInstanceConfiguration } from "types/instance"; | ||
// hooks | ||
import useToast from "hooks/use-toast"; | ||
// mobx store | ||
import { useMobxStore } from "lib/mobx/store-provider"; | ||
|
||
export interface IInstanceEmailForm { | ||
config: IFormattedInstanceConfiguration; | ||
} | ||
|
||
export interface EmailFormValues { | ||
EMAIL_HOST: string; | ||
EMAIL_PORT: string; | ||
EMAIL_HOST_USER: string; | ||
EMAIL_HOST_PASSWORD: string; | ||
EMAIL_USE_TLS: string; | ||
EMAIL_USE_SSL: string; | ||
} | ||
|
||
export const InstanceEmailForm: FC<IInstanceEmailForm> = (props) => { | ||
const { config } = props; | ||
// store | ||
const { instance: instanceStore } = useMobxStore(); | ||
// toast | ||
const { setToastAlert } = useToast(); | ||
// form data | ||
const { | ||
handleSubmit, | ||
control, | ||
formState: { errors, isSubmitting }, | ||
} = useForm<EmailFormValues>({ | ||
defaultValues: { | ||
EMAIL_HOST: config["EMAIL_HOST"], | ||
EMAIL_PORT: config["EMAIL_PORT"], | ||
EMAIL_HOST_USER: config["EMAIL_HOST_USER"], | ||
EMAIL_HOST_PASSWORD: config["EMAIL_HOST_PASSWORD"], | ||
EMAIL_USE_TLS: config["EMAIL_USE_TLS"], | ||
EMAIL_USE_SSL: config["EMAIL_USE_SSL"], | ||
}, | ||
}); | ||
|
||
const onSubmit = async (formData: EmailFormValues) => { | ||
const payload: Partial<EmailFormValues> = { ...formData }; | ||
|
||
await instanceStore | ||
.updateInstanceConfigurations(payload) | ||
.then(() => | ||
setToastAlert({ | ||
title: "Success", | ||
type: "success", | ||
message: "Email Settings updated successfully", | ||
}) | ||
) | ||
.catch((err) => console.error(err)); | ||
}; | ||
|
||
return ( | ||
<div className="flex flex-col gap-8 m-8 w-4/5"> | ||
<div className="pb-2 mb-2 border-b border-custom-border-100"> | ||
<div className="text-custom-text-100 font-medium text-lg">Email</div> | ||
<div className="text-custom-text-300 font-normal text-sm">Email related settings.</div> | ||
</div> | ||
<div className="grid grid-col grid-cols-1 lg:grid-cols-2 items-center justify-between gap-x-16 gap-y-8 w-full"> | ||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Host</h4> | ||
<Controller | ||
control={control} | ||
name="EMAIL_HOST" | ||
render={({ field: { value, onChange, ref } }) => ( | ||
<Input | ||
id="EMAIL_HOST" | ||
name="EMAIL_HOST" | ||
type="text" | ||
value={value} | ||
onChange={onChange} | ||
ref={ref} | ||
hasError={Boolean(errors.EMAIL_HOST)} | ||
placeholder="Email Host" | ||
className="rounded-md font-medium w-full" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
|
||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Port</h4> | ||
<Controller | ||
control={control} | ||
name="EMAIL_PORT" | ||
render={({ field: { value, onChange, ref } }) => ( | ||
<Input | ||
id="EMAIL_PORT" | ||
name="EMAIL_PORT" | ||
type="text" | ||
value={value} | ||
onChange={onChange} | ||
ref={ref} | ||
hasError={Boolean(errors.EMAIL_PORT)} | ||
placeholder="Email Port" | ||
className="rounded-md font-medium w-full" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
</div> | ||
<div className="grid grid-col grid-cols-1 lg:grid-cols-2 items-center justify-between gap-x-16 gap-y-8 w-full"> | ||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Username</h4> | ||
<Controller | ||
control={control} | ||
name="EMAIL_HOST_USER" | ||
render={({ field: { value, onChange, ref } }) => ( | ||
<Input | ||
id="EMAIL_HOST_USER" | ||
name="EMAIL_HOST_USER" | ||
type="text" | ||
value={value} | ||
onChange={onChange} | ||
ref={ref} | ||
hasError={Boolean(errors.EMAIL_HOST_USER)} | ||
placeholder="Username" | ||
className="rounded-md font-medium w-full" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
|
||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Password</h4> | ||
<Controller | ||
control={control} | ||
name="EMAIL_HOST_PASSWORD" | ||
render={({ field: { value, onChange, ref } }) => ( | ||
<Input | ||
id="EMAIL_HOST_PASSWORD" | ||
name="EMAIL_HOST_PASSWORD" | ||
type="text" | ||
value={value} | ||
onChange={onChange} | ||
ref={ref} | ||
hasError={Boolean(errors.EMAIL_HOST_PASSWORD)} | ||
placeholder="Password" | ||
className="rounded-md font-medium w-full" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div className="flex items-center gap-8 pt-4"> | ||
<div> | ||
<div className="text-custom-text-100 font-medium text-sm">Enable TLS</div> | ||
</div> | ||
<div> | ||
<Controller | ||
control={control} | ||
name="EMAIL_USE_TLS" | ||
render={({ field: { value, onChange } }) => ( | ||
<ToggleSwitch | ||
value={Boolean(parseInt(value))} | ||
onChange={() => { | ||
Boolean(parseInt(value)) === true ? onChange("0") : onChange("1"); | ||
}} | ||
size="sm" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div className="flex items-center gap-8 pt-4"> | ||
<div> | ||
<div className="text-custom-text-100 font-medium text-sm">Enable SSL</div> | ||
</div> | ||
<div> | ||
<Controller | ||
control={control} | ||
name="EMAIL_USE_SSL" | ||
render={({ field: { value, onChange } }) => ( | ||
<ToggleSwitch | ||
value={Boolean(parseInt(value))} | ||
onChange={() => { | ||
Boolean(parseInt(value)) === true ? onChange("0") : onChange("1"); | ||
}} | ||
size="sm" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
</div> | ||
|
||
<div className="flex items-center py-1"> | ||
<Button variant="primary" onClick={handleSubmit(onSubmit)} loading={isSubmitting}> | ||
{isSubmitting ? "Saving..." : "Save Changes"} | ||
</Button> | ||
</div> | ||
</div> | ||
); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,132 @@ | ||
import { FC } from "react"; | ||
import { Controller, useForm } from "react-hook-form"; | ||
// ui | ||
import { Button, Input } from "@plane/ui"; | ||
// types | ||
import { IFormattedInstanceConfiguration } from "types/instance"; | ||
// hooks | ||
import useToast from "hooks/use-toast"; | ||
// mobx store | ||
import { useMobxStore } from "lib/mobx/store-provider"; | ||
// icons | ||
import { Copy } from "lucide-react"; | ||
|
||
export interface IInstanceGithubConfigForm { | ||
config: IFormattedInstanceConfiguration; | ||
} | ||
|
||
export interface GithubConfigFormValues { | ||
GITHUB_CLIENT_ID: string; | ||
GITHUB_CLIENT_SECRET: string; | ||
} | ||
|
||
export const InstanceGithubConfigForm: FC<IInstanceGithubConfigForm> = (props) => { | ||
const { config } = props; | ||
// store | ||
const { instance: instanceStore } = useMobxStore(); | ||
// toast | ||
const { setToastAlert } = useToast(); | ||
// form data | ||
const { | ||
handleSubmit, | ||
control, | ||
formState: { errors, isSubmitting }, | ||
} = useForm<GithubConfigFormValues>({ | ||
defaultValues: { | ||
GITHUB_CLIENT_ID: config["GITHUB_CLIENT_ID"], | ||
GITHUB_CLIENT_SECRET: config["GITHUB_CLIENT_SECRET"], | ||
}, | ||
}); | ||
|
||
const onSubmit = async (formData: GithubConfigFormValues) => { | ||
const payload: Partial<GithubConfigFormValues> = { ...formData }; | ||
|
||
await instanceStore | ||
.updateInstanceConfigurations(payload) | ||
.then(() => | ||
setToastAlert({ | ||
title: "Success", | ||
type: "success", | ||
message: "Github Configuration Settings updated successfully", | ||
}) | ||
) | ||
.catch((err) => console.error(err)); | ||
}; | ||
|
||
const originURL = typeof window !== "undefined" ? window.location.origin : ""; | ||
|
||
return ( | ||
<> | ||
<div className="grid grid-col grid-cols-1 lg:grid-cols-2 items-center justify-between gap-x-16 gap-y-8 w-full"> | ||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Client ID</h4> | ||
<Controller | ||
control={control} | ||
name="GITHUB_CLIENT_ID" | ||
render={({ field: { value, onChange, ref } }) => ( | ||
<Input | ||
id="GITHUB_CLIENT_ID" | ||
name="GITHUB_CLIENT_ID" | ||
type="text" | ||
value={value} | ||
onChange={onChange} | ||
ref={ref} | ||
hasError={Boolean(errors.GITHUB_CLIENT_ID)} | ||
placeholder="Github Client ID" | ||
className="rounded-md font-medium w-full" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Client Secret</h4> | ||
<Controller | ||
control={control} | ||
name="GITHUB_CLIENT_SECRET" | ||
render={({ field: { value, onChange, ref } }) => ( | ||
<Input | ||
id="GITHUB_CLIENT_SECRET" | ||
name="GITHUB_CLIENT_SECRET" | ||
type="text" | ||
value={value} | ||
onChange={onChange} | ||
ref={ref} | ||
hasError={Boolean(errors.GITHUB_CLIENT_SECRET)} | ||
placeholder="Github Client Secret" | ||
className="rounded-md font-medium w-full" | ||
/> | ||
)} | ||
/> | ||
</div> | ||
</div> | ||
<div className="grid grid-col grid-cols-1 lg:grid-cols-2 items-center justify-between gap-x-16 gap-y-8 w-full"> | ||
<div className="flex flex-col gap-1"> | ||
<h4 className="text-sm">Origin URL</h4> | ||
<Button | ||
variant="neutral-primary" | ||
className="py-2 flex justify-between items-center" | ||
onClick={() => { | ||
navigator.clipboard.writeText(originURL); | ||
setToastAlert({ | ||
message: "The Origin URL has been successfully copied to your clipboard", | ||
type: "success", | ||
title: "Copied to clipboard", | ||
}); | ||
}} | ||
> | ||
<p className="font-medium text-sm">{originURL}</p> | ||
<Copy size={18} color="#B9B9B9" /> | ||
</Button> | ||
<p className="text-xs text-custom-text-400/60">*paste this URL in your Github console.</p> | ||
</div> | ||
<div className="flex flex-col gap-1"> | ||
<div className="flex items-center p-2"> | ||
<Button variant="primary" onClick={handleSubmit(onSubmit)} loading={isSubmitting}> | ||
{isSubmitting ? "Saving..." : "Save Changes"} | ||
</Button> | ||
</div> | ||
</div> | ||
</div> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.