diff --git a/package-lock.json b/package-lock.json index fe7abf4a..72f5d07a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -344,6 +344,7 @@ "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -369,6 +370,7 @@ "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -476,6 +478,7 @@ "url": "https://github.com/sponsors/ai" } ], + "peer": true, "dependencies": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -1611,6 +1614,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz", "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==", "dev": true, + "peer": true, "dependencies": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -1659,6 +1663,7 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, + "peer": true, "dependencies": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", @@ -2048,7 +2053,8 @@ "version": "8.15.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz", "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", - "dev": true + "dev": true, + "peer": true }, "acorn-import-phases": { "version": "1.0.3", @@ -2062,6 +2068,7 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, + "peer": true, "requires": { "fast-deep-equal": "^3.1.3", "fast-uri": "^3.0.1", @@ -2129,6 +2136,7 @@ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.26.3.tgz", "integrity": "sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==", "dev": true, + "peer": true, "requires": { "baseline-browser-mapping": "^2.8.9", "caniuse-lite": "^1.0.30001746", @@ -2908,6 +2916,7 @@ "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.103.0.tgz", "integrity": "sha512-HU1JOuV1OavsZ+mfigY0j8d1TgQgbZ6M+J75zDkpEAwYeXjWSqrGJtgnPblJjd/mAyTNQ7ygw0MiKOn6etz8yw==", "dev": true, + "peer": true, "requires": { "@types/eslint-scope": "^3.7.7", "@types/estree": "^1.0.8", @@ -2941,6 +2950,7 @@ "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-6.0.1.tgz", "integrity": "sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==", "dev": true, + "peer": true, "requires": { "@discoveryjs/json-ext": "^0.6.1", "@webpack-cli/configtest": "^3.0.1", diff --git a/server/dates.py b/server/dates.py index cd996860..0f1f3d6d 100644 --- a/server/dates.py +++ b/server/dates.py @@ -38,9 +38,8 @@ def mock_get_dates(start_year, end_year, today, month_delta=0): current_month_in_year = "0{}".format(current_month_in_year) months.append("{}_{}_01".format(year, current_month_in_year)) - if year == end_year and current_month_in_year == month_delta and today < 15: - continue - months.append("{}_{}_15".format(year, current_month_in_year)) + if year < 2019: + months.append("{}_{}_15".format(year, current_month_in_year)) if month % 12 == 0: year = year + 1 diff --git a/src/js/techreport/tableLinked.js b/src/js/techreport/tableLinked.js index 5be37525..09d69c75 100644 --- a/src/js/techreport/tableLinked.js +++ b/src/js/techreport/tableLinked.js @@ -81,7 +81,7 @@ class TableLinked { } if(timestamp) { - timestamp.textContent = this.dataArray[1]?.[0]?.date; + timestamp.textContent = UIUtils.printMonthYear(this.dataArray[1]?.[0]?.date); } this.dataArray.forEach(technology => { diff --git a/src/js/techreport/timeseries.js b/src/js/techreport/timeseries.js index 5415002e..07dd3a3f 100644 --- a/src/js/techreport/timeseries.js +++ b/src/js/techreport/timeseries.js @@ -131,7 +131,7 @@ class Timeseries { container.innerHTML = ''; /* Update the date to the most recent timestamp in the dataset */ - viz.querySelector('[data-slot="timestamp"]').innerHTML = sorted?.[0]?.date; + viz.querySelector('[data-slot="timestamp"]').innerHTML = UIUtils.printMonthYear(sorted?.[0]?.date); /* For each of the breakdowns, add a component with the latest data */ config.series.values.forEach(breakdown => { @@ -239,7 +239,7 @@ class Timeseries { value.classList.add('undefined'); value.textContent = 'No data'; } - timestamp.textContent = latest.date; + timestamp.textContent = UIUtils.printMonthYear(latest.date); const techColor = UIUtils.getAppColor(app, this.pageFilters.app, this.pageConfig.colors); const fallback = this.pageConfig.colors.app[index]; card.style.setProperty('--breakdown-color', techColor || fallback); @@ -314,7 +314,7 @@ class Timeseries { const wrapper = document.createElement('div'); wrapper.className = 'tooltip-wrapper'; - const d = Highcharts.dateFormat('%b %e, %Y', this.x); + const d = Highcharts.dateFormat('%b %Y', this.x); const dateEl = document.createElement('p'); dateEl.innerHTML = d; diff --git a/src/js/techreport/utils/ui.js b/src/js/techreport/utils/ui.js index 244aafef..ba765f8c 100644 --- a/src/js/techreport/utils/ui.js +++ b/src/js/techreport/utils/ui.js @@ -61,9 +61,23 @@ function capitalizeFirstLetter(theString) { return theString && typeof theString === 'string' ? theString.charAt(0)?.toUpperCase() + theString.slice(1) : theString; } +function printMonthYear(theDate) { + if (!theDate || theDate.length != 10) return; + + const [year, month] = theDate.split('-'); + const date = new Date(year, month - 1); + const formattedDate = date.toLocaleString('default', { + month: 'long', + year: 'numeric' + }); + + return formattedDate; +} + export const UIUtils = { getAppColor, updateReportComponents, getChangeStatus, capitalizeFirstLetter, + printMonthYear, } diff --git a/src/js/timeseries.js b/src/js/timeseries.js index b949c2e6..c984abd6 100644 --- a/src/js/timeseries.js +++ b/src/js/timeseries.js @@ -317,7 +317,14 @@ function drawChart(options, series) { } const changelog = flags[this.x]; - const tooltip = `

${Highcharts.dateFormat('%b %e, %Y', this.x)}

`; + + // Use short format (month + year) for dates from 2019 onwards when + // we switched to monthly crawls. Show full date for older data that + // may have had mid-month crawls. + const formattedDate = this.x >= Date.UTC(2019, 0, 1) ? + Highcharts.dateFormat('%b %Y', this.x) : + Highcharts.dateFormat('%b %e, %Y', this.x); + const tooltip = `

${formattedDate}

`; // Handle changelog tooltips first. if (!this.points) { @@ -390,7 +397,8 @@ function drawChart(options, series) { }, { type: 'all', text: 'All' - }] + }], + inputDateFormat: '%b %Y', }, xAxis: { type: 'datetime', diff --git a/src/js/utils.js b/src/js/utils.js index efbd86bb..818680e9 100644 --- a/src/js/utils.js +++ b/src/js/utils.js @@ -7,10 +7,21 @@ const prettyDateFormatter = new Intl.DateTimeFormat(undefined, { timeZone: 'UTC' }); +const prettyShortDateFormatter = new Intl.DateTimeFormat(undefined, { + month: 'short', + year: 'numeric', + timeZone: 'UTC' +}); + export const prettyDate = YYYY_MM_DD => { const [YYYY, MM, DD] = YYYY_MM_DD.split('_'); - const d = new Date(Date.UTC(YYYY, MM - 1, DD)); - return getFullDate(d); + if (YYYY > '2018') { + const d = new Date(Date.UTC(YYYY, MM - 1)); + return prettyShortDateFormatter.format(d); + } else { + const d = new Date(Date.UTC(YYYY, MM - 1, DD)); + return prettyDateFormatter.format(d); + } }; export const getFullDate = d => {