Skip to content

Commit

Permalink
feat: add Settings page with Git demo
Browse files Browse the repository at this point in the history
  • Loading branch information
angeloashmore committed Jan 22, 2024
1 parent 727e4b5 commit 1959c66
Show file tree
Hide file tree
Showing 10 changed files with 415 additions and 37 deletions.
4 changes: 2 additions & 2 deletions packages/manager/src/managers/git/GitManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@ import { UnauthorizedError, UnexpectedDataError } from "../../errors";

import { BaseManager } from "../BaseManager";

import { GitRepo, GitRepoSpcifier, Namespace } from "./types";
import { GitRepo, GitRepoSpcifier, Owner } from "./types";

type CreateGitHubAuthStateReturnType = {
key: string;
expiresAt: Date;
};

type GitManagerFetchOwnersReturnType = Namespace[];
type GitManagerFetchOwnersReturnType = Owner[];

type GitManagerFetchReposReturnType = GitRepo[];

Expand Down
5 changes: 4 additions & 1 deletion packages/manager/src/managers/git/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
export type Namespace = {
export type Owner = {
provider: "gitHub";
id: string;
name: string;
type: "user" | "team" | null;
};

export type GitRepo = {
provider: "gitHub";
id: string;
owner: string;
name: string;
Expand All @@ -13,6 +15,7 @@ export type GitRepo = {
};

export type GitRepoSpcifier = {
provider: "gitHub";
owner: string;
name: string;
};
36 changes: 2 additions & 34 deletions packages/slice-machine/pages/settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,27 +7,9 @@ import {
AppLayoutContent,
AppLayoutHeader,
} from "@components/AppLayout";
import { Button } from "@prismicio/editor-ui";
import { managerClient } from "@src/managerClient";
import { ConnectGitRepository } from "@src/features/git/ConnectGitRepository/ConnectGitRepository";

const Settings: React.FC = () => {
const connect = async (provider: "gitHub") => {
switch (provider) {
case "gitHub": {
const state = await managerClient.git.createGitHubAuthState();

const url = new URL(
"https://github.com/apps/prismic-push-models-poc/installations/new",
);
url.searchParams.set("state", state.key);

window.open(url, "git-hub-app-installation");

return;
}
}
};

return (
<>
<Head>
Expand All @@ -39,21 +21,7 @@ const Settings: React.FC = () => {
</AppLayoutHeader>
<AppLayoutContent>
<BaseStyles sx={{ display: "flex", flexDirection: "column" }}>
<fieldset>
<legend>Connected Git Repository</legend>
<ul>
<li>
<Button onClick={() => void connect("gitHub")}>GitHub</Button>
</li>
<li>
<Button disabled>GitLab (soon)</Button>
</li>
<li>
<Button disabled>Bitbucke (soon)</Button>
</li>
</ul>
<p>Learn more about Prismic for Git</p>
</fieldset>
<ConnectGitRepository />
</BaseStyles>
</AppLayoutContent>
</AppLayout>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.root {
max-width: 600px;
}

.buttons {
display: grid;
grid-auto-columns: 1fr;
grid-auto-flow: column;
gap: 8px;
}

.owners {
display: grid;
gap: 8px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,286 @@
import { PropsWithChildren, Suspense, useState } from "react";
import {
Button,
ErrorBoundary,
ProgressCircle,
Select,
SelectItem,
Table,
TableBody,
TableCell,
TableRow,
Text,
} from "@prismicio/editor-ui";

import useSliceMachineActions from "@src/modules/useSliceMachineActions";
import { managerClient } from "@src/managerClient";
import { useSliceMachineConfig } from "@src/hooks/useSliceMachineConfig";
import { useUser } from "@src/hooks/useUser";

import { useGitOwners } from "../useGitOwners";
import { useGitRepos } from "../useGitRepos";
import { useLinkedGitRepos } from "../useLinkedGitRepos";
import { useLinkedGitReposActions } from "../useLinkedGitReposActions";

import * as styles from "./ConnectGitRepository.module.css";

// TODO: Export types from `@slicemachine/manager`
type GitOwner = Awaited<
ReturnType<(typeof managerClient)["git"]["fetchOwners"]>
>[number];
type GitRepo = Awaited<
ReturnType<(typeof managerClient)["git"]["fetchRepos"]>
>[number];

type ConnectButtonBaseProps = PropsWithChildren<{
provider: "gitHub" | "gitLab" | "bitbucket";
disabled?: boolean;
}>;

function ConnectButton(props: ConnectButtonBaseProps) {
const { provider, children, disabled } = props;

const [isLoading, setIsLoading] = useState(false);

const connect = async () => {
switch (provider) {
case "gitHub": {
setIsLoading(true);

const state = await managerClient.git.createGitHubAuthState();

const url = new URL(
"https://github.com/apps/prismic-push-models-poc/installations/new",
);
url.searchParams.set("state", state.key);

window.open(url, "git-hub-app-installation");

return;
}
}
};

return (
<Button
onClick={() => void connect()}
loading={isLoading}
disabled={disabled}
sx={{ width: "100%" }}
>
{children}
</Button>
);
}

function ConnectButtons() {
return (
<ul className={styles.buttons}>

Check failure on line 78 in packages/slice-machine/src/features/git/ConnectGitRepository/ConnectGitRepository.tsx

View workflow job for this annotation

GitHub Actions / packages (slice-machine-ui)

Unsafe assignment of an `any` value
<li>
<ConnectButton provider="gitHub">GitHub</ConnectButton>
</li>
<li>
<ConnectButton provider="gitLab" disabled>
GitLab (soon)
</ConnectButton>
</li>
<li>
<ConnectButton provider="bitbucket" disabled>
Bitbucket (soon)
</ConnectButton>
</li>
</ul>
);
}

type SelectOwnerBaseProps = {
owners: GitOwner[];
onSelect: (owner: GitOwner) => void;
};

function SelectOwnerBase(props: SelectOwnerBaseProps) {
const { owners, onSelect } = props;

const onValueChange = (value: string) => {
const [provider, id] = value.split("@");
const owner = owners.find((o) => o.provider === provider && o.id === id);

if (owner) {
onSelect(owner);
}
};

return (
<Select
color="grey"
placeholder="Select user/org"
onValueChange={onValueChange}
>
{owners.map((owner) => {
return (
<SelectItem key={owner.id} value={`${owner.provider}@${owner.id}`}>
[{owner.provider}] {owner.name}
</SelectItem>
);
})}
</Select>
);
}

function SelectOwner(props: SelectOwnerBaseProps) {
return (
<Suspense fallback={<ProgressCircle />}>
<SelectOwnerBase {...props} />
</Suspense>
);
}

type SelectRepoBaseProps = {
owner?: {
provider: "gitHub";
name: string;
};
onSelect: (repo: GitRepo) => void;
};

function SelectRepoBase(props: SelectRepoBaseProps) {
const { onSelect } = props;

const repos = useGitRepos(
props.owner
? {
provider: props.owner?.provider,
owner: props.owner?.name,
}
: undefined,
);

return (
<Table columnLayout="1fr auto" isInteractive={false}>
<TableBody>
{repos?.map((repo) => {
return (
<TableRow key={repo.id}>
<TableCell>
<Text variant="bold" color="grey12">
{repo.name}
</Text>
</TableCell>
<TableCell>
<Button color="grey" onClick={() => onSelect(repo)}>
Connect
</Button>
</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
);
}

function SelectRepo(props: SelectRepoBaseProps) {
return (
<Suspense fallback={<ProgressCircle />}>
<SelectRepoBase {...props} />
</Suspense>
);
}

function RepoSelector() {
const [config] = useSliceMachineConfig();
const owners = useGitOwners();
const { linkRepo } = useLinkedGitReposActions({
prismic: { domain: config.repositoryName },
});

const [selectedOwner, setSelectedOwner] = useState<GitOwner>();

if (owners.length < 1) {
return <ConnectButtons />;
}

return (
<div>
<label>Owners</label>
<SelectOwner
owners={owners}
onSelect={(owner) => setSelectedOwner(owner)}
/>
<label>Repos</label>
{selectedOwner ? (
<SelectRepo
owner={selectedOwner}
onSelect={(repo) => void linkRepo(repo)}
/>
) : (
<div>Select a user/owner first</div>
)}
</div>
);
}

function LoggedInContents() {
const [config] = useSliceMachineConfig();
const linkedGitRepos = useLinkedGitRepos({
prismic: { domain: config.repositoryName },
});
const { unlinkRepo } = useLinkedGitReposActions({
prismic: { domain: config.repositoryName },
});

if ("error" in linkedGitRepos) {
return <div>TODO: Handle error</div>;
}

if (linkedGitRepos.repos.length === 0) {
return <RepoSelector />;
}

const linkedRepo = linkedGitRepos.repos[0];

return (
<div>
Linked: [{linkedRepo.provider}] {linkedRepo.owner}/{linkedRepo.name}
<Button onClick={() => void unlinkRepo(linkedRepo)}>Disconnect</Button>
</div>
);
}

function LoggedOutContents() {
const { openLoginModal } = useSliceMachineActions();

return (
<div>
You must be logged in to connect a Git repository.
<Button onClick={() => openLoginModal()}>Log in to Prismic</Button>
</div>
);
}

function Contents() {
const { isLoggedIn } = useUser();

if (!isLoggedIn) {
return <LoggedOutContents />;
}

return <LoggedInContents />;
}

export function ConnectGitRepository() {
return (
<fieldset className={styles.root}>

Check failure on line 273 in packages/slice-machine/src/features/git/ConnectGitRepository/ConnectGitRepository.tsx

View workflow job for this annotation

GitHub Actions / packages (slice-machine-ui)

Unsafe assignment of an `any` value
<legend>Connected Git Repository</legend>
<ErrorBoundary
renderError={() => {
return <div>Error</div>;
}}
>
<Suspense fallback={<ProgressCircle />}>
<Contents />
</Suspense>
</ErrorBoundary>
</fieldset>
);
}
Loading

0 comments on commit 1959c66

Please sign in to comment.