Skip to content

Commit 5c8526f

Browse files
authored
Merge pull request #81 from cmu-delphi/release/v2.1.5
Release v2.1.5
2 parents 78415eb + 730f297 commit 5c8526f

File tree

4 files changed

+101
-34
lines changed

4 files changed

+101
-34
lines changed

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "www-epivis",
3-
"version": "2.1.4",
3+
"version": "2.1.5",
44
"private": true,
55
"license": "MIT",
66
"description": "",

src/api/EpiData.ts

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@ export function loadDataSet(
118118
fixedParams: Record<string, unknown>,
119119
userParams: Record<string, unknown>,
120120
columns: string[],
121+
api_key = '',
121122
columnRenamings: Record<string, string> = {},
122123
): Promise<DataGroup | null> {
123124
const duplicates = get(expandedDataGroups).filter((d) => d.title == title);
@@ -131,7 +132,11 @@ export function loadDataSet(
131132
)
132133
.then(() => null);
133134
}
134-
const url = new URL(ENDPOINT + `/${endpoint}/`);
135+
let url_string = ENDPOINT + `/${endpoint}/`;
136+
if (api_key !== '') {
137+
url_string += `?api_key=${api_key}`;
138+
}
139+
const url = new URL(url_string);
135140
const params = cleanParams(userParams);
136141
Object.entries(fixedParams).forEach(([key, value]) => {
137142
url.searchParams.set(key, String(value));
@@ -168,10 +173,14 @@ export function loadDataSet(
168173
});
169174
}
170175

