-
Notifications
You must be signed in to change notification settings - Fork 22
New Feature - Create and manage "Personal Access Tokens" (API Tokens) from "Settings Page" #789
Conversation
I am testing how this works if the Atmosphere API is unreachable. When a token is being created, it will fail and the user will see that it is removed from the list, but the modal will stay open and it will keep saying 'Creating...' I am experimenting with passing two callback functions to the create action, one for failure and one for success. Initially I just made the failure one change the state to not show creating anymore, and it worked out well. It just returned the user to the modal's initial state. Should we add an error message that shows up as part of the modal? Or we could use a NotificationController like we do with the icon select and guacamole color select here is what I experimented with: calvinmclean@2983c70 |
If the Atmosphere API fails to create a token, the modal would still act as if it was trying to create the token. Now, it will go back to the initial state of the modal (while still showing the entered name), and will present a notification with an error message.
Pr is failing the formatter This will replay your pr on top of origin/master, and after each commit is brought over, it will be tested with the formatter. If the formatter fails, it'll stop to let you amend the commit, then you can continue rebasing. |
Thanks, there are some unused variables. Am building with the backend
changes now. After fixing the lint errors and updating change log I'll
remove the WIP status for review.
…On Wed, Aug 15, 2018, 11:28 AM Connor Osborn ***@***.***> wrote:
Pr is failing the formatter
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#789 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AHBmws_8em6tqobt1nAdpOJ1a3RjuvOPks5uRGg2gaJpZM4V65cg>
.
|
My thought is that we need to include the expiration time (and it should probably be 6mo). If it expired w/o the user knowing, they would experience this currently as the token just disappearing from their settings page. (left a comment on atmo pr, because it doesn't include expired tokens in api response). |
import Utils from "./Utils"; | ||
|
||
export default { | ||
create: ({name, atmo_user}, successCallback, failCallback) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Simplify this signature to
create(tokenName, user) => Promise
Since create is returning a promise, anyone who has the promise can promise.then(successCallback)
or promise.catch(failCallback)
export default { | ||
create: ({name, atmo_user}, successCallback, failCallback) => { | ||
if (!name) throw new Error("Missing Token name"); | ||
if (!atmo_user) throw new Error("Missing Token author"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
camelCase
errorMsg: "", | ||
name: this.props.name || "", | ||
successView: false | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all state needs to be included here
mixins: [BootstrapModalMixin], | ||
propTypes: { | ||
user: React.PropTypes.number.isRequired | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
all props need to be included here
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In getInitialState
we were assigning to name
the name
prop and letting in fall through to empty string if not defined name: name || ""
. I removed the use of the name
prop from Create modal as it was left over from when the Edit modal and Create modal were sharing code. Since separating these experiences into their own files we no longer need a name
prop on the Create modal.
}); | ||
actions.APITokenActions.create( | ||
attributes, | ||
this.successCallback, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
w.r.t to my prior comment,
let promise = actions.APITokenActions.create(...);
promise.then(...);
promise.catch(...):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm having trouble getting this interface to work in a way that doesn't feel kludgy. Could you elaborate? The model returned doesn't seem to be a promise unless I make it one in the action and that is where things start to get awkward. I do think it is better than using callbacks just not sure the best way to do it.
I can do let promise = Promise.resolve(...)
here but then I don't get the server response as an argument.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does actions.APITokenActions.create
return?
APITokenStore.remove(token); | ||
token.destroy({ | ||
success: function() { | ||
APITokenStore.emitChange(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
emitChange is a store implementation detail, nothing outside the store should call this. It's an implementation detail, because its part of the inner-mechanics of how the store works that no user of the store need know about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alternatively you can dispatch to the store, and let the store do store stuff
}; | ||
}, | ||
|
||
updateState() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
copy pasta
render() { | ||
let {APITokenStore} = this.props.subscriptions, | ||
profile = this.state.profile, | ||
api_token = APITokenStore.getAll(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
camelCase, and variable doesn't make sense for what should be a collection
{ | ||
token | ||
}, | ||
() => {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You don't need to pass empty callbacks, leave off that arg
<tbody> | ||
{api_token | ||
? api_token.map(this.renderTokenRow) | ||
: []} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Suggestion: (tokens || []).map(this.renderTokenRow)
RE: Showing the expiration date We are modeling the functionality of GH's implementation of "Personal Access Tokens". |
// Add token optimistically | ||
Utils.dispatch(APITokenConstants.ADD_TOKEN, {apiToken}); | ||
|
||
apiToken |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Change this method so that a promise is returned.
let promise = apiToken.save()
promise.done(...)
promise.fail(...)
return promise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This does prove that the model is indeed a promise and removes the then is not a function
error I was getting before. then
however isn't getting called... I'll keep digging.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The model is not a promise
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All I can think of is...
Okay, then lets not have the tokens expire, it was just an edge case I was considering. |
Optimistic logic isn't ideal. When the user hits create, the token is added, and shows in the table, but the modal continues to show in progress. So while the table add is optimistic the modal is not optimistic. We do not need to optimistically add the token, since the use will have to wait to copy the token key. |
Utils.dispatch(APITokenConstants.REMOVE_TOKEN, {apiToken}); | ||
NotificationController.error( | ||
"Error creating token.", | ||
"Your login might be expired. If you continue to see this error " + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Notification controller needs to include the error from the create response. Take a look at the arg to catch.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can add this change
RE: Optimistic logic |
user_id attribute doesn't need to be included in the create call. Since the user must be authenticated (i.e. the api knows exactly who is trying to create the token) to create the token, the api already knows who to create the token for. |
RE: user_id |
All requested changes have been made. Once cyverse/atmosphere#648 has been merged this can be as well. Thanks @cdosborn and @calvinmclean |
Since these tokens do not expire, it's convenient to at least see when the tokens were created. Also, this additional info assists the edge case where someone creates two access tokens with the same name.
Added "Issued" column re: cyverse/atmosphere#648 (comment) |
I tested against an api throwing errors in create/update/delete |
Thanks @cdosborn the updates look good! |
Create and manage "Personal Access Tokens" (API Tokens) from "Settings Page"
This PR is dependent on changes to Atmosphere API cyverse/atmosphere#648
This feature adds a section to the advanced settings page for creating and managing "Personal Access Tokens" or "API Auth Tokens" used to give other applications like the CLI access to the user's account.
This uses a new endpoint
"<root>/access_tokens"
and so a new store, actions, model, and collection have been added to the data layer.Actions the user can take:
Actions are submitted through modals:
APITokenCreate (two views)
Assign a name to Token
Success and Copy Token Hash
Transition, Assign and submit -> Success
APITokenEdit
APITokenDelete
Checklist before merging Pull Requests
flex: "1 0 24px"
.