From 02da8da9614feeabce79468b8c4b37b5a20f47ad Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Fri, 22 Jul 2022 00:34:38 +0530 Subject: [PATCH 01/20] Add namespace-id mapping and make required modifications. --- .../RevisionsList/StudentRevisionsList.jsx | 17 ++++--- app/assets/javascripts/utils/article_utils.js | 44 +++++++++++++++---- config/locales/en.yml | 30 ++++++++++--- 3 files changed, 69 insertions(+), 22 deletions(-) diff --git a/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx b/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx index fe17d8c6d5..9746829bb6 100644 --- a/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx +++ b/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx @@ -8,7 +8,6 @@ import StudentRevisionRow from './StudentRevisionRow'; // Libraries import CourseUtils from '~/app/assets/javascripts/utils/course_utils.js'; -import ArticleUtils from '~/app/assets/javascripts/utils/article_utils.js'; import studentListKeys from '@components/students/shared/StudentList/student_list_keys.js'; export class StudentRevisionsList extends React.Component { @@ -16,7 +15,7 @@ export class StudentRevisionsList extends React.Component { super(props); this.state = { isOpen: false, - namespace: 'all' + namespace: -1 // show all namespace revisions by default }; this.toggleDrawer = this.toggleDrawer.bind(this); @@ -25,7 +24,7 @@ export class StudentRevisionsList extends React.Component { onNamespaceChange = (e) => { // Open the drawer when filter is used if (!this.state.isOpen) this.setState({ isOpen: true }); - return this.setState({ namespace: e.target.value }); + return this.setState({ namespace: Number(e.target.value) }); }; // filter the revisions according to namespace @@ -34,10 +33,10 @@ export class StudentRevisionsList extends React.Component { let revisions = []; if (userRevisions[student.id] !== undefined && userRevisions[student.id] !== null) { - revisions = (this.state.namespace === 'all') + revisions = (this.state.namespace === -1) ? userRevisions[student.id] : userRevisions[student.id].filter((rev) => { - return rev.article.namespace === ArticleUtils.namespaceToId(this.state.namespace); + return rev.article.namespace === this.state.namespace; }); } return revisions; @@ -98,10 +97,10 @@ export class StudentRevisionsList extends React.Component { value={this.state.namespace} onChange={this.onNamespaceChange} > - - - - + + + + ); return ( diff --git a/app/assets/javascripts/utils/article_utils.js b/app/assets/javascripts/utils/article_utils.js index 483f0902ec..af1f5242ee 100644 --- a/app/assets/javascripts/utils/article_utils.js +++ b/app/assets/javascripts/utils/article_utils.js @@ -21,13 +21,41 @@ export default class ArticleUtils { return project === 'wikidata' ? `${messageKey}_wikidata` : messageKey; } - // Mapping of namespace to its id - static namespaceToId(namespace) { - const mapping = { - article: 0, - talk: 1, - user: 2 - }; - return mapping[namespace]; + // The following mapping is also present in article.rb file and, + // wiki.rb has mapping of wikis to namespaces. Hence, any modifications + // in namespaces should also reflect in the corresponding files. + static NamespaceIdMapping = { + 0: 'main', + 1: 'talk', + 2: 'user', + 4: 'project', + 6: 'file', + 8: 'mediaWiki', + 10: 'template', + 12: 'help', + 14: 'category', + 104: 'page', + 108: 'book', + 110: 'wikijunior', + 114: 'translation', + 118: 'draft', + 120: 'property', + 122: 'query', + 146: 'lexeme', + 100: { + wiktionary: 'appendix', + wikisource: 'portal', + wikiversity: 'school' + }, + 102: { + wikisource: 'author', + wikibooks: 'cookbook', + wikiversity: 'portal' + }, + 106: { + wiktionary: 'rhymes', + wikisource: 'index', + wikiversity: 'collection' + } } } diff --git a/config/locales/en.yml b/config/locales/en.yml index 721142c544..6a49623f39 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -1049,15 +1049,35 @@ en: reverts_performed: Reverts performed namespace: + all: All main: Mainspace main_char_added: Mainspace chars added + article: Article + talk: Talk user: Userspace user_char_added: Userspace chars added - filter: - all_ns: All - article_ns: Article - user_ns: User - talk_ns: Talk + project: Project + file: File + mediaWiki: MediaWiki + template: Template + help: Help + category: Category + page: Page + book: Book + wikijunior: WikiJunior + translation: Translation + draft: Draft + property: Property + query: Query + lexeme: Lexeme + appendix: Appendix + portal: Portal + school: School + author: Author + cookbook: Cookbook + rhymes: Rhymes + index: Index + collection: Collection recent_activity: active_courses: Article is active in From 8c237a3c2b83ff1131e31d54650dcf1a2d2cfd43 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Fri, 22 Jul 2022 00:44:23 +0530 Subject: [PATCH 02/20] Add components to display namespace overview stats in tabs. --- .../namespace_overview_stats.jsx | 65 ++++++++++++ .../OverviewStats/overview_stats_tab.jsx | 21 ++++ .../components/common/overview_stats_tabs.jsx | 99 +++++++++++++++++++ .../components/overview/overview_handler.jsx | 12 ++- app/assets/javascripts/reducers/course.js | 3 +- 5 files changed, 195 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx create mode 100644 app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx create mode 100644 app/assets/javascripts/components/common/overview_stats_tabs.jsx diff --git a/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx b/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx new file mode 100644 index 0000000000..f8a085d14a --- /dev/null +++ b/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import OverviewStat from './overview_stat'; + +const NamespaceOverviewStats = ({ statistics }) => { + return ( +
+ + + + + + + +
+ ); +}; + +NamespaceOverviewStats.propTypes = { + statistics: PropTypes.object.isRequired +}; + +export default NamespaceOverviewStats; \ No newline at end of file diff --git a/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx b/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx new file mode 100644 index 0000000000..7e78d96aab --- /dev/null +++ b/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx @@ -0,0 +1,21 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +const OverviewStatsTab = ({ id, title, active, onClick }) => { + const isActive = (active) ? ' active' : ''; + const tabClass = `tab${isActive}`; + return ( +
+

{title}

+
+ ); +}; + +OverviewStatsTab.propTypes = { + id: PropTypes.number.isRequired, + title: PropTypes.string.isRequired, + active: PropTypes.bool.isRequired, + onClick: PropTypes.func.isRequired +}; + +export default OverviewStatsTab; diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx new file mode 100644 index 0000000000..3bc2e8f6c0 --- /dev/null +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -0,0 +1,99 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; + +import OverviewStatsTab from './OverviewStats/overview_stats_tab'; +import NamespaceOverviewStats from './OverviewStats/namespace_overview_stats'; +import WikidataOverviewStats from './wikidata_overview_stats'; + +import ArticleUtils from '../../utils/article_utils'; + + +const OverviewStatsTabs = ({ statistics }) => { + const [currentTabId, setCurrentTabId] = useState(0); + + const getTabTitle = (ns_id, wiki) => { + const project = wiki.split('.')[1]; + let ns_title = ArticleUtils.NamespaceIdMapping[ns_id]; + if (typeof (ns_title) !== 'string') ns_title = ns_title[project]; + return `${I18n.t(`namespace.${ns_title}`)} (${wiki})`; + }; + + const getContentTitle = (ns_id, wiki) => { + 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})`; + }; + + const onTabChange = (e) => { + return setCurrentTabId(Number(e.currentTarget.id)); + }; + + const hasWikidataStats = () => { + if (statistics['www.wikidata.org']) return true; + return false; + } + + const statsDataList = []; + // if there are wikidata overview stats, they should be displayed on first tab + if (hasWikidataStats) { + statsDataList.push({ + id: 0, + tabTitle: 'Wikidata', + contentTitle: null, // title for wikidata stats already exists in WikidataOverviewStats component + data: statistics['www.wikidata.org'] + }); + } + + let index = hasWikidataStats ? 1 : 0; + Object.keys(statistics).forEach((wiki_ns) => { + if (!wiki_ns.includes('namespace')) return; // return if it doesn't contain namespace stats + + const ns_id = Number(wiki_ns.split('-')[2]); // namespace id + const wiki = wiki_ns.split('-')[0]; + const id = index; + const tabTitle = getTabTitle(ns_id, wiki); + const contentTitle = getContentTitle(ns_id, wiki); + const data = statistics[wiki_ns]; + statsDataList.push({ id, tabTitle, contentTitle, data }); + index += 1; + }); + + const tabsList = statsDataList.map((obj) => { + return ( + + ); + }); + + const contentTitle = statsDataList[currentTabId].contentTitle; + const data = statsDataList[currentTabId].data; + const content = (hasWikidataStats && currentTabId === 0) + ? + : ; + + return ( +
+
+ {tabsList} +
+
+

{contentTitle}

+
+ {content} +
+
+
+ ); +}; + +OverviewStatsTabs.propTypes = { + statistics: PropTypes.object.isRequired +}; + +export default OverviewStatsTabs; diff --git a/app/assets/javascripts/components/overview/overview_handler.jsx b/app/assets/javascripts/components/overview/overview_handler.jsx index d68958c8fb..3f912fd4dc 100644 --- a/app/assets/javascripts/components/overview/overview_handler.jsx +++ b/app/assets/javascripts/components/overview/overview_handler.jsx @@ -24,7 +24,7 @@ import { fetchOnboardingAlert } from '../../actions/course_alert_actions'; import { fetchTags } from '../../actions/tag_actions'; import { addValidation, setValid, setInvalid, activateValidations } from '../../actions/validation_actions'; import { getStudentUsers, getWeeksArray, getAllWeeksArray, firstValidationErrorMessage, isValid } from '../../selectors'; -import WikidataOverviewStats from '../common/wikidata_overview_stats'; +import OverviewStatsTabs from '../common/overview_stats_tabs'; const Overview = createReactClass({ displayName: 'Overview', @@ -164,13 +164,17 @@ const Overview = createReactClass({ ) : (
); + + let overviewStatsTabs; + if (course.course_stats && course.course_stats.stats_hash) { + overviewStatsTabs = + } + return (
{ syllabusUpload } - {course.course_stats && } + {overviewStatsTabs} {userArticles}
diff --git a/app/assets/javascripts/reducers/course.js b/app/assets/javascripts/reducers/course.js index 4af1525975..6f2721be78 100644 --- a/app/assets/javascripts/reducers/course.js +++ b/app/assets/javascripts/reducers/course.js @@ -38,7 +38,8 @@ const initialState = { loading: true, updates: {}, wikis: [], - article_count: 0 + article_count: 0, + course_stats: {} }; From a0bb519a86182016f8d7ce1a3f81e0f0fc69fc1f Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Fri, 22 Jul 2022 01:27:58 +0530 Subject: [PATCH 03/20] Modify WikidataOverviewStats container class to adjust css. If the wikidata stats component is used in course overview tabs, there the extra padding and border is not required. But, it is necessary if the component is displayed on campaign overview page. --- .../components/common/overview_stats_tabs.jsx | 2 +- .../common/wikidata_overview_stats.jsx | 9 +++-- app/assets/stylesheets/modules/_stats.styl | 37 +++++++++++++++++++ 3 files changed, 44 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index 3bc2e8f6c0..8c2564fad6 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -74,7 +74,7 @@ const OverviewStatsTabs = ({ statistics }) => { const contentTitle = statsDataList[currentTabId].contentTitle; const data = statsDataList[currentTabId].data; const content = (hasWikidataStats && currentTabId === 0) - ? + ? : ; return ( diff --git a/app/assets/javascripts/components/common/wikidata_overview_stats.jsx b/app/assets/javascripts/components/common/wikidata_overview_stats.jsx index 495e92efc2..54e86ccbbd 100644 --- a/app/assets/javascripts/components/common/wikidata_overview_stats.jsx +++ b/app/assets/javascripts/components/common/wikidata_overview_stats.jsx @@ -3,9 +3,11 @@ import PropTypes from 'prop-types'; import OverviewStat from './OverviewStats/overview_stat'; import I18n from 'i18n-js'; -const WikidataOverviewStats = ({ statistics }) => { +const WikidataOverviewStats = ({ statistics, isCourseOverview }) => { + let containerClass = "wikidata-stats-container"; + if (isCourseOverview) containerClass = "wikidata-stats-container course-overview" return ( -
+

Wikidata stats

@@ -216,7 +218,8 @@ const WikidataOverviewStats = ({ statistics }) => { }; WikidataOverviewStats.propTypes = { - statistics: PropTypes.object + statistics: PropTypes.object.isRequired, + isCourseOverview: PropTypes.bool }; export default WikidataOverviewStats; diff --git a/app/assets/stylesheets/modules/_stats.styl b/app/assets/stylesheets/modules/_stats.styl index 89b1d4072d..419b5ea422 100644 --- a/app/assets/stylesheets/modules/_stats.styl +++ b/app/assets/stylesheets/modules/_stats.styl @@ -66,12 +66,49 @@ &:before left 50% +.overview-stats-tabs-container + background-color: #fff; + border: 1px solid #e2e2e2; + padding: 0px + + .tabs-container + padding: 0px + display: inline-flex + width: 100% + box-shadow: 0px 5px 5px #dfdfdf + background-color: #f5f5f5; + + .tab + padding: 5px 10px 5px 10px + border: 1px solid #e2e2e2 + min-width: 200px + cursor pointer + + &.active + border-bottom: 2px solid $brand_primary + p + color: $brand_primary + + .content-container + padding: 10px 20px + + .title + font-size 20px + font-weight 500 + line-height 55px + -webkit-font-smoothing auto + margin 0 + .wikidata-stats-container background-color: #fff; border: 1px solid #e2e2e2; padding: 0px 20px 10px 20px; margin 0 0 20px 0 + &.course-overview + border: none + padding: 0px + .wikidata-stats-title font-size 20px font-weight 500 From 23821baedab7417f6353fd099ebba262185fdd7d Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Fri, 22 Jul 2022 01:45:41 +0530 Subject: [PATCH 04/20] Some eslint fixes. --- .../common/OverviewStats/namespace_overview_stats.jsx | 2 +- .../javascripts/components/common/overview_stats_tabs.jsx | 6 +++--- .../components/common/wikidata_overview_stats.jsx | 4 ++-- .../javascripts/components/overview/overview_handler.jsx | 2 +- app/assets/javascripts/utils/article_utils.js | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx b/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx index f8a085d14a..5052ddd338 100644 --- a/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx +++ b/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx @@ -62,4 +62,4 @@ NamespaceOverviewStats.propTypes = { statistics: PropTypes.object.isRequired }; -export default NamespaceOverviewStats; \ No newline at end of file +export default NamespaceOverviewStats; diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index 8c2564fad6..f52af09fc9 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -32,12 +32,12 @@ const OverviewStatsTabs = ({ statistics }) => { const hasWikidataStats = () => { if (statistics['www.wikidata.org']) return true; return false; - } + }; const statsDataList = []; // if there are wikidata overview stats, they should be displayed on first tab if (hasWikidataStats) { - statsDataList.push({ + statsDataList.push({ id: 0, tabTitle: 'Wikidata', contentTitle: null, // title for wikidata stats already exists in WikidataOverviewStats component @@ -48,7 +48,7 @@ const OverviewStatsTabs = ({ statistics }) => { let index = hasWikidataStats ? 1 : 0; Object.keys(statistics).forEach((wiki_ns) => { if (!wiki_ns.includes('namespace')) return; // return if it doesn't contain namespace stats - + const ns_id = Number(wiki_ns.split('-')[2]); // namespace id const wiki = wiki_ns.split('-')[0]; const id = index; diff --git a/app/assets/javascripts/components/common/wikidata_overview_stats.jsx b/app/assets/javascripts/components/common/wikidata_overview_stats.jsx index 54e86ccbbd..0f78438ddf 100644 --- a/app/assets/javascripts/components/common/wikidata_overview_stats.jsx +++ b/app/assets/javascripts/components/common/wikidata_overview_stats.jsx @@ -4,8 +4,8 @@ import OverviewStat from './OverviewStats/overview_stat'; import I18n from 'i18n-js'; const WikidataOverviewStats = ({ statistics, isCourseOverview }) => { - let containerClass = "wikidata-stats-container"; - if (isCourseOverview) containerClass = "wikidata-stats-container course-overview" + let containerClass = 'wikidata-stats-container'; + if (isCourseOverview) containerClass = 'wikidata-stats-container course-overview'; return (

Wikidata stats

diff --git a/app/assets/javascripts/components/overview/overview_handler.jsx b/app/assets/javascripts/components/overview/overview_handler.jsx index 3f912fd4dc..b5a93d1f66 100644 --- a/app/assets/javascripts/components/overview/overview_handler.jsx +++ b/app/assets/javascripts/components/overview/overview_handler.jsx @@ -167,7 +167,7 @@ const Overview = createReactClass({ let overviewStatsTabs; if (course.course_stats && course.course_stats.stats_hash) { - overviewStatsTabs = + overviewStatsTabs = ; } return ( diff --git a/app/assets/javascripts/utils/article_utils.js b/app/assets/javascripts/utils/article_utils.js index af1f5242ee..628c493ea2 100644 --- a/app/assets/javascripts/utils/article_utils.js +++ b/app/assets/javascripts/utils/article_utils.js @@ -57,5 +57,5 @@ export default class ArticleUtils { wikisource: 'index', wikiversity: 'collection' } - } + }; } From 918faf07ebb6d66924d90e9d77d0405f78781b57 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sat, 23 Jul 2022 10:13:51 +0530 Subject: [PATCH 05/20] Move stats title function to article utils. --- .../components/common/overview_stats_tabs.jsx | 52 ++++--------------- app/assets/javascripts/utils/article_utils.js | 15 ++++++ 2 files changed, 24 insertions(+), 43 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index f52af09fc9..b4440ee65b 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -11,51 +11,17 @@ import ArticleUtils from '../../utils/article_utils'; const OverviewStatsTabs = ({ statistics }) => { const [currentTabId, setCurrentTabId] = useState(0); - const getTabTitle = (ns_id, wiki) => { - const project = wiki.split('.')[1]; - let ns_title = ArticleUtils.NamespaceIdMapping[ns_id]; - if (typeof (ns_title) !== 'string') ns_title = ns_title[project]; - return `${I18n.t(`namespace.${ns_title}`)} (${wiki})`; - }; - - const getContentTitle = (ns_id, wiki) => { - 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})`; - }; - const onTabChange = (e) => { return setCurrentTabId(Number(e.currentTarget.id)); }; - const hasWikidataStats = () => { - if (statistics['www.wikidata.org']) return true; - return false; - }; - const statsDataList = []; - // if there are wikidata overview stats, they should be displayed on first tab - if (hasWikidataStats) { - statsDataList.push({ - id: 0, - tabTitle: 'Wikidata', - contentTitle: null, // title for wikidata stats already exists in WikidataOverviewStats component - data: statistics['www.wikidata.org'] - }); - } - - let index = hasWikidataStats ? 1 : 0; - Object.keys(statistics).forEach((wiki_ns) => { - if (!wiki_ns.includes('namespace')) return; // return if it doesn't contain namespace stats - - const ns_id = Number(wiki_ns.split('-')[2]); // namespace id - const wiki = wiki_ns.split('-')[0]; + let index = 0; + Object.keys(statistics).forEach((wiki_ns_key) => { const id = index; - const tabTitle = getTabTitle(ns_id, wiki); - const contentTitle = getContentTitle(ns_id, wiki); - const data = statistics[wiki_ns]; - statsDataList.push({ id, tabTitle, contentTitle, data }); + const statsTitle = ArticleUtils.overviewStatsTitle(wiki_ns_key); + const data = statistics[wiki_ns_key]; + statsDataList.push({ id, statsTitle, data }); index += 1; }); @@ -65,15 +31,15 @@ const OverviewStatsTabs = ({ statistics }) => { key={obj.id} id={obj.id} onClick={onTabChange} - title={obj.tabTitle} + title={obj.statsTitle} active={currentTabId === obj.id} /> ); }); - const contentTitle = statsDataList[currentTabId].contentTitle; + const title = statsDataList[currentTabId].statsTitle; const data = statsDataList[currentTabId].data; - const content = (hasWikidataStats && currentTabId === 0) + const content = (title === 'www.wikidata.org') ? : ; @@ -83,7 +49,7 @@ const OverviewStatsTabs = ({ statistics }) => { {tabsList}
-

