Skip to content

Commit

Permalink
[dashboard] Restructure Organization Settings (#19788)
Browse files Browse the repository at this point in the history
* restrcuture Organization settings sub-menu items

* [Organization settings] Bisect General settings (#19790)

* Divide General settings & Policies pages

* Add Enterprise callout

* style improvements

* Apply style suggestions from @corygrunk

* button style changes

* feat: Organization Networking settings page (#19794)

* feat: Organization Authentication settings page (#19795)

* fix typos

* Rephrase copy texts

* styles improvements

* removed unused CSS

* more styles fixes

* fix border changes

* fix submenu in dark mode
  • Loading branch information
Siddhant-K-code authored May 30, 2024
1 parent 828daec commit ed090b0
Show file tree
Hide file tree
Showing 12 changed files with 595 additions and 221 deletions.
6 changes: 6 additions & 0 deletions components/dashboard/src/app/AppRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ const TeamSettings = React.lazy(() => import(/* webpackPrefetch: true */ "../tea
const TeamUsageBasedBilling = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamUsageBasedBilling"));
const SSO = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/SSO"));
const TeamGitIntegrations = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/GitIntegrationsPage"));
const TeamPolicies = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamPolicies"));
const TeamNetworking = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamNetworking"));
const TeamAuthentication = React.lazy(() => import(/* webpackPrefetch: true */ "../teams/TeamAuthentication"));
const Projects = React.lazy(() => import(/* webpackPrefetch: true */ "../projects/Projects"));
const Project = React.lazy(() => import(/* webpackPrefetch: true */ "../projects/Project"));
const ProjectSettings = React.lazy(() => import(/* webpackPrefetch: true */ "../projects/ProjectSettings"));
Expand Down Expand Up @@ -201,6 +204,9 @@ export const AppRoutes = () => {
<Route exact path="/members" component={Members} />
<Route exact path="/settings" component={TeamSettings} />
<Route exact path="/settings/git" component={TeamGitIntegrations} />
<Route exact path="/settings/policy" component={TeamPolicies} />
<Route exact path="/settings/networking" component={TeamNetworking} />
<Route exact path="/settings/auth" component={TeamAuthentication} />
{/* TODO: migrate other org settings pages underneath /settings prefix so we can utilize nested routes */}
<Route exact path="/billing" component={TeamUsageBasedBilling} />
<Route exact path="/sso" component={SSO} />
Expand Down
2 changes: 1 addition & 1 deletion components/dashboard/src/components/PageWithSubMenu.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ export const SubmenuItem: FC<SubmenuItemProps> = ({ title, link, icon }) => {
if (isCurrent) {
classes += " bg-gray-300 text-gray-800 dark:bg-gray-800 dark:text-gray-50";
} else {
classes += " hover:bg-gray-100 dark:hover:bg-gray-800 dark:text-gray-400";
classes += " hover:bg-gray-100 dark:hover:bg-gray-800 dark:text-pk-content-secondary";
}

return (
Expand Down
4 changes: 2 additions & 2 deletions components/dashboard/src/components/PillLabel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export type PillType = "info" | "warn" | "success" | "neutral";

const PillClsMap: Record<PillType, string> = {
info: "bg-blue-50 text-blue-500 dark:bg-blue-500 dark:text-blue-100",
warn: "bg-orange-100 text-orange-700 dark:bg-orange-600 dark:text-orange-100",
warn: "bg-kumquat-ripe text-gray-900",
success: "bg-green-100 text-green-700 dark:bg-green-600 dark:text-green-100",
neutral: "bg-gray-300 text-gray-800 dark:bg-gray-600 dark:text-gray-100",
};
Expand All @@ -27,6 +27,6 @@ const PillClsMap: Record<PillType, string> = {
*/
export default function PillLabel(props: { children?: React.ReactNode; type?: PillType; className?: string }) {
const type = props.type || "info";
const style = `px-2 py-1 text-sm uppercase rounded-xl ${PillClsMap[type]} ${props.className}`;
const style = `px-3 py-0.5 text-xs uppercase rounded-xl font-semibold ${PillClsMap[type]} ${props.className}`;
return <span className={style}>{props.children}</span>;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import React from "react";
export interface LinkButtonProps extends ButtonProps {
asChild?: false;
href: string;
isExternalUrl?: boolean;
}

/**
Expand All @@ -20,7 +21,13 @@ export const LinkButton = React.forwardRef<HTMLButtonElement, LinkButtonProps>(
({ asChild, children, href, ...props }, ref) => {
return (
<Button ref={ref} {...props} asChild>
<Link to={href}>{children}</Link>
{props.isExternalUrl ? (
<a href={href} target="_blank" rel="noreferrer">
{children}
</a>
) : (
<Link to={href}>{children}</Link>
)}
</Button>
);
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export const Heading3: FC<HeadingProps> = ({ id, tracking, className, children,
*/
export const Subheading: FC<HeadingProps> = ({ id, tracking, className, children }) => {
return (
<p id={id} className={cn("text-base text-pk-content-tertiary", getTracking(tracking), className)}>
<p id={id} className={cn("text-base text-pk-content-secondary", getTracking(tracking), className)}>
{children}
</p>
);
Expand Down
5 changes: 1 addition & 4 deletions components/dashboard/src/components/typography/headings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,7 @@ export const Heading3: FC<HeadingProps> = ({ id, color, tracking, className, chi
// Intended to be placed beneath a heading to provide more context
export const Subheading: FC<HeadingProps> = ({ id, tracking, className, children }) => {
return (
<p
id={id}
className={classNames("text-base text-gray-500 dark:text-gray-500", getTracking(tracking), className)}
>
<p id={id} className={classNames("text-base text-pk-content-secondary", getTracking(tracking), className)}>
{children}
</p>
);
Expand Down
17 changes: 17 additions & 0 deletions components/dashboard/src/teams/OrgSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { useCurrentOrg } from "../data/organizations/orgs-query";
import { useFeatureFlag } from "../data/featureflag-query";
import { Organization } from "@gitpod/public-api/lib/gitpod/v1/organization_pb";
import { useIsOwner } from "../data/organizations/members-query";
import { isGitpodIo } from "../utils";

export interface OrgSettingsPageProps {
children: React.ReactNode;
Expand Down Expand Up @@ -82,7 +83,23 @@ function getOrgSettingsMenu(params: {
title: "General",
link: [`/settings`],
},
{
title: "Policies",
link: [`/settings/policy`],
},
];
if (isGitpodIo()) {
result.push(
{
title: "Networking",
link: [`/settings/networking`],
},
{
title: "Authentication",
link: [`/settings/auth`],
},
);
}
if (isOwner && ssoEnabled) {
result.push({
title: "SSO",
Expand Down
113 changes: 113 additions & 0 deletions components/dashboard/src/teams/TeamAuthentication.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
/**
* Copyright (c) 2021 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License.AGPL.txt in the project root for license information.
*/

import { isGitpodIo } from "../utils";
import React from "react";
import { Heading2, Heading3, Subheading } from "../components/typography/headings";
import { OrgSettingsPage } from "./OrgSettingsPage";
import { ConfigurationSettingsField } from "../repositories/detail/ConfigurationSettingsField";
import { useDocumentTitle } from "../hooks/use-document-title";
import { LinkButton } from "@podkit/buttons/LinkButton";
import { CheckCircle2Icon } from "lucide-react";
import { Redirect } from "react-router";
import PillLabel from "../components/PillLabel";

export default function TeamPoliciesPage() {
useDocumentTitle("Organization Settings - Authentication");

if (!isGitpodIo) {
return <Redirect to="/settings" />;
}

return (
<>
<OrgSettingsPage>
<div className="space-y-8">
<div>
<Heading2 className="flex items-center gap-4">
Authentication
<PillLabel type="warn">Enterprise</PillLabel>
</Heading2>
<Subheading className="mt-1">
Manage users through single sign-on and privately authenticate with source control and image
registries.
</Subheading>
</div>

<SSOCard />
<PrivateImageRegistryCard />
<PrivateSourceControlAccess />
</div>
</OrgSettingsPage>
</>
);
}

const SSOCard = () => {
return (
<ConfigurationSettingsField className="bg-pk-surface-secondary">
<Heading3>Single sign-on (SSO)</Heading3>
<Subheading className="mt-1">More control over workspace access for your organization</Subheading>

<div className="mt-8 flex flex-col space-y-2">
<div className="flex flex-row gap-2 items-center text-pk-content-secondary">
<CheckCircle2Icon size={20} className="text-pk-content-primary" />
Includes support for Google, Okta, AWS Cognito and others
</div>
<div className="flex flex-row gap-2 items-center text-pk-content-secondary">
<CheckCircle2Icon size={20} className="text-pk-content-primary" />
Instantly revoke access and off-board users from Gitpod
</div>
</div>

<LinkButton
href="https://www.gitpod.io/contact/enterprise-self-serve"
isExternalUrl={true}
className="mt-8"
>
Request Free Trial
</LinkButton>
</ConfigurationSettingsField>
);
};

const PrivateImageRegistryCard = () => {
return (
<ConfigurationSettingsField className="bg-pk-surface-secondary">
<Heading3>Private container image registry</Heading3>
<Subheading className="mt-1">Provide secure access to private image registries such as ECR</Subheading>

<LinkButton
variant="secondary"
className="mt-8 border border-pk-content-tertiary text-pk-content-primary bg-pk-surface-primary"
href="https://www.gitpod.io/docs/enterprise/setup-gitpod/use-private-ecr-repos-for-workspace-images"
isExternalUrl={true}
>
Documentation
</LinkButton>
</ConfigurationSettingsField>
);
};

const PrivateSourceControlAccess = () => {
return (
<ConfigurationSettingsField className="bg-pk-surface-secondary">
<Heading3>Private source control access</Heading3>
<Subheading className="mt-1">
Connect to your private source control like GitHub, BitBucket and GitLab
</Subheading>

<LinkButton
variant="secondary"
className="mt-8 border border-pk-content-tertiary text-pk-content-primary bg-pk-surface-primary"
href="https://www.gitpod.io/docs/enterprise/setup-gitpod/scm-integration"
isExternalUrl={true}
>
Documentation
</LinkButton>
</ConfigurationSettingsField>
);
};
127 changes: 127 additions & 0 deletions components/dashboard/src/teams/TeamNetworking.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
/**
* Copyright (c) 2021 Gitpod GmbH. All rights reserved.
* Licensed under the GNU Affero General Public License (AGPL).
* See License.AGPL.txt in the project root for license information.
*/

import { isGitpodIo } from "../utils";
import React from "react";
import { Heading2, Heading3, Subheading } from "../components/typography/headings";
import { OrgSettingsPage } from "./OrgSettingsPage";
import { ConfigurationSettingsField } from "../repositories/detail/ConfigurationSettingsField";
import { useDocumentTitle } from "../hooks/use-document-title";
import { LinkButton } from "@podkit/buttons/LinkButton";
import { CheckCircle2Icon } from "lucide-react";
import { Redirect } from "react-router";
import PillLabel from "../components/PillLabel";

export default function TeamPoliciesPage() {
useDocumentTitle("Organization Settings - Networking");

if (!isGitpodIo) {
return <Redirect to="/settings" />;
}

return (
<>
<OrgSettingsPage>
<div className="space-y-8">
<div>
<Heading2 className="flex items-center gap-4">
Networking
<PillLabel type="warn">Enterprise</PillLabel>
</Heading2>
<Subheading className="mt-1">
Self-host a single-tenant installation in your own cloud account.
</Subheading>
</div>

<SelfHostedCalloutCard />
<DeployedRegionCard />
<VPNCard />
</div>
</OrgSettingsPage>
</>
);
}

const SelfHostedCalloutCard = () => {
return (
<ConfigurationSettingsField className="bg-pk-surface-secondary">
<Heading3>Self-host in your cloud account</Heading3>
<Subheading className="mt-1">
Deploy the Gitpod infrastructure into your own cloud account and connect to your private network
</Subheading>

<div className="mt-8 flex flex-col space-y-2">
<div className="flex flex-row gap-2 items-center text-pk-content-secondary">
<CheckCircle2Icon size={20} className="text-pk-content-primary" />
Managed application feature release and backup process
</div>
<div className="flex flex-row gap-2 items-center text-pk-content-secondary">
<CheckCircle2Icon size={20} className="text-pk-content-primary" />
Managed security updates and patches
</div>
</div>

<LinkButton
href="https://www.gitpod.io/contact/enterprise-self-serve"
isExternalUrl={true}
className="mt-8"
>
Request Free Trial
</LinkButton>
</ConfigurationSettingsField>
);
};

const DeployedRegionCard = () => {
return (
<ConfigurationSettingsField className="bg-pk-surface-secondary">
<Heading3>Choose your deployed region</Heading3>
<Subheading className="mt-1">
Deploy Gitpod to any location, such as: United States, South America, Europe and Asia Pacific
</Subheading>

<div className="mt-8 flex flex-col space-y-2">
<div className="flex flex-row gap-2 items-center text-pk-content-secondary">
<CheckCircle2Icon size={20} className="text-pk-content-primary" />
Meet data residency compliance requirements
</div>
<div className="flex flex-row gap-2 items-center text-pk-content-secondary">
<CheckCircle2Icon size={20} className="text-pk-content-primary" />
Reduce latency and bring your code closer to your data
</div>
</div>

<LinkButton
variant="secondary"
className="mt-8 border border-pk-content-tertiary text-pk-content-primary bg-pk-surface-primary"
href="https://www.gitpod.io/docs/enterprise/overview#aws-support-and-regions"
isExternalUrl={true}
>
Documentation
</LinkButton>
</ConfigurationSettingsField>
);
};

const VPNCard = () => {
return (
<ConfigurationSettingsField className="bg-pk-surface-secondary">
<Heading3>Virtual Private Network (VPN)</Heading3>
<Subheading className="mt-1">
Restrict access to your instance using your own private VPN network
</Subheading>

<LinkButton
variant="secondary"
className="mt-8 border border-pk-content-tertiary text-pk-content-primary bg-pk-surface-primary"
href="https://www.gitpod.io/docs/enterprise/getting-started/networking#private-networking-configuration-highly-restrictive"
isExternalUrl={true}
>
Documentation
</LinkButton>
</ConfigurationSettingsField>
);
};
Loading

0 comments on commit ed090b0

Please sign in to comment.