Browse Source

misc preview ui fixes (#4129)

ianedwards 2 years ago
parent
commit
7fb495933b

+ 2 - 2
dashboard/src/lib/addons/index.ts

@@ -38,14 +38,14 @@ export function defaultClientAddon(
     .with("postgres", () =>
       clientAddonValidator.parse({
         expanded: true,
-        name: { readOnly: false, value: "addon" },
+        name: { readOnly: false, value: "postgres" },
         config: defaultPostgresAddon(),
       })
     )
     .with("redis", () =>
       clientAddonValidator.parse({
         expanded: true,
-        name: { readOnly: false, value: "addon" },
+        name: { readOnly: false, value: "redis" },
         config: redisConfigValidator.parse({
           type: "redis",
         }),

+ 4 - 4
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/PreviewEnvs.tsx

@@ -42,15 +42,15 @@ const PreviewEnvs: React.FC = () => {
     <StyledAppDashboard>
       <DashboardHeader
         image={PullRequestIcon}
-        title="Preview Environments"
-        description="Preview environments are created for each pull request. They are automatically deleted when the pull request is closed."
+        title="Preview Apps"
+        description="Preview apps are created for each pull request. They are automatically deleted when the pull request is closed."
         disableLineBreak
       />
       <TabSelector
         noBuffer
         options={[
-          { label: "Environments", value: "environments" },
-          { label: "Settings", value: "config" },
+          { label: "Existing Previews", value: "environments" },
+          { label: "Preview Templates", value: "config" },
         ]}
         currentTab={tab}
         setCurrentTab={(tab: string) => {

+ 12 - 8
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/Addons.tsx

@@ -2,10 +2,10 @@ import React from "react";
 import _ from "lodash";
 import { useFormContext } from "react-hook-form";
 
-import Button from "components/porter/Button";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import { type ButtonStatus } from "main/home/app-dashboard/app-view/AppDataContainer";
+import AppSaveButton from "main/home/app-dashboard/app-view/AppSaveButton";
 import { AddonsList } from "main/home/managed-addons/AddonsList";
 import { type PorterAppFormData } from "lib/porter-apps";
 
@@ -22,16 +22,20 @@ export const Addons: React.FC<Props> = ({ buttonStatus }) => {
     <>
       <Text size={16}>Add-ons</Text>
       <Spacer y={0.5} />
+      <Text color="helper">
+        Include any add-ons you would like to be created with your preview app.
+        These are also ephemeral and will only be accessible for the lifetime of
+        the preview app.
+      </Text>
+      <Spacer y={0.5} />
       <AddonsList />
       <Spacer y={0.75} />
-      <Button
-        type="submit"
+      <AppSaveButton
         status={buttonStatus}
-        loadingText={"Updating..."}
-        disabled={isSubmitting}
-      >
-        Update app
-      </Button>
+        isDisabled={isSubmitting}
+        disabledTooltipMessage={"Please fill out all required fields"}
+        disabledTooltipPosition={"top"}
+      />
     </>
   );
 };

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/PreviewAppDataContainer.tsx

@@ -331,8 +331,8 @@ export const PreviewAppDataContainer: React.FC<Props> = ({
           { label: "Environment Variables", value: "variables" },
           ...(currentProject?.beta_features_enabled
             ? [
-                // { label: "Required Apps", value: "required-apps" },
-                // { label: "Add-ons", value: "addons" },
+                { label: "Required Apps", value: "required-apps" },
+                { label: "Add-ons", value: "addons" },
               ]
             : []),
         ]}

+ 12 - 8
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/RequiredApps.tsx

@@ -9,12 +9,12 @@ import {
 import styled from "styled-components";
 import { z } from "zod";
 
-import Button from "components/porter/Button";
 import Container from "components/porter/Container";
 import Icon from "components/porter/Icon";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import { type ButtonStatus } from "main/home/app-dashboard/app-view/AppDataContainer";
+import AppSaveButton from "main/home/app-dashboard/app-view/AppSaveButton";
 import { useLatestRevision } from "main/home/app-dashboard/app-view/LatestRevisionContext";
 import { AppIcon, AppSource } from "main/home/app-dashboard/apps/AppMeta";
 import {
@@ -145,6 +145,12 @@ export const RequiredApps: React.FC<Props> = ({ buttonStatus }) => {
     <div>
       <Text size={16}>Required Apps</Text>
       <Spacer y={0.5} />
+      <Text color="helper">
+        Apps from other repositories that should be deployed alongside previews
+        of {porterApp.name}. Any selected app will be a copy of the main app
+        running on the cluster.
+      </Text>
+      <Spacer y={0.5} />
       <RequiredAppList>
         {remainingApps.map((ra) => {
           const selectedAppIdx = fields.findIndex(
@@ -168,14 +174,12 @@ export const RequiredApps: React.FC<Props> = ({ buttonStatus }) => {
         })}
       </RequiredAppList>
       <Spacer y={0.75} />
-      <Button
-        type="submit"
+      <AppSaveButton
         status={buttonStatus}
-        loadingText={"Updating..."}
-        disabled={isSubmitting}
-      >
-        Update app
-      </Button>
+        isDisabled={isSubmitting}
+        disabledTooltipMessage={"Please fill out all required fields"}
+        disabledTooltipPosition={"top"}
+      />
     </div>
   );
 };

+ 6 - 8
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/ServiceSettings.tsx

@@ -2,10 +2,10 @@ import React from "react";
 import _ from "lodash";
 import { useFormContext } from "react-hook-form";
 
-import Button from "components/porter/Button";
 import Spacer from "components/porter/Spacer";
 import Text from "components/porter/Text";
 import { type ButtonStatus } from "main/home/app-dashboard/app-view/AppDataContainer";
+import AppSaveButton from "main/home/app-dashboard/app-view/AppSaveButton";
 import { useLatestRevision } from "main/home/app-dashboard/app-view/LatestRevisionContext";
 import ServiceList from "main/home/app-dashboard/validate-apply/services-settings/ServiceList";
 import { type PorterAppFormData } from "lib/porter-apps";
@@ -59,14 +59,12 @@ export const ServiceSettings: React.FC<Props> = ({ buttonStatus }) => {
         allowAddServices={false}
       />
       <Spacer y={0.75} />
-      <Button
-        type="submit"
+      <AppSaveButton
         status={buttonStatus}
-        loadingText={"Updating..."}
-        disabled={isSubmitting}
-      >
-        Update app
-      </Button>
+        isDisabled={isSubmitting}
+        disabledTooltipMessage={"Please fill out all required fields"}
+        disabledTooltipPosition={"top"}
+      />
     </>
   );
 };

+ 2 - 2
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/setup-app/SetupApp.tsx

@@ -83,8 +83,8 @@ const SetupApp: React.FC<Props> = ({ location }) => {
             <Back to="/preview-environments" />
             <DashboardHeader
               prefix={<Icon src={pull_request} />}
-              title={`Preview environments for ${appName}`}
-              description="Set preview environment specific configuration for this application below. Any newly created preview environments will use these settings."
+              title={`Preview apps for ${appName}`}
+              description="Set preview specific configuration for this app below. Any newly created preview apps will use these settings."
               capitalize={false}
               disableLineBreak
             />

+ 11 - 8
dashboard/src/main/home/cluster-dashboard/preview-environments/v2/types.ts

@@ -20,15 +20,18 @@ export const existingTemplateWithEnvValidator = z.object({
         secrets: z.record(z.string()).default({}),
       })
     )
+    .nullable()
     .transform((addons) =>
-      addons.map((a) => {
-        return {
-          ...a,
-          addon: Addon.fromJsonString(atob(a.base64_addon), {
-            ignoreUnknownFields: true,
-          }),
-        };
-      })
+      addons
+        ? addons.map((a) => {
+            return {
+              ...a,
+              addon: Addon.fromJsonString(atob(a.base64_addon), {
+                ignoreUnknownFields: true,
+              }),
+            };
+          })
+        : []
     ),
 });
 

+ 5 - 55
dashboard/src/main/home/managed-addons/AddonsList.tsx

@@ -1,4 +1,4 @@
-import React, { useEffect, useState } from "react";
+import React, { useState } from "react";
 import { zodResolver } from "@hookform/resolvers/zod";
 import {
   Controller,
@@ -12,7 +12,6 @@ import { z } from "zod";
 
 import Button from "components/porter/Button";
 import Container from "components/porter/Container";
-import { ControlledInput } from "components/porter/ControlledInput";
 import Modal from "components/porter/Modal";
 import Select from "components/porter/Select";
 import Spacer from "components/porter/Spacer";
@@ -26,13 +25,6 @@ import redis from "assets/redis.svg";
 import { AddonListRow } from "./AddonListRow";
 
 const addAddonFormValidator = z.object({
-  name: z
-    .string()
-    .min(1, { message: "A service name is required" })
-    .max(30)
-    .regex(/^[a-z0-9-]+$/, {
-      message: 'Lowercase letters, numbers, and " - " only.',
-    }),
   type: z.enum(["postgres", "redis"]),
 });
 type AddAddonFormValues = z.infer<typeof addAddonFormValidator>;
@@ -43,25 +35,14 @@ export const AddonsList: React.FC = () => {
   const { control: appTemplateControl } = useFormContext<AppTemplateFormData>();
 
   // add addon modal form
-  const {
-    register,
-    watch,
-    control,
-    reset,
-    handleSubmit,
-    formState: { errors },
-    setError,
-    clearErrors,
-  } = useForm<AddAddonFormValues>({
+  const { watch, control, reset, handleSubmit } = useForm<AddAddonFormValues>({
     reValidateMode: "onChange",
     resolver: zodResolver(addAddonFormValidator),
     defaultValues: {
-      name: "",
       type: "postgres",
     },
   });
 
-  const addonName = watch("name");
   const addonType = watch("type");
 
   const { append, update, remove, fields } = useFieldArray({
@@ -69,26 +50,9 @@ export const AddonsList: React.FC = () => {
     name: "addons",
   });
 
-  useEffect(() => {
-    const existingAddonNames = fields.map((f) => f.name);
-    if (existingAddonNames.some((n) => n.value === addonName)) {
-      setError("name", {
-        message: "Addon name must be unique",
-      });
-    } else {
-      clearErrors("name");
-    }
-  }, [fields]);
-
   const onSubmit = handleSubmit((data) => {
     const baseAddon = defaultClientAddon(data.type);
-    append({
-      ...baseAddon,
-      name: {
-        value: data.name,
-        readOnly: false,
-      },
-    });
+    append(baseAddon);
 
     reset();
     setShowAddAddonModal(false);
@@ -153,22 +117,8 @@ export const AddonsList: React.FC = () => {
             />
           </Container>
           <Spacer y={1} />
-          <Text color="helper">Name this service:</Text>
-          <Spacer y={0.5} />
-          <ControlledInput
-            type="text"
-            placeholder="ex: my-postgres"
-            width="100%"
-            error={errors.name?.message}
-            {...register("name")}
-          />
-          <Spacer y={1} />
-          <Button
-            type="button"
-            onClick={onSubmit}
-            disabled={!!errors.name?.message}
-          >
-            <I className="material-icons">add</I> Add service
+          <Button type="button" onClick={onSubmit}>
+            <I className="material-icons">add</I> Add
           </Button>
         </Modal>
       )}

+ 2 - 2
dashboard/src/main/home/sidebar/Sidebar.tsx

@@ -260,7 +260,7 @@ class Sidebar extends Component<PropsType, StateType> {
             {currentProject.preview_envs_enabled && (
               <NavButton path="/preview-environments">
                 <Img src={pr_icon} />
-                Preview environments
+                Preview apps
               </NavButton>
             )}
 
@@ -327,7 +327,7 @@ class Sidebar extends Component<PropsType, StateType> {
             {currentProject.preview_envs_enabled && (
               <NavButton path="/preview-environments">
                 <Img src={pr_icon} />
-                Preview environments
+                Preview apps
               </NavButton>
             )}