{contentTitle}

+

{title}

{content}
diff --git a/app/assets/javascripts/utils/article_utils.js b/app/assets/javascripts/utils/article_utils.js index 628c493ea2..6b6e88190b 100644 --- a/app/assets/javascripts/utils/article_utils.js +++ b/app/assets/javascripts/utils/article_utils.js @@ -58,4 +58,19 @@ export default class ArticleUtils { wikiversity: 'collection' } }; + + // Get tabs and stats title for tabbed course overview stats. + // Here, wiki_ns_key is key of a course_stats object, which + // identifies wiki or wiki-namespace of stats, + // eg.: 'en.wikibooks.org-namespace-102', 'www.wikidata.org' + static overviewStatsTitle(wiki_ns_key) { + // If stats is for wikidata overview, directly return the wiki domain + if (!wiki_ns_key.includes('namespace')) return wiki_ns_key; + const project = wiki_ns_key.split('.')[1]; + const wiki_domain = wiki_ns_key.split('-')[0]; + const ns_id = wiki_ns_key.split('-')[2]; + let ns_title = ArticleUtils.NamespaceIdMapping[ns_id]; + if (typeof (ns_title) !== 'string') ns_title = ns_title[project]; + return `${wiki_domain} - ${I18n.t(`namespace.${ns_title}`)}`; + }; } From 8f2d6ca424d1d7d60924d34b26fd01694d6720f2 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sat, 23 Jul 2022 10:37:24 +0530 Subject: [PATCH 06/20] Refined some code. --- .../components/common/overview_stats_tabs.jsx | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index b4440ee65b..0979649b1f 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -15,30 +15,29 @@ const OverviewStatsTabs = ({ statistics }) => { return setCurrentTabId(Number(e.currentTarget.id)); }; - const statsDataList = []; + const statsList = []; + const tabsList = []; + let index = 0; Object.keys(statistics).forEach((wiki_ns_key) => { - const id = index; const statsTitle = ArticleUtils.overviewStatsTitle(wiki_ns_key); - const data = statistics[wiki_ns_key]; - statsDataList.push({ id, statsTitle, data }); - index += 1; - }); - - const tabsList = statsDataList.map((obj) => { - return ( + const statsData = statistics[wiki_ns_key]; + + statsList.push({ statsTitle, statsData }); + tabsList.push( - ); + ) + index += 1; }); - const title = statsDataList[currentTabId].statsTitle; - const data = statsDataList[currentTabId].data; + const title = statsList[currentTabId].statsTitle; + const data = statsList[currentTabId].statsData; const content = (title === 'www.wikidata.org') ? : ; From 9cc4b4420a0c58ae62a920e51e89208d9de7ecaf Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sat, 23 Jul 2022 11:28:24 +0530 Subject: [PATCH 07/20] Test for overview stats title util function. --- app/assets/javascripts/utils/article_utils.js | 15 ------------- app/assets/javascripts/utils/wiki_utils.js | 19 ++++++++++++++++- test/utils/wiki_utils.spec.js | 21 ++++++++++++++++++- 3 files changed, 38 insertions(+), 17 deletions(-) diff --git a/app/assets/javascripts/utils/article_utils.js b/app/assets/javascripts/utils/article_utils.js index 6b6e88190b..628c493ea2 100644 --- a/app/assets/javascripts/utils/article_utils.js +++ b/app/assets/javascripts/utils/article_utils.js @@ -58,19 +58,4 @@ export default class ArticleUtils { wikiversity: 'collection' } }; - - // Get tabs and stats title for tabbed course overview stats. - // Here, wiki_ns_key is key of a course_stats object, which - // identifies wiki or wiki-namespace of stats, - // eg.: 'en.wikibooks.org-namespace-102', 'www.wikidata.org' - static overviewStatsTitle(wiki_ns_key) { - // If stats is for wikidata overview, directly return the wiki domain - if (!wiki_ns_key.includes('namespace')) return wiki_ns_key; - const project = wiki_ns_key.split('.')[1]; - const wiki_domain = wiki_ns_key.split('-')[0]; - const ns_id = wiki_ns_key.split('-')[2]; - let ns_title = ArticleUtils.NamespaceIdMapping[ns_id]; - if (typeof (ns_title) !== 'string') ns_title = ns_title[project]; - return `${wiki_domain} - ${I18n.t(`namespace.${ns_title}`)}`; - }; } diff --git a/app/assets/javascripts/utils/wiki_utils.js b/app/assets/javascripts/utils/wiki_utils.js index f39bcb0e27..cc48cc54fd 100644 --- a/app/assets/javascripts/utils/wiki_utils.js +++ b/app/assets/javascripts/utils/wiki_utils.js @@ -1,3 +1,5 @@ +import ArticleUtils from './article_utils'; + const toWikiDomain = (wiki) => { const subdomain = wiki.language || 'www'; return `${subdomain}.${wiki.project}.org`; @@ -20,4 +22,19 @@ const trackedWikisMaker = (course) => { } return trackedWikis; }; -export { trackedWikisMaker, formatOption, toWikiDomain }; + +// Get tabs and stats title for tabbed course overview stats. +// Here, wiki_ns_key is key of a course_stats object, which +// identifies wiki or wiki-namespace of stats, +// eg.: 'en.wikibooks.org-namespace-102', 'www.wikidata.org' +const overviewStatsTitle = (wiki_ns_key) => { + // If stats are for wikidata overview, directly return the wiki domain + if (!wiki_ns_key.includes('namespace')) return wiki_ns_key; + const project = wiki_ns_key.split('.')[1]; + const wiki_domain = wiki_ns_key.split('-')[0]; + const ns_id = wiki_ns_key.split('-')[2]; + let ns_title = ArticleUtils.NamespaceIdMapping[ns_id]; + if (typeof (ns_title) !== 'string') ns_title = ns_title[project]; + return `${wiki_domain} - ${I18n.t(`namespace.${ns_title}`)}`; +}; +export { trackedWikisMaker, formatOption, toWikiDomain, overviewStatsTitle }; diff --git a/test/utils/wiki_utils.spec.js b/test/utils/wiki_utils.spec.js index 5675332665..b64bdcb68e 100644 --- a/test/utils/wiki_utils.spec.js +++ b/test/utils/wiki_utils.spec.js @@ -1,5 +1,5 @@ import '../testHelper'; -import { formatOption, toWikiDomain, trackedWikisMaker } from '../../app/assets/javascripts/utils/wiki_utils'; +import { formatOption, toWikiDomain, trackedWikisMaker, overviewStatsTitle } from '../../app/assets/javascripts/utils/wiki_utils'; describe('formatOption', () => { @@ -67,3 +67,22 @@ describe('trackedWikisMaker', () => { } ); }); + +describe('overviewStatsTitle', () => { + test( + 'returns title in form of \'wiki - namespace\' if stats are for a tracked namespace', + () => { + const wiki_ns_key = 'en.wikibooks.org-namespace-102'; + const result = overviewStatsTitle(wiki_ns_key); + const expected = 'en.wikibooks.org - Cookbook'; + expect(result).toBe(expected); + }); + test( + 'returns wiki domain as title if stats are for wikidata overview', + () => { + const wiki_ns_key = 'www.wikidata.org'; + const result = overviewStatsTitle(wiki_ns_key); + const expected = 'www.wikidata.org'; + expect(result).toBe(expected); + }); +}); From 5670769649fa40e75e9245c971159a4179aa8586 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sun, 24 Jul 2022 23:45:41 +0530 Subject: [PATCH 08/20] Minor changes --- .../components/common/overview_stats_tabs.jsx | 4 ++-- .../components/common/wikidata_overview_stats.jsx | 8 ++++++-- app/assets/javascripts/utils/wiki_utils.js | 6 +++--- test/utils/wiki_utils.spec.js | 12 ++++++------ 4 files changed, 17 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index 0979649b1f..adb1d194c3 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -5,7 +5,7 @@ import OverviewStatsTab from './OverviewStats/overview_stats_tab'; import NamespaceOverviewStats from './OverviewStats/namespace_overview_stats'; import WikidataOverviewStats from './wikidata_overview_stats'; -import ArticleUtils from '../../utils/article_utils'; +import { overviewStatsLabel } from '../../utils/wiki_utils'; const OverviewStatsTabs = ({ statistics }) => { @@ -20,7 +20,7 @@ const OverviewStatsTabs = ({ statistics }) => { let index = 0; Object.keys(statistics).forEach((wiki_ns_key) => { - const statsTitle = ArticleUtils.overviewStatsTitle(wiki_ns_key); + const statsTitle = overviewStatsLabel(wiki_ns_key); const statsData = statistics[wiki_ns_key]; statsList.push({ statsTitle, statsData }); diff --git a/app/assets/javascripts/components/common/wikidata_overview_stats.jsx b/app/assets/javascripts/components/common/wikidata_overview_stats.jsx index 0f78438ddf..0155481f35 100644 --- a/app/assets/javascripts/components/common/wikidata_overview_stats.jsx +++ b/app/assets/javascripts/components/common/wikidata_overview_stats.jsx @@ -5,10 +5,14 @@ import I18n from 'i18n-js'; const WikidataOverviewStats = ({ statistics, isCourseOverview }) => { let containerClass = 'wikidata-stats-container'; - if (isCourseOverview) containerClass = 'wikidata-stats-container course-overview'; + let title = 'Wikidata stats'; + if (isCourseOverview) { + containerClass = 'wikidata-stats-container course-overview'; + title = null; + } return (
-

