Path: blob/main/components/dashboard/src/login/SSOLoginForm.tsx
3606 views
/**1* Copyright (c) 2023 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { FC, useCallback, useState } from "react";7import Alert from "../components/Alert";8import { Button } from "@podkit/buttons/Button";9import { TextInputField } from "../components/forms/TextInputField";10import { useOnBlurError } from "../hooks/use-onblur-error";11import { openOIDCStartWindow } from "../provider-utils";12import { useFeatureFlag } from "../data/featureflag-query";13import { useLocation } from "react-router";14import { useOnboardingState } from "../dedicated-setup/use-needs-setup";15import { getOrgSlugFromQuery } from "../data/organizations/orgs-query";16import { storageAvailable } from "../utils";1718function getOrgSlugFromPath(path: string) {19// '/login/acme' => ['', 'login', 'acme']20const pathSegments = path.split("/");21if (pathSegments[1] !== "login") {22return;23}24return pathSegments[2];25}2627type Props = {28onSuccess: () => void;29};30export const SSOLoginForm: FC<Props> = ({ onSuccess }) => {31const location = useLocation();32const { data: onboardingState } = useOnboardingState();33const singleOrgMode = (onboardingState?.organizationCountTotal || 0) < 2;3435const [orgSlug, setOrgSlug] = useState(36getOrgSlugFromPath(location.pathname) || getOrgSlugFromQuery(location.search) || readSSOOrgSlug() || "",37);38const [error, setError] = useState("");3940const oidcServiceEnabled = useFeatureFlag("oidcServiceEnabled");4142const openLoginWithSSO = useCallback(43async (e: React.FormEvent<HTMLFormElement>) => {44e.preventDefault();45persistSSOOrgSlug(orgSlug.trim());4647try {48await openOIDCStartWindow({49orgSlug,50onSuccess: onSuccess,51onError: (payload) => {52let errorMessage: string;53if (typeof payload === "string") {54errorMessage = payload;55} else {56errorMessage = payload.description ? payload.description : `Error: ${payload.error}`;57}58setError(errorMessage);59},60});61} catch (error) {62console.log(error);63}64},65[onSuccess, orgSlug],66);6768const slugError = useOnBlurError(69"Organization slug must not be longer than 63 characters.",70orgSlug.trim().length <= 63,71);7273// Don't render anything if not enabled74if (!oidcServiceEnabled) {75return null;76}7778return (79<form onSubmit={openLoginWithSSO}>80<div className="mt-10 space-y-2 w-56">81{!singleOrgMode && (82<TextInputField83label="Organization"84placeholder="my-organization"85value={orgSlug}86onChange={setOrgSlug}87error={slugError.message}88onBlur={slugError.onBlur}89/>90)}91<Button92type="submit"93className="w-full"94variant="secondary"95disabled={!singleOrgMode && (!orgSlug.trim() || !slugError.isValid)}96>97Continue {singleOrgMode ? "" : "with SSO"}98</Button>99{error && <Alert type="info">{error}</Alert>}100</div>101</form>102);103};104105function readSSOOrgSlug(): string | undefined {106const isLocalStorageAvailable = storageAvailable("localStorage");107if (isLocalStorageAvailable) {108return window.localStorage.getItem("sso-org-slug") || undefined;109}110return undefined;111}112113function persistSSOOrgSlug(slug: string) {114const isLocalStorageAvailable = storageAvailable("localStorage");115if (isLocalStorageAvailable) {116window.localStorage.setItem("sso-org-slug", slug.trim());117}118}119120121