ProjectSettings: update rowy run section

This commit is contained in:
Sidney Alcantara
2021-09-15 22:56:33 +10:00
parent 64b6f9c271
commit 8844a8fab3
4 changed files with 270 additions and 80 deletions

View File

@@ -129,7 +129,11 @@ export default function About() {
<Typography display="block">
{name} v{version}
</Typography>
{latestUpdate === null ? (
{checkState === "LOADING" ? (
<Typography color="textSecondary" display="block">
Checking for updates
</Typography>
) : latestUpdate === null ? (
<Typography color="textSecondary" display="block">
Up to date
</Typography>

View File

@@ -1,77 +0,0 @@
import { Typography, Link, Grid, TextField } from "@mui/material";
import LoadingButton from "@mui/lab/LoadingButton";
import InlineOpenInNewIcon from "components/InlineOpenInNewIcon";
import { IProjectSettingsChildProps } from "pages/Settings/ProjectSettings";
import WIKI_LINKS from "constants/wikiLinks";
import { name } from "@root/package.json";
import { runRepoUrl } from "constants/runRoutes";
export default function rowyRun({
settings,
updateSettings,
}: IProjectSettingsChildProps) {
return (
<>
<Typography>
{name} Run is a Cloud Run instance that provides back-end functionality,
such as table action scripts, user management, and easy Cloud Function
deployment.{" "}
<Link
href={WIKI_LINKS.functions}
target="_blank"
rel="noopener noreferrer"
>
Learn more
<InlineOpenInNewIcon />
</Link>
</Typography>
<div>
<Grid
container
spacing={1}
alignItems="center"
justifyContent="space-between"
>
<Grid item xs={12} sm>
<Typography>
If you have not yet deployed {name} Run, click this button and
follow the prompts on Cloud Shell.
</Typography>
</Grid>
<Grid item>
<LoadingButton
href={`https://deploy.cloud.run/?git_repo=${runRepoUrl}.git`}
target="_blank"
rel="noopener noreferrer"
loading={
settings.rowyRunDeployStatus === "BUILDING" ||
settings.rowyRunDeployStatus === "COMPLETE"
}
loadingIndicator={
settings.rowyRunDeployStatus === "COMPLETE"
? "Deployed"
: undefined
}
>
Deploy to Cloud Run
</LoadingButton>
</Grid>
</Grid>
</div>
<TextField
label="Cloud Run Instance URL"
id="rowyRunUrl"
defaultValue={settings.rowyRunUrl}
onChange={(e) => updateSettings({ rowyRunUrl: e.target.value })}
fullWidth
placeholder="https://<id>.run.app"
type="url"
autoComplete="url"
/>
</>
);
}

View File

@@ -0,0 +1,263 @@
import { useState, useCallback, useEffect } from "react";
import createPersistedState from "use-persisted-state";
import { differenceInDays } from "date-fns";
import {
Typography,
Link,
Divider,
Button,
Grid,
TextField,
} from "@mui/material";
import LoadingButton from "@mui/lab/LoadingButton";
import InlineOpenInNewIcon from "components/InlineOpenInNewIcon";
import { IProjectSettingsChildProps } from "pages/Settings/ProjectSettings";
import WIKI_LINKS from "constants/wikiLinks";
import { name } from "@root/package.json";
import { RunRoutes, runRepoUrl } from "constants/runRoutes";
const useLastCheckedUpdateState = createPersistedState(
"__ROWY__RUN_LAST_CHECKED_UPDATE"
);
export const useLatestUpdateState = createPersistedState(
"__ROWY__RUN_LATEST_UPDATE"
);
export default function RowyRun({
settings,
updateSettings,
}: IProjectSettingsChildProps) {
const [inputRowyRunUrl, setInputRowyRunUrl] = useState(settings.rowyRunUrl);
const [verified, setVerified] = useState<boolean | "LOADING" | undefined>();
const handleVerify = async () => {
setVerified("LOADING");
try {
const versionReq = await fetch(inputRowyRunUrl + RunRoutes.version.path, {
method: RunRoutes.version.method,
}).then((res) => res.json());
if (!versionReq.version) throw new Error("No version found");
else {
setVerified(true);
setVersion(versionReq.version);
updateSettings({ rowyRunUrl: inputRowyRunUrl });
}
} catch (e) {
console.error(e);
setVerified(false);
}
};
const [lastCheckedUpdate, setLastCheckedUpdate] =
useLastCheckedUpdateState<string>();
const [latestUpdate, setLatestUpdate] = useLatestUpdateState<null | Record<
string,
any
>>(null);
const [checkState, setCheckState] = useState<null | "LOADING" | "NO_UPDATE">(
null
);
const [version, setVersion] = useState("");
useEffect(() => {
fetch(settings.rowyRunUrl + RunRoutes.version.path, {
method: RunRoutes.version.method,
})
.then((res) => res.json())
.then((data) => setVersion(data.version));
}, [settings.rowyRunUrl]);
const checkForUpdate = useCallback(async () => {
setCheckState("LOADING");
// https://docs.github.com/en/rest/reference/repos#get-the-latest-release
const endpoint =
runRepoUrl.replace("github.com", "api.github.com/repos") +
"/releases/latest";
try {
const versionReq = await fetch(
settings.rowyRunUrl + RunRoutes.version.path,
{ method: RunRoutes.version.method }
).then((res) => res.json());
const version = versionReq.version;
setVersion(version);
const req = await fetch(endpoint, {
headers: {
Accept: "application/vnd.github.v3+json",
},
});
const res = await req.json();
if (res.tag_name > "v" + version) {
setLatestUpdate(res);
setCheckState(null);
} else {
setCheckState("NO_UPDATE");
}
setLastCheckedUpdate(new Date().toISOString());
} catch (e) {
console.error(e);
setLatestUpdate(null);
setCheckState("NO_UPDATE");
}
}, [setLastCheckedUpdate, setLatestUpdate, settings.rowyRunUrl]);
// Check for new updates on page load, if last check was more than 7 days ago
useEffect(() => {
if (!lastCheckedUpdate) checkForUpdate();
else if (differenceInDays(new Date(), new Date(lastCheckedUpdate)) > 7)
checkForUpdate();
}, [lastCheckedUpdate, checkForUpdate]);
// Verify latest update is not installed yet
useEffect(() => {
if (version && latestUpdate?.tag_name <= "v" + version)
setLatestUpdate(null);
}, [latestUpdate, setLatestUpdate, version]);
const deployButton = window.location.hostname.includes("rowy.app") ? (
<LoadingButton
href={`https://deploy.cloud.run/?git_repo=${runRepoUrl}.git`}
target="_blank"
rel="noopener noreferrer"
loading={
settings.rowyRunDeployStatus === "BUILDING" ||
settings.rowyRunDeployStatus === "COMPLETE"
}
loadingIndicator={
settings.rowyRunDeployStatus === "COMPLETE" ? "Deployed" : undefined
}
>
One-Click Deploy
</LoadingButton>
) : (
<Button href={runRepoUrl} target="_blank" rel="noopener noreferrer">
Deploy Instructions
</Button>
);
return (
<>
<Typography>
{name} Run is a Cloud Run instance that provides back-end functionality,
such as table action scripts, user management, and easy Cloud Function
deployment.{" "}
<Link
href={WIKI_LINKS.functions}
target="_blank"
rel="noopener noreferrer"
>
Learn more
<InlineOpenInNewIcon />
</Link>
</Typography>
<Divider />
{settings.rowyRunUrl && (
<div>
<Grid container spacing={1} alignItems="center" direction="row">
<Grid item xs>
<Typography display="block">
{name} Run v{version}
</Typography>
{checkState === "LOADING" ? (
<Typography color="textSecondary" display="block">
Checking for updates
</Typography>
) : latestUpdate === null ? (
<Typography color="textSecondary" display="block">
Up to date
</Typography>
) : (
<Link
href={latestUpdate.html_url}
target="_blank"
rel="noopener noreferrer"
variant="body2"
display="block"
>
Update available: {latestUpdate.tag_name}
<InlineOpenInNewIcon />
</Link>
)}
</Grid>
<Grid item>
{latestUpdate === null ? (
<LoadingButton
onClick={checkForUpdate}
loading={checkState === "LOADING"}
>
Check for Updates
</LoadingButton>
) : (
deployButton
)}
</Grid>
</Grid>
</div>
)}
{settings.rowyRunUrl && <Divider />}
{!settings.rowyRunUrl && (
<div>
<Grid
container
spacing={1}
alignItems="center"
justifyContent="space-between"
>
<Grid item xs={12} sm>
<Typography>
If you have not yet deployed {name} Run, click this button and
follow the prompts on Cloud Shell.
</Typography>
</Grid>
<Grid item>{deployButton}</Grid>
</Grid>
</div>
)}
<div>
<Grid container spacing={1} alignItems="center" direction="row">
<Grid item xs>
<TextField
label="Cloud Run Instance URL"
id="rowyRunUrl"
value={inputRowyRunUrl}
onChange={(e) => setInputRowyRunUrl(e.target.value)}
fullWidth
placeholder="https://<id>.run.app"
type="url"
autoComplete="url"
error={verified === false}
helperText={
verified === true
? `${name} Run is set up correctly`
: verified === false
? `${name} Run is not set up correctly`
: " "
}
/>
</Grid>
<Grid item>
<LoadingButton
loading={verified === "LOADING"}
onClick={handleVerify}
>
Verify
</LoadingButton>
</Grid>
</Grid>
</div>
</>
);
}

View File

@@ -7,7 +7,7 @@ import { Container, Stack, Fade } from "@mui/material";
import SettingsSkeleton from "components/Settings/SettingsSkeleton";
import SettingsSection from "components/Settings/SettingsSection";
import About from "components/Settings/ProjectSettings/About";
import CloudRun from "@src/components/Settings/ProjectSettings/CloudRun";
import RowyRun from "@src/components/Settings/ProjectSettings/RowyRun";
import Authentication from "components/Settings/ProjectSettings/Authentication";
import Customization from "components/Settings/ProjectSettings/Customization";
@@ -68,7 +68,7 @@ export default function ProjectSettingsPage() {
const sections = [
{ title: "About", Component: About },
{ title: `${name} Run`, Component: CloudRun, props: childProps },
{ title: `${name} Run`, Component: RowyRun, props: childProps },
{ title: "Authentication", Component: Authentication, props: childProps },
{ title: "Customization", Component: Customization, props: childProps },
];