Skip to content

Commit

Permalink
Build out a simple login form for the explorer so it can be deployed
Browse files Browse the repository at this point in the history
  • Loading branch information
fredex42 committed Mar 17, 2024
1 parent c373456 commit 40f4429
Show file tree
Hide file tree
Showing 5 changed files with 479 additions and 13 deletions.
8 changes: 6 additions & 2 deletions explorer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,23 @@
"private": true,
"dependencies": {
"@codemirror/language": "6.0.0",
"@emotion/react": "^11.11.1",
"@guardian/source-foundations": "^14.1.4",
"@guardian/source-react-components": "^22.0.2",
"graphiql": "^2.4.7",
"graphql": "^16.8.1",
"graphql-ws": "^5.14.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-is": "^18.2.0"
"react-is": "^18.2.0",
"tslib": "^2.6.2"
},
"devDependencies": {
"@types/react": "^18.2.13",
"@types/react-dom": "^18.2.6",
"browserify-sign": "^4.2.2",
"buffer": "^6.0.3",
"crypto-browserify": "^3.12.0",
"browserify-sign": "^4.2.2",
"css-loader": "^6.8.1",
"html-webpack-plugin": "^5.5.3",
"process": "^0.11.10",
Expand Down
103 changes: 103 additions & 0 deletions explorer/src/LoginForm.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import React, {useEffect, useMemo, useState} from "react";
import {GraphiQL} from "graphiql";
import { createGraphiQLFetcher, Fetcher } from '@graphiql/toolkit';
import {css} from "@emotion/react";
import 'graphiql/graphiql.css';
import {Button, TextInput} from "@guardian/source-react-components";

const loginContainer = css`
margin: auto;
width: fit-content;
height: fit-content;
display: flex;
flex-direction: column;
`;

const loginElement = css`
align-self: center;
`
const inputStyle = css`
max-width: 800px;
width: 800px;
`;

const buttonContainer = css`
display: flex;
margin-top: 1em;
width: 100%;
flex-direction: row;
justify-content: space-evenly;
`;

export const LoginForm:React.FC = () => {
const defaultBaseUrl = localStorage.getItem("CapiGQLBase") ?? "https://";
const defaultApiKey = localStorage.getItem("CapiGQLKey") ?? "";
const [haveCachedLogin, setHaveCachedLogin] = useState(!!(localStorage.getItem("CapiGQLBase") && localStorage.getItem("CapiGQLKey")));

const [baseUrl, setBaseUrl] = useState(defaultBaseUrl);
const [apiKey, setApiKey] = useState(defaultApiKey);
const [readyToGo, setReadyToGo] = useState(false);
const [urlIsValid, setUrlIsValid] = useState(false);
const urlValidator = /^https?:\/\/[\w-:.]+$/;

useEffect(() => {
setUrlIsValid(urlValidator.test(baseUrl));
}, [baseUrl]);

const clearCache = () => {
localStorage.removeItem("CapiGQLBase");
localStorage.removeItem("CapiGQLKey");
setBaseUrl("https://");
setApiKey("");
setHaveCachedLogin(false);
}

const fetcher = useMemo<Fetcher|null>(()=>{
if(readyToGo) {
localStorage.setItem("CapiGQLBase", baseUrl);
localStorage.setItem("CapiGQLKey", apiKey);

return createGraphiQLFetcher({url: `${baseUrl}/query`, headers: {'X-Api-Key': apiKey}});
} else {
return null;
}
}, [readyToGo]);


return fetcher && readyToGo ?
<GraphiQL fetcher={fetcher} /> :
<div css={loginContainer}>
<div css={loginElement}>
<h1>Please log in</h1>
</div>
<div css={loginElement}>
<TextInput label="CAPI GraphQL base URL"
css={inputStyle}
value={baseUrl}
error={urlIsValid ? undefined : "Please input only a base URL with no trailing slash, i.e. https://my.server.name"}
onChange={(evt)=>setBaseUrl(evt.target.value)}/>
</div>
<div css={loginElement}>
<TextInput label="API key"
css={inputStyle}
value={apiKey}
type="password"
onChange={(evt)=>setApiKey(evt.target.value)}
/>
</div>
<div css={buttonContainer}>
<div>
<Button disabled={!urlIsValid || apiKey==""}
onClick={()=>setReadyToGo(true)}>
Connect
</Button>
</div>
<div>
<Button disabled={!haveCachedLogin}
priority="secondary"
onClick={clearCache}>
Clear</Button>
</div>
</div>
</div>
}
8 changes: 2 additions & 6 deletions explorer/src/main.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import { createGraphiQLFetcher } from '@graphiql/toolkit';
import { GraphiQL } from 'graphiql';
import React from 'react';
import ReactDOM from 'react-dom';

import 'graphiql/graphiql.css';

const fetcher = createGraphiQLFetcher({ url: "/query", headers: {'X-Consumer-Username': ":internal"} });
import {LoginForm} from "./LoginForm";

const rootElem = document.createElement('div');
rootElem.setAttribute("style","height: 100vh");

document.body.append(rootElem)
ReactDOM.render(
<GraphiQL fetcher={fetcher} />,
<LoginForm />,
rootElem,
);
5 changes: 3 additions & 2 deletions explorer/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
"jsx": "react",
"module": "ES2015",
"moduleResolution": "node",
"sourceMap": true,
"strict": true,
"isolatedModules": true,
"target": "ES2016"
"target": "ES2016",
"jsx": "react-jsx",
"jsxImportSource": "@emotion/react"
},
"include": ["./src/", "__tests__", "types.d.ts"],
"exclude": ["node_modules"]
Expand Down
Loading

0 comments on commit 40f4429

Please sign in to comment.