171-
export function fetchCOVIDcastMeta(): Promise<
172-
{ geo_type: string; signal: string; data_source: string; time_type?: string }[]
173-
> {
174-
const url = new URL(ENDPOINT + `/covidcast_meta/`);
176+
export function fetchCOVIDcastMeta(
177+
api_key: string,
178+
): Promise<{ geo_type: string; signal: string; data_source: string; time_type?: string }[]> {
179+
let url_string = ENDPOINT + `/covidcast_meta/`;
180+
if (api_key !== '') {
181+
url_string += `?api_key=${api_key}`;
182+
}
183+
const url = new URL(url_string);
175184
url.searchParams.set('format', 'json');
176185
return fetchImpl<{ geo_type: string; signal: string; data_source: string; time_type?: string }[]>(url).catch(
177186
(error) => {
@@ -190,8 +199,9 @@ export function importCDC({ locations, auth }: { locations: string; auth?: strin
190199
{
191200
epiweeks: epiRange(firstEpiWeek.cdc, currentEpiWeek),
192201
},
193-
{ auth, locations },
202+
{ locations },
194203
['total', 'num1', 'num2', 'num3', 'num4', 'num5', 'num6', 'num7', 'num8'],
204+
auth,
195205
);
196206
}
197207

@@ -201,12 +211,14 @@ export function importCOVIDcast({
201211
geo_value,
202212
signal,
203213
time_type = 'day',
214+
api_key,
204215
}: {
205216
data_source: string;
206217
signal: string;
207218
time_type?: string;
208219
geo_type: string;
209220
geo_value: string;
221+
api_key: string;
210222
}): Promise<DataGroup | null> {
211223
const title = `[API] COVIDcast: ${data_source}:${signal} (${geo_type}:${geo_value})`;
212224
return loadDataSet(
@@ -221,6 +233,7 @@ export function importCOVIDcast({
221233
},
222234
{ data_source, signal, time_type, geo_type, geo_value },
223235
['value', 'stderr', 'sample_size'],
236+
api_key,
224237
);
225238
}
226239

@@ -343,7 +356,7 @@ export function importFluView({
343356
{
344357
epiweeks: epiRange(firstEpiWeek.fluview, currentEpiWeek),
345358
},
346-
{ regions, issues, lag, auth },
359+
{ regions, issues, lag },
347360
[
348361
'wili',
349362
'ili',
@@ -357,6 +370,7 @@ export function importFluView({
357370
'num_age_4',
358371
'num_age_5',
359372
],
373+
auth,
360374
{
361375
wili: '%wILI',
362376
ili: '%ILI',
@@ -395,8 +409,9 @@ export function importGHT({
395409
{
396410
epiweeks: epiRange(firstEpiWeek.ght, currentEpiWeek),
397411
},
398-
{ auth, locations, query },
412+
{ locations, query },
399413
['value'],
414+
auth,
400415
);
401416
}
402417

@@ -456,8 +471,9 @@ export function importQuidel({ auth, locations }: { auth: string; locations: str
456471
{
457472
epiweeks: epiRange(firstEpiWeek.quidel, currentEpiWeek),
458473
},
459-
{ auth, locations },
474+
{ locations },
460475
['value'],
476+
auth,
461477
);
462478
}
463479
export function importSensors({
@@ -478,8 +494,9 @@ export function importSensors({
478494
{
479495
epiweeks: epiRange(firstEpiWeek.sensors, currentEpiWeek),
480496
},
481-
{ auth, names, locations },
497+
{ names, locations },
482498
['value'],
499+
auth,
483500
);
484501
}
485502
// twtr
@@ -504,8 +521,9 @@ export function importTwitter({
504521
: {
505522
epiweeks: epiRange(firstEpiWeek.twitter, currentEpiWeek),
506523
},
507-
{ auth, locations, resolution },
524+
{ locations, resolution },
508525
['num', 'total', 'percent'],
526+
auth,
509527
);
510528
}
511529
export function importWiki({

src/components/dialogs/dataSources/COVIDcast.svelte

Lines changed: 69 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,13 @@
77
88
export let id: string;
99
10+
let api_key = '';
1011
let data_source = '';
1112
let signal = '';
1213
let geo_type = '';
1314
let geo_value = '';
15+
let form_key = '';
16+
let valid_key = true;
1417
1518
let dataSources: (LabelValue & { signals: string[] })[] = [];
1619
let geoTypes: string[] = [];
@@ -23,38 +26,77 @@
2326
}
2427
}
2528
26-
onMount(() => {
27-
fetchCOVIDcastMeta().then((res) => {
28-
geoTypes = [...new Set(res.map((d) => d.geo_type))];
29-
const byDataSource = new Map<string, LabelValue & { signals: string[] }>();
30-
for (const row of res) {
31-
const ds = byDataSource.get(row.data_source);
32-
if (!ds) {
33-
byDataSource.set(row.data_source, {
34-
label: row.data_source,
35-
value: row.data_source,
36-
signals: [row.signal],
37-
});
38-
} else if (!ds.signals.includes(row.signal)) {
39-
ds.signals.push(row.signal);
29+
// Helper function; delay invoking "fn" until "ms" milliseconds have passed
30+
const debounce = (fn: Function, ms = 500) => {
31+
let timeoutId: ReturnType<typeof setTimeout>;
32+
return function (this: any, ...args: any[]) {
33+
clearTimeout(timeoutId);
34+
timeoutId = setTimeout(() => fn.apply(this, args), ms);
35+
};
36+
};
37+
38+
function fetchMetadata() {
39+
fetchCOVIDcastMeta(form_key).then((res) => {
40+
if (res.length == 0) {
41+
valid_key = false;
42+
} else {
43+
valid_key = true;
44+
api_key = form_key; // API key is valid -> use it to fetch data later on
45+
geoTypes = [...new Set(res.map((d) => d.geo_type))];
46+
const byDataSource = new Map<string, LabelValue & { signals: string[] }>();
47+
for (const row of res) {
48+
const ds = byDataSource.get(row.data_source);
49+
if (!ds) {
50+
byDataSource.set(row.data_source, {
51+
label: row.data_source,
52+
value: row.data_source,
53+
signals: [row.signal],
54+
});
55+
} else if (!ds.signals.includes(row.signal)) {
56+
ds.signals.push(row.signal);
57+
}
4058
}
59+
byDataSource.forEach((entry) => {
60+
entry.signals.sort();
61+
});
62+
dataSources = [...byDataSource.values()].sort((a, b) => a.value.localeCompare(b.value));
4163
}
42-
byDataSource.forEach((entry) => {
43-
entry.signals.sort();
44-
});
45-
dataSources = [...byDataSource.values()].sort((a, b) => a.value.localeCompare(b.value));
4664
});
65+
}
66+
67+
onMount(() => {
68+
fetchMetadata();
4769
});
4870
4971
export function importDataSet() {
50-
return fetchCOVIDcastMeta().then((res) => {
72+
return fetchCOVIDcastMeta(api_key).then((res) => {
5173
const meta = res.filter((row) => row.data_source === data_source && row.signal === signal);
5274
const time_type = meta[0].time_type;
53-
return importCOVIDcast({ data_source, signal, geo_type, geo_value, time_type });
75+
return importCOVIDcast({ data_source, signal, geo_type, geo_value, time_type, api_key });
5476
});
5577
}
5678
</script>
5779

80+
<div>
81+
<label class="uk-form-label" for="{id}-apikey">
82+
<a href="https://cmu-delphi.github.io/delphi-epidata/api/api_keys.html">API Key</a> (optional)
83+
</label>
84+
<div class="uk-form-controls">
85+
<input
86+
id="{id}-apikey"
87+
type="text"
88+
class="uk-input"
89+
class:uk-form-danger={!valid_key}
90+
name="api_key"
91+
required={false}
92+
bind:value={form_key}
93+
on:input={debounce(() => fetchMetadata(), 500)}
94+
/>
95+
{#if !valid_key}
96+
<div class="invalid">API key is invalid - ignoring</div>
97+
{/if}
98+
</div>
99+
</div>
58100
<SelectField id="{id}-r" label="Data Source" name="data_source" bind:value={data_source} options={dataSources} />
59101
<SelectField id="{id}-r" label="Data Signal" name="signal" bind:value={signal} options={dataSignals} />
60102
<SelectField id="{id}-gt" label="Geographic Type" bind:value={geo_type} name="geo_type" options={geoTypes} />
@@ -65,3 +107,10 @@
65107
name="geo_values"
66108
placeholder="e.g., PA or 42003"
67109
/>
110+
111+
<style>
112+
.invalid {
113+
color: red;
114+
font-size: 0.75rem;
115+
}
116+
</style>

0 commit comments

Comments
 (0)