Wikidata stats

+

{title}

{I18n.t('metrics.general')}
diff --git a/app/assets/javascripts/utils/wiki_utils.js b/app/assets/javascripts/utils/wiki_utils.js index cc48cc54fd..673e02224d 100644 --- a/app/assets/javascripts/utils/wiki_utils.js +++ b/app/assets/javascripts/utils/wiki_utils.js @@ -23,11 +23,11 @@ const trackedWikisMaker = (course) => { return trackedWikis; }; -// Get tabs and stats title for tabbed course overview stats. +// Get label for tabs and stats data of tabbed course overview stats. // Here, wiki_ns_key is key of a course_stats object, which // identifies wiki or wiki-namespace of stats, // eg.: 'en.wikibooks.org-namespace-102', 'www.wikidata.org' -const overviewStatsTitle = (wiki_ns_key) => { +const overviewStatsLabel = (wiki_ns_key) => { // If stats are for wikidata overview, directly return the wiki domain if (!wiki_ns_key.includes('namespace')) return wiki_ns_key; const project = wiki_ns_key.split('.')[1]; @@ -37,4 +37,4 @@ const overviewStatsTitle = (wiki_ns_key) => { if (typeof (ns_title) !== 'string') ns_title = ns_title[project]; return `${wiki_domain} - ${I18n.t(`namespace.${ns_title}`)}`; }; -export { trackedWikisMaker, formatOption, toWikiDomain, overviewStatsTitle }; +export { trackedWikisMaker, formatOption, toWikiDomain, overviewStatsLabel }; diff --git a/test/utils/wiki_utils.spec.js b/test/utils/wiki_utils.spec.js index b64bdcb68e..bda9155627 100644 --- a/test/utils/wiki_utils.spec.js +++ b/test/utils/wiki_utils.spec.js @@ -1,5 +1,5 @@ import '../testHelper'; -import { formatOption, toWikiDomain, trackedWikisMaker, overviewStatsTitle } from '../../app/assets/javascripts/utils/wiki_utils'; +import { formatOption, toWikiDomain, trackedWikisMaker, overviewStatsLabel } from '../../app/assets/javascripts/utils/wiki_utils'; describe('formatOption', () => { @@ -68,20 +68,20 @@ describe('trackedWikisMaker', () => { ); }); -describe('overviewStatsTitle', () => { +describe('overviewStatsLabel', () => { test( - 'returns title in form of \'wiki - namespace\' if stats are for a tracked namespace', + 'returns stats label in form of \'wiki - namespace\' if stats are for a tracked namespace', () => { const wiki_ns_key = 'en.wikibooks.org-namespace-102'; - const result = overviewStatsTitle(wiki_ns_key); + const result = overviewStatsLabel(wiki_ns_key); const expected = 'en.wikibooks.org - Cookbook'; expect(result).toBe(expected); }); test( - 'returns wiki domain as title if stats are for wikidata overview', + 'returns wiki domain as label if stats are for wikidata overview', () => { const wiki_ns_key = 'www.wikidata.org'; - const result = overviewStatsTitle(wiki_ns_key); + const result = overviewStatsLabel(wiki_ns_key); const expected = 'www.wikidata.org'; expect(result).toBe(expected); }); From 7dd7f26070539562694acd5d3db141e55e70fb57 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Mon, 25 Jul 2022 00:01:37 +0530 Subject: [PATCH 09/20] Lint fixes --- .../javascripts/components/common/overview_stats_tabs.jsx | 4 ++-- app/assets/javascripts/utils/wiki_utils.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index adb1d194c3..e2d2d3d8a3 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -22,7 +22,7 @@ const OverviewStatsTabs = ({ statistics }) => { Object.keys(statistics).forEach((wiki_ns_key) => { const statsTitle = overviewStatsLabel(wiki_ns_key); const statsData = statistics[wiki_ns_key]; - + statsList.push({ statsTitle, statsData }); tabsList.push( { title={statsTitle} active={currentTabId === index} /> - ) + ); index += 1; }); diff --git a/app/assets/javascripts/utils/wiki_utils.js b/app/assets/javascripts/utils/wiki_utils.js index 673e02224d..830b86584d 100644 --- a/app/assets/javascripts/utils/wiki_utils.js +++ b/app/assets/javascripts/utils/wiki_utils.js @@ -24,7 +24,7 @@ const trackedWikisMaker = (course) => { }; // Get label for tabs and stats data of tabbed course overview stats. -// Here, wiki_ns_key is key of a course_stats object, which +// Here, wiki_ns_key is key of a course_stats object, which // identifies wiki or wiki-namespace of stats, // eg.: 'en.wikibooks.org-namespace-102', 'www.wikidata.org' const overviewStatsLabel = (wiki_ns_key) => { From f0e4e0b70f6f99f8d3cedc61dd45e5ba52b92c8d Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Mon, 25 Jul 2022 00:35:25 +0530 Subject: [PATCH 10/20] Fix ruby spec test. --- spec/features/wikidata_course_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/features/wikidata_course_spec.rb b/spec/features/wikidata_course_spec.rb index 9f17cbc823..fa9f47860b 100644 --- a/spec/features/wikidata_course_spec.rb +++ b/spec/features/wikidata_course_spec.rb @@ -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') expect(page).to have_content('Claims') end From c0b47bcfddb9c272322af26e2948d01e1b9485b5 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Wed, 27 Jul 2022 01:10:18 +0530 Subject: [PATCH 11/20] New stats content component. --- .../OverviewStats/overview_stats_content.jsx | 28 +++++++++++++++++++ .../components/common/overview_stats_tabs.jsx | 16 ++--------- 2 files changed, 31 insertions(+), 13 deletions(-) create mode 100644 app/assets/javascripts/components/common/OverviewStats/overview_stats_content.jsx diff --git a/app/assets/javascripts/components/common/OverviewStats/overview_stats_content.jsx b/app/assets/javascripts/components/common/OverviewStats/overview_stats_content.jsx new file mode 100644 index 0000000000..c1c46ab591 --- /dev/null +++ b/app/assets/javascripts/components/common/OverviewStats/overview_stats_content.jsx @@ -0,0 +1,28 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +import WikidataOverviewStats from '../wikidata_overview_stats'; +import NamespaceOverviewStats from './namespace_overview_stats'; + +const OverviewStatsContent = ({ content }) => { + const title = content.statsTitle; + const data = content.statsData; + const statistics = (title === 'www.wikidata.org') + ? + : ; + + return ( +
+

{title}

+
+ {statistics} +
+
+ ); +}; + +OverviewStatsContent.propTypes = { + content: PropTypes.object.isRequired +}; + +export default OverviewStatsContent; diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index e2d2d3d8a3..c89216b7c2 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -2,8 +2,7 @@ import React, { useState } from 'react'; import PropTypes from 'prop-types'; import OverviewStatsTab from './OverviewStats/overview_stats_tab'; -import NamespaceOverviewStats from './OverviewStats/namespace_overview_stats'; -import WikidataOverviewStats from './wikidata_overview_stats'; +import OverviewStatsContent from './OverviewStats/overview_stats_content'; import { overviewStatsLabel } from '../../utils/wiki_utils'; @@ -36,23 +35,14 @@ const OverviewStatsTabs = ({ statistics }) => { index += 1; }); - const title = statsList[currentTabId].statsTitle; - const data = statsList[currentTabId].statsData; - const content = (title === 'www.wikidata.org') - ? - : ; + const content = ; return (
{tabsList}
-
-

{title}

-
- {content} -
-
+ {content}
); }; From ae7d15def36db1edbeb49f2472b55a0c836352cd Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Wed, 27 Jul 2022 01:11:07 +0530 Subject: [PATCH 12/20] New UI for tabs. --- app/assets/stylesheets/modules/_stats.styl | 23 ++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/app/assets/stylesheets/modules/_stats.styl b/app/assets/stylesheets/modules/_stats.styl index 981df152f2..d1ec82600b 100644 --- a/app/assets/stylesheets/modules/_stats.styl +++ b/app/assets/stylesheets/modules/_stats.styl @@ -69,28 +69,35 @@ .overview-stats-tabs-container background-color: #fff; border: 1px solid #e2e2e2; - padding: 0px + padding: 20px .tabs-container padding: 0px display: inline-flex width: 100% - box-shadow: 0px 5px 5px #dfdfdf - background-color: #f5f5f5; + border-bottom: 2px solid $brand_primary .tab - padding: 5px 10px 5px 10px - border: 1px solid #e2e2e2 + padding: 8px 12px 8px 12px min-width: 200px cursor pointer + margin-right: 20px + position: relative + top: 2px + + p + font-size: 13px + font-weight: 600 + color: #666 &.active - border-bottom: 2px solid $brand_primary + background-color: $brand_primary + border: none p - color: $brand_primary + color: #fff .content-container - padding: 10px 20px + padding: 0px .title font-size 20px From d8d7bf00902240ae2c481b3bdd0c0af192888985 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Wed, 27 Jul 2022 13:03:56 +0530 Subject: [PATCH 13/20] Add method to get namespace id from title. --- .../RevisionsList/StudentRevisionsList.jsx | 18 ++++++++++-------- app/assets/javascripts/utils/article_utils.js | 7 +++++++ 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx b/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx index 9746829bb6..aa9defd008 100644 --- a/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx +++ b/app/assets/javascripts/components/students/components/Articles/SelectedStudent/RevisionsList/StudentRevisionsList.jsx @@ -8,6 +8,7 @@ import StudentRevisionRow from './StudentRevisionRow'; // Libraries import CourseUtils from '~/app/assets/javascripts/utils/course_utils.js'; +import ArticleUtils from '~/app/assets/javascripts/utils/article_utils.js'; import studentListKeys from '@components/students/shared/StudentList/student_list_keys.js'; export class StudentRevisionsList extends React.Component { @@ -15,7 +16,7 @@ export class StudentRevisionsList extends React.Component { super(props); this.state = { isOpen: false, - namespace: -1 // show all namespace revisions by default + namespace: 'all' // show all namespace revisions by default }; this.toggleDrawer = this.toggleDrawer.bind(this); @@ -24,7 +25,7 @@ export class StudentRevisionsList extends React.Component { onNamespaceChange = (e) => { // Open the drawer when filter is used if (!this.state.isOpen) this.setState({ isOpen: true }); - return this.setState({ namespace: Number(e.target.value) }); + return this.setState({ namespace: e.target.value }); }; // filter the revisions according to namespace @@ -33,10 +34,11 @@ export class StudentRevisionsList extends React.Component { let revisions = []; if (userRevisions[student.id] !== undefined && userRevisions[student.id] !== null) { - revisions = (this.state.namespace === -1) + revisions = (this.state.namespace === 'all') ? userRevisions[student.id] : userRevisions[student.id].filter((rev) => { - return rev.article.namespace === this.state.namespace; + const current_ns_id = ArticleUtils.getNamespaceId(this.state.namespace); + return rev.article.namespace === current_ns_id; }); } return revisions; @@ -97,10 +99,10 @@ export class StudentRevisionsList extends React.Component { value={this.state.namespace} onChange={this.onNamespaceChange} > - - - - + + + + ); return ( diff --git a/app/assets/javascripts/utils/article_utils.js b/app/assets/javascripts/utils/article_utils.js index 628c493ea2..c0fc512c25 100644 --- a/app/assets/javascripts/utils/article_utils.js +++ b/app/assets/javascripts/utils/article_utils.js @@ -58,4 +58,11 @@ export default class ArticleUtils { wikiversity: 'collection' } }; + + // Get namespace id from its title + static getNamespaceId(namespace) { + const ns_id_mapping = this.NamespaceIdMapping; + const ns_id = Object.keys(ns_id_mapping).find(ns => ns_id_mapping[ns] === namespace); + return Number(ns_id); + } } From 49b696bdc14771d5b736bd9daf2fc81e7cd39e78 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Thu, 28 Jul 2022 19:52:38 +0530 Subject: [PATCH 14/20] Write ruby test for tabbed course stats --- spec/features/detailed_course_stats_spec.rb | 45 +++++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 spec/features/detailed_course_stats_spec.rb diff --git a/spec/features/detailed_course_stats_spec.rb b/spec/features/detailed_course_stats_spec.rb new file mode 100644 index 0000000000..2cec0efb5f --- /dev/null +++ b/spec/features/detailed_course_stats_spec.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe 'Detailed course overview stats', type: :feature, js: true do + let(:course) { create(:course, start: '2022-01-01', end: '2023-01-01') } + before do + create(:course_stats, course: course, + stats_hash: { + 'www.wikidata.org': { + 'claims created': 35, + 'other updates': 2, + 'unknown': 6 + }, + 'en.wikibooks.org-namespace-102': { + 'new_count': 5, + 'edited_count': 72 + }, + 'en.wikipedia.org-namespace-0': { + 'new_count': 16, + 'edited_count': 103 + } + } + ) + visit "/courses/#{course.slug}" + end + + it 'shows tabs for all the course stats objects' do + expect(page.find('#tab-0')).to have_content('www.wikidata.org') + expect(page.find('#tab-1')).to have_content('en.wikibooks.org - Cookbook') + expect(page.find('#tab-2')).to have_content('en.wikipedia.org - Mainspace') + end + + it 'shows cookbook stats on clicking the \'en.wikibooks.org - Cookbook\' tab' do + page.find('#tab-1').click + expect(page).to have_content('en.wikibooks.org - Cookbook') + expect(page).to have_content('Articles Edited') + end + + it 'shows wikidata overview stats on clicking the \'www.wikidata.org\' tab' do + page.find('#tab-0').click + expect(page).to have_content('www.wikidata.org') + expect(page).to have_content('Claims') + end +end From f7c9833d01af838c5af2c645b6cf98269aae88d1 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Thu, 28 Jul 2022 22:53:38 +0530 Subject: [PATCH 15/20] Change tab id --- .../components/common/OverviewStats/overview_stats_tab.jsx | 3 ++- .../javascripts/components/common/overview_stats_tabs.jsx | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx b/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx index 7e78d96aab..61d52a6b1f 100644 --- a/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx +++ b/app/assets/javascripts/components/common/OverviewStats/overview_stats_tab.jsx @@ -4,8 +4,9 @@ import PropTypes from 'prop-types'; const OverviewStatsTab = ({ id, title, active, onClick }) => { const isActive = (active) ? ' active' : ''; const tabClass = `tab${isActive}`; + const tabId = `tab-${id}`; return ( -
+

