Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Instance Admin Panel: Configuration Settings #2800

Merged
merged 5 commits into from
Nov 20, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions packages/ui/src/icons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ export * from "./transfer-icon";
export * from "./running-icon";
export * from "./calendar-before-icon";
export * from "./calendar-after-icon";
export * from "./openai-icon";
prateekshourya29 marked this conversation as resolved.
Show resolved Hide resolved
24 changes: 24 additions & 0 deletions packages/ui/src/icons/openai-icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react";

import { ISvgIcons } from "./type";

export const OpenAIIcon: React.FC<ISvgIcons> = ({
width = "24",
height = "24",
className,
color,
}) => (
<svg
width={width}
height={height}
className={className}
viewBox="0 0 16 16"
fill="currentColor"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill={color ? color : "currentColor"}
d="M14.9449 6.63667C15.3128 5.53251 15.1861 4.32296 14.5978 3.31862C13.7131 1.77818 11.9345 0.985658 10.1974 1.35861C9.42464 0.488052 8.3144 -0.00701896 7.15045 7.52099e-05C5.37487 -0.0039786 3.79946 1.1392 3.2532 2.82862C2.11256 3.06222 1.12799 3.7762 0.551837 4.78813C-0.339497 6.32452 -0.1363 8.26123 1.05451 9.57872C0.686626 10.6829 0.813308 11.8924 1.40162 12.8968C2.28637 14.4372 4.06498 15.2297 5.80204 14.8568C6.5743 15.7273 7.68504 16.2224 8.849 16.2148C10.6256 16.2194 12.2015 15.0752 12.7478 13.3842C13.8884 13.1506 14.873 12.4367 15.4491 11.4247C16.3394 9.88833 16.1357 7.95314 14.9454 6.63565L14.9449 6.63667ZM8.85001 15.1552C8.13907 15.1563 7.45043 14.9075 6.90468 14.4519C6.92951 14.4387 6.97259 14.4149 7.00046 14.3977L10.2293 12.5329C10.3945 12.4392 10.4959 12.2634 10.4949 12.0733V7.52141L11.8595 8.30937C11.8742 8.31646 11.8838 8.33065 11.8858 8.34687V12.1164C11.8838 13.7927 10.5263 15.1517 8.85001 15.1552ZM2.32133 12.3667C1.9651 11.7516 1.8369 11.0305 1.95902 10.3307C1.98284 10.3449 2.02489 10.3707 2.05479 10.388L5.28366 12.2527C5.44733 12.3485 5.65003 12.3485 5.81421 12.2527L9.75604 9.9765V11.5524C9.75705 11.5686 9.74945 11.5843 9.73678 11.5945L6.47295 13.479C5.01915 14.3161 3.1625 13.8185 2.32184 12.3667H2.32133ZM1.47155 5.31867C1.82626 4.70249 2.38619 4.23124 3.05305 3.98649C3.05305 4.01436 3.05152 4.06351 3.05152 4.09797V7.82798C3.05051 8.0175 3.15186 8.19333 3.31654 8.28707L7.25838 10.5628L5.89376 11.3507C5.88008 11.3599 5.86285 11.3614 5.84765 11.3548L2.58331 9.46876C1.13255 8.62861 0.63494 6.77247 1.47104 5.31918L1.47155 5.31867ZM12.6834 7.9278L8.74157 5.65159L10.1062 4.86414C10.1199 4.85502 10.1371 4.8535 10.1523 4.86009L13.4166 6.7446C14.8699 7.58425 15.3681 9.44342 14.5284 10.8967C14.1732 11.5119 13.6138 11.9831 12.9474 12.2284V8.3869C12.9489 8.19738 12.8481 8.02206 12.6839 7.9278H12.6834ZM14.0414 5.88367C14.0176 5.86898 13.9756 5.84364 13.9457 5.82641L10.7168 3.96166C10.5531 3.86589 10.3504 3.86589 10.1863 3.96166L6.24442 6.23787V4.66196C6.2434 4.64574 6.251 4.63003 6.26367 4.6199L9.52751 2.7369C10.9813 1.89827 12.84 2.3974 13.6781 3.8517C14.0323 4.46585 14.1605 5.1849 14.0404 5.88367H14.0414ZM5.50257 8.69245L4.13744 7.9045C4.12275 7.8974 4.11312 7.88321 4.11109 7.867V4.09746C4.11211 2.41919 5.47368 1.05913 7.15197 1.06015C7.86189 1.06015 8.54902 1.30946 9.09476 1.76348C9.06993 1.77666 9.02737 1.80047 8.99899 1.8177L5.77012 3.68245C5.60493 3.7762 5.50358 3.95153 5.50459 4.14155L5.50257 8.69144V8.69245ZM6.24391 7.09424L7.99972 6.08028L9.75553 7.09373V9.12115L7.99972 10.1346L6.24391 9.12115V7.09424Z"
/>
</svg>
);
287 changes: 287 additions & 0 deletions web/components/instance/authorization-form.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,287 @@
import { FC } from "react";
import { Controller, useForm } from "react-hook-form";
// ui
import { Button, Input, ToggleSwitch } from "@plane/ui";
import { Disclosure, Transition } from "@headlessui/react";
// types
import { IFormattedInstanceConfiguration } from "types/instance";
// hooks
import useToast from "hooks/use-toast";
// mobx store
import { useMobxStore } from "lib/mobx/store-provider";
// icons
import { ChevronDown, ChevronRight, Copy } from "lucide-react";

