Skip to content

Commit

Permalink
CLDR-17658 Virtual scroller for Dashboard (#3780)
Browse files Browse the repository at this point in the history
  • Loading branch information
btangmu authored Jun 6, 2024
1 parent 92849d0 commit d63e30e
Show file tree
Hide file tree
Showing 7 changed files with 219 additions and 413 deletions.
35 changes: 35 additions & 0 deletions tools/cldr-apps/js/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions tools/cldr-apps/js/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
"marked": "^4.3.0",
"swagger-client": "^3.26.7",
"vue": "^3.2.47",
"vue-virtual-scroller": "^2.0.0-beta.8",
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.0/xlsx-0.20.0.tgz"
}
}
5 changes: 5 additions & 0 deletions tools/cldr-apps/js/src/esm/cldrComponents.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ import {
Tooltip,
UploadDragger,
} from "ant-design-vue";

import VueVirtualScroller from "vue-virtual-scroller";
// Note: 'notification' is a function and is imported as a function in cldrVue.mjs,
// or within a specific app.

Expand Down Expand Up @@ -88,6 +90,9 @@ function setup(app) {
app.component("cldr-report-response", ReportResponse);
app.component("cldr-searchbutton", SearchButton);
app.component("cldr-value", CldrValue);

// some plugins we can pull in wholesale
app.use(VueVirtualScroller);
}

export { setup };
172 changes: 26 additions & 146 deletions tools/cldr-apps/js/src/esm/cldrDash.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,6 @@ import * as cldrStatus from "./cldrStatus.mjs";
import * as cldrSurvey from "./cldrSurvey.mjs";
import * as XLSX from "xlsx";

/**
* Notifications in these categories are combined so that there is not more than one per page.
* These categories can have well over 10,000 notifications, causing performance problems on
* the front end.
*/
const CATS_ONE_PER_PAGE = ["Abstained" /* , "Missing" */];

