Commit eac06503 authored by David Haynes's avatar David Haynes 🙆

Complete final pass on debug components

- add favicon as well

Closes #188
parent bdb603ea
Pipeline #3820 passed with stage
in 2 minutes and 7 seconds
...@@ -22,3 +22,6 @@ mysqlclient = "*" ...@@ -22,3 +22,6 @@ mysqlclient = "*"
[requires] [requires]
python_version = "3.7" python_version = "3.7"
[pipenv]
allow_prereleases = true
import React from "react"; import React from "react";
import * as Yup from "yup"; import * as Yup from "yup";
import { Formik, Field, Form as FormikForm, ErrorMessage } from "formik"; import { Formik, Field, Form, ErrorMessage } from "formik";
import { GetCSRFToken } from "../../Utils"; import { GetCSRFToken } from "../../Utils";
import { SingleDatePicker } from "react-dates"; import { SingleDatePicker } from "react-dates";
import moment from "moment"; import moment from "moment";
import { Form, FormGroup, Button, Card, CardBody, CardTitle } from "reactstrap"; import { FormGroup, Button, Card, CardBody, CardTitle } from "reactstrap";
const DebugCreateYup = Yup.object().shape({ const DebugCreateYup = Yup.object().shape({
destination: Yup.string() destination: Yup.string()
...@@ -33,18 +33,17 @@ class DebugCreate extends React.Component { ...@@ -33,18 +33,17 @@ class DebugCreate extends React.Component {
<CardTitle>Create</CardTitle> <CardTitle>Create</CardTitle>
<Formik <Formik
initialValues={{ initialValues={{
destination: "",
short: "", short: "",
destination: "",
expires: moment(new Date()) expires: moment(new Date())
}} }}
validationSchema={DebugCreateYup} validationSchema={DebugCreateYup}
onSubmit={(values, { setSubmitting }) => { onSubmit={({ destination, short, expires }, { setSubmitting }) => {
const newValues = { const newValues = {
destination: values.destination, destination: destination,
short: values.short, short: short,
date_expires: values.expires.format() date_expires: expires.format()
}; };
console.log(newValues);
fetch("/api/golinks/", { fetch("/api/golinks/", {
method: "post", method: "post",
headers: { headers: {
...@@ -58,44 +57,40 @@ class DebugCreate extends React.Component { ...@@ -58,44 +57,40 @@ class DebugCreate extends React.Component {
}} }}
render={({ values, isSubmitting, setFieldValue }) => ( render={({ values, isSubmitting, setFieldValue }) => (
<Form> <Form>
<FormikForm> <FormGroup>
<FormGroup> {"Destination: "}
{"Destination: "} <Field
<Field className="form-control"
className="form-control" name="destination"
name="destination" placeholder="https://longwebsitelink.com"
placeholder="https://longwebsitelink.com" />
/> <ErrorMessage name="destination" component="div" />
<ErrorMessage name="destination" component="div" /> </FormGroup>
</FormGroup> <FormGroup>
<FormGroup> {"Short: "}
{"Short: "} <Field className="form-control" name="short" />
<Field className="form-control" name="short" /> <ErrorMessage name="short" />
<ErrorMessage name="short" /> </FormGroup>
</FormGroup> <FormGroup>
<FormGroup> {"Expires: "}
{"Expires: "} <br />
<br /> <SingleDatePicker
<SingleDatePicker date={values["expires"]} // momentPropTypes.momentObj or null
date={values["expires"]} // momentPropTypes.momentObj or null onDateChange={date => setFieldValue("expires", date)} // PropTypes.func.isRequired
onDateChange={date => setFieldValue("expires", date)} // PropTypes.func.isRequired focused={this.state.focused} // PropTypes.bool
focused={this.state.focused} // PropTypes.bool onFocusChange={({ focused }) => this.setState({ focused })} // PropTypes.func.isRequired
onFocusChange={({ focused }) => id="expires" // PropTypes.string.isRequired,
this.setState({ focused }) />
} // PropTypes.func.isRequired <ErrorMessage name="expires" />
id="expires" // PropTypes.string.isRequired, </FormGroup>
/> <Button
<ErrorMessage name="expires" /> type="submit"
</FormGroup> disabled={isSubmitting}
<Button outline
type="submit" color="primary"
disabled={isSubmitting} >
outline Submit
color="primary" </Button>
>
Submit
</Button>
</FormikForm>
</Form> </Form>
)} )}
/> />
......
...@@ -2,6 +2,7 @@ import React from "react"; ...@@ -2,6 +2,7 @@ import React from "react";
import * as Yup from "yup"; import * as Yup from "yup";
import { GetCSRFToken } from "../../Utils"; import { GetCSRFToken } from "../../Utils";
import { Formik, Field, Form, ErrorMessage } from "formik"; import { Formik, Field, Form, ErrorMessage } from "formik";
import { Button, Card, CardBody, CardTitle, FormGroup } from "reactstrap";
const DebugDeleteYup = Yup.object().shape({ const DebugDeleteYup = Yup.object().shape({
short: Yup.string() short: Yup.string()
...@@ -11,33 +12,46 @@ const DebugDeleteYup = Yup.object().shape({ ...@@ -11,33 +12,46 @@ const DebugDeleteYup = Yup.object().shape({
const DebugDelete = () => ( const DebugDelete = () => (
<div> <div>
<Formik <Card>
initialValues={{ short: "" }} <CardBody>
validationSchema={DebugDeleteYup} <CardTitle>Delete</CardTitle>
onSubmit={(values, { setSubmitting }) => {
const deleteURL = "/api/golinks/" + values.short; <Formik
fetch(deleteURL, { initialValues={{ short: "" }}
method: "delete", validationSchema={DebugDeleteYup}
headers: { onSubmit={(values, { setSubmitting }) => {
"Content-Type": "application/json", const deleteURL = "/api/golinks/" + values.short;
"X-CSRFToken": GetCSRFToken() fetch(deleteURL, {
} method: "delete",
}) headers: {
.then(response => console.log(response)) "Content-Type": "application/json",
.then(setSubmitting(false)); "X-CSRFToken": GetCSRFToken()
}} }
render={({ isSubmitting }) => ( })
<Form> .then(response => console.log(response))
{"Short: "} .then(setSubmitting(false));
<Field name="short" /> }}
<ErrorMessage name="short" /> render={({ isSubmitting }) => (
<br /> <Form>
<button type="submit" disabled={isSubmitting}> <FormGroup>
Submit {"Short: "}
</button> <Field className="form-control" name="short" />
</Form> <ErrorMessage name="short" />
)} </FormGroup>
/>
<Button
type="submit"
disabled={isSubmitting}
outline
color="primary"
>
Submit
</Button>
</Form>
)}
/>
</CardBody>
</Card>
</div> </div>
); );
......
import React from "react"; import React from "react";
import { GetAllGoLinks } from "../../Utils"; import { GetAllGoLinks } from "../../Utils";
import { Button } from "reactstrap"; import { Button, Card, CardBody, CardTitle, Table } from "reactstrap";
class DebugRead extends React.Component { class DebugRead extends React.Component {
constructor(props) { constructor(props) {
...@@ -30,15 +30,42 @@ class DebugRead extends React.Component { ...@@ -30,15 +30,42 @@ class DebugRead extends React.Component {
render() { render() {
return ( return (
<div> <div>
<Button onClick={this.refreshGoLinks} color="primary"> <Card>
Refresh <CardBody>
</Button>{" "} <CardTitle className="d-flex">
{this.state.GoLinks.map(golink => ( Read{" "}
<li key={golink.short}> <Button
<a href={`/${golink.short}`}> /{golink.short}</a> |{" "} className="ml-auto"
{golink.destination} onClick={this.refreshGoLinks}
</li> outline
))} color="primary"
>
Refresh
</Button>
</CardTitle>
<Table>
<thead>
<tr>
<th>short</th>
<th>destination</th>
<th>expires</th>
</tr>
</thead>
<tbody>
{this.state.GoLinks.map(golink => (
<tr key={golink.short}>
<td>
<a href={`/${golink.short}`}> /{golink.short}</a>
</td>
<td>{golink.destination}</td>
<td>{golink.date_expires}</td>
</tr>
))}
</tbody>
</Table>
</CardBody>
</Card>
</div> </div>
); );
} }
......
...@@ -2,6 +2,9 @@ import React from "react"; ...@@ -2,6 +2,9 @@ import React from "react";
import * as Yup from "yup"; import * as Yup from "yup";
import { Formik, Field, Form, ErrorMessage } from "formik"; import { Formik, Field, Form, ErrorMessage } from "formik";
import { GetCSRFToken } from "../../Utils"; import { GetCSRFToken } from "../../Utils";
import { FormGroup, Button, Card, CardBody, CardTitle } from "reactstrap";
import { SingleDatePicker } from "react-dates";
import moment from "moment";
const DebugUpdateYup = Yup.object().shape({ const DebugUpdateYup = Yup.object().shape({
destination: Yup.string() destination: Yup.string()
...@@ -12,70 +15,108 @@ const DebugUpdateYup = Yup.object().shape({ ...@@ -12,70 +15,108 @@ const DebugUpdateYup = Yup.object().shape({
.max(20, "Too Long!"), .max(20, "Too Long!"),
newshort: Yup.string() newshort: Yup.string()
.required("Required") .required("Required")
.max(20, "Too Long!") .max(20, "Too Long!"),
// expires: Yup.date() expires: Yup.date()
// .nullable() .nullable()
// .min(new Date(new Date().getTime() + 24 * 60 * 60 * 1000)) .min(new Date())
}); });
const DebugUpdate = () => ( class DebugUpdate extends React.Component {
<div> constructor(props) {
<Formik super(props);
initialValues={{ this.state = {
oldshort: "", focused: false
newshort: "", };
newdestination: "", }
expires: new Date()
}} render() {
validationSchema={DebugUpdateYup} return (
onSubmit={( <div>
{ newshort, oldshort, expires, destination }, <Card>
{ setSubmitting } <CardBody>
) => { <CardTitle>Update</CardTitle>
const updateURL = "/api/golinks/" + oldshort + "/"; <Formik
const payload = { initialValues={{
short: newshort, oldshort: "",
destination: destination, newshort: "",
expires: expires newdestination: "",
}; expires: moment(new Date())
fetch(updateURL, { }}
method: "put", validationSchema={DebugUpdateYup}
headers: { onSubmit={(
"Content-Type": "application/json", { newshort, destination, expires },
"X-CSRFToken": GetCSRFToken() { setSubmitting }
}, ) => {
body: JSON.stringify(payload) const updateURL = "/api/golinks/" + oldshort + "/";
}) const payload = {
.then(response => console.log(response)) short: newshort,
.then(setSubmitting(false)); destination: destination,
}} expires: expires.format()
render={({ isSubmitting }) => ( };
<Form> fetch(updateURL, {
{"Old Short: "} method: "put",
<Field name="oldshort" /> headers: {
<ErrorMessage name="oldshort" /> "Content-Type": "application/json",
<br /> "X-CSRFToken": GetCSRFToken()
},
body: JSON.stringify(payload)
})
.then(response => console.log(response))
.then(setSubmitting(false));
}}
render={({ values, isSubmitting, setFieldValue }) => (
<Form>
<FormGroup>
{"Old Short: "}
<Field className="form-control" name="oldshort" />
<ErrorMessage name="oldshort" />
</FormGroup>
{"New Destination: "} <FormGroup>
<Field name="destination" placeholder="https://longwebsitelink.com" /> {"New Destination: "}
<ErrorMessage name="destination" component="div" /> <Field
<br /> className="form-control"
name="destination"
placeholder="https://longwebsitelink.com"
/>
<ErrorMessage name="destination" component="div" />
</FormGroup>
{"New Short: "} <FormGroup>
<Field name="newshort" /> {"New Short: "}
<ErrorMessage name="newshort" /> <Field className="form-control" name="newshort" />
<br /> <ErrorMessage name="newshort" />
</FormGroup>
{"New Expires: "} <FormGroup>
<Field type="select" name="expires" placeholder="leave blank" /> {"Expires: "}
<ErrorMessage name="expires" /> <br />
<br /> <SingleDatePicker
<button type="submit" disabled={isSubmitting}> date={values["expires"]} // momentPropTypes.momentObj or null
Submit onDateChange={date => setFieldValue("expires", date)} // PropTypes.func.isRequired
</button> focused={this.state.focused} // PropTypes.bool
</Form> onFocusChange={({ focused }) =>
)} this.setState({ focused })
/> } // PropTypes.func.isRequired
</div> id="expires" // PropTypes.string.isRequired,
); />
<ErrorMessage name="expires" />
</FormGroup>
<Button
type="submit"
disabled={isSubmitting}
outline
color="primary"
>
Submit
</Button>
</Form>
)}
/>
</CardBody>
</Card>
</div>
);
}
}
export default DebugUpdate; export default DebugUpdate;
...@@ -16,16 +16,21 @@ class DebugCRUD extends React.Component { ...@@ -16,16 +16,21 @@ class DebugCRUD extends React.Component {
render() { render() {
return ( return (
<AuthedPageTemplate> <AuthedPageTemplate>
<DebugCreate /> <div className="my-3">
<DebugCreate />
</div>
<h3>Read</h3> <div className="my-3">
<DebugRead /> <DebugRead />
</div>
<h3>Update</h3> <div className="my-3">
<DebugUpdate /> <DebugUpdate />
</div>
<h3>Delete</h3> <div className="my-3">
<DebugDelete /> <DebugDelete />
</div>
</AuthedPageTemplate> </AuthedPageTemplate>
); );
} }
......
...@@ -10,6 +10,76 @@ ...@@ -10,6 +10,76 @@
<meta name="theme-color" content="#006633" /> <meta name="theme-color" content="#006633" />
<meta name="description" content="University-branded URL shortening" /> <meta name="description" content="University-branded URL shortening" />
<title>SRCT Go 3</title> <title>SRCT Go 3</title>
<link
rel="apple-touch-icon"
sizes="57x57"
href="static/apple-icon-57x57.png"
/>
<link
rel="apple-touch-icon"
sizes="60x60"
href="static/apple-icon-60x60.png"
/>
<link
rel="apple-touch-icon"
sizes="72x72"
href="static/apple-icon-72x72.png"
/>
<link
rel="apple-touch-icon"
sizes="76x76"
href="static/apple-icon-76x76.png"
/>
<link
rel="apple-touch-icon"
sizes="114x114"
href="static/apple-icon-114x114.png"
/>
<link
rel="apple-touch-icon"
sizes="120x120"
href="static/apple-icon-120x120.png"
/>
<link
rel="apple-touch-icon"
sizes="144x144"
href="static/apple-icon-144x144.png"
/>
<link
rel="apple-touch-icon"
sizes="152x152"
href="static/apple-icon-152x152.png"
/>
<link
rel="apple-touch-icon"
sizes="180x180"
href="static/apple-icon-180x180.png"
/>
<link
rel="icon"
type="image/png"
sizes="192x192"
href="static/android-icon-192x192.png"
/>
<link
rel="icon"
type="image/png"
sizes="32x32"
href="static/favicon-32x32.png"
/>
<link
rel="icon"
type="image/png"
sizes="96x96"
href="static/favicon-96x96.png"
/>
<link
rel="icon"
type="image/png"
sizes="16x16"
href="static/favicon-16x16.png"
/>
<link rel="manifest" href="static/manifest.json" />
</head> </head>
<body> <body>
......
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>
\ No newline at end of file
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment