Skip to content
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

New export ux #28795

Merged
merged 14 commits into from
Jun 3, 2019
Merged

New export ux #28795

merged 14 commits into from
Jun 3, 2019

Conversation

cpirich
Copy link
Contributor

@cpirich cpirich commented May 29, 2019

  • In preparation for student testing this week, we have updated the Export user experience (under the exportExpo experiment flag)
  • The Export button has been added to the project header (when the experiment is enabled) like this:

Screen Shot 2019-05-28 at 10 56 43 PM

Screen Shot 2019-05-28 at 10 54 06 PM

Screen Shot 2019-05-28 at 10 51 52 PM

Screen Shot 2019-05-28 at 10 52 09 PM

Screen Shot 2019-05-28 at 10 52 24 PM

Screen Shot 2019-05-28 at 10 52 38 PM

@cpirich cpirich requested review from Hamms and islemaster May 29, 2019 05:58
@cpirich
Copy link
Contributor Author

cpirich commented May 29, 2019

@ryansloan

Copy link
Contributor

@ryansloan ryansloan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tweaked some strings

apps/src/code-studio/components/ExportAllowedDialog.jsx Outdated Show resolved Hide resolved
apps/src/code-studio/components/ExportAllowedDialog.jsx Outdated Show resolved Hide resolved
Copy link
Contributor

@ryansloan ryansloan left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strings LGTM

Copy link
Contributor

@Hamms Hamms left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks awesome! I have a couple nits, and two larger comments:

First, I am super concerned about the size and complexity of the ExportAllowedDialog component. Can it be broken up into multiple components? Perhaps reconceived as a generic "dialog with multiple pages" component, and then the implementation logic moved into individual Components representing each page in sequence?

Second, looks like there are quite a few places in this using hardcoded English strings. Can these all be pulled out into i18n strings?

<p style={styles.title}>{titleText}</p>
</div>
<div style={styles.section}>
<p style={styles.p} dangerouslySetInnerHTML={{__html: headerText}} />
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

prefer using the UnsafeRenderedMarkdown component when we want to format strings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just played with it now and it isn't really working. I can't put it inside a <p> tag. When I put it inside a <div>, it loses the styles I applied. Plus it instantiates a markdown processor that I don't need. Seems like a good idea to have a reusable component, but it doesn't seem like the right fit for this scenario.

} = this.getActionButtonInfo();
const showShareWarning =
!this.props.canShareSocial &&
(this.props.appType === 'applab' || this.props.appType === 'gamelab');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there a specific reason why weblab is included in the "sharing enabled" logic, but not here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question. This copied the logic from ShareAllowedDialog - out of caution, I suggested to @ryansloan that we stick with the same logic for exporting. But I didn't try to revisit that logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That said, I should probably just remove the weblab references since we don't plan to support exporting weblab sites as mobile apps.


export default connect(
state => ({
allowExportExpo: state.pageConstants.allowExportExpo || false,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

isn't the || false here redundant?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It ensures that we satisfy a PropTypes requirement

return <ExportAllowedDialog {...otherProps} />;
}

return <ShareDisallowedDialog />; // TODO: re-use or create ExportDisallowedDialog?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd very much prefer to either create an ExportDisallowedDialog or rename ShareDisallowedDialog to something more generic

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I figured out a way to eliminate the extra component altogether. Trying to mimic the layers of warnings in the share dialog has been a little challenging. There are so many that have been bolted on!

@cpirich
Copy link
Contributor Author

cpirich commented May 31, 2019

This looks awesome! I have a couple nits, and two larger comments:

First, I am super concerned about the size and complexity of the ExportAllowedDialog component. Can it be broken up into multiple components? Perhaps reconceived as a generic "dialog with multiple pages" component, and then the implementation logic moved into individual Components representing each page in sequence?

I'm ok with doing that, though I'd prefer to do it after we lock in on a design (post student testing).

Second, looks like there are quite a few places in this using hardcoded English strings. Can these all be pulled out into i18n strings?

As this is only exposed by applab/gamelab, I'm following the pattern that we use throughout those apps where we do use hardcoded strings and do not use i18n

Copy link
Contributor

@islemaster islemaster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! I'm not quite ready to approve. I know this is still behind an experiment, but I'd like to see at least an initial test for each bit of new business logic. Specifically:

  • ExportAllowedDialog's publishExpoExport and publishAndGenerateApk methods.
  • ExportDialog's decision about whether export is allowed.
  • ProjectHeader and ProjectBackedHeader's new includeExportInProjectHeader props.
  • The new /sms/send_download route.

study: 'finish-dialog-export',
study_group: 'v1',
event: 'project-export',
project_id: dashboard.project && dashboard.project.getCurrentId(),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can import project directly without referring to the dashboard global, and it'll work just as well.

return;
}

await this.publishExpoExport();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it weird, from a student perspective, that generating the APK here could result in us showing this Expo error?

Failed to publish project to Expo. Please try again later.

There's a slight action-at-a-distance pattern here by depending on the state changes caused by publishExpoExport. I also suspect that this await is likely, but not guaranteed, to wait until the async setState calls in publishExpoExport complete.

I might call exportApp directly from publishAndGenerateApk, trading a little duplication for more control over what we do with the Expo results.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is really good feedback. My solution is a little different from what you proposed, because I know that for the iOS case, I need to do publishExpoExport(), but not the rest of the steps in publishAndGenerateApk(), so I want to keep them separate.

I've changed publishExpoExport() to return an object (essentially the exportResult or a similarly shaped object for the "already exported" or failure cases). This way we don't rely on the async setState() as a method to pass the results in this chained async scenario.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That sounds great. 👍

case 'publish':
return this.renderPublishPage();
case 'generating':
return this.renderGeneratingPage();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling out a personal preference for subcomponents over helper render methods, but that's easy to fix later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood, I'd be happy to revisit this later.

@@ -30,7 +27,6 @@ $(document).ready(function()
});

var petition;
$(document).ready(function()
{
$(document).ready(function() {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did this file change at all, or just get Prettier run on it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just prettier. somewhat on accident, but I decided to leave it since this now seems to match our preferred style.

return {
...state,
...initialState,
isOpen: true
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems like overkill.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

overkill meaning using redux to track whether the dialog is open? I agree that it is odd, but I started by following the share dialog and reduced most of the code away. I decided to keep this part because it allows us to use the dialog in a more "modeless" fashion (where you could close it while the export is underway, and open it back up later). I'm still in discussions with @ryansloan over the UI metaphor we'd use to enable that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I specifically meant ...state, ...initialState, isOpen: true when there's only the one property here. I think I see the spirit of the thing though. 😁

Copy link
Contributor

@islemaster islemaster left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 Updates look great. Thanks for adding good tests! :shipit:

@cpirich
Copy link
Contributor Author

cpirich commented Jun 3, 2019

Merging since #28886 has been merged to staging, resolving these unrelated failures that I was seeing above...

@cpirich cpirich merged commit 08416cd into staging Jun 3, 2019
@cpirich cpirich deleted the cpirich/new-export-ux branch June 3, 2019 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

5 participants