Skip to content

Commit

Permalink
feat: [WD-16398] Set default storage pool for new project... (#982)
Browse files Browse the repository at this point in the history
...on creation

## Done
- Create new project case
    - Used StoragePool Selector component
    - Disabled storage pool selector (sps) when profiles are shared.
- Selected storage pool becomes project's default profile's storage pool
when saved.
    - Error handling.
- Edit project case
    - Storage pool is disabled
- Help text shown to direct the user on where to edit the storage pool
- Initial value of storage pool is set to be the default profile's
storage pool.

## QA

1. Run the LXD-UI:
- On the demo server via the link posted by @webteam-app below. This is
only available for PRs created by collaborators of the repo. Ask
@mas-who or @edlerd for access.
- With a local copy of this branch, [build and run as described in the
docs](../CONTRIBUTING.md#setting-up-for-development).
2. Perform the following QA steps:
- [List the steps to QA the new feature(s) or prove that a bug has been
resolved]

## Screenshots


![image](https://github.com/user-attachments/assets/b8dcfcfe-6f16-419e-8f16-1a5d63c76406)
  • Loading branch information
Kxiru authored Nov 8, 2024
2 parents de45aa3 + 238e344 commit 49e0323
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 137 deletions.
69 changes: 54 additions & 15 deletions src/pages/projects/CreateProject.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { FC, useEffect, useState } from "react";
import { ActionButton, Button, useNotify } from "@canonical/react-components";
import { useFormik } from "formik";
import * as Yup from "yup";
import { useQueryClient } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "util/queryKeys";
import { checkDuplicateName } from "util/helpers";
import { checkDuplicateName, getDefaultStoragePool } from "util/helpers";
import { useNavigate } from "react-router-dom";
import { updateMaxHeight } from "util/updateMaxHeight";
import useEventListener from "@use-it/event-listener";
Expand Down Expand Up @@ -42,6 +42,7 @@ import { slugify } from "util/slugify";
import { useToastNotification } from "context/toastNotificationProvider";
import { useSupportedFeatures } from "context/useSupportedFeatures";
import ResourceLink from "components/ResourceLink";
import { fetchProfile, updateProfile } from "api/profiles";

export type ProjectFormValues = ProjectDetailsFormValues &
ProjectResourceLimitsFormValues &
Expand All @@ -60,6 +61,11 @@ const CreateProject: FC = () => {
const { hasProjectsNetworksZones, hasStorageBuckets } =
useSupportedFeatures();

const { data: profile } = useQuery({
queryKey: [queryKeys.profiles, "default", "default"],
queryFn: () => fetchProfile("default", "default"),
});

const ProjectSchema = Yup.object().shape({
name: Yup.string()
.test("deduplicate", "A project with this name already exists", (value) =>
Expand All @@ -74,12 +80,30 @@ const CreateProject: FC = () => {
useEffect(updateFormHeight, [notify.notification?.message, section]);
useEventListener("resize", updateFormHeight);

const notifySuccess = (values: ProjectFormValues) => {
navigate(`/ui/project/${values.name}/instances`);
toastNotify.success(
<>
Project{" "}
<ResourceLink
type="project"
value={values.name}
to={`/ui/project/${values.name}/instances`}
/>{" "}
created.
</>,
);
};

const formik = useFormik<ProjectFormValues>({
initialValues: {
name: "",
restricted: false,
readOnly: false,
entityType: "project",
default_instance_storage_pool: profile
? getDefaultStoragePool(profile)
: "",
},
validationSchema: ProjectSchema,
onSubmit: (values) => {
Expand Down Expand Up @@ -110,19 +134,34 @@ const CreateProject: FC = () => {
},
}),
)
.then(() => {
navigate(`/ui/project/${values.name}/instances`);
toastNotify.success(
<>
Project{" "}
<ResourceLink
type="project"
value={values.name}
to={`/ui/project/${values.name}/instances`}
/>{" "}
created.
</>,
);
.then(async () => {
if (
!values.default_instance_storage_pool ||
values.features_profiles === false
) {
notifySuccess(values);
return;
}
const profile = await fetchProfile("default", values.name);
profile.devices = {
root: {
path: "/",
pool: values.default_instance_storage_pool,
type: "disk",
},
};

updateProfile(profile, values.name)
.then(() => {
notifySuccess(values);
})
.catch((e: Error) => {
navigate(`/ui/project/${values.name}/instances`);
toastNotify.failure(
`Successfully created ${profile.name}, Failed to attach storage pool`,
e,
);
});
})
.catch((e: Error) => {
formik.setSubmitting(false);
Expand Down
9 changes: 7 additions & 2 deletions src/pages/projects/EditProject.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FC, useEffect } from "react";
import { Button, useNotify } from "@canonical/react-components";
import { updateProject } from "api/projects";
import { useQueryClient } from "@tanstack/react-query";
import { useQuery, useQueryClient } from "@tanstack/react-query";
import { queryKeys } from "util/queryKeys";
import { PROJECT_DETAILS } from "pages/projects/forms/ProjectFormMenu";
import { useFormik } from "formik";
Expand All @@ -23,6 +23,7 @@ import { useToastNotification } from "context/toastNotificationProvider";
import { useSupportedFeatures } from "context/useSupportedFeatures";
import FormSubmitBtn from "components/forms/FormSubmitBtn";
import ResourceLink from "components/ResourceLink";
import { fetchProfile } from "api/profiles";

interface Props {
project: LxdProject;
Expand All @@ -38,6 +39,10 @@ const EditProject: FC<Props> = ({ project }) => {
const { hasProjectsNetworksZones, hasStorageBuckets } =
useSupportedFeatures();

const { data: profile } = useQuery({
queryKey: [queryKeys.profiles, "default", project.name],
queryFn: () => fetchProfile("default", project.name),
});
const updateFormHeight = () => {
updateMaxHeight("form-contents", "p-bottom-controls");
};
Expand All @@ -48,7 +53,7 @@ const EditProject: FC<Props> = ({ project }) => {
name: Yup.string().required(),
});

const initialValues = getProjectEditValues(project);
const initialValues = getProjectEditValues(project, profile);

const formik: FormikProps<ProjectFormValues> = useFormik({
initialValues: initialValues,
Expand Down
Loading

0 comments on commit 49e0323

Please sign in to comment.