feature: project templates with docs

This commit is contained in:
Scott Wilson
2024-11-06 23:12:32 -08:00
parent c6fa647825
commit 9b246166a1
72 changed files with 2847 additions and 104 deletions
+91 -17
View File
@@ -19,6 +19,7 @@ import {
faExclamationCircle,
faFileShield,
faHandPeace,
faInfoCircle,
faList,
faMagnifyingGlass,
faNetworkWired,
@@ -69,6 +70,10 @@ import {
useRegisterUserAction
} from "@app/hooks/api";
import { INTERNAL_KMS_KEY_ID } from "@app/hooks/api/kms/types";
import {
DefaultProjectTemplateIdentifier,
useListProjectTemplates
} from "@app/hooks/api/projectTemplates";
// import { fetchUserWsKey } from "@app/hooks/api/keys/queries";
import { useFetchServerStatus } from "@app/hooks/api/serverDetails";
import { Workspace } from "@app/hooks/api/types";
@@ -482,7 +487,8 @@ const formSchema = yup.object({
.trim()
.max(64, "Too long, maximum length is 64 characters"),
addMembers: yup.bool().required().label("Add Members"),
kmsKeyId: yup.string().label("KMS Key ID")
kmsKeyId: yup.string().label("KMS Key ID"),
templateId: yup.string().label("Project Template ID")
});
type TAddProjectFormData = yup.InferType<typeof formSchema>;
@@ -537,7 +543,12 @@ const OrganizationPage = () => {
enabled: permission.can(OrgPermissionActions.Read, OrgPermissionSubjects.Kms)
});
const onCreateProject = async ({ name, addMembers, kmsKeyId }: TAddProjectFormData) => {
const onCreateProject = async ({
name,
addMembers,
kmsKeyId,
templateId
}: TAddProjectFormData) => {
// type check
if (!currentOrg) return;
if (!user) return;
@@ -548,7 +559,8 @@ const OrganizationPage = () => {
}
} = await createWs.mutateAsync({
projectName: name,
kmsKeyId: kmsKeyId !== INTERNAL_KMS_KEY_ID ? kmsKeyId : undefined
kmsKeyId: kmsKeyId !== INTERNAL_KMS_KEY_ID ? kmsKeyId : undefined,
templateId: templateId === DefaultProjectTemplateIdentifier ? undefined : templateId
});
if (addMembers) {
@@ -579,6 +591,15 @@ const OrganizationPage = () => {
const { subscription } = useSubscription();
const canReadProjectTemplates = permission.can(
OrgPermissionActions.Read,
OrgPermissionSubjects.ProjectTemplates
);
const { data: projectTemplates = [] } = useListProjectTemplates({
enabled: canReadProjectTemplates && subscription?.projectTemplates
});
const isAddingProjectsAllowed = subscription?.workspaceLimit
? subscription.workspacesUsed < subscription.workspaceLimit
: true;
@@ -1037,20 +1058,73 @@ const OrganizationPage = () => {
subTitle="This project will contain your secrets and configurations."
>
<form onSubmit={handleSubmit(onCreateProject)}>
<Controller
control={control}
name="name"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Project Name"
isError={Boolean(error)}
errorText={error?.message}
>
<Input {...field} placeholder="Type your project name" />
</FormControl>
)}
/>
<div className="flex gap-2">
<Controller
control={control}
name="name"
defaultValue=""
render={({ field, fieldState: { error } }) => (
<FormControl
label="Project Name"
isError={Boolean(error)}
errorText={error?.message}
className="flex-1"
>
<Input {...field} placeholder="Type your project name" />
</FormControl>
)}
/>
<Controller
control={control}
name="templateId"
render={({ field: { value, onChange } }) => (
<OrgPermissionCan
I={OrgPermissionActions.Read}
a={OrgPermissionSubjects.ProjectTemplates}
>
{(isAllowed) => (
<FormControl
label="Project Template"
icon={<FontAwesomeIcon icon={faInfoCircle} size="sm" />}
tooltipText={
<>
<p>
Create this project from a template to provision it with custom
environments and roles.
</p>
{subscription && !subscription.projectTemplates && (
<p className="pt-2">Project templates are a paid feature.</p>
)}
</>
}
>
<Select
defaultValue={DefaultProjectTemplateIdentifier}
placeholder={DefaultProjectTemplateIdentifier}
isDisabled={!isAllowed || !subscription?.projectTemplates}
value={value}
onValueChange={onChange}
className="w-44"
>
<SelectItem value={DefaultProjectTemplateIdentifier}>
{DefaultProjectTemplateIdentifier}
</SelectItem>
{projectTemplates
.filter(
(template) => template.name !== DefaultProjectTemplateIdentifier
)
.map((template) => (
<SelectItem key={template.id} value={template.id}>
{template.name}
</SelectItem>
))}
</Select>
</FormControl>
)}
</OrgPermissionCan>
)}
/>
</div>
<div className="mt-4 pl-1">
<Controller
control={control}