export interface IInstanceAuthorizationForm {
config: IFormattedInstanceConfiguration;
}

export interface AuthorizationFormValues {
ENABLE_SIGNUP: string;
GOOGLE_CLIENT_ID: string;
GOOGLE_CLIENT_SECRET: string;
GITHUB_CLIENT_ID: string;
GITHUB_CLIENT_SECRET: string;
}

export const InstanceAuthorizationForm: FC<IInstanceAuthorizationForm> = (props) => {
const { config } = props;
// store
const { instance: instanceStore } = useMobxStore();
// toast
const { setToastAlert } = useToast();
// form data
const {
handleSubmit,
control,
formState: { errors, isSubmitting },
} = useForm<AuthorizationFormValues>({
defaultValues: {
ENABLE_SIGNUP: config["ENABLE_SIGNUP"],
GOOGLE_CLIENT_ID: config["GOOGLE_CLIENT_ID"],
GOOGLE_CLIENT_SECRET: config["GOOGLE_CLIENT_SECRET"],
GITHUB_CLIENT_ID: config["GITHUB_CLIENT_ID"],
GITHUB_CLIENT_SECRET: config["GITHUB_CLIENT_SECRET"],
},
});

const onSubmit = async (formData: AuthorizationFormValues) => {
const payload: Partial<AuthorizationFormValues> = { ...formData };

await instanceStore
.updateInstanceConfigurations(payload)
.then(() =>
setToastAlert({
title: "Success",
type: "success",
message: "Authorization Settings updated successfully",
})
)
.catch((err) => console.error(err));
};

const originURL = typeof window !== "undefined" ? window.location.origin : "";

return (
<div className="flex flex-col gap-8 m-8 w-4/5">
<div className="flex items-center gap-8 pb-4 border-b border-custom-border-100">
<div>
<div className="text-custom-text-100 font-medium text-sm">Enable sign-up</div>
<div className="text-custom-text-300 font-normal text-xs">
Keep the doors open so people can join your workspaces.
</div>
</div>
<div>
<Controller
control={control}
name="ENABLE_SIGNUP"
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 flex-col gap-y-6 py-2">
<Disclosure as="div">
{({ open }) => (
<div className="w-full">
<Disclosure.Button
as="button"
type="button"
className="flex items-center justify-between w-full py-2 border-b border-custom-border-100"
>
<span className="text-lg font-medium tracking-tight">Google</span>
{open ? <ChevronDown className="h-5 w-5" /> : <ChevronRight className="h-5 w-5" />}
</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 className="flex flex-col gap-8 px-2 py-8">
<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
prateekshourya29 marked this conversation as resolved.
Show resolved Hide resolved
control={control}
name="GOOGLE_CLIENT_ID"
render={({ field: { value, onChange, ref } }) => (
<Input
id="GOOGLE_CLIENT_ID"
name="GOOGLE_CLIENT_ID"
type="text"
value={value}
onChange={onChange}
ref={ref}
hasError={Boolean(errors.GOOGLE_CLIENT_ID)}
placeholder="Google 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="GOOGLE_CLIENT_SECRET"
render={({ field: { value, onChange, ref } }) => (
<Input
id="GOOGLE_CLIENT_SECRET"
name="GOOGLE_CLIENT_SECRET"
type="text"
value={value}
onChange={onChange}
ref={ref}
hasError={Boolean(errors.GOOGLE_CLIENT_SECRET)}
placeholder="Google 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 Google developer console.
</p>
</div>
</div>
</Disclosure.Panel>
</Transition>
</div>
)}
</Disclosure>
<Disclosure as="div">
{({ open }) => (
<div className="w-full">
<Disclosure.Button
as="button"
type="button"
className="flex items-center justify-between w-full py-2 border-b border-custom-border-100"
>
<span className="text-lg font-medium tracking-tight">Github</span>
{open ? <ChevronDown className="h-5 w-5" /> : <ChevronRight className="h-5 w-5" />}
</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 className="flex flex-col gap-8 px-2 py-8">
<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>
</Disclosure.Panel>
</Transition>
</div>
)}
</Disclosure>
</div>

<div className="flex items-center py-2">
<Button variant="primary" onClick={handleSubmit(onSubmit)} loading={isSubmitting}>
{isSubmitting ? "Saving..." : "Save Changes"}
</Button>
</div>
</div>
);
};
Loading
Loading