diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 9260ff00..791c26c2 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,12 +6,12 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4.0.1 with: path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS key: ${{ runner.OS }}-node2-${{ hashFiles('**/package-lock.json') }} diff --git a/.github/workflows/create_release.yml b/.github/workflows/create_release.yml index 2aa6320a..e95ef52b 100644 --- a/.github/workflows/create_release.yml +++ b/.github/workflows/create_release.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: main ssh-key: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_SSH }} @@ -25,7 +25,7 @@ jobs: echo -n "::set-output name=next_tag::" npm version --no-git-tag-version ${{ github.event.inputs.versionName }} - name: Create pull request into main - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v4 with: branch: release/${{ steps.version.outputs.next_tag }} commit-message: 'chore: release ${{ steps.version.outputs.next_tag }}' @@ -37,7 +37,7 @@ jobs: body: | Releasing ${{ steps.version.outputs.next_tag }}. - name: Check out delphi epidata - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_PAT }} repository: cmu-delphi/delphi-epidata diff --git a/.github/workflows/release_main.yml b/.github/workflows/release_main.yml index c9a7516c..49414e70 100644 --- a/.github/workflows/release_main.yml +++ b/.github/workflows/release_main.yml @@ -17,16 +17,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 - name: Extract version id: extract_version run: node -pe "'::set-output name=version::' + require('./package.json').version" - name: Create Release id: create_release - uses: release-drafter/release-drafter@v5 + uses: release-drafter/release-drafter@v6 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: @@ -42,12 +42,12 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 - - uses: actions/setup-node@v2 + uses: actions/checkout@v4 + - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4.0.1 with: path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS key: ${{ runner.OS }}-node2-${{ hashFiles('**/package-lock.json') }} @@ -57,7 +57,7 @@ jobs: - name: Build Assets run: npm pack - name: Upload Release Asset - uses: AButler/upload-release-assets@v2.0 + uses: AButler/upload-release-assets@v3.0 with: files: 'www-covidcast-*.tgz' repo-token: ${{ secrets.GITHUB_TOKEN }} @@ -70,15 +70,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: repository: cmu-delphi/www-main ssh-key: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_SSH }} - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4.0.1 with: path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS key: ${{ runner.OS }}-main-node2-${{ hashFiles('**/package-lock.json') }} @@ -89,7 +89,7 @@ jobs: run: | npm install https://github.com/cmu-delphi/www-covidcast/releases/download/${{ needs.create_release.outputs.tag_name }}/www-covidcast-${{ needs.create_release.outputs.version }}.tgz - name: Create pull request to update COVIDcast - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v5 with: token: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_PAT }} branch: bot/update-covidcast @@ -106,7 +106,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ref: dev ssh-key: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_SSH }} diff --git a/.github/workflows/update_gdocs_data.yml b/.github/workflows/update_gdocs_data.yml index ed9f9602..5e2582a4 100644 --- a/.github/workflows/update_gdocs_data.yml +++ b/.github/workflows/update_gdocs_data.yml @@ -6,14 +6,14 @@ jobs: runs-on: ubuntu-latest steps: - name: Check out code - uses: actions/checkout@v2 + uses: actions/checkout@v4 with: ssh-key: ${{ secrets.CMU_DELPHI_DEPLOY_MACHINE_SSH }} - - uses: actions/setup-node@v2 + - uses: actions/setup-node@v4 with: - node-version: 16 + node-version: 18 - name: Cache Node.js modules - uses: actions/cache@v2 + uses: actions/cache@v4.0.1 with: path: ~/.npm # npm cache files are stored in `~/.npm` on Linux/macOS key: ${{ runner.OS }}-node2-${{ hashFiles('**/package-lock.json') }} @@ -23,7 +23,7 @@ jobs: - name: Update Docs run: npm run gen - name: Create pull request into main - uses: peter-evans/create-pull-request@v3 + uses: peter-evans/create-pull-request@v4 with: branch: bot/update-docs commit-message: 'chore: update docs' diff --git a/package-lock.json b/package-lock.json index ca067315..66c38456 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "www-covidcast", - "version": "3.2.10", + "version": "3.2.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "www-covidcast", - "version": "3.2.10", + "version": "3.2.11", "license": "MIT", "dependencies": { "uikit": "^3.16.13" @@ -4557,12 +4557,12 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -7249,9 +7249,9 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "dependencies": { "to-regex-range": "^5.0.1" @@ -16064,16 +16064,16 @@ } }, "node_modules/ws": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", - "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "engines": { "node": ">=10.0.0" }, "peerDependencies": { "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" + "utf-8-validate": ">=5.0.2" }, "peerDependenciesMeta": { "bufferutil": { @@ -19588,12 +19588,12 @@ } }, "braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "requires": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" } }, "browser-process-hrtime": { @@ -21581,9 +21581,9 @@ } }, "fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, "requires": { "to-regex-range": "^5.0.1" @@ -28111,9 +28111,9 @@ } }, "ws": { - "version": "8.8.0", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.8.0.tgz", - "integrity": "sha512-JDAgSYQ1ksuwqfChJusw1LSJ8BizJ2e/vVu5Lxjq3YvNJNlROv1ui4i+c/kUUrPheBvQl4c5UbERhTwKa6QBJQ==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.17.1.tgz", + "integrity": "sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==", "dev": true, "requires": {} }, diff --git a/package.json b/package.json index 53ac1fbc..50b1817f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "www-covidcast", - "version": "3.2.10", + "version": "3.2.11", "private": true, "license": "MIT", "description": "", diff --git a/src/blocks/NoRecentDataWarning.svelte b/src/blocks/NoRecentDataWarning.svelte index 1b4d21cb..1a86e115 100644 --- a/src/blocks/NoRecentDataWarning.svelte +++ b/src/blocks/NoRecentDataWarning.svelte @@ -10,14 +10,15 @@ */ export let date; - export let warningType; - function switchDate() { date.set(minMaxDate); } -{#if warningType === 1} + + + +{#if minMaxDate.getTime() === date.value.getTime()}
This date, {formatDateYearDayOfWeekAbbr(minMaxDate)}, is the most recent that has data for all three of the @@ -27,7 +28,8 @@
This date ({formatDateYearDayOfWeekAbbr(date.value)}) does not yet have data for all of the highlighted
diff --git a/src/modes/exportdata/ExportData.svelte b/src/modes/exportdata/ExportData.svelte
index b04c2da7..bde068c3 100644
--- a/src/modes/exportdata/ExportData.svelte
+++ b/src/modes/exportdata/ExportData.svelte
@@ -27,18 +27,37 @@
}
}
+ // Pre-fill the form from URL parameters.
+ // Supported parameters: data_source, signal, start_day, end_day, geo_type, geo_value, as_of
+ const urlParams = new URLSearchParams(window.location.search);
+
+ // Overwrite default source & sensor if these are present in the URL
+ if (urlParams.has('data_source')) {
+ sourceValue = urlParams.get('data_source');
+
+ if (urlParams.has('signal')) {
+ sensorValue = urlParams.get('signal');
+ }
+ }
+
$: isWeekly = sensor ? sensor.isWeeklySignal : false;
$: formatDate = isWeekly ? (d) => formatWeek(d).replace('W', '') : formatDateISO;
- let geoType = 'county';
+ let geoType = urlParams.has('geo_type') ? urlParams.get('geo_type') : 'county';
let startDate = new Date();
let endDate = new Date();
function initDate(date) {
const param = new DateParam(date);
- endDate = param.sparkLineTimeFrame.max;
- startDate = param.sparkLineTimeFrame.min;
+
+ // Populate date based on URL params or, if absent, the current date
+ startDate = urlParams.has('start_day') ? new Date(urlParams.get('start_day')) : param.sparkLineTimeFrame.min;
+ endDate = urlParams.has('end_day') ? new Date(urlParams.get('end_day')) : param.sparkLineTimeFrame.max;
+
+ // Also normalize the dates to the current timezone
+ startDate = new Date(startDate.getTime() - startDate.getTimezoneOffset() * -60000);
+ endDate = new Date(endDate.getTime() - endDate.getTimezoneOffset() * -60000);
}
$: initDate($currentDateObject);
@@ -59,12 +78,20 @@
let geoValuesMode = 'all';
let geoValues = [];
+ let geoURLSet = false;
$: geoItems = [...(infosByLevel[geoType] || []), ...(geoType === 'county' ? infosByLevel.state : [])];
$: {
if (geoItems != null) {
geoValues = [];
geoValuesMode = guessMode(geoItems.length);
}
+
+ // Populate region based on URL params... but let the user override this later
+ if (urlParams.has('geo_value') && !geoURLSet) {
+ let infos = infosByLevel[geoType].filter((d) => d.propertyId == urlParams.get('geo_value'));
+ addRegion(infos[0]);
+ geoURLSet = true;
+ }
}
function flatIds(geoValues) {
@@ -90,6 +117,13 @@
}
}
$: usesAsOf = asOfMode !== 'latest' && asOfDate instanceof Date;
+ // set as_of based on URL params, if it's a valid date
+ if (urlParams.has('as_of') && !isNaN(new Date(urlParams.get('as_of')))) {
+ asOfMode = 'single';
+ asOfDate = new Date(urlParams.get('as_of'));
+ // Also normalize the dates to the current timezone
+ asOfDate = new Date(asOfDate.getTime() - asOfDate.getTimezoneOffset() * -60000);
+ }
let form = null;
@@ -104,6 +138,14 @@
);
});
}
+ // Fix up the UI if we got an inactive sensor from the URL parameters.
+ if (sensor && !sensor.active) {
+ showInActive = true;
+ // Force an update to sourceValue to set related reactive statements correctly.
+ let temp = sourceValue;
+ sourceValue = '';
+ sourceValue = temp;
+ }
});
function addRegion(detail) {
diff --git a/src/modes/summary/Overview.svelte b/src/modes/summary/Overview.svelte
index fc4b4a8a..cc96f3d0 100644
--- a/src/modes/summary/Overview.svelte
+++ b/src/modes/summary/Overview.svelte
@@ -6,7 +6,7 @@
import MaxDateHint from '../../blocks/MaxDateHint.svelte';
import NoRecentDataWarning from '../../blocks/NoRecentDataWarning.svelte';
import { defaultDeathSensor, defaultCasesSensor, defaultHospitalSensor, metaDataManager } from '../../stores';
- import { onMount, beforeUpdate } from 'svelte';
+ import { onMount } from 'svelte';
/**
* @type {import("../../stores/params").DateParam}
@@ -30,44 +30,30 @@
$: hospitalTrend = trends[1];
$: deathTrend = trends[2];
- let minMaxDate = new Date();
+ // Get the latest date that has data for all 3 indicators(CASES, HOSPITAL_ADMISSION and DEATHS).
+ $: minMaxDate = new Date(
+ Math.min(
+ ...[CASES, HOSPITAL_ADMISSION, DEATHS].map((s) => {
+ // As DEATHS sensor is weekly based, we need to add 6 days to the max date of DEATHS sensor to get the last day of the week.
+ if (s.name === 'COVID Deaths') {
+ return s.timeFrame.max.getTime() + 6 * 24 * 60 * 60 * 1000; // add 6 days to the max date of DEATHS sensor to get the last day of the week.
+ } else {
+ return s.timeFrame.max;
+ }
+ }),
+ ),
+ );
onMount(() => {
- [CASES, HOSPITAL_ADMISSION].map((s) => {
- if (s.timeFrame.max < minMaxDate) {
- minMaxDate = s.timeFrame.max;
- }
- });
let urlSearchParams = new URLSearchParams(window.location.search);
if (!urlSearchParams.has('date')) {
- // if no date is specified in the URL, default to the latest day before today with data from all 3 highlighted indicators
+ // if no date is specified in the URL, default to the latest day with data from 3 highlighted indicators (CASES, HOSPITAL_ADMISSION and DEATHS).
date.set(minMaxDate);
}
});
-
- // warningType is indicator of which exact warning message should be shown.
- // By default, when user opens page with no specified date, the date will be set to the latest date we have data for all 3 indicators.
- // In this case, warningType should be set to 1.
- // In case selected date is set to future date (date > minMaxDate, where we don't have recent data for all 3 indicators), the warningType will be set to 2
- // which has different warning message.
- // In case selected date is set to some date which is < minMaxDate, the warningType will be set to 0 which means that we will not show
- // any warning message.
-
- // warningType should be set in beforeUpdate() method, to guess correct warningType.
-
- let warningType = 1;
- beforeUpdate(() => {
- if (date.value > minMaxDate) {
- warningType = 2;
- } else if (date.value < minMaxDate) {
- warningType = 0;
- } else {
- warningType = 1;
- }
- });
-