-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add quicksight dashboard #97
Conversation
ca15ea1
to
c042fc3
Compare
c042fc3
to
06f4d42
Compare
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 wasn't entirely sure if this PR was ready for review yet, but I have a few comments/suggestions that I hope can be helpful in any case.
src/index.tsx
Outdated
<Route | ||
path="/admin/web/dashboard/quicksight(/:library)" | ||
component={QuicksightDashboardPage} | ||
/> |
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 believe this dashboard is meant to be displayed as an alternative to the current "snapshot" dashboard via a toggle on the DashboardPage
, so we shouldn't need a QuicksightDashboardPage
or its associated route.
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.
Okay - I'll fix that.
const server = setupServer( | ||
rest.get("*/admin/libraries", (req, res, ctx) => res(ctx.json(libraries))), | ||
|
||
rest.get("*/admin/quicksight_embed/" + dashboardId + "?libraryUuids=" + libraries["libraries"][0]["uuid"], (req, res, ctx) => res(ctx.json(dashboardUrlData))) |
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.
For msw
`setupServer, we should setup rest endpoint routes. rather than full URLs, so that we're matching the path part, but not the query params. We can get at the query params with something like...
const libraryUuids = req.url.searchParams.get("libraryUuids");
... and use them to adjust the response as needed (e.g., to distinguish "good" or "bad" requests.
src/actions.ts
Outdated
@@ -1095,4 +1097,12 @@ export default class ActionCreator extends BaseActionCreator { | |||
value, | |||
}; | |||
} | |||
|
|||
fetchDashboardUri(dashboardId: string) { | |||
const url = "/admin/quicksight_embed/" + dashboardId; |
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.
We can use string interpolation here:
const url = `/admin/quicksight_embed/${dashboardId}`;
Of course, you would need to append the libraryUuids query param, as well.
src/actions.ts
Outdated
@@ -1095,4 +1097,12 @@ export default class ActionCreator extends BaseActionCreator { | |||
value, | |||
}; | |||
} | |||
|
|||
fetchDashboardUri(dashboardId: string) { |
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.
A few things here:
- We need a reducer for this action (note also that other server fetch-related actions have additional state constants (for loading, success, etc.) above for use with the associated reducer).
- Need tests for this action in
./src/__tests__/actions-test.ts
. - Since we already have a
Dashboard
in the app, we should probably call this something different, likefetchQuicksiteUri
, to avoid confusion. What is currently theActionCreator.DASHBOARD_URI
constant above (and associated state constants) should match this. - We will probably need to pass in the library UUIDs here, as well, so that you can use them to form the complete URL.
If we plan to fetch the QS embed names, we'll probably want an additional action.
fetch( | ||
"/admin/quicksight_embed/" + | ||
this.props.dashboardId + | ||
"?libraryUuids=" + | ||
library_uuids | ||
) | ||
.then((response) => response.json()) | ||
.then((data) => this.setState({ embedUrl: data["embedUrl"] })) | ||
.catch((error) => { | ||
console.error(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.
Usually with Redux we would dispatch a Redux action to perform this fetch elsewhere (and it looks like we have added an action for this). Any reason why we need to code the fetch 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.
I changed this to dispatch to an action, but I don't think it is exactly right yet. I would like to get this out since this is really just a rough pass.
embedUrl: string; | ||
} | ||
|
||
class QuicksightDashboard extends React.Component< |
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.
Can we implement this as a functional component with hooks, rather than as a higher order connected class component? The former is the current recommendation when developing new components. The latter requires a lot more boilerplate (and obfuscation), especially with Redux connected HoCs.
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.
Yes - will rework this once we get some feedback.
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 is not critical for now. We already have Redux connected HoCs, so continuing to use them is fine.
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.
We should test some non-happy paths here, as well:
- What happens when there is an error in one or more of the requested UUIDs?
- What happens when a requested UUID doesn't exist (same as above or does QS ignore)?
- ... maybe some others -- I don't understand the QS dashboard flow as well as I'd like.
"/admin/quicksight_embed/" + | ||
this.props.dashboardId + | ||
"?libraryUuids=" + | ||
library_uuids | ||
) |
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.
We can use string interpolation here, if we don't remove this fetch in favor of a dispatched Redux action.
…to fit the container.
7de047b
to
ac37ef2
Compare
embedUrl: string; | ||
} | ||
|
||
class QuicksightDashboard extends React.Component< |
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 is not critical for now. We already have Redux connected HoCs, so continuing to use them is fine.
// TODO: For whatever reason, the "this.props.libraries" variable was not being | ||
// set when I tried to put this logic in the render method (nor did it work trying to access it in this method). |
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.
It doesn't look like libraries
is being passed as a prop
from QuicksightDashboardPage
l.46, so that's probably why we don't see it here. We are passing dashboardId
there, but not library
.
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.
Right - "libraries" is the list of libraries that is being pulled from the store - at least I'd like to be pulling it from the store. But it doesn't get loaded. I removed the reference to "library" for now, because of the way the QS filtering is working: it's always returning the list of libraries the user has access to. So in the library QS view, users can look across all libraries, any group of libraries or a single library.
} | ||
|
||
/** Page holds quicksight dashboards. */ | ||
export default class DashboardPage extends React.Component<QuicksightDashboardPageProps> { |
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.
We should use QuicksightDashboardPage
-- rather than DashboardPage
-- here, since it could be confusing. DashboardPage
is used in the DashboardPage
component, so using it here could be confusing.
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.
Good point I'll fix that.
src/index.tsx
Outdated
@@ -87,6 +88,10 @@ class CirculationAdmin { | |||
path="/admin/web/dashboard(/:library)" | |||
component={DashboardPage} | |||
/> | |||
<Route | |||
path="/admin/web/quicksight(/:library)" |
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.
Not sure why we're passing the library here, since it is not currently used to select which libraryUuid
s are selected for inclusion.
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.
Right - I'll remove that for now. Oversight.
<div className="quicksight-dashboard"> | ||
<Header /> | ||
<main className="body"> | ||
<QuicksightDashboard dashboardId="library"/> |
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 is where we can pass the library
prop into the QuicksightDashboard
component.
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.
For the demo, we'll leave the library prop off so the user can select the libraries they have access to when viewing the report.
@tdilauro : updates are in. |
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 added a few follow-on comments related to the most recent changes.
Also a reminder about the hardcoded dashboardId
and follow-on changes that would be needed if it were removed.
export interface QuicksightDashboardPageProps | ||
extends React.Props<QuicksightDashboardPageProps> { | ||
params: { | ||
library?: string; | ||
}; | ||
} |
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.
Since we're no longer passing a library
param here, we no longer need the QuicksightDashboardPageProps
interface, so we should get rid of this.
We'll also need to remove it from the class definition below.
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.
We're not passing it now, but we may want to pass it later. Ie if we want to pre-select the library. To make this work, we'll need to make some changes on the backend. But I'm thinking we may want to leave this param in here for the time being.
export default class QuicksightDashboardPage extends React.Component< | ||
QuicksightDashboardPageProps | ||
> { |
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.
Since we no longer need QuicksightDashboardPageProps
, we can change the props type here to none, like this:
export default class QuicksightDashboardPage extends React.Component<never> {
...
<div className="quicksight-dashboard"> | ||
<Header /> | ||
<main className="body"> | ||
<QuicksightDashboard dashboardId="library" /> |
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.
Again, we don't need to pass this hardcoded dashboarId
prop here. We can just use the hardcoded value directly in the child component.
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 remove this - but it was my assumption that the admin interface may provide more than one dashboard depending on the access level of the user.
|
||
export interface QuicksightDashboardOwnProps { | ||
store?: Store<RootState>; | ||
dashboardId?: string; |
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.
We won't need dashboardId
as a prop here, assuming that we stop passing the hardcoded value from the parent page.
this.props.fetchLibraries().then((libs) => { | ||
try { | ||
this.props | ||
.fetchQuicksightEmbedUrl(this.props.dashboardId, libs) |
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.
Assuming that we stop passing the hardcoded value from the parent page, we should replace this.props.dashboardId
with a new constant in this module.
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.
We may offer other dashboards down the road depending on the user's permissions. However for now, I suppose I can make this a constant.
src/actions.ts
Outdated
@@ -190,6 +190,7 @@ export default class ActionCreator extends BaseActionCreator { | |||
static readonly RESET_ADOBE_ID = "RESET_ADOBE_ID"; | |||
|
|||
static readonly DIAGNOSTICS = "DIAGNOSTICS"; | |||
static readonly QUICKSIGHT_EMBEDDED_URL: "QUICKSIGHT_EMBEDDED_URL"; |
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 think I missed this before, but the value of this constant needs to assigned with and equal sign.
static readonly QUICKSIGHT_EMBEDDED_URL = "QUICKSIGHT_EMBEDDED_URL";
This might be why we were running into trouble using Redux actions dispatch. I also note that the various state constants for the QUICKSIGHT_EMBEDDED_URL
action are not defined, which would also prevent actions dispatch from working properly. There are assumptions/naming conventions for these on which fetchJSON
depends. A good template for that would be the STATS
action:
...
static readonly STATS = "STATS";
...
static readonly STATS_REQUEST = "STATS_REQUEST";
static readonly STATS_SUCCESS = "STATS_SUCCESS";
static readonly STATS_FAILURE = "STATS_FAILURE";
static readonly STATS_LOAD = "STATS_LOAD";
...
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'll fix.
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.
Good 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 understanding what you did with the Stats piece now a little better. I'd like to get this out there for front-end feedback, but I will plan to rework the fetching using RTK before we goes live.
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 looks good for now and doesn't appear to break functionality elsewhere in the app.
Description
Once you've logged in, to see the dashboard you need to go to:
http://localhost:8080/admin/web/quicksight
The URL is not exposed in the App (since I don't think it is quite ready for prime time).
Motivation and Context
https://ebce-lyrasis.atlassian.net/browse/PP-517
How Has This Been Tested?
Added unit test.
Tested it manually.
Checklist: