-
Notifications
You must be signed in to change notification settings - Fork 77
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[generic issuance] pipeline CRUD app with minimal UI (#1451)
Closes #1428 TODO - [x] Request types - [x] Move requests to passport-interface - [x] Integrating with pipeline DB - [x] Integrating with user DB - [x] DB testing - [ ] proposed refreshPipeline() in-memory command #1456 - [ ] end-to-end API tests #1457 What's in here: - CRUD endpoints for pipeline definitions - MVP UI that allows interacting with this CRUD UI via JSON (see video below) - Basic 'permission control' for the CRUD actions, e.g., you must own a pipeline to delete it, but you can read or write to a pipeline if you are either an owner or editor - Pipeline Definition schema validation on the backend What's not in here: - The best state management / client-side fetching system - Any admin user logic - Comprehensive tests (in progress) https://github.com/proofcarryingdata/zupass/assets/36896271/c3277ca4-caca-4249-868f-cc167c80f896
- Loading branch information
Showing
30 changed files
with
1,104 additions
and
252 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,6 @@ | ||
# This token is used to authenticate Stytch requests for user authentication. | ||
# If you are on the team, message @rrrliu to get one. | ||
STYTCH_PUBLIC_TOKEN= | ||
STYTCH_PUBLIC_TOKEN= | ||
|
||
PASSPORT_CLIENT_URL="http://localhost:3000" | ||
PASSPORT_SERVER_URL="http://localhost:3002" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,16 +1,4 @@ | ||
export const PCD_GITHUB_URL = "https://github.com/proofcarryingdata/pcd"; | ||
|
||
export const IS_PROD = process.env.NODE_ENV === "production"; | ||
export const IS_STAGING = process.env.NODE_ENV === "staging"; | ||
|
||
export const ZUPASS_URL = IS_PROD | ||
? "https://zupass.org/" | ||
: IS_STAGING | ||
? "https://staging.zupass.org/" | ||
: "http://localhost:3000/"; | ||
|
||
export const ZUPASS_SERVER_URL = IS_PROD | ||
? "https://api.zupass.org/" | ||
: IS_STAGING | ||
? "https://api-staging.zupass.org/" | ||
: "http://localhost:3002/"; | ||
export const ZUPASS_URL = process.env.PASSPORT_CLIENT_URL; | ||
export const ZUPASS_SERVER_URL = process.env.PASSPORT_SERVER_URL; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { | ||
PipelineDefinition, | ||
requestGenericIssuanceDeletePipeline, | ||
requestGenericIssuanceGetPipeline, | ||
requestGenericIssuanceUpsertPipeline | ||
} from "@pcd/passport-interface"; | ||
import { useStytchUser } from "@stytch/react"; | ||
import { ReactNode, useEffect, useState } from "react"; | ||
import { Link, useParams } from "react-router-dom"; | ||
import { ZUPASS_SERVER_URL } from "../constants"; | ||
|
||
function format(obj: object): string { | ||
return JSON.stringify(obj, null, 2); | ||
} | ||
|
||
export default function Pipeline(): ReactNode { | ||
const params = useParams(); | ||
const { user } = useStytchUser(); | ||
const { id } = params; | ||
// TODO: After MVP, replace with RTK hooks or a more robust state management. | ||
const [savedPipeline, setSavedPipeline] = useState<PipelineDefinition>(); | ||
const [textareaValue, setTextareaValue] = useState(""); | ||
const [queryLoading, setQueryLoading] = useState(true); | ||
const [saveLoading, setSaveLoading] = useState(false); | ||
const [error, setError] = useState(""); | ||
|
||
async function savePipeline(): Promise<void> { | ||
setSaveLoading(true); | ||
const res = await requestGenericIssuanceUpsertPipeline( | ||
ZUPASS_SERVER_URL, | ||
JSON.parse(textareaValue) | ||
); | ||
if (res.success) { | ||
setSavedPipeline(res.value); | ||
setTextareaValue(format(res.value)); | ||
setError(""); | ||
} else { | ||
setError(`An error occured while saving: ${res.error}`); | ||
} | ||
setSaveLoading(false); | ||
} | ||
|
||
async function deletePipeline(): Promise<void> { | ||
if (confirm("Are you sure you would like to delete this pipeline?")) { | ||
const res = await requestGenericIssuanceDeletePipeline( | ||
ZUPASS_SERVER_URL, | ||
id | ||
); | ||
if (res.success) { | ||
window.location.href = "/#/dashboard"; | ||
} else { | ||
setError(`An error occured while deleting: ${res.error}`); | ||
} | ||
} | ||
} | ||
|
||
useEffect(() => { | ||
async function fetchPipeline(): Promise<void> { | ||
const res = await requestGenericIssuanceGetPipeline( | ||
ZUPASS_SERVER_URL, | ||
id | ||
); | ||
if (res.success) { | ||
setSavedPipeline(res.value); | ||
setTextareaValue(format(res.value)); | ||
setError(""); | ||
} else { | ||
setError( | ||
`This pipeline "${id}" is invalid or you do not have access to this pipeline.` | ||
); | ||
setSavedPipeline(undefined); | ||
} | ||
setQueryLoading(false); | ||
} | ||
fetchPipeline(); | ||
}, [id]); | ||
|
||
if (!user) { | ||
window.location.href = "/"; | ||
} | ||
|
||
if (queryLoading) { | ||
return <div>Loading...</div>; | ||
} | ||
|
||
const hasEdits = format(savedPipeline) !== textareaValue; | ||
|
||
return ( | ||
<div> | ||
{savedPipeline && ( | ||
<> | ||
<p> | ||
<textarea | ||
cols={50} | ||
rows={30} | ||
value={textareaValue} | ||
onChange={(e): void => setTextareaValue(e.target.value)} | ||
/> | ||
</p> | ||
<p> | ||
{hasEdits && ( | ||
<button disabled={saveLoading} onClick={savePipeline}> | ||
{saveLoading ? "Saving..." : "Save changes"} | ||
</button> | ||
)} | ||
{!hasEdits && <button disabled>All changes saved ✅</button>} | ||
</p> | ||
<p> | ||
<button onClick={deletePipeline}>Delete pipeline</button> | ||
</p> | ||
</> | ||
)} | ||
{error && ( | ||
<p> | ||
<strong>Error: </strong> | ||
{error} | ||
</p> | ||
)} | ||
<p> | ||
<Link to="/dashboard"> | ||
<button>Return to all pipelines</button> | ||
</Link> | ||
</p> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.