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

CLDR-17658 Virtual scroller for Dashboard #3780

Merged
merged 1 commit into from
Jun 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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",
Copy link
Member Author

Choose a reason for hiding this comment

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

IMPORTANT: this is a "beta" version

"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
Loading