{title}

); diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index c89216b7c2..e445b4b845 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -11,7 +11,9 @@ const OverviewStatsTabs = ({ statistics }) => { const [currentTabId, setCurrentTabId] = useState(0); const onTabChange = (e) => { - return setCurrentTabId(Number(e.currentTarget.id)); + const tabId = e.currentTarget.id; + const tabIdNumber = Number(tabId.split('-')[1]); + return setCurrentTabId(tabIdNumber); }; const statsList = []; From c170b1c6d7544da1f4256ef6696e725ad0d66813 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Thu, 28 Jul 2022 22:55:25 +0530 Subject: [PATCH 16/20] Update format method for all course stats --- app/helpers/course_helper.rb | 15 +++++++++------ app/presenters/courses_presenter.rb | 4 ++-- app/views/campaigns/show.json.jbuilder | 2 +- app/views/courses/course.json.jbuilder | 2 +- 4 files changed, 13 insertions(+), 10 deletions(-) diff --git a/app/helpers/course_helper.rb b/app/helpers/course_helper.rb index d373e34961..c3830fabe7 100644 --- a/app/helpers/course_helper.rb +++ b/app/helpers/course_helper.rb @@ -29,12 +29,15 @@ def course_i18n(message_key, course = nil) I18n.t("#{string_prefix}.#{message_key}") end - def format_wikidata_stats(course_stats) - course_stats['www.wikidata.org']['other updates'] += course_stats['www.wikidata.org']['unknown'] - course_stats['www.wikidata.org'].reject! { |k, _v| k == 'unknown' } - course_stats.each_value do |stat| - stat.each do |key, value| - stat[key] = number_to_human(value) + def format_course_stats(course_stats) + course_stats.each do |wiki_ns_key, wiki_ns_stats| + if wiki_ns_key == 'www.wikidata.org' + course_stats[wiki_ns_key]['other updates'] += course_stats[wiki_ns_key]['unknown'] + course_stats[wiki_ns_key].reject! { |k, _v| k == 'unknown' } + end + # convert stats to human readable values + course_stats[wiki_ns_key].each do |stat_key, stat| + course_stats[wiki_ns_key][stat_key] = number_to_human(stat) end end course_stats diff --git a/app/presenters/courses_presenter.rb b/app/presenters/courses_presenter.rb index d06c44ba97..a327f7139a 100644 --- a/app/presenters/courses_presenter.rb +++ b/app/presenters/courses_presenter.rb @@ -151,9 +151,9 @@ def trained_percent end def wikidata_stats - stats ||= courses.joins(:course_stat).where.not(course_stats: nil).map do |course| + stats ||= courses.joins(:course_stat).where.not(course_stats: nil).map { |course| course.course_stat.stats_hash['www.wikidata.org'] - end + }.compact return { 'www.wikidata.org' => stats.inject { |a, b| a.merge(b) { |_, x, y| x + y } } } end diff --git a/app/views/campaigns/show.json.jbuilder b/app/views/campaigns/show.json.jbuilder index 7d581a49e7..4fa5a74ee3 100644 --- a/app/views/campaigns/show.json.jbuilder +++ b/app/views/campaigns/show.json.jbuilder @@ -31,7 +31,7 @@ if @campaign json.created_at @campaign.created_at if @presenter.wikidata_stats['www.wikidata.org'] - json.course_stats format_wikidata_stats(@presenter.wikidata_stats) + json.course_stats format_course_stats(@presenter.wikidata_stats) end end end diff --git a/app/views/courses/course.json.jbuilder b/app/views/courses/course.json.jbuilder index e68fccca14..bf1992940f 100644 --- a/app/views/courses/course.json.jbuilder +++ b/app/views/courses/course.json.jbuilder @@ -35,7 +35,7 @@ json.course do json.wiki_string_prefix @course.home_wiki.string_prefix if @course.course_stat - @course.course_stat.stats_hash = format_wikidata_stats(@course.course_stat.stats_hash) + @course.course_stat.stats_hash = format_course_stats(@course.course_stat.stats_hash) json.course_stats @course.course_stat, :id, :stats_hash end From 8aea63738374fa1332113d5bf6d69760ae131357 Mon Sep 17 00:00:00 2001 From: Vaidehi A Date: Thu, 28 Jul 2022 23:03:22 +0530 Subject: [PATCH 17/20] Update renderZero prop for all namespace attributes --- .../common/OverviewStats/namespace_overview_stats.jsx | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx b/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx index 5052ddd338..c1f853a33e 100644 --- a/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx +++ b/app/assets/javascripts/components/common/OverviewStats/namespace_overview_stats.jsx @@ -17,28 +17,28 @@ const NamespaceOverviewStats = ({ statistics }) => { className="stat-display__value" stat = {statistics.edited_count} statMsg={I18n.t('metrics.articles_edited')} - renderZero={true} + renderZero={false} /> { className="stat-display__value" stat={statistics.views_count} statMsg={I18n.t('metrics.view_count_description')} - renderZero={true} + renderZero={false} />
); From 1639e9f806721613465d047c2f2864c1e0798b54 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sat, 30 Jul 2022 01:03:08 +0530 Subject: [PATCH 18/20] Update feature test --- spec/features/detailed_course_stats_spec.rb | 29 +++++++++++++-------- 1 file changed, 18 insertions(+), 11 deletions(-) diff --git a/spec/features/detailed_course_stats_spec.rb b/spec/features/detailed_course_stats_spec.rb index 2cec0efb5f..5cb3a345e9 100644 --- a/spec/features/detailed_course_stats_spec.rb +++ b/spec/features/detailed_course_stats_spec.rb @@ -25,21 +25,28 @@ visit "/courses/#{course.slug}" end - it 'shows tabs for all the course stats objects' do + it 'shows all the course_stat objects in a tabbed UI layout' do + # Tabs corresponding to all the stats are rendered expect(page.find('#tab-0')).to have_content('www.wikidata.org') expect(page.find('#tab-1')).to have_content('en.wikibooks.org - Cookbook') expect(page.find('#tab-2')).to have_content('en.wikipedia.org - Mainspace') - end - it 'shows cookbook stats on clicking the \'en.wikibooks.org - Cookbook\' tab' do - page.find('#tab-1').click - expect(page).to have_content('en.wikibooks.org - Cookbook') - expect(page).to have_content('Articles Edited') - end + # Default tab's content matches first course_stat object's stats + expect(page.find('.tab.active')).to have_content('www.wikidata.org') + expect(page.find('.content-container .title')).to have_content('www.wikidata.org') + expect(page.find('.content-container')).to have_content("Claims\n35") + + # Clicking other tabs renders the respective stats data + page.find('.tab', text: 'en.wikibooks.org - Cookbook').click + expect(page.find('.tab.active')).to have_content('en.wikibooks.org - Cookbook') + expect(page.find('.content-container .title')).not_to have_content('www.wikidata.org') + expect(page.find('.content-container .title')).to have_content('en.wikibooks.org - Cookbook') + expect(page.find('.content-container')).to have_content("72\nArticles Edited") - it 'shows wikidata overview stats on clicking the \'www.wikidata.org\' tab' do - page.find('#tab-0').click - expect(page).to have_content('www.wikidata.org') - expect(page).to have_content('Claims') + page.find('.tab', text: 'en.wikipedia.org - Mainspace').click + expect(page.find('.tab.active')).to have_content('en.wikipedia.org - Mainspace') + expect(page.find('.content-container .title')).not_to have_content('en.wikibooks.org - Cookbook') + expect(page.find('.content-container .title')).to have_content('en.wikipedia.org - Mainspace') + expect(page.find('.content-container')).to have_content("16\nArticles Created") end end From 34b8c98c8dbf8f367b6d64a5d7f5e8b25b48c67e Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sat, 30 Jul 2022 09:35:46 +0530 Subject: [PATCH 19/20] Handle rendering of tabs if there's only one stats object --- .../components/common/overview_stats_tabs.jsx | 4 +++- app/assets/stylesheets/modules/_stats.styl | 9 ++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index e445b4b845..43cf8afef3 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -38,10 +38,12 @@ const OverviewStatsTabs = ({ statistics }) => { }); const content = ; + // Hide tabs container if there is only one tab + const tabsClass = `tabs-container${(tabsList.length === 1) ? ' hide' : ''}` return (
-
+
{tabsList}
{content} diff --git a/app/assets/stylesheets/modules/_stats.styl b/app/assets/stylesheets/modules/_stats.styl index d1ec82600b..3778320a37 100644 --- a/app/assets/stylesheets/modules/_stats.styl +++ b/app/assets/stylesheets/modules/_stats.styl @@ -69,10 +69,13 @@ .overview-stats-tabs-container background-color: #fff; border: 1px solid #e2e2e2; - padding: 20px + padding: 0px 20px 20px 20px .tabs-container - padding: 0px + &.hide + display: none + + padding: 20px 0px 0px 0px display: inline-flex width: 100% border-bottom: 2px solid $brand_primary @@ -87,7 +90,6 @@ p font-size: 13px - font-weight: 600 color: #666 &.active @@ -95,6 +97,7 @@ border: none p color: #fff + font-weight: 600 .content-container padding: 0px From 6f58d37726a0175deab3870ebe4d1a47eaed8324 Mon Sep 17 00:00:00 2001 From: Vaidehi Date: Sat, 30 Jul 2022 10:01:21 +0530 Subject: [PATCH 20/20] Fix some Lint errors --- .../components/common/overview_stats_tabs.jsx | 2 +- app/helpers/course_helper.rb | 2 +- app/presenters/courses_presenter.rb | 4 ++-- spec/features/detailed_course_stats_spec.rb | 22 ++++++++++--------- 4 files changed, 16 insertions(+), 14 deletions(-) diff --git a/app/assets/javascripts/components/common/overview_stats_tabs.jsx b/app/assets/javascripts/components/common/overview_stats_tabs.jsx index 43cf8afef3..63c79f7c95 100644 --- a/app/assets/javascripts/components/common/overview_stats_tabs.jsx +++ b/app/assets/javascripts/components/common/overview_stats_tabs.jsx @@ -39,7 +39,7 @@ const OverviewStatsTabs = ({ statistics }) => { const content = ; // Hide tabs container if there is only one tab - const tabsClass = `tabs-container${(tabsList.length === 1) ? ' hide' : ''}` + const tabsClass = `tabs-container${(tabsList.length === 1) ? ' hide' : ''}`; return (
diff --git a/app/helpers/course_helper.rb b/app/helpers/course_helper.rb index c3830fabe7..8cea5f8220 100644 --- a/app/helpers/course_helper.rb +++ b/app/helpers/course_helper.rb @@ -30,7 +30,7 @@ def course_i18n(message_key, course = nil) end def format_course_stats(course_stats) - course_stats.each do |wiki_ns_key, wiki_ns_stats| + course_stats.each do |wiki_ns_key, _wiki_ns_stats| if wiki_ns_key == 'www.wikidata.org' course_stats[wiki_ns_key]['other updates'] += course_stats[wiki_ns_key]['unknown'] course_stats[wiki_ns_key].reject! { |k, _v| k == 'unknown' } diff --git a/app/presenters/courses_presenter.rb b/app/presenters/courses_presenter.rb index a327f7139a..9f4a23f14b 100644 --- a/app/presenters/courses_presenter.rb +++ b/app/presenters/courses_presenter.rb @@ -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| course.course_stat.stats_hash['www.wikidata.org'] - }.compact + end return { 'www.wikidata.org' => stats.inject { |a, b| a.merge(b) { |_, x, y| x + y } } } end diff --git a/spec/features/detailed_course_stats_spec.rb b/spec/features/detailed_course_stats_spec.rb index 5cb3a345e9..de96283206 100644 --- a/spec/features/detailed_course_stats_spec.rb +++ b/spec/features/detailed_course_stats_spec.rb @@ -4,24 +4,24 @@ describe 'Detailed course overview stats', type: :feature, js: true do let(:course) { create(:course, start: '2022-01-01', end: '2023-01-01') } + before do create(:course_stats, course: course, - stats_hash: { + stats_hash: { 'www.wikidata.org': { - 'claims created': 35, - 'other updates': 2, - 'unknown': 6 + 'claims created' => 35, + 'other updates' => 2, + 'unknown' => 6 }, 'en.wikibooks.org-namespace-102': { - 'new_count': 5, - 'edited_count': 72 + 'new_count' => 5, + 'edited_count' => 72 }, 'en.wikipedia.org-namespace-0': { - 'new_count': 16, - 'edited_count': 103 + 'new_count' => 16, + 'edited_count' => 103 } - } - ) + }) visit "/courses/#{course.slug}" end @@ -45,7 +45,9 @@ page.find('.tab', text: 'en.wikipedia.org - Mainspace').click expect(page.find('.tab.active')).to have_content('en.wikipedia.org - Mainspace') + # rubocop:disable Layout/LineLength expect(page.find('.content-container .title')).not_to have_content('en.wikibooks.org - Cookbook') + # rubocop:enable Layout/LineLength expect(page.find('.content-container .title')).to have_content('en.wikipedia.org - Mainspace') expect(page.find('.content-container')).to have_content("16\nArticles Created") end