class DashData {
/**
* Construct a new DashData object
Expand All @@ -31,8 +24,6 @@ class DashData {
// An object whose keys are xpstrid (xpath hex IDs like "db7b4f2df0427e4"), and whose values are DashEntry objects
this.pathIndex = {};
this.hiddenObject = null;
this.pageCombinedEntries = {}; // map page to array of notification xpstrid on that page
this.updatingPath = false;
}

addEntriesFromJson(notifications) {
Expand All @@ -53,107 +44,32 @@ class DashData {
* @param {Object} e (entry in old format, from json)
*/
addEntry(cat, group, e) {
try {
this.addCategory(cat);
this.catSize[cat]++;
if (!this.catFirst[cat]) {
this.catFirst[cat] = e.xpstrid;
}
if (CATS_ONE_PER_PAGE.includes(cat)) {
this.addCombinedEntry(cat, group, e);
} else if (this.pathIndex[e.xpstrid]) {
this.updateEntry(cat, group, e);
} else {
this.addNewEntry(cat, group, e);
}
} catch (err) {
console.error("Error in addEntry: " + err);
this.addCategory(cat);
this.catSize[cat]++;
if (!this.catFirst[cat]) {
this.catFirst[cat] = e.xpstrid;
}
}

addCombinedEntry(cat, group, e) {
try {
const page = group.page;
if (!this.pageCombinedEntries[cat]) {
this.pageCombinedEntries[cat] = {};
if (this.pathIndex[e.xpstrid]) {
const dashEntry = this.pathIndex[e.xpstrid];
dashEntry.addCategory(cat);
dashEntry.setWinning(e.winning);
if (e.comment) {
dashEntry.setComment(e.comment);
}
if (!this.pageCombinedEntries[cat][page]?.length) {
this.pageCombinedEntries[cat][page] = new Array(e.xpstrid);
this.addNewEntry(cat, group, e);
} else {
// TODO: make this work. unshift instead of push may be appropriate
// during an update (following a vote), since the combined notification
// is temporarily removed then added back, and in this case it may belong
// at the start of the array, not the end.
// Reference: https://unicode-org.atlassian.net/browse/CLDR-17658
if (this.updatingPath) {
this.pageCombinedEntries[cat][page].unshift(e.xpstrid);
} else {
this.pageCombinedEntries[cat][page].push(e.xpstrid);
}
// Use the FIRST item in the array as the representative,
// with its comment indicating the size of the array
const xpstrid = this.pageCombinedEntries[cat][page][0];
if (!xpstrid) {
console.error(
"Existing xpstrid not found in addCombinedEntries for cat = " +
cat +
", page = " +
page
);
return;
}
const dashEntry = this.pathIndex[xpstrid];
if (!dashEntry) {
console.error(
"Existing entry not found in addCombinedEntry for cat = " +
cat +
", page = " +
page
);
return;
}
this.setComment(dashEntry, cat, page, null);
if (e.subtype) {
dashEntry.setSubtype(e.subtype);
}
} catch (err) {
console.error("Error in addCombinedEntry: " + err);
}
}

updateEntry(cat, group, e) {
const dashEntry = this.pathIndex[e.xpstrid];
dashEntry.addCategory(cat);
dashEntry.setWinning(e.winning);
this.setComment(dashEntry, cat, group.page, e.comment);
if (e.subtype) {
dashEntry.setSubtype(e.subtype);
}
}

addNewEntry(cat, group, e) {
const dashEntry = new DashEntry(e.xpstrid, e.code, e.english);
dashEntry.setSectionPageHeader(group.section, group.page, group.header);
dashEntry.addCategory(cat);
dashEntry.setWinning(e.winning);
dashEntry.setPreviousEnglish(e.previousEnglish);
this.setComment(dashEntry, cat, group.page, e.comment);
dashEntry.setSubtype(e.subtype);
dashEntry.setChecked(this.itemIsChecked(e));
this.entries.push(dashEntry);
this.pathIndex[e.xpstrid] = dashEntry;
return e.xpstrid;
}

setComment(dashEntry, cat, page, comment) {
if (CATS_ONE_PER_PAGE.includes(cat)) {
dashEntry.setComment(
"Total " +
cat +
" entries on this page: " +
this.pageCombinedEntries[cat][page].length
);
} else {
dashEntry.setComment(comment);
const dashEntry = new DashEntry(e.xpstrid, e.code, e.english);
dashEntry.setSectionPageHeader(group.section, group.page, group.header);
dashEntry.addCategory(cat);
dashEntry.setWinning(e.winning);
dashEntry.setPreviousEnglish(e.previousEnglish);
dashEntry.setComment(e.comment);
dashEntry.setSubtype(e.subtype);
dashEntry.setChecked(this.itemIsChecked(e));
this.entries.push(dashEntry);
this.pathIndex[e.xpstrid] = dashEntry;
}
}

Expand Down Expand Up @@ -234,13 +150,9 @@ class DashData {
}

removeEntry(dashEntry) {
const xpstrid = dashEntry.xpstrid;
this.removeEntryCats(dashEntry);
// Changed xpstrid means the entry wasn't really removed but was kept as representative of combined category
if (xpstrid === dashEntry.xpstrid) {
const index = this.entries.indexOf(dashEntry);
this.entries.splice(index, 1);
}
const index = this.entries.indexOf(dashEntry);
this.entries.splice(index, 1);
}

removeEntryCats(dashEntry) {
Expand All @@ -250,42 +162,12 @@ class DashData {
this.cats.delete(cat);
delete this.catSize[cat];
}
if (CATS_ONE_PER_PAGE.includes(cat)) {
this.removeCombinedEntryCat(dashEntry, cat);
} else if (this.catFirst[cat] === dashEntry.xpstrid) {
if (this.catFirst[cat] === dashEntry.xpstrid) {
this.findCatFirst(cat);
}
});
}

removeCombinedEntryCat(dashEntry, cat) {
const page = dashEntry.page;
this.pageCombinedEntries[cat][page].shift();
if (this.pageCombinedEntries[cat][page].length > 0) {
if (this.catFirst[cat] === dashEntry.xpstrid) {
const nextXpstrid = this.pageCombinedEntries[cat][page][0];
// If this is the only category for this entry, then we can revise the
// entry to use the next xpstrid for the page -- unless that next xpstrid
// is already present for a different category...
if (dashEntry.cats.size === 1 && !this.pathIndex[nextXpstrid]) {
dashEntry.xpstrid = nextXpstrid;
delete this.pathIndex.xpstrid;
this.pathIndex[nextXpstrid] = dashEntry;
this.catFirst[cat] = nextXpstrid;
this.setComment(dashEntry, cat, page, null);
} else {
// TODO: fix this; work in progress
// Reference: https://unicode-org.atlassian.net/browse/CLDR-17658
// Remove this cat from the existing entry
dashEntry.cats.delete(cat);
// if (dashEntry.cats.size === 0) {
// delete this.pathIndex.xpstrid;
// }
}
}
}
}

findCatFirst(cat) {
for (let dashEntry of this.entries) {
if (dashEntry.cat === cat) {
Expand Down Expand Up @@ -453,7 +335,6 @@ function convertData(json) {
* containing notifications for a single path (old format)
*/
function updatePath(dashData, json) {
dashData.updatingPath = true;
try {
if (json.xpstrid in dashData.pathIndex) {
// We already have an entry for this path
Expand All @@ -471,7 +352,6 @@ function updatePath(dashData, json) {
} catch (e) {
cldrNotify.exception(e, "updating path for Dashboard");
}
dashData.updatingPath = false;
return dashData; // for unit test
}

Expand Down Expand Up @@ -595,7 +475,7 @@ async function downloadXlsx(data, locale, cb) {
* @returns {Array<CheckStatusSummary>}
*/
async function getLocaleErrors(locale) {
const client = await cldrClient.getClient();
const client = cldrClient.getClient();
return await client.apis.voting.getLocaleErrors({ locale });
}

Expand Down
1 change: 1 addition & 0 deletions tools/cldr-apps/js/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
// module stylesheets need to go here. See cldrVue.mjs
// example: import 'someModule/dist/someModule.css'
import "ant-design-vue/dist/antd.min.css";
import "vue-virtual-scroller/dist/vue-virtual-scroller.css";

// global stylesheets
import "./css/cldrForum.css";
Expand Down
Loading

0 comments on commit d63e30e

Please sign in to comment.