diff --git a/app/helpers/includes.ts b/app/helpers/includes.ts new file mode 100644 index 00000000000..61c4ad18d27 --- /dev/null +++ b/app/helpers/includes.ts @@ -0,0 +1,7 @@ +import { helper } from '@ember/component/helper'; + +export function includes([array, value]: [unknown[], unknown]): boolean { + return array.includes(value); +} + +export default helper(includes); diff --git a/app/modifiers/metrics-chart.ts b/app/modifiers/metrics-chart.ts new file mode 100644 index 00000000000..ab62236670b --- /dev/null +++ b/app/modifiers/metrics-chart.ts @@ -0,0 +1,52 @@ +import Modifier from 'ember-modifier'; +import bb, { line, subchart } from 'billboard.js'; + +interface MetricsChartArgs { + positional: []; + named: { + dataColumns?: Array>, + dataRows?: Array>, + }; +} + +export default class MetricsChart extends Modifier { + chart: any = null; + + didReceiveArguments() { + if (this.chart) { + this.chart.destroy(); + } + this.chart = bb.generate({ + bindto: this.element, + data: { + type: line(), + x: 'report_date', + // columns: this.args.named.dataColumns, + rows: this.args.named.dataRows, + }, + axis: { + x: { + type: 'timeseries', + tick: { + format: '%Y-%m-%d', + }, + }, + }, + subchart: { + show: subchart(), + showHandle: true, + }, + tooltip: { + grouped: false, + linked: true, + }, + }); + } + + willRemove() { + if (this.chart) { + this.chart.destroy(); + } + } +} + diff --git a/app/osf-metrics/loading.hbs b/app/osf-metrics/loading.hbs new file mode 100644 index 00000000000..c65ea504165 --- /dev/null +++ b/app/osf-metrics/loading.hbs @@ -0,0 +1 @@ + diff --git a/app/osf-metrics/report-detail/controller.ts b/app/osf-metrics/report-detail/controller.ts new file mode 100644 index 00000000000..14e65f151a0 --- /dev/null +++ b/app/osf-metrics/report-detail/controller.ts @@ -0,0 +1,124 @@ +import Controller from '@ember/controller'; +import { action, get } from '@ember/object'; +import { tracked } from '@glimmer/tracking'; +import { MetricsReportAttrs } from './route'; + + +type ReportFields = { + keywordFields: string[], + numericFields: string[], +}; + + +function gatherFields(obj: any): ReportFields { + const keywordFields: string[] = [] + const numericFields: string[] = [] + for (const fieldName in obj) { + if (fieldName === 'report_date' || fieldName === 'timestamp') { + continue; + } + const fieldValue = obj[fieldName]; + switch (typeof fieldValue) { + case 'string': + keywordFields.push(fieldName); + break; + case 'number': + numericFields.push(fieldName); + break; + case 'object': + const nestedFields = gatherFields(fieldValue); + keywordFields.push(...nestedFields.keywordFields.map( + nestedFieldName => `${fieldName}.${nestedFieldName}`, + )); + numericFields.push(...nestedFields.numericFields.map( + nestedFieldName => `${fieldName}.${nestedFieldName}`, + )); + break; + default: + console.log(`ignoring unexpected ${fieldName}: ${fieldValue}`) + } + } + return { + keywordFields, + numericFields, + }; +} + + +export default class MetricsReportDetailController extends Controller { + queryParams = [ + { daysBack: { scope: 'controller' as const } }, + 'yFields', + 'xGroupField', + 'xGroupFilter', + ] + + @tracked daysBack: string = '13'; + @tracked model: MetricsReportAttrs[] = []; + @tracked yFields: string[] = []; + @tracked xGroupField?: string; + @tracked xField: string = 'report_date'; + @tracked xGroupFilter: string = ''; + + get reportFields(): ReportFields { + const aReport: MetricsReportAttrs = this.model![0]; + return gatherFields(aReport); + } + + get chartRows(): Array>{ + if (!this.xGroupField) { + const fieldNames = [this.xField, ...this.yFields]; + const rows = this.model.map( + datum => fieldNames.map( + fieldName => (get(datum, fieldName) as string | number | undefined) ?? null, + ), + ); + return [fieldNames, ...rows]; + } + const groupedFieldNames = new Set(); + const rowsByX: any = {}; + for (const datum of this.model) { + const xValue = get(datum, this.xField) as string; + if (!rowsByX[xValue]) { + rowsByX[xValue] = {}; + } + const groupName = get(datum, this.xGroupField) as string; + if (!this.xGroupFilter || groupName.includes(this.xGroupFilter)) { + this.yFields.forEach(fieldName => { + const groupedField = `${groupName} ${fieldName}`; + groupedFieldNames.add(groupedField); + const fieldValue = get(datum, fieldName); + rowsByX[xValue][groupedField] = fieldValue; + }); + } + } + const rows = Object.entries(rowsByX).map( + ([xValue, rowData]: [string, any]) => { + const yValues = [...groupedFieldNames].map( + groupedFieldName => (rowData[groupedFieldName] as string | number | undefined) ?? null, + ); + return [xValue, ...yValues]; + }, + ); + return [ + [this.xField, ...groupedFieldNames], + ...rows, + ]; + } + + @action + yFieldToggle(fieldName: string) { + if (this.yFields.includes(fieldName)) { + this.yFields = this.yFields.filter(f => f !== fieldName); + } else { + this.yFields = [...this.yFields, fieldName]; + } + } +} + +declare module '@ember/controller' { + interface Registry { + 'osf-metrics.report-detail': MetricsReportDetailController; + } +} + diff --git a/app/osf-metrics/report-detail/route.ts b/app/osf-metrics/report-detail/route.ts new file mode 100644 index 00000000000..04df89d658a --- /dev/null +++ b/app/osf-metrics/report-detail/route.ts @@ -0,0 +1,47 @@ +import Route from '@ember/routing/route'; +import config from 'ember-get-config'; + +const { + OSF: { + apiUrl, + }, +} = config; + +export interface MetricsReportAttrs { + report_date: string, // YYYY-MM-DD + [attr: string]: string | number | object, +} + +interface MetricsReport { + id: string; + type: string; + attributes: MetricsReportAttrs; +} + +interface RecentMetricsReportResponse { + data: MetricsReport[]; +} + +export default class OsfMetricsRoute extends Route { + queryParams = { + daysBack: { + refreshModel: true, + }, + yFields: { + replace: true, + }, + xGroupField: { + replace: true, + }, + xGroupFilter: { + replace: true, + }, + } + + async model(params: { daysBack: string, reportName?: string }) { + const url = `${apiUrl}/_/metrics/reports/${params.reportName}/recent/?days_back=${params.daysBack}` + const response = await fetch(url); + const responseJson: RecentMetricsReportResponse = await response.json(); + return responseJson.data.map(datum => datum.attributes); + } +} diff --git a/app/osf-metrics/report-detail/template.hbs b/app/osf-metrics/report-detail/template.hbs new file mode 100644 index 00000000000..1891d61a2a2 --- /dev/null +++ b/app/osf-metrics/report-detail/template.hbs @@ -0,0 +1,43 @@ +

+ days back + {{#each (array '7' '13' '31' '73' '371') as |daysBackOption|}} + | {{daysBackOption}} + {{/each}} +

+

+ data fields (y-axis) + {{#each this.reportFields.numericFields as |fieldName|}} + | + {{/each}} +

+{{#if this.reportFields.keywordFields.length}} +

+ group by + + {{item}} + +

+

+ +

+{{/if}} +{{#if (and this.model.length this.yFields.length)}} +
+
+
+{{/if}} diff --git a/app/osf-metrics/route.ts b/app/osf-metrics/route.ts new file mode 100644 index 00000000000..332cc0fe5dc --- /dev/null +++ b/app/osf-metrics/route.ts @@ -0,0 +1,29 @@ +import Route from '@ember/routing/route'; +import config from 'ember-get-config'; + +const { + OSF: { + apiUrl, + }, +} = config; + +interface MetricsReportName { + id: string; + type: 'metrics-report-name'; + links: { + recent: string, + }; +} + +interface MetricsReportNameResponse { + data: MetricsReportName[]; +} + +export default class OsfMetricsRoute extends Route { + async model() { + const url = `${apiUrl}/_/metrics/reports/`; + const response = await fetch(url); + const responseJson: MetricsReportNameResponse = await response.json(); + return responseJson.data.map(metricsReport => metricsReport.id); + } +} diff --git a/app/osf-metrics/styles.scss b/app/osf-metrics/styles.scss new file mode 100644 index 00000000000..b75348341b7 --- /dev/null +++ b/app/osf-metrics/styles.scss @@ -0,0 +1,17 @@ +.OsfMetrics { + display: flex; + flex-direction: column; + align-items: center; +} + +.OsfMetrics > p { + max-width: 62vw; +} + +.OsfMetrics > section { + width: 87vw; +} + +.OsfMetrics :global(.active) { + font-weight: bold; +} diff --git a/app/osf-metrics/template.hbs b/app/osf-metrics/template.hbs new file mode 100644 index 00000000000..98eff869517 --- /dev/null +++ b/app/osf-metrics/template.hbs @@ -0,0 +1,12 @@ +{{page-title 'osf metrics'}} +
+

osf metrics

+

+ reports + {{#each @model as |reportName|}} + | + {{reportName}} + {{/each}} +

+ {{outlet}} +
diff --git a/app/router.ts b/app/router.ts index 5b23632bdec..054b41d9347 100644 --- a/app/router.ts +++ b/app/router.ts @@ -42,6 +42,9 @@ Router.map(function() { }); }); this.route('support'); + this.route('osf-metrics', function() { + this.route('report-detail', { path: '/:reportName' }); + }); this.route('meetings', function() { this.route('detail', { path: '/:meeting_id' }); }); diff --git a/ember-cli-build.js b/ember-cli-build.js index c2d5a623a9b..3d5578035e3 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -127,5 +127,7 @@ module.exports = function(defaults) { app.import('node_modules/wicg-inert/dist/inert.min.js'); + app.import('node_modules/billboard.js/dist/billboard.css'); + return app.toTree(); }; diff --git a/package.json b/package.json index 03ad9306bc7..9ee9f29a7fe 100644 --- a/package.json +++ b/package.json @@ -102,6 +102,7 @@ "@typescript-eslint/eslint-plugin": "^4.22.0", "@typescript-eslint/parser": "^4.22.0", "babel-eslint": "^8.0.0", + "billboard.js": "3.6.3", "bootstrap-sass": "^3.3.7", "broccoli-asset-rev": "^3.0.0", "chai": "^4.1.2", diff --git a/yarn.lock b/yarn.lock index 03ef0f15d53..d70273e4cc6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5429,6 +5429,24 @@ big.js@^5.2.2: resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== +billboard.js@3.6.3: + version "3.6.3" + resolved "https://registry.yarnpkg.com/billboard.js/-/billboard.js-3.6.3.tgz#e20da91565468444429160cbc1f86efdaa3b38b9" + integrity sha512-8QXQ5RCKGqRshGtAFGPEsSTTznJ4N6pXscAiusyYIIjl5FqfdS1Q3t49MICQTYaKRTbnyJan8qqb27uiU36x4A== + dependencies: + d3-axis "^3.0.0" + d3-brush "^3.0.0" + d3-drag "^3.0.0" + d3-dsv "^3.0.1" + d3-ease "^3.0.1" + d3-interpolate "^3.0.1" + d3-scale "^4.0.2" + d3-selection "^3.0.0" + d3-shape "^3.1.0" + d3-time-format "^4.1.0" + d3-transition "^3.0.1" + d3-zoom "^3.0.0" + binary-extensions@^1.0.0: version "1.13.1" resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" @@ -7267,6 +7285,11 @@ commander@2.8.x: dependencies: graceful-readlink ">= 1.0.0" +commander@7: + version "7.2.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== + commander@7.1.0: version "7.1.0" resolved "https://registry.yarnpkg.com/commander/-/commander-7.1.0.tgz#f2eaecf131f10e36e07d894698226e36ae0eb5ff" @@ -7736,11 +7759,23 @@ d3-array@1, d3-array@^1.1.1, d3-array@^1.2.0: resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-1.2.4.tgz#635ce4d5eea759f6f605863dbcfc30edc737f71f" integrity sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw== +"d3-array@2 - 3", "d3-array@2.10.0 - 3": + version "3.2.0" + resolved "https://registry.yarnpkg.com/d3-array/-/d3-array-3.2.0.tgz#15bf96cd9b7333e02eb8de8053d78962eafcff14" + integrity sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g== + dependencies: + internmap "1 - 2" + d3-axis@1: version "1.0.12" resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-1.0.12.tgz#cdf20ba210cfbb43795af33756886fb3638daac9" integrity sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ== +d3-axis@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-axis/-/d3-axis-3.0.0.tgz#c42a4a13e8131d637b745fc2973824cfeaf93322" + integrity sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw== + d3-brush@1: version "1.1.6" resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-1.1.6.tgz#b0a22c7372cabec128bdddf9bddc058592f89e9b" @@ -7752,6 +7787,17 @@ d3-brush@1: d3-selection "1" d3-transition "1" +d3-brush@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-brush/-/d3-brush-3.0.0.tgz#6f767c4ed8dcb79de7ede3e1c0f89e63ef64d31c" + integrity sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "3" + d3-transition "3" + d3-chord@1: version "1.0.6" resolved "https://registry.yarnpkg.com/d3-chord/-/d3-chord-1.0.6.tgz#309157e3f2db2c752f0280fedd35f2067ccbb15f" @@ -7770,6 +7816,11 @@ d3-color@1: resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-1.4.1.tgz#c52002bf8846ada4424d55d97982fef26eb3bc8a" integrity sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q== +"d3-color@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-color/-/d3-color-3.1.0.tgz#395b2833dfac71507f12ac2f7af23bf819de24e2" + integrity sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA== + d3-contour@1: version "1.3.2" resolved "https://registry.yarnpkg.com/d3-contour/-/d3-contour-1.3.2.tgz#652aacd500d2264cb3423cee10db69f6f59bead3" @@ -7782,6 +7833,11 @@ d3-dispatch@1: resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-1.0.6.tgz#00d37bcee4dd8cd97729dd893a0ac29caaba5d58" integrity sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA== +"d3-dispatch@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dispatch/-/d3-dispatch-3.0.1.tgz#5fc75284e9c2375c36c839411a0cf550cbfc4d5e" + integrity sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg== + d3-drag@1: version "1.2.5" resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-1.2.5.tgz#2537f451acd39d31406677b7dc77c82f7d988f70" @@ -7790,6 +7846,14 @@ d3-drag@1: d3-dispatch "1" d3-selection "1" +"d3-drag@2 - 3", d3-drag@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-drag/-/d3-drag-3.0.0.tgz#994aae9cd23c719f53b5e10e3a0a6108c69607ba" + integrity sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg== + dependencies: + d3-dispatch "1 - 3" + d3-selection "3" + d3-dsv@1: version "1.2.0" resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-1.2.0.tgz#9d5f75c3a5f8abd611f74d3f5847b0d4338b885c" @@ -7799,11 +7863,25 @@ d3-dsv@1: iconv-lite "0.4" rw "1" +d3-dsv@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-dsv/-/d3-dsv-3.0.1.tgz#c63af978f4d6a0d084a52a673922be2160789b73" + integrity sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q== + dependencies: + commander "7" + iconv-lite "0.6" + rw "1" + d3-ease@1: version "1.0.7" resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.7.tgz#9a834890ef8b8ae8c558b2fe55bd57f5993b85e2" integrity sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ== +"d3-ease@1 - 3", d3-ease@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-3.0.1.tgz#9658ac38a2140d59d346160f1f6c30fda0bd12f4" + integrity sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w== + d3-fetch@1: version "1.2.0" resolved "https://registry.yarnpkg.com/d3-fetch/-/d3-fetch-1.2.0.tgz#15ce2ecfc41b092b1db50abd2c552c2316cf7fc7" @@ -7826,6 +7904,11 @@ d3-format@1: resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.4.5.tgz#374f2ba1320e3717eb74a9356c67daee17a7edb4" integrity sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ== +"d3-format@1 - 3": + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-3.1.0.tgz#9260e23a28ea5cb109e93b21a06e24e2ebd55641" + integrity sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA== + d3-geo@1: version "1.12.1" resolved "https://registry.yarnpkg.com/d3-geo/-/d3-geo-1.12.1.tgz#7fc2ab7414b72e59fbcbd603e80d9adc029b035f" @@ -7845,11 +7928,23 @@ d3-interpolate@1: dependencies: d3-color "1" +"d3-interpolate@1 - 3", "d3-interpolate@1.2.0 - 3", d3-interpolate@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-interpolate/-/d3-interpolate-3.0.1.tgz#3c47aa5b32c5b3dfb56ef3fd4342078a632b400d" + integrity sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g== + dependencies: + d3-color "1 - 3" + d3-path@1: version "1.0.9" resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.9.tgz#48c050bb1fe8c262493a8caf5524e3e9591701cf" integrity sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg== +"d3-path@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-3.0.1.tgz#f09dec0aaffd770b7995f1a399152bf93052321e" + integrity sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w== + d3-polygon@1: version "1.0.6" resolved "https://registry.yarnpkg.com/d3-polygon/-/d3-polygon-1.0.6.tgz#0bf8cb8180a6dc107f518ddf7975e12abbfbd38e" @@ -7885,11 +7980,27 @@ d3-scale@2: d3-time "1" d3-time-format "2" +d3-scale@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-4.0.2.tgz#82b38e8e8ff7080764f8dcec77bd4be393689396" + integrity sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ== + dependencies: + d3-array "2.10.0 - 3" + d3-format "1 - 3" + d3-interpolate "1.2.0 - 3" + d3-time "2.1.1 - 3" + d3-time-format "2 - 4" + d3-selection@1, d3-selection@^1.1.0: version "1.4.2" resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.4.2.tgz#dcaa49522c0dbf32d6c1858afc26b6094555bc5c" integrity sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg== +"d3-selection@2 - 3", d3-selection@3, d3-selection@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-3.0.0.tgz#c25338207efa72cc5b9bd1458a1a41901f1e1b31" + integrity sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ== + d3-shape@1: version "1.3.7" resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-1.3.7.tgz#df63801be07bc986bc54f63789b4fe502992b5d7" @@ -7897,6 +8008,13 @@ d3-shape@1: dependencies: d3-path "1" +d3-shape@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/d3-shape/-/d3-shape-3.1.0.tgz#c8a495652d83ea6f524e482fca57aa3f8bc32556" + integrity sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ== + dependencies: + d3-path "1 - 3" + d3-time-format@2: version "2.3.0" resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.3.0.tgz#107bdc028667788a8924ba040faf1fbccd5a7850" @@ -7904,16 +8022,35 @@ d3-time-format@2: dependencies: d3-time "1" +"d3-time-format@2 - 4", d3-time-format@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-4.1.0.tgz#7ab5257a5041d11ecb4fe70a5c7d16a195bb408a" + integrity sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg== + dependencies: + d3-time "1 - 3" + d3-time@1: version "1.1.0" resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-1.1.0.tgz#b1e19d307dae9c900b7e5b25ffc5dcc249a8a0f1" integrity sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA== +"d3-time@1 - 3", "d3-time@2.1.1 - 3": + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-time/-/d3-time-3.0.0.tgz#65972cb98ae2d4954ef5c932e8704061335d4975" + integrity sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ== + dependencies: + d3-array "2 - 3" + d3-timer@1: version "1.0.10" resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-1.0.10.tgz#dfe76b8a91748831b13b6d9c793ffbd508dd9de5" integrity sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw== +"d3-timer@1 - 3": + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-timer/-/d3-timer-3.0.1.tgz#6284d2a2708285b1abb7e201eda4380af35e63b0" + integrity sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA== + d3-transition@1: version "1.3.2" resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-1.3.2.tgz#a98ef2151be8d8600543434c1ca80140ae23b398" @@ -7926,6 +8063,17 @@ d3-transition@1: d3-selection "^1.1.0" d3-timer "1" +"d3-transition@2 - 3", d3-transition@3, d3-transition@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/d3-transition/-/d3-transition-3.0.1.tgz#6869fdde1448868077fdd5989200cb61b2a1645f" + integrity sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w== + dependencies: + d3-color "1 - 3" + d3-dispatch "1 - 3" + d3-ease "1 - 3" + d3-interpolate "1 - 3" + d3-timer "1 - 3" + d3-voronoi@1: version "1.1.4" resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.4.tgz#dd3c78d7653d2bb359284ae478645d95944c8297" @@ -7942,6 +8090,17 @@ d3-zoom@1: d3-selection "1" d3-transition "1" +d3-zoom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-3.0.0.tgz#d13f4165c73217ffeaa54295cd6969b3e7aee8f3" + integrity sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw== + dependencies: + d3-dispatch "1 - 3" + d3-drag "2 - 3" + d3-interpolate "1 - 3" + d3-selection "2 - 3" + d3-transition "2 - 3" + d3@^5.0.0, d3@^5.4.0: version "5.16.0" resolved "https://registry.yarnpkg.com/d3/-/d3-5.16.0.tgz#9c5e8d3b56403c79d4ed42fbd62f6113f199c877" @@ -13082,6 +13241,13 @@ iconv-lite@0.4, iconv-lite@0.4.24, iconv-lite@^0.4.13, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@0.6: + version "0.6.3" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501" + integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + icss-replace-symbols@^1.0.2, icss-replace-symbols@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" @@ -13305,6 +13471,11 @@ internal-slot@^1.0.3: has "^1.0.3" side-channel "^1.0.4" +"internmap@1 - 2": + version "2.0.3" + resolved "https://registry.yarnpkg.com/internmap/-/internmap-2.0.3.tgz#6685f23755e43c524e251d29cbc97248e3061009" + integrity sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg== + intersection-observer-admin@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/intersection-observer-admin/-/intersection-observer-admin-0.3.2.tgz#0b6e95ce7272a383e8bbdd47f9ff48de9eab9919" @@ -18513,7 +18684,7 @@ safe-regex@^1.1.0: dependencies: ret "~0.1.10" -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==