Skip to content

Commit

Permalink
Merge pull request #13 from jonfairbanks/develop
Browse files Browse the repository at this point in the history
Edit/Delete Support for UI
  • Loading branch information
jonfairbanks authored Jun 22, 2019
2 parents c7348e5 + 8a96bb6 commit c394adc
Show file tree
Hide file tree
Showing 6 changed files with 163 additions and 33 deletions.
23 changes: 10 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,6 @@ location ~* "^/[0-9a-z!?@_-]{1,99}$" {
proxy_set_header X-Real-IP $remote_addr;
rewrite ^/(.*)$ https://my-api-url.com/api/item/$1 redirect;
}
location /status/ {
auth_basic "Administrator Login";
auth_basic_user_file /etc/nginx/.htpasswd;
proxy_pass http://127.0.0.1:7000/status;
proxy_set_header x-real-ip $remote_addr;
# Upgrade for Websockets
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
location /socket.io {
proxy_pass http://127.0.0.1:7000;
proxy_set_header x-real-ip $remote_addr;
Expand Down Expand Up @@ -127,18 +117,25 @@ By default, the Yo backend API is open which would allow anyone who knew your AP
- Before leaving Auth0, create a user account for your application under User & Roles.
- When starting the Yo client, pass `REACT_APP_AUTH=true` as an ENV variable to enforce user logins.
- When starting the Yo server, pass `AUTH=true` as an ENV variable to enable authentication checks.
- Navigate to Yo and login with the previously created user. If successful, you should be logged into the dashboard successfully.
- Navigate to Yo and login with the previously created user. If successful, you should be logged into the dashboard successfully.

By default, sign-ups via the Auth0 UI are disabled. If you would like to allow user-signup however, you can force this on by passing `REACT_APP_SIGNUPS=true` during Yo client startup.

## Extras
- If you're using PM2 to manage your node processes, you can use the included `yo-pm2.yaml` to start and deploy the app.
- Yo can also be deployed via Docker using the included `docker-compose.yaml` file. Enter the Yo root directory and run `docker-compose up` to deploy the Yo client, backend and

## ☑ TODO

- [x] Auto Update Tab Data
- [x] Client Dockerfile
- [x] Server Dockerfile
- [x] API Authentication
- [ ] Better Error Handling when Navigating to Unset Names
- [x] Edit/Delete Functionality
- [ ] Build and Deploy App
- [ ] Better Error Handling when Navigating to Unset Links
- [ ] Pass through for Query Parameters
- [ ] Swipeable Tabs
- [ ] Edit/Delete Functionality
- [ ] Further refactor Home.js

## Contributers
Expand Down
1 change: 1 addition & 0 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"moment": "^2.24.0",
"querystringify": "^2.1.1",
"react": "^16.8.6",
"react-bootstrap-sweetalert": "^4.4.1",
"react-copy-to-clipboard": "^5.0.1",
"react-dom": "^16.8.6",
"react-router-dom": "^5.0.0",
Expand Down
151 changes: 143 additions & 8 deletions client/src/components/home/Home.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import io from 'socket.io-client';
import {CopyToClipboard} from 'react-copy-to-clipboard';
import Auth0Lock from 'auth0-lock';
import axios from "axios";
import SweetAlert from "react-bootstrap-sweetalert";

const socket = io(config.socketUrl);

Expand Down Expand Up @@ -49,12 +50,16 @@ class Home extends Component {
this.getLiveYos = this.getLiveYos.bind(this);
this.hideErrorDiags = this.hideErrorDiags.bind(this);
this.handleCopy = this.handleCopy.bind(this);
this.handleEdit = this.handleEdit.bind(this);
this.handleDelete = this.handleDelete.bind(this);
this.handleUpdate = this.handleUpdate.bind(this);
this.handleCancel = this.handleCancel.bind(this);
}

handleUserInput(e) {
const name = e.target.name;
const value = e.target.value;
this.setState({ [name]: value });
this.setState({ [name]: value, editingOriginalUrl: value });
}

extractHostname(url) {
Expand Down Expand Up @@ -187,6 +192,91 @@ class Home extends Component {
});
}

handleUpdate() {
var accessToken = null;
try{ accessToken = localStorage.getItem("accessToken") }catch(e) { accessToken = null };
var updEndpoint = this.state.apiUrl + "update/" + this.state.editingLink;
var body = { originalUrl: this.state.editingOriginalUrl }
axios.post(updEndpoint, body, { 'headers' : {'Content-Type': 'application/json', 'Authorization': "Bearer " + accessToken} })
.then(
this.setState({
alert: (
<SweetAlert
success
allowEscape
confirmBtnCssClass="modal-close waves-effect btn"
title={"Updated " + this.state.editingLink + "!"}
onConfirm={this.handleCancel}
>
This link was successfully updated.
</SweetAlert>
)
}),
setTimeout(() => {
this.handleCancel()
}, 5000)
)
.catch(err =>
this.setState({
alert: (
<SweetAlert
warning
allowEscape
confirmBtnCssClass="modal-close waves-effect btn"
title={"Internal Error"}
onConfirm={this.setState({alert: null})}
>
There was an error while updating {this.state.editingLink}.
</SweetAlert>
)
})
)
}

handleDelete() {
var accessToken = null;
try{ accessToken = localStorage.getItem("accessToken") }catch(e) { accessToken = null };
var delEndpoint = this.state.apiUrl + "delete/" + this.state.editingLink;
axios.post(delEndpoint, null, { 'headers' : {'Content-Type': 'application/json', 'Authorization': "Bearer " + accessToken} })
.then(
this.setState({
alert: (
<SweetAlert
success
allowEscape
confirmBtnCssClass="modal-close waves-effect btn"
title={"Deleted " + this.state.editingLink + "!"}
onConfirm={this.handleCancel}
>
This link was successfully deleted.
</SweetAlert>
)
}),
setTimeout(() => {
this.handleCancel()
}, 5000)
)
.catch(err =>
this.setState({
alert: (
<SweetAlert
warning
allowEscape
confirmBtnCssClass="modal-close waves-effect btn"
title={"Internal Error"}
onConfirm={this.handleCancel}
>
There was an error while deleting {this.state.editingLink}.
</SweetAlert>
)
})
)
}

handleCancel() {
this.setState({alert: null});
}

renderButton() {
if (!this.state.showLoading) {
return (
Expand Down Expand Up @@ -249,7 +339,7 @@ class Home extends Component {
allowedConnections: ["Username-Password-Authentication"],
rememberLastLogin: false,
allowForgotPassword: false,
allowSignUp: false,
allowSignUp: process.env.REACT_APP_SIGNUPS || false,
closable: false,
languageDictionary: {"title":"Yo - The URL Shortener"},
theme: {
Expand Down Expand Up @@ -465,7 +555,7 @@ class Home extends Component {
<input disabled style={{cursor: "not-allowed"}} placeholder={this.state.editingLink} id="edit-linkName"/>
<label className="grey-text text-darken-3" htmlFor="edit-linkName">Link Name</label>
<br/><br/>
<input style={{color: "#424242"}} defaultValue={this.state.editingOriginalUrl} id="edit-originalUrl"/>
<input style={{color: "#424242"}} onChange={this.handleUserInput.bind(this)} defaultValue={this.state.editingOriginalUrl} id="edit-originalUrl"/>
<label className="grey-text text-darken-3" htmlFor="edit-originalUrl">Original URL</label>
<br/>
</div>
Expand All @@ -474,17 +564,62 @@ class Home extends Component {
href="#!"
style={{float: "left"}}
className="modal-close waves-effect waves-red red darken-2 btn"
onClick={e =>
window.confirm("Are you sure you want to permanently delete this link?") &&
console.log("Deleted!")
}
onClick={e =>
this.setState({
alert: (
<SweetAlert
danger
showCancel
allowEscape
confirmBtnText="Yes, delete it!"
confirmBtnBsStyle="danger"
confirmBtnCssClass="modal-close waves-effect waves-red red darken-2 btn"
cancelBtnBsStyle="default"
cancelBtnCssClass="modal-close waves-effect waves-white btn grey"
title={"Delete " + this.state.editingLink + "?"}
onConfirm={this.handleDelete}
onCancel={this.handleCancel}
>
Are you sure? This is permanent!
</SweetAlert>
)
})
}
>
Delete
</a>
<a href="#!" className="modal-close waves-effect waves-white btn grey">Cancel</a>
<a style={{marginLeft: "8px"}} href="#!" className="waves-effect waves-teal btn">Update</a>
<a
href="#!"
style={{marginLeft: "8px"}}
className="modal-close waves-effect waves-teal btn"
onClick={e =>
this.setState({
alert: (
<SweetAlert
info
showCancel
allowEscape
confirmBtnText="Yes, update it!"
confirmBtnBsStyle="default"
confirmBtnCssClass="waves-effect waves-teal btn"
cancelBtnBsStyle="default"
cancelBtnCssClass="modal-close waves-effect waves-white btn grey"
title={"Update " + this.state.editingLink + "?"}
onConfirm={this.handleUpdate}
onCancel={this.handleCancel}
>
Do you want to update the current URL?
</SweetAlert>
)
})
}
>
Update
</a>
</div>
</div>
{this.state.alert}
</div>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion client/src/config/config.js.example
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
module.exports = {
apiUrl: "https://yo-api.mysite.io/api/",
apiUrl: "https://yo-api.mysite.io/api/", // Include the trailing slash!
socketUrl: "https://yo-api.mysite.io",
baseUrl: "https://yo.mysite.io",
blockedNames: ['socket.io'], // Items listed here will be blocked as linkNames
Expand Down
19 changes: 8 additions & 11 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4391,17 +4391,7 @@ fstream-ignore@^1.0.5:
inherits "2"
minimatch "^3.0.0"

fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
mkdirp ">=0.5 0"
rimraf "2"

fstream@^1.0.12:
fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.12, fstream@^1.0.2:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
Expand Down Expand Up @@ -8264,6 +8254,13 @@ react-app-polyfill@^1.0.1:
regenerator-runtime "0.13.2"
whatwg-fetch "3.0.0"

react-bootstrap-sweetalert@^4.4.1:
version "4.4.1"
resolved "https://registry.yarnpkg.com/react-bootstrap-sweetalert/-/react-bootstrap-sweetalert-4.4.1.tgz#94410a79c6d6a1e7ce4ede810904c90d08f6a01a"
integrity sha512-czUP6EPXb6GZopxxkixm+a5OaV+kbdxhFbsHaFNIF3l9jBypHCv29TrV8OOruAwrG+GpCmEd8LzzyYPZ0aL9TA==
dependencies:
object-assign "^4.1.0"

react-copy-to-clipboard@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/react-copy-to-clipboard/-/react-copy-to-clipboard-5.0.1.tgz#8eae107bb400be73132ed3b6a7b4fb156090208e"
Expand Down
Binary file modified images/architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit c394adc

Please sign in to comment.