Skip to content

Commit

Permalink
genericize types, add controlled input password view (#4591)
Browse files Browse the repository at this point in the history
  • Loading branch information
Feroze Mohideen authored Apr 30, 2024
1 parent f5ef333 commit 5099d3a
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 76 deletions.
1 change: 1 addition & 0 deletions dashboard/src/assets/eye-off.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions dashboard/src/assets/eye.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
60 changes: 42 additions & 18 deletions dashboard/src/components/porter/ControlledInput.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import React from "react";
import React, { useState } from "react";
import styled from "styled-components";

import eyeOff from "assets/eye-off.svg";
import eye from "assets/eye.svg";

import Container from "./Container";
import Icon from "./Icon";
import Spacer from "./Spacer";
import Tooltip from "./Tooltip";

/*
Expand Down Expand Up @@ -45,6 +52,11 @@ export const ControlledInput = React.forwardRef<
},
ref
) => {
const [isVisible, setIsVisible] = useState(false);
const toggleVisibility = (): void => {
setIsVisible(!isVisible);
};

return disabled && disabledTooltip ? (
<Tooltip content={disabledTooltip} position="right">
<Block width={width}>
Expand Down Expand Up @@ -72,29 +84,41 @@ export const ControlledInput = React.forwardRef<
</Block>
</Tooltip>
) : (
<Block width={width}>
{label && <Label>{label}</Label>}
<StyledInput
name={name}
type={type}
autoComplete={autoComplete}
placeholder={placeholder}
defaultValue={defaultValue}
onChange={onChange}
onBlur={onBlur}
ref={ref}
disabled={disabled}
width={width}
height={height}
hasError={(error && true) || error === ""}
/>
<div>
<Container row>
<Block width={width}>
{label && <Label>{label}</Label>}
<StyledInput
name={name}
type={type === "password" && !isVisible ? "password" : "text"}
autoComplete={autoComplete}
placeholder={placeholder}
defaultValue={defaultValue}
onChange={onChange}
onBlur={onBlur}
ref={ref}
disabled={disabled}
width={width}
height={height}
hasError={(error && true) || error === ""}
/>
</Block>
{type === "password" && (
<>
<Spacer inline x={0.5} />
<div onClick={toggleVisibility} style={{ cursor: "pointer" }}>
<Icon src={isVisible ? eyeOff : eye} />
</div>
</>
)}
</Container>
{error && (
<Error>
<i className="material-icons">error</i>
{error}
</Error>
)}
</Block>
</div>
);
}
);
Expand Down
5 changes: 4 additions & 1 deletion dashboard/src/lib/addons/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,11 @@ export const clientAddonValidator = z.object({
tailscaleConfigValidator,
]),
});
export type ClientAddonType = z.infer<
typeof clientAddonValidator
>["config"]["type"];
export type ClientAddon = z.infer<typeof clientAddonValidator> & {
template: AddonTemplate;
template: AddonTemplate<ClientAddonType>;
};
export const legacyAddonValidator = z.object({
name: z.string(),
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/lib/addons/metabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export const metabaseConfigValidator = z.object({
datastore: z
.object({
host: z.string().nonempty(),
port: z.number(),
port: z.coerce.number(),
databaseName: z.string().nonempty(),
username: z.string().nonempty(),
password: z.string().nonempty(),
Expand Down
113 changes: 96 additions & 17 deletions dashboard/src/lib/addons/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import NewRelicForm from "main/home/add-on-dashboard/newrelic/NewRelicForm";
import TailscaleForm from "main/home/add-on-dashboard/tailscale/TailscaleForm";
import TailscaleOverview from "main/home/add-on-dashboard/tailscale/TailscaleOverview";

import { type ClientAddon } from ".";
import { type ClientAddon, type ClientAddonType } from ".";

export type AddonTemplateTag =
| "Monitoring"
Expand Down Expand Up @@ -39,34 +39,68 @@ export const DEFAULT_ADDON_TAB = {
component: () => null,
};

export type AddonTemplate = {
type: ClientAddon["config"]["type"];
export type AddonTemplate<T extends ClientAddonType> = {
type: T;
displayName: string;
description: string;
icon: string;
tags: AddonTemplateTag[];
tabs: AddonTab[]; // this what is rendered on the dashboard after the addon is deployed
defaultValues: ClientAddon["config"] & { type: T };
};

export const ADDON_TEMPLATE_REDIS: AddonTemplate = {
export const ADDON_TEMPLATE_REDIS: AddonTemplate<"redis"> = {
type: "redis",
displayName: "Redis",
description: "An in-memory database that persists on disk.",
icon: "https://cdn4.iconfinder.com/data/icons/redis-2/1451/Untitled-2-512.png",
tags: ["Database"],
tabs: [],
defaultValues: {
type: "redis",
cpuCores: {
value: 0.5,
readOnly: false,
},
ramMegabytes: {
value: 512,
readOnly: false,
},
storageGigabytes: {
value: 1,
readOnly: false,
},
password: "",
},
};

export const ADDON_TEMPLATE_POSTGRES: AddonTemplate = {
export const ADDON_TEMPLATE_POSTGRES: AddonTemplate<"postgres"> = {
type: "postgres",
displayName: "Postgres",
description: "An object-relational database system.",
icon: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/postgresql/postgresql-original.svg",
tags: ["Database"],
tabs: [],
defaultValues: {
type: "postgres",
cpuCores: {
value: 0.5,
readOnly: false,
},
ramMegabytes: {
value: 512,
readOnly: false,
},
storageGigabytes: {
value: 1,
readOnly: false,
},
username: "postgres",
password: "postgres",
},
};

export const ADDON_TEMPLATE_DATADOG: AddonTemplate = {
export const ADDON_TEMPLATE_DATADOG: AddonTemplate<"datadog"> = {
type: "datadog",
displayName: "DataDog",
description:
Expand All @@ -91,9 +125,19 @@ export const ADDON_TEMPLATE_DATADOG: AddonTemplate = {
component: Settings,
},
],
defaultValues: {
type: "datadog",
cpuCores: 0.5,
ramMegabytes: 512,
site: "datadoghq.com",
apiKey: "",
loggingEnabled: false,
apmEnabled: false,
dogstatsdEnabled: false,
},
};

export const ADDON_TEMPLATE_MEZMO: AddonTemplate = {
export const ADDON_TEMPLATE_MEZMO: AddonTemplate<"mezmo"> = {
type: "mezmo",
displayName: "Mezmo",
description: "A popular logging management system.",
Expand All @@ -117,9 +161,13 @@ export const ADDON_TEMPLATE_MEZMO: AddonTemplate = {
component: Settings,
},
],
defaultValues: {
type: "mezmo",
ingestionKey: "",
},
};

export const ADDON_TEMPLATE_METABASE: AddonTemplate = {
export const ADDON_TEMPLATE_METABASE: AddonTemplate<"metabase"> = {
type: "metabase",
displayName: "Metabase",
description: "An open-source business intelligence tool.",
Expand All @@ -142,9 +190,22 @@ export const ADDON_TEMPLATE_METABASE: AddonTemplate = {
component: Settings,
},
],
defaultValues: {
type: "metabase",
exposedToExternalTraffic: true,
porterDomain: "",
customDomain: "",
datastore: {
host: "",
port: 0,
databaseName: "",
username: "",
password: "",
},
},
};

export const ADDON_TEMPLATE_NEWRELIC: AddonTemplate = {
export const ADDON_TEMPLATE_NEWRELIC: AddonTemplate<"newrelic"> = {
type: "newrelic",
displayName: "New Relic",
description: "Monitor your applications and infrastructure.",
Expand All @@ -168,9 +229,21 @@ export const ADDON_TEMPLATE_NEWRELIC: AddonTemplate = {
component: Settings,
},
],
defaultValues: {
type: "newrelic",
licenseKey: "",
insightsKey: "",
personalApiKey: "",
accountId: "",
loggingEnabled: false,
kubeEventsEnabled: false,
metricsAdapterEnabled: false,
prometheusEnabled: false,
pixieEnabled: false,
},
};

export const ADDON_TEMPLATE_TAILSCALE: AddonTemplate = {
export const ADDON_TEMPLATE_TAILSCALE: AddonTemplate<"tailscale"> = {
type: "tailscale",
displayName: "Tailscale",
description: "A VPN for your applications and datastores.",
Expand Down Expand Up @@ -199,12 +272,18 @@ export const ADDON_TEMPLATE_TAILSCALE: AddonTemplate = {
component: Settings,
},
],
defaultValues: {
type: "tailscale",
authKey: "",
subnetRoutes: [],
},
};

export const SUPPORTED_ADDON_TEMPLATES: AddonTemplate[] = [
ADDON_TEMPLATE_DATADOG,
ADDON_TEMPLATE_MEZMO,
ADDON_TEMPLATE_METABASE,
ADDON_TEMPLATE_NEWRELIC,
ADDON_TEMPLATE_TAILSCALE,
];
export const SUPPORTED_ADDON_TEMPLATES: Array<AddonTemplate<ClientAddonType>> =
[
ADDON_TEMPLATE_DATADOG,
ADDON_TEMPLATE_MEZMO,
ADDON_TEMPLATE_METABASE,
ADDON_TEMPLATE_NEWRELIC,
ADDON_TEMPLATE_TAILSCALE,
];
17 changes: 12 additions & 5 deletions dashboard/src/main/home/add-on-dashboard/AddonForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { ControlledInput } from "components/porter/ControlledInput";
import Spacer from "components/porter/Spacer";
import Text from "components/porter/Text";
import VerticalSteps from "components/porter/VerticalSteps";
import { defaultClientAddon, type ClientAddon } from "lib/addons";
import { type ClientAddon, type ClientAddonType } from "lib/addons";
import { type AddonTemplate } from "lib/addons/template";
import { useAddonList } from "lib/hooks/useAddon";
import { useDefaultDeploymentTarget } from "lib/hooks/useDeploymentTarget";
Expand All @@ -20,10 +20,12 @@ import DashboardHeader from "../cluster-dashboard/DashboardHeader";
import ClusterContextProvider from "../infrastructure-dashboard/ClusterContextProvider";
import Configuration from "./common/Configuration";

type Props = {
template: AddonTemplate;
type Props<T extends ClientAddonType> = {
template: AddonTemplate<T>;
};
const AddonForm: React.FC<Props> = ({ template }) => {
const AddonForm = <T extends ClientAddonType>({
template,
}: Props<T>): JSX.Element => {
const { currentProject, currentCluster } = useContext(Context);
const { defaultDeploymentTarget, isDefaultDeploymentTargetLoading } =
useDefaultDeploymentTarget();
Expand Down Expand Up @@ -56,7 +58,12 @@ const AddonForm: React.FC<Props> = ({ template }) => {
}, [watchName]);

useEffect(() => {
reset(defaultClientAddon(template.type));
reset({
expanded: true,
name: { readOnly: false, value: template.type },
config: template.defaultValues,
template,
});
}, [template]);

useEffect(() => {
Expand Down
Loading

0 comments on commit 5099d3a

Please sign in to comment.