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

Frontend changes for showing tabbed course overview stats #5064

Merged
merged 23 commits into from
Aug 1, 2022

Conversation

vaidehi44
Copy link
Contributor

What this PR does

This PR contains frontend changes corresponding to tabbed overview stats presented on course overview page.

The structure for course_stats object is -

{
  'www.wikidata.org' => WIKIDATA_STATS,
  'en.wikipedia.org-namespace-0' => ENWIKI_MAINSPACE_STATS,
  'en.wikibooks.org-namespace-102' => WIKIBOOKS_COOKBOOT_STATS
} 

Screenshots

image
image

@ragesoss
Copy link
Member

I think there's some room for design improvements for the tabs. I'm still unsure whether showing all the tabs like this would be better than have a dropdown to select between them, but here's the design (by Toqa, a designer I hired to work on it a few months ago) that we have for it:

Final 1

Final 2

renderZero={true}
/>
<OverviewStat
id="student-editors"
Copy link
Member

Choose a reason for hiding this comment

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

I don't think the user count needs to be in any namespace-specific stats.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Won't it give insight of how many students worked on particular tracked namespace?

const OverviewStatsTabs = ({ statistics }) => {
const [currentTabId, setCurrentTabId] = useState(0);

const getTabTitle = (ns_id, wiki) => {
Copy link
Member

Choose a reason for hiding this comment

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

These two functions should probably be in a utils file rather than in this component. Tests for them would also be good.

const project = wiki.split('.')[1];
let ns_title = ArticleUtils.NamespaceIdMapping[ns_id];
if (typeof (ns_title) !== 'string') ns_title = ns_title[project];
return `Stats for ${I18n.t(`namespace.${ns_title}`)} (${wiki})`;
Copy link
Member

Choose a reason for hiding this comment

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

This message shouldn't be hard-coded in English. Per the design image I shared, we might not need a message like this anyway; the label for each tab could just be the domain plus the namespace name (when there is one).

};

const statsDataList = [];
// if there are wikidata overview stats, they should be displayed on first tab
Copy link
Member

Choose a reason for hiding this comment

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

This and the forEach loop are more data manipulation than I'd like to see. If possible, it would be best to do this in a way that doesn't special-case Wikidata. (I don't think it necessarily needs to be first.)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Also, I got this conceptual question. For each tab we have a different content rendered by different component. So, is it better to create this components, store and use them (like I am doing now), or is it better to initialize and render them instantaneously when a tab is selected?

I think in our case, the compoents are not that heavy and so they can probably be stored before hand.

import studentListKeys from '@components/students/shared/StudentList/student_list_keys.js';

export class StudentRevisionsList extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: false,
namespace: 'all'
namespace: -1 // show all namespace revisions by default
Copy link
Member

Choose a reason for hiding this comment

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

For a code comprehensibility perspective, I don't think replacing strings with numbers here is helpful. Do the changes here have any effect on behavior? If they are unrelated to displaying stats on the Overview tab, they probably shouldn't be included in this PR.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These changes are related to the namespace filter of revisions table.
Actually, earlier this code used namespaceToId function from ArticleUtils. But, now that I have defined new mapping function there (NamespaceIdMapping), that function would have become its duplicate. Hence, some changes reflected here.
Should I open another pr then?

Copy link
Member

Choose a reason for hiding this comment

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

I think this is okay, except... is there any reason to use -1 in place of all? The other integer values all map to a mainspace, but this one does not and -1 not as easy to interpret as all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Actually, I don't know what number to use for 'all', because for other options it would be their namespace id. May be, we can still use the strings - 'all', 'article', 'talk', etc.

Copy link
Member

Choose a reason for hiding this comment

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

I think a mix of numbers (for actual namespaces) and a string for all would be okay. But also, using strings for all of the values seems find to me.

@ragesoss
Copy link
Member

I think the namespace titles displayed in the tabs could be something like: en.wikibooks.org - Cookbook, en.wikipedia.org - Mainspace and www.wikidata.org.

It would be good to treat the titles in parallel, so that whatever parsing of the stats hash key is used, it works the same way for keys that include a namespace and those that don't. (ie, it should be able to handle www.wikidata.org, www.wikidata.org-namespace-120, en.wikibooks.org, and en.wikibooks.org-102.)

@vaidehi44
Copy link
Contributor Author

I think there's some room for design improvements for the tabs. I'm still unsure whether showing all the tabs like this would be better than have a dropdown to select between them, but here's the design (by Toqa, a designer I hired to work on it a few months ago) that we have for it:

Final 1

Final 2

I guess, right now the only reason for not having tabs would be because they can extend horizontally beyond page. But, if it is handled and made scrollable or something like that, I would prefer tabs than dropdowns :).

@vaidehi44
Copy link
Contributor Author

Should I also modify the UI for the aggregated mainspace stats at the top, according to the design?

@ragesoss
Copy link
Member

ragesoss commented Jul 22, 2022 via email

@vaidehi44
Copy link
Contributor Author

It would be good to treat the titles in parallel, so that whatever parsing of the stats hash key is used, it works the same way for keys that include a namespace and those that don't. (ie, it should be able to handle www.wikidata.org, www.wikidata.org-namespace-120, en.wikibooks.org, and en.wikibooks.org-102.)

I didn't get this. Should the namespace titles and stats title be same? Or there shouldn't be any stats title?

@ragesoss
Copy link
Member

ragesoss commented Jul 22, 2022 via email

@ragesoss
Copy link
Member

ragesoss commented Jul 22, 2022 via email

@vaidehi44
Copy link
Contributor Author

@ragesoss I have pushed most of the changes suggested except tabs UI. I feel that the tabs design which you have shared is too ordinary 😅. So, I tried out some stuff myself. Do you think, we can may be try something from these, or anything else?

Screenshot (28)

Screenshot (29)

Screenshot (38)

@ragesoss
Copy link
Member

I like the third one!

const title = statsList[currentTabId].statsTitle;
const data = statsList[currentTabId].statsData;
const content = (title === 'www.wikidata.org')
? <WikidataOverviewStats statistics={data} isCourseOverview={true}/>
Copy link
Member

Choose a reason for hiding this comment

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

It might make sense here to implement another simple component (eg, OverviewStatsTab (singular)), so that this tabs component has a simple job: render all the tabs and render the content for the current tab. The new component would be in charge of which component to render for the current tab content.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Well, I have already created a component named OverviewStatsTab which renders a tab.
May be we can name it OverviewStatsContent or OverviewStatsData or anything like that. And, you are saying that the logic of identifying the content (whether it is wikidata or namespace stats) according to active tab, should be done in this component? Instead of having statsList, we should use this new component?

Copy link
Member

Choose a reason for hiding this comment

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

You're right, OverviewStatsTab would be a bad name for it, and the component you have now called that is appropriately named. OverviewStatsContent sounds good.

And yes, I think having this component identify wikidata vs namespace stats should be done in that new component.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

@ragesoss, I have created the OverviewStatsContent component. Please check it along with OverviewStatsTabs to confirm if that's okay.

Copy link
Member

Choose a reason for hiding this comment

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

yes, it looks good to me.

const WikidataOverviewStats = ({ statistics }) => {
const WikidataOverviewStats = ({ statistics, isCourseOverview }) => {
let containerClass = 'wikidata-stats-container';
let title = 'Wikidata stats';
Copy link
Member

Choose a reason for hiding this comment

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

It looks like this title isn't used in the the latest screenshots you shared?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, it is used. In the last one. Here, the title isn't "Wikidata stats", but "www.wikidata.org". I thought that this would be in accordance with other namespace stats and their title. So, "Wikidata Stats" would be only shown for campaign overview stats. Is it okay?

@@ -23,7 +23,7 @@

it 'shows Wikidata stats on the Home tab' do
visit "/courses/#{course.slug}"
expect(page).to have_content('Wikidata stats')
expect(page).to have_content('www.wikidata.org')
Copy link
Member

Choose a reason for hiding this comment

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

I'd like this PR to include a ruby feature spec for having multiple tabs and interacting with them. This file could be renamed detailed course stats or similar, and then the spec could be basically the same as this Wikidata one except with multiple tabs worth of data in the CoursesStats record.

The spec should test clicking through different tabs and seeing the different stats render.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

okay!

course.course_stat.stats_hash['www.wikidata.org']
end
}.compact
Copy link
Member

Choose a reason for hiding this comment

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

I think rubocop will complain about using braces for a multi-line block instead of do/end. You can still chain the do/end syntax with end.compact.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ohkk, thanks.

visit "/courses/#{course.slug}"
end

it 'shows tabs for all the course stats objects' do
Copy link
Member

Choose a reason for hiding this comment

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

I think it would be a little better to condense this into one test example, because only loading the page once will be a little faster, and all these tasks together represent a typical user flow: first load the page and see the expected tabs, then look at the default tab's content and confirm that at least one of the expected stats is being displayed (eg, 35 claimed created), then click to the next tab (ideally identifying it by the rendered label rather than the tab-1 id) and verify that the wikidata stats are gone and the new stats are there, then clicking the third tab and doing the same thing.

@ragesoss
Copy link
Member

ragesoss commented Aug 1, 2022

@vaidehi44 can you include before/after screenshots for the case of just Wikidata stats?

@@ -151,9 +151,9 @@ def trained_percent
end

def wikidata_stats
stats ||= courses.joins(:course_stat).where.not(course_stats: nil).map { |course|
stats ||= courses.joins(:course_stat).where.not(course_stats: nil).filter_map do |course|
Copy link
Member

Choose a reason for hiding this comment

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

nice

@vaidehi44
Copy link
Contributor Author

vaidehi44 commented Aug 1, 2022

@vaidehi44 can you include before/after screenshots for the case of just Wikidata stats?

@ragesoss

Before

image

After

image

@ragesoss
Copy link
Member

ragesoss commented Aug 1, 2022

Okay! I think this is ready to merge. Anything you can think of that should be done before that?

@vaidehi44
Copy link
Contributor Author

@ragesoss, I think, one thing which needs to be done is to handle overflow of tabs if there are more number of tabs. Of course, this can be done later too as now in prod there won't be any tabs.

@ragesoss
Copy link
Member

ragesoss commented Aug 1, 2022

Good point. Do you have a plan for that? I'm fine with either merging this now and handling tab overflow in a separate PR, or including it in this one.

@vaidehi44
Copy link
Contributor Author

I have some ideas, but not a perfect plan. So, I think I can open a seperate a PR for this. We can may be try different things there.

@ragesoss ragesoss merged commit 1df0914 into WikiEducationFoundation:master Aug 1, 2022
@ragesoss
Copy link
Member

ragesoss commented Oct 11, 2022 via email

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.

2 participants