diff --git a/covidseq/resources/schemas/covidseq.xml b/covidseq/resources/schemas/covidseq.xml index 6de4c263e..29da021be 100644 --- a/covidseq/resources/schemas/covidseq.xml +++ b/covidseq/resources/schemas/covidseq.xml @@ -102,7 +102,9 @@ cDNA_Plate_Location - + + RQG_alt_ID + true diff --git a/covidseq/resources/schemas/dbscripts/sqlserver/covidseq-21.003-21.004.sql b/covidseq/resources/schemas/dbscripts/sqlserver/covidseq-21.003-21.004.sql new file mode 100644 index 000000000..98cc10388 --- /dev/null +++ b/covidseq/resources/schemas/dbscripts/sqlserver/covidseq-21.003-21.004.sql @@ -0,0 +1 @@ +ALTER TABLE covidseq.samples ADD rqg_alt_id varchar(200); \ No newline at end of file diff --git a/covidseq/resources/web/covidseq/panel/SampleImportPanel.js b/covidseq/resources/web/covidseq/panel/SampleImportPanel.js index 772477723..f496d68b9 100644 --- a/covidseq/resources/web/covidseq/panel/SampleImportPanel.js +++ b/covidseq/resources/web/covidseq/panel/SampleImportPanel.js @@ -26,9 +26,12 @@ Ext4.define('CovidSeq.panel.SampleImportPanel', { allowBlank: true },{ name: 'cdna_plate_id', - labels: ['cDNA_Plate_ID', 'RQG_alt_ID', 'MM Alt ID', 'Alt ID', 'MM ID', 'RQG_alt_ID'], + labels: ['cDNA_Plate_ID', 'MM Alt ID', 'Alt ID', 'MM ID'], alwaysShow: true, allowBlank: true + },{ + name: 'RQG_alt_ID', + labels: ['RQG_alt_ID', 'RQG_alt_ID'] },{ name: 'gender', labels: ['Gender', 'Sex'], @@ -226,7 +229,8 @@ Ext4.define('CovidSeq.panel.SampleImportPanel', { if (panel.COUNTY_MAP[val]) { if (row.state) { - if (panel.STATE_ABBREV[val.toLowerCase()]) { + // Correct state, if needed: + if (panel.STATE_ABBREV[row.state.toLowerCase()]) { row.state = panel.STATE_ABBREV[row.state.toLowerCase()] } @@ -574,6 +578,11 @@ Ext4.define('CovidSeq.panel.SampleImportPanel', { var errorMessages = []; var infoMessages = []; Ext4.Array.forEach(rows, function(row, rowIdx){ + // skip blank rows: + if (Ext4.isEmpty(row.join(''))) { + return; + } + var data = { objectId: LABKEY.Utils.generateUUID() }; @@ -640,7 +649,7 @@ Ext4.define('CovidSeq.panel.SampleImportPanel', { // CT of record is N for taqpath, N1 for CDC? - data._patientid = data.patientid || data.state + '-OHSU-' + data.samplename.replaceAll('CV', ''); + data._patientid = data.patientid || data.state + '-OHSU-' + (data.samplename ? data.samplename.replaceAll('CV', '') : 'Sample'); ret.push(data); }, this); diff --git a/covidseq/src/org/labkey/covidseq/CovidseqDataProvider.java b/covidseq/src/org/labkey/covidseq/CovidseqDataProvider.java index b685df28e..90cf16863 100644 --- a/covidseq/src/org/labkey/covidseq/CovidseqDataProvider.java +++ b/covidseq/src/org/labkey/covidseq/CovidseqDataProvider.java @@ -6,6 +6,7 @@ import org.labkey.api.laboratory.AbstractDataProvider; import org.labkey.api.laboratory.LaboratoryService; import org.labkey.api.laboratory.NavItem; +import org.labkey.api.laboratory.QueryCountNavItem; import org.labkey.api.laboratory.QueryImportNavItem; import org.labkey.api.laboratory.SummaryNavItem; import org.labkey.api.ldk.table.QueryCache; @@ -15,6 +16,7 @@ import org.labkey.api.view.ViewContext; import org.labkey.api.view.template.ClientDependency; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -91,7 +93,18 @@ public Module getOwningModule() @Override public List getSummary(Container c, User u) { - return Collections.emptyList(); + List items = new ArrayList<>(); + + for (NavItem nav : getSampleNavItems(c, u)) + { + if (nav.isVisible(c, u)) + { + QueryImportNavItem item = ((QueryImportNavItem)nav); + items.add(new QueryCountNavItem(this, item.getSchema(), item.getQuery(), item.getItemType(), item.getReportCategory(), item.getLabel())); + } + } + + return Collections.unmodifiableList(items); } @Override diff --git a/covidseq/src/org/labkey/covidseq/CovidseqModule.java b/covidseq/src/org/labkey/covidseq/CovidseqModule.java index b5796d777..e1fa71e8c 100644 --- a/covidseq/src/org/labkey/covidseq/CovidseqModule.java +++ b/covidseq/src/org/labkey/covidseq/CovidseqModule.java @@ -41,7 +41,7 @@ public String getName() @Override public @Nullable Double getSchemaVersion() { - return 21.003; + return 21.004; } @Override diff --git a/mGAP/resources/etls/prime-seq.xml b/mGAP/resources/etls/prime-seq.xml index c6a31d3b6..a8f394aa7 100644 --- a/mGAP/resources/etls/prime-seq.xml +++ b/mGAP/resources/etls/prime-seq.xml @@ -94,6 +94,8 @@ liftedVcfId/library_id/name sitesOnlyVcfId/dataid/DataFileUrl sitesOnlyVcfId/name + novelSitesVcfId/dataid/DataFileUrl + novelSitesVcfId/name humanJbrowseId objectId @@ -104,6 +106,7 @@ + diff --git a/mGAP/resources/queries/mGAP/subjectsSource.sql b/mGAP/resources/queries/mGAP/subjectsSource.sql index d30fba46d..e81d5be2b 100644 --- a/mGAP/resources/queries/mGAP/subjectsSource.sql +++ b/mGAP/resources/queries/mGAP/subjectsSource.sql @@ -3,6 +3,8 @@ SELECT coalesce(s.gender, d.gender) as gender, coalesce(s.species, d.species) as species, coalesce(s.geographic_origin, d.geographic_origin) as geographic_origin, +-- TODO: geographic origin score + CASE WHEN d.center IS NOT NULL THEN d.center WHEN s.subjectname IS NOT NULL THEN 'ONPRC' diff --git a/mGAP/resources/queries/mGAP/userRequests/.qview.xml b/mGAP/resources/queries/mGAP/userRequests/.qview.xml index da6852317..5fff46319 100644 --- a/mGAP/resources/queries/mGAP/userRequests/.qview.xml +++ b/mGAP/resources/queries/mGAP/userRequests/.qview.xml @@ -9,6 +9,7 @@ + diff --git a/mGAP/resources/schemas/dbscripts/postgresql/mgap-16.61-16.62.sql b/mGAP/resources/schemas/dbscripts/postgresql/mgap-16.61-16.62.sql new file mode 100644 index 000000000..1575f958f --- /dev/null +++ b/mGAP/resources/schemas/dbscripts/postgresql/mgap-16.61-16.62.sql @@ -0,0 +1 @@ +ALTER TABLE mgap.variantList ALTER COLUMN cadd TYPE DOUBLE PRECISION USING cadd::double precision; \ No newline at end of file diff --git a/mGAP/resources/schemas/dbscripts/postgresql/mgap-16.62-16.63.sql b/mGAP/resources/schemas/dbscripts/postgresql/mgap-16.62-16.63.sql new file mode 100644 index 000000000..93bde7eb1 --- /dev/null +++ b/mGAP/resources/schemas/dbscripts/postgresql/mgap-16.62-16.63.sql @@ -0,0 +1 @@ +ALTER TABLE mGAP.variantCatalogReleases ADD novelSitesVcfId int; \ No newline at end of file diff --git a/mGAP/resources/schemas/dbscripts/sqlserver/mgap-16.61-16.62.sql b/mGAP/resources/schemas/dbscripts/sqlserver/mgap-16.61-16.62.sql new file mode 100644 index 000000000..f3df21a83 --- /dev/null +++ b/mGAP/resources/schemas/dbscripts/sqlserver/mgap-16.61-16.62.sql @@ -0,0 +1 @@ +ALTER TABLE mgap.variantList ALTER COLUMN cadd DOUBLE PRECISION; \ No newline at end of file diff --git a/mGAP/resources/schemas/dbscripts/sqlserver/mgap-16.62-16.63.sql b/mGAP/resources/schemas/dbscripts/sqlserver/mgap-16.62-16.63.sql new file mode 100644 index 000000000..93bde7eb1 --- /dev/null +++ b/mGAP/resources/schemas/dbscripts/sqlserver/mgap-16.62-16.63.sql @@ -0,0 +1 @@ +ALTER TABLE mGAP.variantCatalogReleases ADD novelSitesVcfId int; \ No newline at end of file diff --git a/mGAP/resources/schemas/mgap.xml b/mGAP/resources/schemas/mgap.xml index 96b65a274..ee022ea76 100644 --- a/mGAP/resources/schemas/mgap.xml +++ b/mGAP/resources/schemas/mgap.xml @@ -158,6 +158,15 @@ rowid + + Novel Sites For This Release + true + + sequenceanalysis + outputfiles + rowid + + Genome Browser (Human) true diff --git a/mGAP/resources/views/phenotypes.html b/mGAP/resources/views/phenotypes.html index 5b200d4e6..8a03b9ac1 100644 --- a/mGAP/resources/views/phenotypes.html +++ b/mGAP/resources/views/phenotypes.html @@ -41,8 +41,7 @@ ['No Genetic Association Reported','Cardiovascular Phenotypes','Ueda, et al. 2019','https://www.ncbi.nlm.nih.gov/pubmed/30723724'], ['Genetic Association Reported','Retinal Disease','Moshiri, et al. 2019','https://www.ncbi.nlm.nih.gov/pubmed/30667376'], ['Genetic Association Reported','Bardet-Biedl Syndrome','Peterson, et al. 2019','https://www.ncbi.nlm.nih.gov/pubmed/31589838'], - ['Genetic Association Reported','Epidermolysis Bullosa','Johnson, et al. 2019',''] - + ['Genetic Association Reported','Epidermolysis Bullosa','Johnson, et al. 2019','https://www.ncbi.nlm.nih.gov/pubmed/32096448'] ]; var dataMap = {}; @@ -82,6 +81,83 @@ var rowId = mGAP.Utils.getMGapReleaseId(); var url = LABKEY.ActionURL.buildURL('mgap', 'phenotypeList', null, {release: rowId}); $('#traitUrl').attr('href', url); + + + //COVID data: + var covidRows = [ + ['LZTFL1','SARS-CoV-2 Infection, COVID-19 severity','x','x','x','x','x','x','2:101823807..101843715'], + ['CXCR6','SARS-CoV-2 Infection, COVID-19 severity','x','x','x','x','x','x','2:101948255..101953190'], + ['CCR9','SARS-CoV-2 Infection, COVID-19 severity','x','x','x','x','x','x','2:101888276..101907994'], + ['CCR1','SARS-CoV-2 Infection, COVID-19 severity','x','x','x','x','x','x','2:102205536..102212086'], + ['CCR3','SARS-CoV-2 Infection, COVID-19 severity','x','x','x','x','x','x','2:102268893..102269960'], + ['RPL24','SARS-CoV-2 Infection','','','','','','x','2:174444785..174450351'], + ['NXPE3','SARS-CoV-2 Infection','','','','','','x','2:174323787..174365577'], + ['ZBTB1','SARS-CoV-2 Infection','','','','','','x','7:126570101..126598047'], + ['CEP97','SARS-CoV-2 Infection','','','','','','x','2:174379912..174413230'], + ['FOXP4','COVID-19 severity','','','','','','x','4:127783384..127837788'], + ['CCHCR1','COVID-19 severity','','x','','x','','','4:138774693..138790019'], + ['ABO','SARS-CoV-2 Infection','x','x','x','','x','x','15:7086376..7107347'], + ['OAS1','COVID-19 severity','x','','','x','','x','11:112632314..112654759'], + ['OAS2','COVID-19 severity','x','','','x','','x','11:112695363..112728626'], + ['OAS3','COVID-19 severity','x','','','x','','x','11:112661047..112689871'], + ['KANSL1','COVID-19 severity','','','','','','x','16:57818339..58014773'], + ['WNT3','COVID-19 severity','','','','','','x','16:57171387..57225633'], + ['TAC4','COVID-19 severity','','','','','','x','X:89,480,106..89,483,948'], + ['KAT7','COVID-19 severity','','','','','','x','16:46957860..47008121'], + ['DPP9','COVID-19 severity','x','x','','x','','x','19:4604356..4656762'], + ['TYK2','COVID-19 severity','','','','x','','x','19:10110204..10144759'], + ['ICAM5','COVID-19 severity','','','','x','','x','19:10044223..10051556'], + ['ICAM3','COVID-19 severity','','','','x','','x','19:10088945..10110262'], + ['ICAM4','COVID-19 severity','','','','x','','x','19:10041723..10043298'], + ['ICAM1','COVID-19 severity','','','','x','','x','19:10024950..10040084'], + ['PLEKHA4','SARS-CoV-2 Infection','','','','','','x','19:48819628..48850822'], + ['PPP1R15A','SARS-CoV-2 Infection','','','','','','x','19:48854619..48858778'], + ['TULP2','SARS-CoV-2 Infection','','','','','','x','19:48864508..48880575'], + ['NUCB1','SARS-CoV-2 Infection','','','','','','x','19:48881525..48906138'], + ['IFNAR2','COVID-19 severity','x','x','','x','','x','3:13289046..13325302'], + ['IL10RB','COVID-19 severity','x','x','','x','','x','3:13,254,913..13,288,351'], + ['TMPRSS2','COVID-19 severity','x','x','','x','','x','3:5139757..5184755'], + ['ACE2','SARS-CoV-2 Infection','','','','','','','X:15247646..15300547'] + ]; + + covidRows = covidRows.map(function(r){ + var publications = [] + if (r[2]) { + publications.push('Roberts et al.') + } + if (r[3]) { + publications.push('Horowitz et al.') + } + if (r[4]) { + publications.push('Shelton et al.') + } + if (r[5]) { + publications.push('Pairo-Castineira et al.') + } + if (r[6]) { + publications.push('Ellinghaus et al.') + } + if (r[7]) { + publications.push('COVID-19 HGI') + } + + var url = LABKEY.ActionURL.buildURL('mgap', 'genomebrowser', null, {location: r[8]}) + return ['' + r[0] + '', r[1], publications.join('
')] + }) + + var table = $('#covidPublicationsTable').DataTable({ + data: covidRows, + pageLength: 500, + + dom: '', + buttons: [], + order: [], + columns: [ + {title: 'Candidate Gene'}, + {title: 'Phenotype', sortable: false, width: 250}, + {title: 'Publications', sortable: false} + ] + }); }); })(jQuery); @@ -111,4 +187,15 @@

Published Macaque Models:

Table I. Published macaque disease models with and without reported genetic associations.
+ +
+

COVID Genetic Associations:

+
+
+ The development of COVID-19 vaccines and therapies required extensive testing of their safety and efficacy in nonhuman primates (NHPs) before these new treatments could be used in humans (reviewed in this article). A growing number of human genes have been implicated in COVID-19 disease severity and hospitalization. The table to the right list many of these genes (summarized in: https://www.covid19hg.org/), and provides links to mGAP variants in each gene. +
+
+ Table II. Genes associated with COVID-19 severity and links to macaque variants (Based on Karlsen et al.). Click the gene name to load the genome browser, showing macaque variants in that gene. +
+
\ No newline at end of file diff --git a/mGAP/src/org/labkey/mgap/mGAPModule.java b/mGAP/src/org/labkey/mgap/mGAPModule.java index d6dd356c8..58766cfec 100644 --- a/mGAP/src/org/labkey/mgap/mGAPModule.java +++ b/mGAP/src/org/labkey/mgap/mGAPModule.java @@ -61,7 +61,7 @@ public String getName() @Override public Double getSchemaVersion() { - return 16.60; + return 16.63; } @Override diff --git a/mGAP/src/org/labkey/mgap/mGapMaintenanceTask.java b/mGAP/src/org/labkey/mgap/mGapMaintenanceTask.java index a3a4e93ee..0acd09231 100644 --- a/mGAP/src/org/labkey/mgap/mGapMaintenanceTask.java +++ b/mGAP/src/org/labkey/mgap/mGapMaintenanceTask.java @@ -120,7 +120,7 @@ private void inspectReleaseFolder(String releaseId, File baseDir, Container c, U expectedFiles.add(new File(f.getPath() + ".tbi")); }); - final Set fields = PageFlowUtil.set("vcfId", "variantTable", "liftedVcfId", "sitesOnlyVcfId"); + final Set fields = PageFlowUtil.set("vcfId", "variantTable", "liftedVcfId", "sitesOnlyVcfId", "novelSitesVcfId"); new TableSelector(QueryService.get().getUserSchema(u, c, mGAPSchema.NAME).getTable(mGAPSchema.TABLE_VARIANT_CATALOG_RELEASES), fields, new SimpleFilter(FieldKey.fromString("objectid"), releaseId), null).forEachResults(rs -> { for (String field : fields) { diff --git a/mGAP/src/org/labkey/mgap/pipeline/mGapReleaseGenerator.java b/mGAP/src/org/labkey/mgap/pipeline/mGapReleaseGenerator.java index cd5d2b08c..ec5ef0236 100644 --- a/mGAP/src/org/labkey/mgap/pipeline/mGapReleaseGenerator.java +++ b/mGAP/src/org/labkey/mgap/pipeline/mGapReleaseGenerator.java @@ -52,6 +52,7 @@ import org.labkey.api.sequenceanalysis.pipeline.SequenceAnalysisJobSupport; import org.labkey.api.sequenceanalysis.pipeline.SequenceOutputHandler; import org.labkey.api.sequenceanalysis.pipeline.ToolParameterDescriptor; +import org.labkey.api.sequenceanalysis.run.AbstractDiscvrSeqWrapper; import org.labkey.api.sequenceanalysis.run.GeneToNameTranslator; import org.labkey.api.sequenceanalysis.run.SelectVariantsWrapper; import org.labkey.api.util.FileType; @@ -92,6 +93,7 @@ public class mGapReleaseGenerator extends AbstractParameterizedOutputHandler inputs, List outputTableMap = new HashMap<>(); Map liftedVcfMap = new HashMap<>(); Map sitesOnlyVcfMap = new HashMap<>(); + Map novelSitesVcfMap = new HashMap<>(); Map trackVCFMap = new HashMap<>(); for (SequenceOutputFile so : outputsCreated) @@ -291,6 +298,11 @@ else if (so.getCategory().contains("mGAP Release: Sites Only")) String name = so.getName().replaceAll(": Sites Only", ""); sitesOnlyVcfMap.put(name, so); } + else if (so.getCategory().contains("mGAP Release: Novel Sites")) + { + String name = so.getName().replaceAll(": Novel Sites", ""); + novelSitesVcfMap.put(name, so); + } else if (so.getCategory().endsWith("Release")) { outputVCFMap.put(so.getName(), so); @@ -340,6 +352,12 @@ else if (so.getCategory().endsWith("Release Track")) throw new PipelineJobException("Unable to find sites-only VCF for release: " + release); } + SequenceOutputFile novelSitesVcf = novelSitesVcfMap.get(release); + if (novelSitesVcf == null) + { + throw new PipelineJobException("Unable to find novel sites VCF for release: " + release); + } + //find basic stats: job.getLogger().info("inspecting file: " + so.getName()); int totalSubjects; @@ -404,6 +422,7 @@ else if (so.getCategory().endsWith("Release Track")) row.put("vcfId", so.getRowid()); row.put("liftedVcfId", liftedVcf.getRowid()); row.put("sitesOnlyVcfId", sitesOnlyVcf.getRowid()); + row.put("novelSitesVcfId", novelSitesVcf.getRowid()); row.put("variantTable", so2.getRowid()); row.put("genomeId", so.getLibrary_id()); row.put("totalSubjects", totalSubjects); @@ -443,7 +462,8 @@ else if (so.getCategory().endsWith("Release Track")) map.put("omim_phenotype", queryOmim(line[9], job.getContainer(), job.getLogger())); map.put("af", line[10]); map.put("identifier", line[11]); - map.put("cadd", line[12]); + Double cadd = StringUtils.trimToNull(line[12]) == null ? null : Double.parseDouble(line[12]); + map.put("cadd", cadd); map.put("objectId", new GUID().toString()); variantTableRows.add(map); @@ -775,6 +795,14 @@ public void processFilesRemote(List inputFiles, JobContext c ReferenceGenome grch37Genome = ctx.getSequenceSupport().getCachedGenome(ctx.getParams().getInt(AnnotationStep.GRCH37)); int genomeId = ctx.getSequenceSupport().getCachedObject(MMUL_GENOME, Integer.class); ReferenceGenome genome = ctx.getSequenceSupport().getCachedGenome(genomeId); + boolean testOnly = ctx.getParams().optBoolean("testOnly", false); + + int priorReleaseId = ctx.getParams().optInt(PRIOR_RELEASE); + File priorReleaseVcf = ctx.getSequenceSupport().getCachedData(priorReleaseId); + if (!priorReleaseVcf.exists()) + { + throw new PipelineJobException("Unable to find prior release VCF: " + priorReleaseVcf.getPath()); + } String releaseVersion = ctx.getParams().optString("releaseVersion", "0.0"); File primaryTrackVcf = new File(ctx.getOutputDir(), "mGap.v" + FileUtil.makeLegalName(releaseVersion).replaceAll(" ", "_") + ".vcf.gz"); @@ -798,17 +826,23 @@ public void processFilesRemote(List inputFiles, JobContext c File renamedVcfDone = new File(renamedVcf.getPath() + ".done"); if (renamedVcfDone.exists()) { - ctx.getLogger().info("File already copied: " + renamedVcf.getPath()); + ctx.getLogger().info("File already present: " + renamedVcf.getPath()); } else { - ctx.getLogger().info("Copying VCF: " + renamedVcf.getPath()); - if (renamedVcf.exists()) + if (track.isPrimary()) { - renamedVcf.delete(); + annotateBasedOnPriorRelease(ctx, vcf, priorReleaseVcf, releaseVersion, primaryTrackVcf, genome, testOnly); + } + else + { + ctx.getLogger().info("Copying VCF: " + renamedVcf.getPath()); + if (renamedVcf.exists()) + { + renamedVcf.delete(); + } + FileUtils.copyFile(vcf, renamedVcf); } - FileUtils.copyFile(vcf, renamedVcf); - if (renamedVcfIdx.exists()) { @@ -844,7 +878,6 @@ public void processFilesRemote(List inputFiles, JobContext c //Then summarize: ctx.getLogger().info("inspecting primary VCF and creating summary table"); inspectAndSummarizeVcf(ctx, primaryTrackVcf, translator, genome, true); - boolean testOnly = ctx.getParams().optBoolean("testOnly", false); SequenceOutputFile output = new SequenceOutputFile(); output.setFile(primaryTrackVcf); @@ -861,13 +894,31 @@ public void processFilesRemote(List inputFiles, JobContext c output2.setLibrary_id(genome.getGenomeId()); ctx.getFileManager().addSequenceOutput(output2); - File lifted = liftToHuman(ctx, primaryTrackVcf, genome, grch37Genome); + File sitesOnlyVcf = getSitesOnlyVcf(ctx, primaryTrackVcf, genome); + + File lifted = liftToHuman(ctx, primaryTrackVcf, sitesOnlyVcf, grch37Genome); SequenceOutputFile output3 = new SequenceOutputFile(); output3.setFile(lifted); output3.setName("mGAP Release: " + releaseVersion + " Lifted to Human"); output3.setCategory((testOnly ? "Test " : "") + "mGAP Release Lifted to Human"); output3.setLibrary_id(grch37Genome.getGenomeId()); ctx.getFileManager().addSequenceOutput(output3); + + SequenceOutputFile output4 = new SequenceOutputFile(); + output4.setFile(getNovelSitesVcfName(ctx.getOutputDir(), primaryTrackVcf)); + output4.setName("mGAP Release: " + releaseVersion + " Novel Sites"); + output4.setCategory((testOnly ? "Test " : "") + "mGAP Release: Novel Sites"); + output4.setLibrary_id(genome.getGenomeId()); + ctx.getFileManager().addSequenceOutput(output4); + } + + private void annotateBasedOnPriorRelease(JobContext ctx, File inputVcf, File priorReleaseVcf, String releaseVersion, File primaryTrackVcf, ReferenceGenome genome, boolean testOnly) throws PipelineJobException + { + // Annotate relative to previous release and make sites-only VCF + File droppedFromPriorRelease = getDroppedSitesVcfName(ctx.getOutputDir(), primaryTrackVcf); + File novelInRelease = getNovelSitesVcfName(ctx.getOutputDir(), primaryTrackVcf); + + new AnnotateNovelSitesWrapper(ctx.getLogger()).execute(inputVcf, priorReleaseVcf, novelInRelease, droppedFromPriorRelease, releaseVersion, primaryTrackVcf); } private void checkVcfAnnotationsAndSamples(File vcfInput, boolean skipAnnotationChecks) throws PipelineJobException @@ -906,11 +957,11 @@ private void checkVcfAnnotationsAndSamples(File vcfInput, boolean skipAnnotation } } - private File liftToHuman(JobContext ctx, File primaryTrackVcf, ReferenceGenome sourceGenome, ReferenceGenome grch37Genome) throws PipelineJobException + private File getSitesOnlyVcf(JobContext ctx, File primaryTrackVcf, ReferenceGenome sourceGenome) throws PipelineJobException { //drop genotypes for performance: ctx.getLogger().info("creating VCF without genotypes"); - File noGenotypes = new File(primaryTrackVcf.getParentFile(), SequenceAnalysisService.get().getUnzippedBaseName(primaryTrackVcf.getName()) + ".noGenotypes.vcf.gz"); + File noGenotypes = getSitesOnlyVcfName(ctx.getOutputDir(), primaryTrackVcf); if (indexExists(noGenotypes)) { ctx.getLogger().info("resuming from file: " + noGenotypes.getPath()); @@ -928,6 +979,11 @@ private File liftToHuman(JobContext ctx, File primaryTrackVcf, ReferenceGenome s output.setLibrary_id(sourceGenome.getGenomeId()); ctx.getFileManager().addSequenceOutput(output); + return noGenotypes; + } + + private File liftToHuman(JobContext ctx, File primaryTrackVcf, File noGenotypes, ReferenceGenome grch37Genome) throws PipelineJobException + { //lift to target genome Integer chainFileId = ctx.getSequenceSupport().getCachedObject(AnnotationStep.CHAIN_FILE, Integer.class); File chainFile = ctx.getSequenceSupport().getCachedData(chainFileId); @@ -951,6 +1007,21 @@ private File liftToHuman(JobContext ctx, File primaryTrackVcf, ReferenceGenome s return liftedToGRCh37; } + private File getSitesOnlyVcfName(File outDir, File primaryTrackVcf) + { + return new File(outDir, SequenceAnalysisService.get().getUnzippedBaseName(primaryTrackVcf.getName()) + ".sitesOnly.vcf.gz"); + } + + private File getDroppedSitesVcfName(File outDir, File primaryTrackVcf) + { + return new File(outDir, SequenceAnalysisService.get().getUnzippedBaseName(primaryTrackVcf.getName()) + ".droppedFromPriorRelease.vcf.gz"); + } + + private File getNovelSitesVcfName(File outDir, File primaryTrackVcf) + { + return new File(outDir, SequenceAnalysisService.get().getUnzippedBaseName(primaryTrackVcf.getName()) + ".newToRelease.vcf.gz"); + } + private File getLiftedVcfName(File outDir, File primaryTrackVcf) { return new File(outDir, SequenceAnalysisService.get().getUnzippedBaseName(primaryTrackVcf.getName()) + ".liftToGRCh37.vcf.gz"); @@ -1447,7 +1518,7 @@ private void generateSummary(JobContext ctx, File variantsToTable, File output, try (BufferedReader reader = Readers.getReader(variantsToTable)) { lineNo++; - if (lineNo % 1000000 == 0) + if (lineNo % 500000 == 0) { ctx.getLogger().info("processed " + lineNo + " lines"); } @@ -1558,58 +1629,6 @@ private void maybeWriteVariantLine(Set> queuedLines, VariantContext queuedLines.add(Arrays.asList(vc.getContig(), String.valueOf(vc.getStart()), vc.getReference().getDisplayString(), allele, source, reason, (description == null ? "" : description), StringUtils.join(overlappingGenes, ";"), StringUtils.join(omims, ";"), StringUtils.join(omimds, ";"), af == null ? "" : af.toString(), identifier == null ? "" : identifier, cadd == null ? "" : cadd.toString())); } - private String getPrimaryTrackName(File trackFile) throws PipelineJobException - { - Set ret = new HashSet<>(); - try (CSVReader reader = new CSVReader(Readers.getReader(trackFile), '\t')) - { - String[] line; - while ((line = reader.readNext()) != null) - { - boolean isPrimary = ConvertHelper.convert(line[2], Boolean.class); - if (isPrimary) - { - ret.add(line[0]); - } - } - } - catch (IOException e) - { - throw new PipelineJobException(e); - } - - if (ret.size() != 1) - { - throw new PipelineJobException("Expected a single track labeled as primary: " + StringUtils.join(ret, ";")); - } - - return ret.iterator().next(); - } - - private Map> parseTrackMap(File trackFile) throws PipelineJobException - { - Map> ret = new HashMap<>(); - try (CSVReader reader = new CSVReader(Readers.getReader(trackFile), '\t')) - { - String[] line; - while ((line = reader.readNext()) != null) - { - if (!ret.containsKey(line[0])) - { - ret.put(line[0], new ArrayList<>()); - } - - ret.get(line[0]).add(line[1]); - } - } - catch (IOException e) - { - throw new PipelineJobException(e); - } - - return ret; - } - private boolean indexExists(File vcf) { File idx = new File(vcf.getPath() + ".tbi"); @@ -1812,4 +1831,40 @@ public void testOMIMParse() throws Exception } } } + + private static class AnnotateNovelSitesWrapper extends AbstractDiscvrSeqWrapper + { + public AnnotateNovelSitesWrapper(Logger log) + { + super(log); + } + + public File execute(File vcf, File referenceVcf, File novelSitesVcf, File missingSitesVcf, String versionString, File vcfOutput) throws PipelineJobException + { + List args = new ArrayList<>(getBaseArgs()); + args.add("AnnotateNovelSites"); + args.add("-V"); + args.add(vcf.getPath()); + args.add("-rv"); + args.add(referenceVcf.getPath()); + args.add("-ns"); + args.add(novelSitesVcf.getPath()); + args.add("-ms"); + args.add(missingSitesVcf.getPath()); + + args.add("-an"); + args.add("mGAPV"); + args.add("-ad"); + args.add("The first mGAP version where variants at this site appeared"); + args.add("-av"); + args.add(versionString); + + args.add("-O"); + args.add(vcfOutput.getPath()); + + execute(args); + + return vcfOutput; + } + } } diff --git a/mGAP/src/org/labkey/mgap/query/UserRequestCustomizer.java b/mGAP/src/org/labkey/mgap/query/UserRequestCustomizer.java index 0db598bf7..8e951ac6e 100644 --- a/mGAP/src/org/labkey/mgap/query/UserRequestCustomizer.java +++ b/mGAP/src/org/labkey/mgap/query/UserRequestCustomizer.java @@ -37,7 +37,6 @@ public void addUserCol(AbstractTableInfo ti) ")) THEN " + ti.getSqlDialect().getBooleanTRUE() + " ELSE " + ti.getSqlDialect().getBooleanFALSE() + " END)"), JdbcType.BOOLEAN, ti.getColumn("userId")); col.setLabel("Has mGAP Access?"); col.setReadOnly(true); - col.setIsUnselectable(true); col.setUserEditable(false); ti.addColumn(col); } diff --git a/mcc/package-lock.json b/mcc/package-lock.json index e83642320..4c1dd055b 100644 --- a/mcc/package-lock.json +++ b/mcc/package-lock.json @@ -9,16 +9,20 @@ "version": "0.0.0", "dependencies": { "@labkey/api": "^1.8.0", + "@labkey/components": "2.157.0", + "@material-ui/core": "^4.12.4", + "@material-ui/styles": "^4.11.5", "chart.js": "^3.7.0", - "nanoid": "^3.2.0", "react": "^17.0.2", "react-dom": "^17.0.2", "react-hot-loader": "^4.13.0", - "react-tooltip": "^4.2.21" + "react-tooltip": "^4.2.21", + "uuid": "^8.3.2" }, "devDependencies": { "@labkey/build": "^5.0.0", "@types/jest": "^27.4.0", + "@types/uuid": "^8.3.4", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", "jest": "^27.4.7", @@ -30,7 +34,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, "dependencies": { "@babel/highlight": "^7.14.5" }, @@ -42,7 +45,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -51,7 +53,6 @@ "version": "7.14.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.3.tgz", "integrity": "sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.12.13", "@babel/generator": "^7.14.3", @@ -81,7 +82,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -90,7 +90,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", - "dev": true, "dependencies": { "@babel/types": "^7.15.0", "jsesc": "^2.5.1", @@ -129,7 +128,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", - "dev": true, "dependencies": { "@babel/compat-data": "^7.15.0", "@babel/helper-validator-option": "^7.14.5", @@ -147,7 +145,6 @@ "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, "bin": { "semver": "bin/semver.js" } @@ -232,7 +229,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dev": true, "dependencies": { "@babel/helper-get-function-arity": "^7.14.5", "@babel/template": "^7.14.5", @@ -246,7 +242,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dev": true, "dependencies": { "@babel/types": "^7.14.5" }, @@ -258,7 +253,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", - "dev": true, "dependencies": { "@babel/types": "^7.14.5" }, @@ -270,7 +264,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", - "dev": true, "dependencies": { "@babel/types": "^7.15.0" }, @@ -282,7 +275,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dev": true, "dependencies": { "@babel/types": "^7.14.5" }, @@ -294,7 +286,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", - "dev": true, "dependencies": { "@babel/helper-module-imports": "^7.14.5", "@babel/helper-replace-supers": "^7.15.0", @@ -313,7 +304,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, "dependencies": { "@babel/types": "^7.14.5" }, @@ -325,7 +315,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -348,7 +337,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", - "dev": true, "dependencies": { "@babel/helper-member-expression-to-functions": "^7.15.0", "@babel/helper-optimise-call-expression": "^7.14.5", @@ -363,7 +351,6 @@ "version": "7.14.8", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", - "dev": true, "dependencies": { "@babel/types": "^7.14.8" }, @@ -387,7 +374,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dev": true, "dependencies": { "@babel/types": "^7.14.5" }, @@ -399,7 +385,6 @@ "version": "7.14.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -408,7 +393,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -432,7 +416,6 @@ "version": "7.15.3", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", - "dev": true, "dependencies": { "@babel/template": "^7.14.5", "@babel/traverse": "^7.15.0", @@ -446,7 +429,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", @@ -460,7 +442,6 @@ "version": "7.15.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", - "dev": true, "bin": { "parser": "bin/babel-parser.js" }, @@ -830,7 +811,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", - "dev": true, "dependencies": { "@babel/helper-plugin-utils": "^7.14.5" }, @@ -1693,11 +1673,22 @@ } }, "node_modules/@babel/runtime": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz", - "integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==", - "dev": true, + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime-corejs2": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.17.9.tgz", + "integrity": "sha512-+QThIsnjVY12uURTvmnW33risFZ7ulq6OWw0VJL08UwiYiWVp9PM63s+W1L2ppajYyKAYKb7afcGYSHzA0k04Q==", "dependencies": { + "core-js": "^2.6.5", "regenerator-runtime": "^0.13.4" }, "engines": { @@ -1708,7 +1699,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", "@babel/parser": "^7.14.5", @@ -1722,7 +1712,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.14.5", "@babel/generator": "^7.15.0", @@ -1742,7 +1731,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", - "dev": true, "dependencies": { "@babel/helper-validator-identifier": "^7.14.9", "to-fast-properties": "^2.0.0" @@ -1766,6 +1754,368 @@ "node": ">=10.0.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.9.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz", + "integrity": "sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==", + "dependencies": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/runtime": "^7.13.10", + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.5", + "@emotion/serialize": "^1.0.2", + "babel-plugin-macros": "^2.6.1", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@emotion/cache": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", + "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", + "dependencies": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "node_modules/@emotion/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.3.1.tgz", + "integrity": "sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + }, + "peerDependencies": { + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/core/node_modules/@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "dependencies": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "node_modules/@emotion/core/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/@emotion/core/node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "dependencies": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "node_modules/@emotion/core/node_modules/@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" + }, + "node_modules/@emotion/core/node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "node_modules/@emotion/core/node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "node_modules/@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", + "dependencies": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" + } + }, + "node_modules/@emotion/css/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/@emotion/css/node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "dependencies": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "node_modules/@emotion/css/node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "node_modules/@emotion/css/node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "node_modules/@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "node_modules/@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "dependencies": { + "@emotion/memoize": "0.7.4" + } + }, + "node_modules/@emotion/is-prop-valid/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "node_modules/@emotion/react": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.0.tgz", + "integrity": "sha512-lBVSF5d0ceKtfKCDQJveNAtkC7ayxpVlgOohLgXqRwqWr9bOf4TZAFFyIcNngnV6xK6X4x2ZeXq7vliHkoVkxQ==", + "dependencies": { + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/cache": "^11.7.1", + "@emotion/serialize": "^1.0.3", + "@emotion/utils": "^1.1.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.0.0", + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.3.tgz", + "integrity": "sha512-2mSSvgLfyV3q+iVh3YWgNlUc2a9ZlDU7DjuP5MjK3AXRR0dYigCrP99aeFtaB2L/hjfEZdSThn5dsZ0ufqbvsA==", + "dependencies": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "node_modules/@emotion/styled": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", + "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "dependencies": { + "@emotion/styled-base": "^10.3.0", + "babel-plugin-emotion": "^10.0.27" + }, + "peerDependencies": { + "@emotion/core": "^10.0.27", + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/styled-base": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz", + "integrity": "sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "@emotion/is-prop-valid": "0.8.8", + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3" + }, + "peerDependencies": { + "@emotion/core": "^10.0.28", + "react": ">=16.3.0" + } + }, + "node_modules/@emotion/styled-base/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/@emotion/styled-base/node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "dependencies": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "node_modules/@emotion/styled-base/node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "node_modules/@emotion/styled-base/node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "node_modules/@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "node_modules/@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "node_modules/@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-free": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", + "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==", + "hasInstallScript": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-regular-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz", + "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", + "hasInstallScript": true, + "dependencies": { + "@fortawesome/fontawesome-common-types": "^0.2.36" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/react-fontawesome": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.15.tgz", + "integrity": "sha512-/HFHdcoLESxxMkqZAcZ6RXDJ69pVApwdwRos/B2kiMWxDSAX2dFK8Er2/+rG+RsrzWB/dsAyjefLmemgmfE18g==", + "dependencies": { + "prop-types": "^15.7.2" + }, + "peerDependencies": { + "@fortawesome/fontawesome-svg-core": "^1.2.32", + "react": ">=16.x" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "peerDependencies": { + "react": "*" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -2439,15 +2789,15 @@ } }, "node_modules/@labkey/api": { - "version": "1.8.0", - "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.8.0.tgz", - "integrity": "sha1-DiGjCOphC25lFsGwX3BC7kGmhlc=", + "version": "1.10.0", + "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.10.0.tgz", + "integrity": "sha1-+n1L8fL1dpJRP0sc0qyjxN2F6GA=", "license": "Apache-2.0" }, "node_modules/@labkey/build": { - "version": "5.0.0", - "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/build/-/@labkey/build-5.0.0.tgz", - "integrity": "sha1-b1nqEvp+G6My9Q0zBWzx4/dLAJc=", + "version": "5.0.1", + "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/build/-/@labkey/build-5.0.1.tgz", + "integrity": "sha1-6eEqx45lpOjriEge9CRZXSSH1Fs=", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -2467,11 +2817,11 @@ "fork-ts-checker-webpack-plugin": "6.2.10", "html-webpack-plugin": "5.3.1", "mini-css-extract-plugin": "1.6.0", - "node-sass": "6.0.1", + "node-sass": "7.0.1", "react-hot-loader": "4.12.21", "resolve-url-loader": "3.1.2", "rimraf": "3.0.2", - "sass-loader": "11.1.1", + "sass-loader": "12.6.0", "style-loader": "2.0.0", "typescript": "4.3.2", "webpack": "5.65.0", @@ -2583,78 +2933,498 @@ "node": ">= 8" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, + "node_modules/@labkey/components": { + "version": "2.157.0", + "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/components/-/@labkey/components-2.157.0.tgz", + "integrity": "sha1-N5gCKlitMFruewPoYB/28/8cX8A=", + "license": "SEE LICENSE IN LICENSE.txt", + "dependencies": { + "@fortawesome/fontawesome-free": "5.15.4", + "@fortawesome/fontawesome-svg-core": "1.2.36", + "@fortawesome/free-regular-svg-icons": "5.15.4", + "@fortawesome/free-solid-svg-icons": "5.15.4", + "@fortawesome/react-fontawesome": "0.1.15", + "@labkey/api": "1.10.0", + "bootstrap": "3.4.1", + "classnames": "2.3.1", + "font-awesome": "4.7.0", + "formsy-react": "1.1.5", + "formsy-react-components": "1.1.0", + "history": "4.7.2", + "immer": "9.0.6", + "immutable": "3.8.2", + "jquery": "3.6.0", + "moment": "2.27.0", + "moment-jdateformatparser": "1.1.0", + "moment-timezone": "0.5.31", + "normalizr": "3.6.1", + "numeral": "2.0.6", + "react": "16.14.0", + "react-beautiful-dnd": "13.1.0", + "react-bootstrap": "0.33.1", + "react-bootstrap-toggle": "2.3.2", + "react-color": "2.19.3", + "react-datepicker": "4.2.1", + "react-dom": "16.14.0", + "react-redux": "5.1.0", + "react-router": "3.2.6", + "react-select": "4.3.1", + "react-sticky": "6.0.3", + "react-treebeard": "3.2.4", + "reactn": "2.2.7", + "redux-actions": "2.3.2", + "use-immer": "0.6.0", + "vis-network": "6.5.2" + }, + "peerDependencies": { + "immutable": "^3.8.2", + "jquery": "^3.4.1", + "react": "^16.0", + "react-bootstrap": "^0.33.1", + "react-dom": "^16.0", + "reactn": "^2.2.7" + } + }, + "node_modules/@labkey/components/node_modules/formsy-react": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/formsy-react/-/formsy-react-1.1.5.tgz", + "integrity": "sha512-nNWe4Vbp6aDQ/zSxJ7gVQgD5+avFRVbydcjA2Om42flxpQFrKE54AAbuyEj3Jvv+2b9LVl+WLMAPalyvLjwNcQ==", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "form-data-to-object": "^0.2.0", + "prop-types": "^15.5.10" }, - "engines": { - "node": ">= 8" + "peerDependencies": { + "react": "^15.6.1 || ^16.0.0", + "react-dom": "^15.6.1 || ^16.0.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "engines": { - "node": ">= 8" + "node_modules/@labkey/components/node_modules/formsy-react-components": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/formsy-react-components/-/formsy-react-components-1.1.0.tgz", + "integrity": "sha512-GUgnIqXbXNPf7auP4nwk5PF6477r5UhdQoO1aNCvQajLarUu/Jj8PaxTCHu56tNGSlewACqRV44m8MrYOMzdTQ==", + "dependencies": { + "classnames": "^2.2.5", + "prop-types": "^15.5.10" + }, + "peerDependencies": { + "formsy-react": "^1.1.0", + "react": "^15.6.1 || ^16.0.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/@labkey/components/node_modules/react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/@sinonjs/commons": { - "version": "1.8.3", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", - "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", - "dev": true, + "node_modules/@labkey/components/node_modules/react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", "dependencies": { - "type-detect": "4.0.8" + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + }, + "peerDependencies": { + "react": "^16.14.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", - "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", - "dev": true, + "node_modules/@labkey/components/node_modules/react-redux": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.0.tgz", + "integrity": "sha512-CRMpEx8+ccpoVxQrQDkG1obExNYpj6dZ1Ni7lUNFB9wcxOhy02tIqpFo4IUXc0kYvCGMu6ABj9A4imEX2VGZJQ==", "dependencies": { - "@sinonjs/commons": "^1.7.0" + "@babel/runtime": "^7.1.2", + "hoist-non-react-statics": "^3.0.0", + "invariant": "^2.2.4", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.1", + "react-is": "^16.6.0", + "react-lifecycles-compat": "^3.0.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0-0 || ^16.0.0-0", + "redux": "^2.0.0 || ^3.0.0 || ^4.0.0-0" } }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" + "node_modules/@labkey/components/node_modules/react-router": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-3.2.6.tgz", + "integrity": "sha512-nlxtQE8B22hb/JxdaslI1tfZacxFU8x8BJryXOnR2RxB4vc01zuHYAHAIgmBkdk1kzXaA25hZxK6KAH/+CXArw==", + "dependencies": { + "create-react-class": "^15.5.1", + "history": "^3.0.0", + "hoist-non-react-statics": "^3.3.2", + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.0", + "warning": "^3.0.0" + }, + "peerDependencies": { + "react": "^0.14.0 || ^15.0.0 || ^16.0.0" } }, - "node_modules/@types/babel__core": { - "version": "7.1.18", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", - "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", - "dev": true, + "node_modules/@labkey/components/node_modules/react-router/node_modules/history": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", + "integrity": "sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw=", "dependencies": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "query-string": "^4.2.2", + "warning": "^3.0.0" + } + }, + "node_modules/@labkey/components/node_modules/scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "dependencies": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "node_modules/@labkey/components/node_modules/vis-data": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/vis-data/-/vis-data-6.6.1.tgz", + "integrity": "sha512-xmujDB2Dzf8T04rGFJ9OP4OA6zRVrz8R9hb0CVKryBrZRCljCga9JjSfgctA8S7wdZu7otDtUIwX4ZOgfV/57w==", + "hasInstallScript": true, + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/visjs" + }, + "peerDependencies": { + "moment": "^2.24.0", + "uuid": "^7.0.0 || ^8.0.0", + "vis-util": "^4.0.0" + } + }, + "node_modules/@labkey/components/node_modules/vis-network": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/vis-network/-/vis-network-6.5.2.tgz", + "integrity": "sha512-Dj5oEtZMUWuhq7D7dwdmxmtJgrK3kwfV4Ov/ePSrhPZgNdJlXzpeDZU/Eq0pKGyOAPLClemgVImc0bZpZ4Yafw==", + "hasInstallScript": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/visjs" + }, + "peerDependencies": { + "keycharm": "^0.2.0", + "moment": "^2.24.0", + "vis-data": "^6.2.1", + "vis-util": "^1.1.8" + } + }, + "node_modules/@material-ui/core": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/core/node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/@material-ui/core/node_modules/react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/styles/node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "node_modules/@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "engines": { + "node": ">=8.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/material-ui" + }, + "peerDependencies": { + "@types/react": "^16.8.6 || ^17.0.0", + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/system/node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, + "node_modules/@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "peerDependencies": { + "@types/react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "dependencies": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + }, + "engines": { + "node": ">=8.0.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/fs/node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@npmcli/move-file/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@sinonjs/commons": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", + "integrity": "sha512-xkNcLAn/wZaX14RPlwizcKicDk9G3F8m2nU3L7Ukm5zBgTwiT0wsoFAHx9Jq56fJA1z/7uKGtCRu16sOUCLIHQ==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-8.1.0.tgz", + "integrity": "sha512-OAPJUAtgeINhh/TAlUID4QTs53Njm7xzddaVlEs/SXwgtiD1tW22zAB/W1wdqfrpmikgaWQ9Fw6Ws+hsiRm5Vg==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^1.7.0" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/babel__core": { + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.18.tgz", + "integrity": "sha512-S7unDjm/C7z2A2R9NzfKCK1I+BAALDtxEmsJBwlB3EzNfb929ykjL++1CK9LO++EIp2fQrC8O+BwjKvz6UeDyQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", "@types/babel__traverse": "*" } }, @@ -2782,6 +3552,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -2864,8 +3643,7 @@ "node_modules/@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "node_modules/@types/prettier": { "version": "2.4.3", @@ -2876,8 +3654,7 @@ "node_modules/@types/prop-types": { "version": "15.7.3", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" }, "node_modules/@types/qs": { "version": "6.9.7", @@ -2891,12 +3668,46 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "node_modules/@types/react": { + "version": "16.14.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.25.tgz", + "integrity": "sha512-cXRVHd7vBT5v1is72mmvmsg9stZrbJO04DJqFeh3Yj2tVKO6vmxg5BI+ybI6Ls7ROXRG3aFbZj9x0WA3ZAoDQw==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@types/react-redux": { + "version": "7.1.24", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", + "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", + "dependencies": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "node_modules/@types/react-transition-group": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "dependencies": { + "@types/react": "*" + } + }, "node_modules/@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, + "node_modules/@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, "node_modules/@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -2931,6 +3742,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "node_modules/@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "node_modules/@types/ws": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", @@ -3265,6 +4082,20 @@ "node": ">= 6.0.0" } }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -3342,15 +4173,6 @@ "ajv": "^6.9.1" } }, - "node_modules/amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true, - "engines": { - "node": ">=0.4.2" - } - }, "node_modules/ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -3391,7 +4213,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "dependencies": { "color-convert": "^1.9.0" }, @@ -3413,43 +4234,22 @@ } }, "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, "node_modules/are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dev": true, "dependencies": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/are-we-there-yet/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/are-we-there-yet/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" } }, "node_modules/argparse": { @@ -3529,9 +4329,9 @@ } }, "node_modules/asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "dependencies": { "safer-buffer": "~2.1.0" @@ -3547,9 +4347,9 @@ } }, "node_modules/async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "dependencies": { "lodash": "^4.17.14" @@ -3717,15 +4517,59 @@ "webpack": ">=2" } }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, + "node_modules/babel-plugin-dynamic-import-node": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", + "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", + "dev": true, + "dependencies": { + "object.assign": "^4.1.0" + } + }, + "node_modules/babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", + "dependencies": { + "@babel/helper-module-imports": "^7.0.0", + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/serialize": "^0.11.16", + "babel-plugin-macros": "^2.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^1.0.5", + "find-root": "^1.1.0", + "source-map": "^0.5.7" + } + }, + "node_modules/babel-plugin-emotion/node_modules/@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "node_modules/babel-plugin-emotion/node_modules/@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", "dependencies": { - "object.assign": "^4.1.0" + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" } }, + "node_modules/babel-plugin-emotion/node_modules/@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "node_modules/babel-plugin-emotion/node_modules/csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + }, "node_modules/babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -3757,6 +4601,16 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "node_modules/babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "dependencies": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, "node_modules/babel-plugin-polyfill-corejs2": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", @@ -3805,6 +4659,11 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + }, "node_modules/babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -3959,6 +4818,14 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "node_modules/bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==", + "engines": { + "node": ">=6" + } + }, "node_modules/bootstrap-sass": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap-sass/-/bootstrap-sass-3.4.1.tgz", @@ -3997,7 +4864,6 @@ "version": "4.16.7", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", - "dev": true, "dependencies": { "caniuse-lite": "^1.0.30001248", "colorette": "^1.2.2", @@ -4058,11 +4924,51 @@ "node": ">= 0.8" } }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cacache/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -4075,7 +4981,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -4117,14 +5022,19 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", - "dev": true, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - } + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + } + ] }, "node_modules/caseless": { "version": "0.12.0", @@ -4136,7 +5046,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "dependencies": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -4257,6 +5166,11 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "node_modules/classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "node_modules/clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -4288,58 +5202,35 @@ } }, "node_modules/cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "dependencies": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, "node_modules/cliui/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/cliui/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/cliui/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/cliui/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/clone-deep": { @@ -4356,6 +5247,14 @@ "node": ">=6" } }, + "node_modules/clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==", + "engines": { + "node": ">=6" + } + }, "node_modules/co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", @@ -4366,15 +5265,6 @@ "node": ">= 0.12.0" } }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -4385,7 +5275,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "dependencies": { "color-name": "1.1.3" } @@ -4393,14 +5282,21 @@ "node_modules/color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } }, "node_modules/colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" }, "node_modules/combined-stream": { "version": "1.0.8", @@ -4549,7 +5445,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, "dependencies": { "safe-buffer": "~5.1.1" } @@ -4574,7 +5469,6 @@ "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", "deprecated": "core-js@<3.3 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", - "dev": true, "hasInstallScript": true }, "node_modules/core-js-compat": { @@ -4610,7 +5504,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, "dependencies": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.1.0", @@ -4622,6 +5515,15 @@ "node": ">=8" } }, + "node_modules/create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "dependencies": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "node_modules/cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -4666,6 +5568,14 @@ "urix": "^0.1.0" } }, + "node_modules/css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "dependencies": { + "tiny-invariant": "^1.0.6" + } + }, "node_modules/css-loader": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.6.tgz", @@ -4757,6 +5667,15 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "dependencies": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "node_modules/css-what": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", @@ -4817,8 +5736,7 @@ "node_modules/csstype": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", - "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==", - "dev": true + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" }, "node_modules/d": { "version": "1.0.1", @@ -4856,11 +5774,22 @@ "node": ">=10" } }, + "node_modules/date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==", + "engines": { + "node": ">=0.11" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/date-fns" + } + }, "node_modules/debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dependencies": { "ms": "2.1.2" }, @@ -4929,7 +5858,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, "dependencies": { "is-arguments": "^1.0.4", "is-date-object": "^1.0.1", @@ -4982,7 +5910,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "dependencies": { "object-keys": "^1.0.12" }, @@ -5118,6 +6045,14 @@ "utila": "~0.4" } }, + "node_modules/dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "dependencies": { + "@babel/runtime": "^7.1.2" + } + }, "node_modules/dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -5228,8 +6163,7 @@ "node_modules/electron-to-chromium": { "version": "1.3.803", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.803.tgz", - "integrity": "sha512-tmRK9qB8Zs8eLMtTBp+w2zVS9MUe62gQQQHjYdAc5Zljam3ZIokNb+vZLPRz9RCREp6EFRwyhOFwbt1fEriQ2Q==", - "dev": true + "integrity": "sha512-tmRK9qB8Zs8eLMtTBp+w2zVS9MUe62gQQQHjYdAc5Zljam3ZIokNb+vZLPRz9RCREp6EFRwyhOFwbt1fEriQ2Q==" }, "node_modules/emittery": { "version": "0.8.1", @@ -5244,9 +6178,9 @@ } }, "node_modules/emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "node_modules/emojis-list": { @@ -5266,6 +6200,29 @@ "node": ">= 0.8" } }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/enhanced-resolve": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", @@ -5458,11 +6415,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, "node_modules/error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "dependencies": { "is-arrayish": "^0.2.1" } @@ -5560,7 +6522,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -5575,7 +6536,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -6012,6 +6972,11 @@ "url": "https://github.com/avajs/find-cache-dir?sponsor=1" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "node_modules/find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -6045,6 +7010,14 @@ } } }, + "node_modules/font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=", + "engines": { + "node": ">=0.10.3" + } + }, "node_modules/forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -6196,6 +7169,11 @@ "node": ">= 0.12" } }, + "node_modules/form-data-to-object": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/form-data-to-object/-/form-data-to-object-0.2.0.tgz", + "integrity": "sha1-96jmjd2RChEApl4lrGpIQUP/gWg=" + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -6270,8 +7248,7 @@ "node_modules/function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "node_modules/function.prototype.name": { "version": "1.1.4", @@ -6301,19 +7278,44 @@ } }, "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dev": true, "dependencies": { - "aproba": "^1.0.3", + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/gaze": { @@ -6332,7 +7334,6 @@ "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, "engines": { "node": ">=6.9.0" } @@ -6350,7 +7351,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, "dependencies": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -6466,7 +7466,6 @@ "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, "engines": { "node": ">=4" } @@ -6492,9 +7491,9 @@ } }, "node_modules/globule": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", - "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", + "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", "dev": true, "dependencies": { "glob": "~7.1.1", @@ -6553,7 +7552,6 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "dependencies": { "function-bind": "^1.1.1" }, @@ -6561,18 +7559,6 @@ "node": ">= 0.4.0" } }, - "node_modules/has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", @@ -6586,7 +7572,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, "engines": { "node": ">=4" } @@ -6595,7 +7580,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -6607,7 +7591,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "dependencies": { "has-symbols": "^1.0.2" }, @@ -6633,6 +7616,18 @@ "he": "bin/he" } }, + "node_modules/history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", + "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "dependencies": { + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "resolve-pathname": "^2.2.0", + "value-equal": "^0.4.0", + "warning": "^3.0.0" + } + }, "node_modules/hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -6798,6 +7793,12 @@ "entities": "^2.0.0" } }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "node_modules/http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -6919,6 +7920,20 @@ "node": ">=10.17.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -6952,11 +7967,27 @@ "node": ">= 4" } }, + "node_modules/immer": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz", + "integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/immer" + } + }, + "node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -7005,6 +8036,12 @@ "node": ">=8" } }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, "node_modules/inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -7044,6 +8081,14 @@ "node": ">= 0.10" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -7063,7 +8108,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -7078,8 +8122,7 @@ "node_modules/is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "node_modules/is-bigint": { "version": "1.0.1", @@ -7133,7 +8176,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, "dependencies": { "has": "^1.0.3" }, @@ -7145,7 +8187,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -7178,15 +8219,12 @@ } }, "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, "node_modules/is-generator-fn": { @@ -7210,6 +8248,17 @@ "node": ">=0.10.0" } }, + "node_modules/is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, "node_modules/is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -7292,7 +8341,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -7696,15 +8744,6 @@ } } }, - "node_modules/jest-cli/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-cli/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -7736,17 +8775,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/jest-cli/node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "node_modules/jest-cli/node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -7765,12 +8793,6 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "node_modules/jest-cli/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "node_modules/jest-cli/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -7780,41 +8802,6 @@ "node": ">=8" } }, - "node_modules/jest-cli/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-cli/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/jest-cli/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -7827,32 +8814,6 @@ "node": ">=8" } }, - "node_modules/jest-cli/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/jest-cli/node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-cli/node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -7871,15 +8832,6 @@ "node": ">=10" } }, - "node_modules/jest-cli/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/jest-config": { "version": "27.4.7", "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-27.4.7.tgz", @@ -9323,6 +10275,11 @@ "url": "https://github.com/chalk/supports-color?sponsor=1" } }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, "node_modules/js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -9440,7 +10397,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "bin": { "jsesc": "bin/jsesc" }, @@ -9457,8 +10413,7 @@ "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "node_modules/json-schema": { "version": "0.4.0", @@ -9482,7 +10437,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, "dependencies": { "minimist": "^1.2.5" }, @@ -9520,6 +10474,99 @@ "node": ">=0.6.0" } }, + "node_modules/jss": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.9.0.tgz", + "integrity": "sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/jss" + } + }, + "node_modules/jss-plugin-camel-case": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.9.0.tgz", + "integrity": "sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.9.0" + } + }, + "node_modules/jss-plugin-default-unit": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.9.0.tgz", + "integrity": "sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0" + } + }, + "node_modules/jss-plugin-global": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.9.0.tgz", + "integrity": "sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0" + } + }, + "node_modules/jss-plugin-nested": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.9.0.tgz", + "integrity": "sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-props-sort": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.9.0.tgz", + "integrity": "sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0" + } + }, + "node_modules/jss-plugin-rule-value-function": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.9.0.tgz", + "integrity": "sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0", + "tiny-warning": "^1.0.2" + } + }, + "node_modules/jss-plugin-vendor-prefixer": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.9.0.tgz", + "integrity": "sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA==", + "dependencies": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.9.0" + } + }, + "node_modules/keycharm": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.2.0.tgz", + "integrity": "sha1-+m6i5DuQpoAohD0n8gddNajD5vk=", + "peer": true + }, + "node_modules/keycode": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", + "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==" + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -9539,9 +10586,9 @@ } }, "node_modules/klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true, "engines": { "node": ">= 8" @@ -9572,8 +10619,7 @@ "node_modules/lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/loader-runner": { "version": "4.2.0", @@ -9623,8 +10669,12 @@ "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "node_modules/lodash.debounce": { "version": "4.0.8", @@ -9718,6 +10768,33 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, "node_modules/makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -9739,6 +10816,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -9760,6 +10842,11 @@ "node": ">= 4.0.0" } }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "node_modules/meow": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", @@ -9798,15 +10885,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/meow/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/merge-descriptors": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", @@ -9981,9 +11059,9 @@ } }, "node_modules/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "node_modules/minimist-options": { "version": "4.1.0", @@ -10000,9 +11078,9 @@ } }, "node_modules/minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "dev": true, "dependencies": { "yallist": "^4.0.0" @@ -10011,6 +11089,71 @@ "node": ">=8" } }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -10036,6 +11179,33 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==", + "engines": { + "node": "*" + } + }, + "node_modules/moment-jdateformatparser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/moment-jdateformatparser/-/moment-jdateformatparser-1.1.0.tgz", + "integrity": "sha1-TGuuM+IJDONS05uHfpsxcJkoscc=", + "dependencies": { + "moment": ">=1.5.0" + } + }, + "node_modules/moment-timezone": { + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "dependencies": { + "moment": ">= 2.9.0" + }, + "engines": { + "node": "*" + } + }, "node_modules/moo": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", @@ -10045,8 +11215,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/multicast-dns": { "version": "6.2.3", @@ -10068,15 +11237,16 @@ "dev": true }, "node_modules/nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "dev": true }, "node_modules/nanoid": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "dev": true, "bin": { "nanoid": "bin/nanoid.cjs" }, @@ -10155,37 +11325,93 @@ "integrity": "sha512-PPmu8eEeG9saEUvI97fm4OYxXVB6bFvyNTyiUOBichBpFG8A1Ljw3bY62+5oOjDEMHRnd0Y7HQ+x7uzxOzC6JA==", "dev": true, "engines": { - "node": ">= 6.0.0" + "node": ">= 6.0.0" + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", + "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16" } }, - "node_modules/node-gyp": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", "dev": true, "dependencies": { - "env-paths": "^2.2.0", - "glob": "^7.1.4", - "graceful-fs": "^4.2.3", - "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", - "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", - "which": "^2.0.2" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" }, - "bin": { - "node-gyp": "bin/node-gyp.js" + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" }, "engines": { - "node": ">= 10.12.0" + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } }, "node_modules/node-gyp/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -10197,6 +11423,18 @@ "node": ">=10" } }, + "node_modules/node-gyp/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/node-int64": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", @@ -10206,18 +11444,17 @@ "node_modules/node-releases": { "version": "1.1.74", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.74.tgz", - "integrity": "sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==", - "dev": true + "integrity": "sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==" }, "node_modules/node-sass": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz", - "integrity": "sha512-f+Rbqt92Ful9gX0cGtdYwjTrWAaGURgaK5rZCWOgCNyGWusFYHhbqCCBoFBeat+HKETOU02AyTxNhJV0YZf2jQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.1.tgz", + "integrity": "sha512-uMy+Xt29NlqKCFdFRZyXKOTqGt+QaKHexv9STj2WeLottnlqZEEWx6Bj0MXNthmFRRdM/YwyNo/8Tr46TOM0jQ==", "dev": true, "hasInstallScript": true, "dependencies": { "async-foreach": "^0.1.3", - "chalk": "^1.1.1", + "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "gaze": "^1.0.0", "get-stdin": "^4.0.1", @@ -10225,10 +11462,10 @@ "lodash": "^4.17.15", "meow": "^9.0.0", "nan": "^2.13.2", - "node-gyp": "^7.1.0", - "npmlog": "^4.0.0", + "node-gyp": "^8.4.1", + "npmlog": "^5.0.0", "request": "^2.88.0", - "sass-graph": "2.2.5", + "sass-graph": "4.0.0", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, @@ -10240,37 +11477,73 @@ } }, "node_modules/node-sass/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, "node_modules/node-sass/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/node-sass/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/node-sass/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/node-sass/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" } }, "node_modules/node-sass/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, "engines": { - "node": ">=0.8.0" + "node": ">=8" } }, "node_modules/nopt": { @@ -10304,9 +11577,9 @@ } }, "node_modules/normalize-package-data/node_modules/semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "dependencies": { "lru-cache": "^6.0.0" @@ -10327,6 +11600,11 @@ "node": ">=0.10.0" } }, + "node_modules/normalizr": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/normalizr/-/normalizr-3.6.1.tgz", + "integrity": "sha512-8iEmqXmPtll8PwbEFrbPoDxVw7MKnNvt3PZzR2Xvq9nggEEOgBlNICPXYzyZ4w4AkHUzCU998mdatER3n2VaMA==" + }, "node_modules/npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -10340,15 +11618,15 @@ } }, "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dev": true, "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" } }, "node_modules/nth-check": { @@ -10363,13 +11641,12 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, + "node_modules/numeral": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz", + "integrity": "sha1-StCAk21EPCVhrtnyGX7//iX05QY=", "engines": { - "node": ">=0.10.0" + "node": "*" } }, "node_modules/nwsapi": { @@ -10408,7 +11685,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -10424,7 +11700,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, "engines": { "node": ">= 0.4" } @@ -10660,7 +11935,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -10672,7 +11946,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -10750,8 +12023,7 @@ "node_modules/path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { "version": "0.1.7", @@ -10763,7 +12035,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -10771,8 +12042,7 @@ "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "node_modules/picomatch": { "version": "2.3.1", @@ -10807,6 +12077,11 @@ "node": ">=8" } }, + "node_modules/popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "node_modules/portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -11000,6 +12275,34 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/promise-retry/node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -11034,6 +12337,26 @@ "reflect.ownkeys": "^0.2.0" } }, + "node_modules/prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "dependencies": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, + "node_modules/prop-types-extra/node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -11072,14 +12395,26 @@ } }, "node_modules/qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, "engines": { "node": ">=0.6" } }, + "node_modules/query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "dependencies": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -11113,11 +12448,15 @@ "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, "dependencies": { "performance-now": "^2.1.0" } }, + "node_modules/raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "node_modules/railroad-diagrams": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", @@ -11191,6 +12530,95 @@ "node": ">=0.10.0" } }, + "node_modules/react-beautiful-dnd": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", + "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==", + "dependencies": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + }, + "peerDependencies": { + "react": "^16.8.5 || ^17.0.0", + "react-dom": "^16.8.5 || ^17.0.0" + } + }, + "node_modules/react-bootstrap": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz", + "integrity": "sha512-qWTRravSds87P8WC82tETy2yIso8qDqlIm0czsrduCaYAFtHuyLu0XDbUlfLXeRzqgwm5sRk2wRaTNoiVkk/YQ==", + "dependencies": { + "@babel/runtime-corejs2": "^7.0.0", + "classnames": "^2.2.5", + "dom-helpers": "^3.2.0", + "invariant": "^2.2.4", + "keycode": "^2.2.0", + "prop-types": "^15.6.1", + "prop-types-extra": "^1.0.1", + "react-overlays": "^0.9.0", + "react-prop-types": "^0.4.0", + "react-transition-group": "^2.0.0", + "uncontrollable": "^7.0.2", + "warning": "^3.0.0" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "node_modules/react-bootstrap-toggle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/react-bootstrap-toggle/-/react-bootstrap-toggle-2.3.2.tgz", + "integrity": "sha512-OPoPt+z0uu0Y96RXJ57Hq71VJna+RVtCviRsAMu/5OFS7bO80qVhoASuxK/kNsclSrSpHAaBfygHjpf6sd6CLQ==", + "dependencies": { + "classnames": "^2.2.5", + "prop-types": "^15.5.10", + "resize-observer-polyfill": "^1.5.0" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "dependencies": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + }, + "peerDependencies": { + "react": "*" + } + }, + "node_modules/react-datepicker": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.2.1.tgz", + "integrity": "sha512-0gcvHMnX8rS1fV90PjjsB7MQdsWNU77JeVHf6bbwK9HnFxgwjVflTx40ebKmHV+leqe+f+FgUP9Nvqbe5RGyfA==", + "dependencies": { + "@popperjs/core": "^2.9.2", + "classnames": "^2.2.6", + "date-fns": "^2.0.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.10.0", + "react-popper": "^2.2.5" + }, + "peerDependencies": { + "react": "^16.9.0 || ^17", + "react-dom": "^16.9.0 || ^17" + } + }, "node_modules/react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -11204,6 +12632,11 @@ "react": "17.0.2" } }, + "node_modules/react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, "node_modules/react-hot-loader": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.0.tgz", @@ -11240,15 +12673,172 @@ "node": ">= 8" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" - }, - "node_modules/react-lifecycles-compat": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", - "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + "node_modules/react-input-autosize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", + "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "dependencies": { + "prop-types": "^15.5.8" + }, + "peerDependencies": { + "react": "^16.3.0 || ^17.0.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, + "node_modules/react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" + }, + "node_modules/react-onclickoutside": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz", + "integrity": "sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==", + "funding": { + "type": "individual", + "url": "https://github.com/Pomax/react-onclickoutside/blob/master/FUNDING.md" + }, + "peerDependencies": { + "react": "^15.5.x || ^16.x || ^17.x", + "react-dom": "^15.5.x || ^16.x || ^17.x" + } + }, + "node_modules/react-overlays": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.9.3.tgz", + "integrity": "sha512-u2T7nOLnK+Hrntho4p0Nxh+BsJl0bl4Xuwj/Y0a56xywLMetgAfyjnDVrudLXsNcKGaspoC+t3C1V80W9QQTdQ==", + "dependencies": { + "classnames": "^2.2.5", + "dom-helpers": "^3.2.1", + "prop-types": "^15.5.10", + "prop-types-extra": "^1.0.1", + "react-transition-group": "^2.2.1", + "warning": "^3.0.0" + }, + "peerDependencies": { + "react": ">=16.3.0", + "react-dom": ">=16.3.0" + } + }, + "node_modules/react-popper": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", + "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==", + "dependencies": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "peerDependencies": { + "@popperjs/core": "^2.0.0", + "react": "^16.8.0 || ^17" + } + }, + "node_modules/react-popper/node_modules/warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, + "node_modules/react-prop-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz", + "integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=", + "dependencies": { + "warning": "^3.0.0" + }, + "peerDependencies": { + "react": ">=0.14.0" + } + }, + "node_modules/react-redux": { + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.8.tgz", + "integrity": "sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==", + "dependencies": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "peerDependencies": { + "react": "^16.8.3 || ^17 || ^18" + }, + "peerDependenciesMeta": { + "react-dom": { + "optional": true + }, + "react-native": { + "optional": true + } + } + }, + "node_modules/react-redux/node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + }, + "node_modules/react-select": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-4.3.1.tgz", + "integrity": "sha512-HBBd0dYwkF5aZk1zP81Wx5UsLIIT2lSvAY2JiJo199LjoLHoivjn9//KsmvQMEFGNhe58xyuOITjfxKCcGc62Q==", + "dependencies": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.1.1", + "memoize-one": "^5.0.0", + "prop-types": "^15.6.0", + "react-input-autosize": "^3.0.0", + "react-transition-group": "^4.3.0" + }, + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0", + "react-dom": "^16.8.0 || ^17.0.0" + } + }, + "node_modules/react-select/node_modules/dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "dependencies": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "node_modules/react-select/node_modules/react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "dependencies": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + }, + "peerDependencies": { + "react": ">=16.6.0", + "react-dom": ">=16.6.0" + } + }, + "node_modules/react-sticky": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/react-sticky/-/react-sticky-6.0.3.tgz", + "integrity": "sha512-LNH4UJlRatOqo29/VHxDZOf6fwbgfgcHO4mkEFvrie5FuaZCSTGtug5R8NGqJ0kSnX8gHw8qZN37FcvnFBJpTQ==", + "dependencies": { + "prop-types": "^15.5.8", + "raf": "^3.3.0" + }, + "peerDependencies": { + "react": ">=15", + "react-dom": ">=15" + } }, "node_modules/react-tooltip": { "version": "4.2.21", @@ -11274,6 +12864,76 @@ "uuid": "dist/bin/uuid" } }, + "node_modules/react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "dependencies": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0", + "react-dom": ">=15.0.0" + } + }, + "node_modules/react-treebeard": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/react-treebeard/-/react-treebeard-3.2.4.tgz", + "integrity": "sha512-TsvdUq2kbLavRXa8k4mmqfPse8HmSA9G9s1SZUtIpiYSccSwa0Tm6miMgx7DZ5gpKofQ+j/3Ua0rjsahM3/FQg==", + "dependencies": { + "@emotion/core": "^10.0.10", + "@emotion/styled": "^10.0.10", + "deep-equal": "^1.0.1", + "shallowequal": "^1.1.0", + "velocity-react": "^1.4.1" + }, + "peerDependencies": { + "@babel/runtime": ">=7.0.0", + "@emotion/styled": "^10.0.10", + "prop-types": ">=15.7.2", + "react": ">=16.7.0", + "react-dom": ">=16.7.0" + } + }, + "node_modules/react-treebeard/node_modules/velocity-react": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/velocity-react/-/velocity-react-1.4.3.tgz", + "integrity": "sha512-zvefGm85A88S3KdF9/dz5vqyFLAiwKYlXGYkHH2EbXl+CZUD1OT0a0aS1tkX/WXWTa/FUYqjBaAzAEFYuSobBQ==", + "dependencies": { + "lodash": "^4.17.5", + "prop-types": "^15.5.8", + "react-transition-group": "^2.0.0", + "velocity-animate": "^1.4.0" + }, + "peerDependencies": { + "react": "^15.3.0 || ^16.0.0", + "react-dom": "^15.3.0 || ^16.0.0" + } + }, + "node_modules/reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "dependencies": { + "lodash": "^4.0.1" + } + }, + "node_modules/reactn": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/reactn/-/reactn-2.2.7.tgz", + "integrity": "sha512-cqnt23kWN/ABqEZhW3OlpqI1DgTaaNDeHpSHtyd81qk0H1jd32zPTzJ69Hpzti2WakwNYveGFPIgI6i7E7nXOA==", + "dependencies": { + "use-force-update": "^1.0.5" + }, + "peerDependencies": { + "@types/react": "^16.8.0", + "react": "*", + "react-dom": "*" + } + }, "node_modules/read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -11393,6 +13053,30 @@ "node": ">=8" } }, + "node_modules/reduce-reducers": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/reduce-reducers/-/reduce-reducers-0.1.5.tgz", + "integrity": "sha512-uoVmQnZQ+BtKKDKpBdbBri5SLNyIK9ULZGOA504++VbHcwouWE+fJDIo8AuESPF9/EYSkI0v05LDEQK6stCbTA==" + }, + "node_modules/redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "dependencies": { + "@babel/runtime": "^7.9.2" + } + }, + "node_modules/redux-actions": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/redux-actions/-/redux-actions-2.3.2.tgz", + "integrity": "sha512-PPclrJFIbDzD48oNj46biisg34NTtb1VxP9MTTAxsgIFuV4mEe5UXLRNBwyqrlXrMQHUbmpnjJupxocS4mxpvA==", + "dependencies": { + "invariant": "^2.2.1", + "lodash": "^4.13.1", + "lodash-es": "^4.17.4", + "reduce-reducers": "^0.1.0" + } + }, "node_modules/reflect.ownkeys": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", @@ -11420,8 +13104,7 @@ "node_modules/regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "node_modules/regenerator-transform": { "version": "0.14.5", @@ -11442,7 +13125,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", - "dev": true, "dependencies": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -11552,6 +13234,16 @@ "node": ">= 6" } }, + "node_modules/request/node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -11570,23 +13262,21 @@ "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "node_modules/requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "node_modules/resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "node_modules/resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, "dependencies": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" @@ -11620,11 +13310,15 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } }, + "node_modules/resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" + }, "node_modules/resolve-url": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", @@ -11833,8 +13527,7 @@ "node_modules/safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "node_modules/safer-buffer": { "version": "2.1.2", @@ -11843,31 +13536,34 @@ "dev": true }, "node_modules/sass-graph": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", - "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.0.tgz", + "integrity": "sha512-WSO/MfXqKH7/TS8RdkCX3lVkPFQzCgbqdGsmSKq6tlPU+GpGEsa/5aW18JqItnqh+lPtcjifqdZ/VmiILkKckQ==", "dev": true, "dependencies": { "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^13.3.2" + "lodash": "^4.17.11", + "scss-tokenizer": "^0.3.0", + "yargs": "^17.2.1" }, "bin": { "sassgraph": "bin/sassgraph" + }, + "engines": { + "node": ">=12" } }, "node_modules/sass-loader": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-11.1.1.tgz", - "integrity": "sha512-fOCp/zLmj1V1WHDZbUbPgrZhA7HKXHEqkslzB+05U5K9SbSbcmH91C7QLW31AsXikxUMaxXRhhcqWZAxUMLDyA==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", "dev": true, "dependencies": { "klona": "^2.0.4", "neo-async": "^2.6.2" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 12.13.0" }, "funding": { "type": "opencollective", @@ -11875,8 +13571,9 @@ }, "peerDependencies": { "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0", "sass": "^1.3.0", + "sass-embedded": "*", "webpack": "^5.0.0" }, "peerDependenciesMeta": { @@ -11888,6 +13585,9 @@ }, "sass": { "optional": true + }, + "sass-embedded": { + "optional": true } } }, @@ -11931,25 +13631,22 @@ } }, "node_modules/scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.3.0.tgz", + "integrity": "sha512-14Zl9GcbBvOT9057ZKjpz5yPOyUWG2ojd9D5io28wHRYsOrs7U95Q+KNL87+32p8rc+LvDpbu/i9ZYjM9Q+FsQ==", "dev": true, "dependencies": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" + "js-base64": "^2.4.3", + "source-map": "^0.7.1" } }, "node_modules/scss-tokenizer/node_modules/source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", "dev": true, - "dependencies": { - "amdefine": ">=0.0.4" - }, "engines": { - "node": ">=0.8.0" + "node": ">= 8" } }, "node_modules/select-hose": { @@ -12170,9 +13867,9 @@ } }, "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "node_modules/sisteransi": { @@ -12190,6 +13887,16 @@ "node": ">=8" } }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, "node_modules/sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -12201,13 +13908,32 @@ "websocket-driver": "^0.7.4" } }, - "node_modules/sockjs/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", "dev": true, - "bin": { - "uuid": "dist/bin/uuid" + "dependencies": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" } }, "node_modules/source-list-map": { @@ -12220,7 +13946,6 @@ "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -12341,9 +14066,9 @@ "dev": true }, "node_modules/sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "dependencies": { "asn1": "~0.2.3", @@ -12365,6 +14090,18 @@ "node": ">=0.10.0" } }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/stack-utils": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", @@ -12428,6 +14165,14 @@ "safe-buffer": "~5.1.0" } }, + "node_modules/strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -12492,17 +14237,38 @@ } }, "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" } }, "node_modules/string.prototype.trim": { @@ -12642,11 +14408,15 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "dependencies": { "has-flag": "^3.0.0" }, @@ -12907,6 +14677,24 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "node_modules/tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "node_modules/tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "node_modules/tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==", + "engines": { + "node": "*" + } + }, "node_modules/tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -12917,7 +14705,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, "engines": { "node": ">=4" } @@ -13045,15 +14832,6 @@ "node": ">=10" } }, - "node_modules/ts-jest/node_modules/yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", - "dev": true, - "engines": { - "node": ">=10" - } - }, "node_modules/tslib": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", @@ -13167,6 +14945,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "dependencies": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + }, + "peerDependencies": { + "react": ">=15.0.0" + } + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -13207,6 +14999,24 @@ "node": ">=4" } }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, "node_modules/universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -13241,6 +15051,28 @@ "deprecated": "Please see https://github.com/lydell/urix#deprecated", "dev": true }, + "node_modules/use-force-update": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/use-force-update/-/use-force-update-1.0.7.tgz", + "integrity": "sha512-k5dppYhO+I5X/cd7ildbrzeMZJkWwdAh5adaIk0qKN2euh7J0h2GBGBcB4QZ385eyHHnp7LIygvebdRx3XKdwA==" + }, + "node_modules/use-immer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.6.0.tgz", + "integrity": "sha512-dFGRfvWCqPDTOt/S431ETYTg6+uxbpb7A1pptufwXVzGJY3RlXr38+3wyLNpc6SbbmAKjWl6+EP6uW74fkEsXQ==", + "peerDependencies": { + "immer": ">=2.0.0", + "react": "^16.8.0 || ^17.0.1" + } + }, + "node_modules/use-memo-one": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", + "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0" + } + }, "node_modules/util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -13263,13 +15095,11 @@ } }, "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", - "dev": true, + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "bin": { - "uuid": "bin/uuid" + "uuid": "dist/bin/uuid" } }, "node_modules/v8-to-istanbul": { @@ -13305,6 +15135,11 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -13314,6 +15149,11 @@ "node": ">= 0.8" } }, + "node_modules/velocity-animate": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/velocity-animate/-/velocity-animate-1.5.2.tgz", + "integrity": "sha512-m6EXlCAMetKztO1ppBhGU1/1MR3IiEevO6ESq6rcrSQ3Q77xYSW13jkfXW88o4xMrkXJhy/U7j4wFR/twMB0Eg==" + }, "node_modules/verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -13328,6 +15168,19 @@ "extsprintf": "^1.2.0" } }, + "node_modules/vis-util": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-4.3.4.tgz", + "integrity": "sha512-hJIZNrwf4ML7FYjs+m+zjJfaNvhjk3/1hbMdQZVnwwpOFJS/8dMG8rdbOHXcKoIEM6U5VOh3HNpaDXxGkOZGpw==", + "peer": true, + "engines": { + "node": ">=8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/visjs" + } + }, "node_modules/w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -13358,6 +15211,14 @@ "makeerror": "1.0.12" } }, + "node_modules/warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", @@ -13885,19 +15746,13 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "node_modules/wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "dependencies": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "node_modules/wildcard": { @@ -13916,61 +15771,74 @@ } }, "node_modules/wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "dependencies": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/wrap-ansi/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-name": "~1.1.4" }, "engines": { - "node": ">=6" + "node": ">=7.0.0" } }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "dependencies": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, "node_modules/wrappy": { @@ -14025,10 +15893,13 @@ "dev": true }, "node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } }, "node_modules/yallist": { "version": "4.0.0", @@ -14040,127 +15911,44 @@ "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, "engines": { "node": ">= 6" } }, "node_modules/yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", "dev": true, "dependencies": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" - } - }, - "node_modules/yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "node_modules/yargs/node_modules/ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "dependencies": { - "locate-path": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/yargs/node_modules/locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "dependencies": { - "p-limit": "^2.0.0" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/yargs/node_modules/path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true, - "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/yargs/node_modules/string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, - "dependencies": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - }, "engines": { - "node": ">=6" + "node": ">=10" } }, - "node_modules/yargs/node_modules/strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true, - "dependencies": { - "ansi-regex": "^4.1.0" - }, "engines": { - "node": ">=6" + "node": ">=12" } } }, @@ -14169,7 +15957,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz", "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==", - "dev": true, "requires": { "@babel/highlight": "^7.14.5" } @@ -14177,14 +15964,12 @@ "@babel/compat-data": { "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.15.0.tgz", - "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==", - "dev": true + "integrity": "sha512-0NqAC1IJE0S0+lL1SWFMxMkz1pKCNCjI4tr2Zx4LJSXxCLAdr6KyArnY+sno5m3yH9g737ygOyPABDsnXkpxiA==" }, "@babel/core": { "version": "7.14.3", "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.14.3.tgz", "integrity": "sha512-jB5AmTKOCSJIZ72sd78ECEhuPiDMKlQdDI/4QRI6lzYATx5SSogS1oQA2AoPecRCknm30gHi2l+QVvNUu3wZAg==", - "dev": true, "requires": { "@babel/code-frame": "^7.12.13", "@babel/generator": "^7.14.3", @@ -14206,8 +15991,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -14215,7 +15999,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.15.0.tgz", "integrity": "sha512-eKl4XdMrbpYvuB505KTta4AV9g+wWzmVBW69tX0H2NwKVKd2YJbKgyK6M8j/rgLbmHOYJn6rUklV677nOyJrEQ==", - "dev": true, "requires": { "@babel/types": "^7.15.0", "jsesc": "^2.5.1", @@ -14245,7 +16028,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.15.0.tgz", "integrity": "sha512-h+/9t0ncd4jfZ8wsdAsoIxSa61qhBYlycXiHWqJaQBCXAhDCMbPRSMTGnZIkkmt1u4ag+UQmuqcILwqKzZ4N2A==", - "dev": true, "requires": { "@babel/compat-data": "^7.15.0", "@babel/helper-validator-option": "^7.14.5", @@ -14256,8 +16038,7 @@ "semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==" } } }, @@ -14322,7 +16103,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.14.5.tgz", "integrity": "sha512-Gjna0AsXWfFvrAuX+VKcN/aNNWonizBj39yGwUzVDVTlMYJMK2Wp6xdpy72mfArFq5uK+NOuexfzZlzI1z9+AQ==", - "dev": true, "requires": { "@babel/helper-get-function-arity": "^7.14.5", "@babel/template": "^7.14.5", @@ -14333,7 +16113,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.14.5.tgz", "integrity": "sha512-I1Db4Shst5lewOM4V+ZKJzQ0JGGaZ6VY1jYvMghRjqs6DWgxLCIyFt30GlnKkfUeFLpJt2vzbMVEXVSXlIFYUg==", - "dev": true, "requires": { "@babel/types": "^7.14.5" } @@ -14342,7 +16121,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.14.5.tgz", "integrity": "sha512-R1PXiz31Uc0Vxy4OEOm07x0oSjKAdPPCh3tPivn/Eo8cvz6gveAeuyUUPB21Hoiif0uoPQSSdhIPS3352nvdyQ==", - "dev": true, "requires": { "@babel/types": "^7.14.5" } @@ -14351,7 +16129,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.15.0.tgz", "integrity": "sha512-Jq8H8U2kYiafuj2xMTPQwkTBnEEdGKpT35lJEQsRRjnG0LW3neucsaMWLgKcwu3OHKNeYugfw+Z20BXBSEs2Lg==", - "dev": true, "requires": { "@babel/types": "^7.15.0" } @@ -14360,7 +16137,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.14.5.tgz", "integrity": "sha512-SwrNHu5QWS84XlHwGYPDtCxcA0hrSlL2yhWYLgeOc0w7ccOl2qv4s/nARI0aYZW+bSwAL5CukeXA47B/1NKcnQ==", - "dev": true, "requires": { "@babel/types": "^7.14.5" } @@ -14369,7 +16145,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.15.0.tgz", "integrity": "sha512-RkGiW5Rer7fpXv9m1B3iHIFDZdItnO2/BLfWVW/9q7+KqQSDY5kUfQEbzdXM1MVhJGcugKV7kRrNVzNxmk7NBg==", - "dev": true, "requires": { "@babel/helper-module-imports": "^7.14.5", "@babel/helper-replace-supers": "^7.15.0", @@ -14385,7 +16160,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.14.5.tgz", "integrity": "sha512-IqiLIrODUOdnPU9/F8ib1Fx2ohlgDhxnIDU7OEVi+kAbEZcyiF7BLU8W6PfvPi9LzztjS7kcbzbmL7oG8kD6VA==", - "dev": true, "requires": { "@babel/types": "^7.14.5" } @@ -14393,8 +16167,7 @@ "@babel/helper-plugin-utils": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.14.5.tgz", - "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==", - "dev": true + "integrity": "sha512-/37qQCE3K0vvZKwoK4XU/irIJQdIfCJuhU5eKnNxpFDsOkgFaUAwbv+RYw6eYgsC0E4hS7r5KqGULUogqui0fQ==" }, "@babel/helper-remap-async-to-generator": { "version": "7.14.5", @@ -14411,7 +16184,6 @@ "version": "7.15.0", "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.15.0.tgz", "integrity": "sha512-6O+eWrhx+HEra/uJnifCwhwMd6Bp5+ZfZeJwbqUTuqkhIT6YcRhiZCOOFChRypOIe0cV46kFrRBlm+t5vHCEaA==", - "dev": true, "requires": { "@babel/helper-member-expression-to-functions": "^7.15.0", "@babel/helper-optimise-call-expression": "^7.14.5", @@ -14423,7 +16195,6 @@ "version": "7.14.8", "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.14.8.tgz", "integrity": "sha512-TrFN4RHh9gnWEU+s7JloIho2T76GPwRHhdzOWLqTrMnlas8T9O7ec+oEDNsRXndOmru9ymH9DFrEOxpzPoSbdg==", - "dev": true, "requires": { "@babel/types": "^7.14.8" } @@ -14441,7 +16212,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.14.5.tgz", "integrity": "sha512-hprxVPu6e5Kdp2puZUmvOGjaLv9TCe58E/Fl6hRq4YiVQxIcNvuq6uTM2r1mT/oPskuS9CgR+I94sqAYv0NGKA==", - "dev": true, "requires": { "@babel/types": "^7.14.5" } @@ -14449,14 +16219,12 @@ "@babel/helper-validator-identifier": { "version": "7.14.9", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz", - "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==", - "dev": true + "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==" }, "@babel/helper-validator-option": { "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.14.5.tgz", - "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==", - "dev": true + "integrity": "sha512-OX8D5eeX4XwcroVW45NMvoYaIuFI+GQpA2a8Gi+X/U/cDUIRsV37qQfF905F0htTRCREQIB4KqPeaveRJUl3Ow==" }, "@babel/helper-wrap-function": { "version": "7.14.5", @@ -14474,7 +16242,6 @@ "version": "7.15.3", "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.15.3.tgz", "integrity": "sha512-HwJiz52XaS96lX+28Tnbu31VeFSQJGOeKHJeaEPQlTl7PnlhFElWPj8tUXtqFIzeN86XxXoBr+WFAyK2PPVz6g==", - "dev": true, "requires": { "@babel/template": "^7.14.5", "@babel/traverse": "^7.15.0", @@ -14485,7 +16252,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz", "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==", - "dev": true, "requires": { "@babel/helper-validator-identifier": "^7.14.5", "chalk": "^2.0.0", @@ -14495,8 +16261,7 @@ "@babel/parser": { "version": "7.15.3", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.15.3.tgz", - "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==", - "dev": true + "integrity": "sha512-O0L6v/HvqbdJawj0iBEfVQMc3/6WP+AeOsovsIgBFyJaG+W2w7eqvZB7puddATmWuARlm1SX7DwxJ/JJUnDpEA==" }, "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { "version": "7.14.5", @@ -14743,7 +16508,6 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.14.5.tgz", "integrity": "sha512-ohuFIsOMXJnbOMRfX7/w7LocdR6R7whhuRD4ax8IipLcLPlZGJKkBxgHp++U4N/vKyU16/YDQr2f5seajD3jIw==", - "dev": true, "requires": { "@babel/helper-plugin-utils": "^7.14.5" } @@ -15331,11 +17095,19 @@ } }, "@babel/runtime": { - "version": "7.15.3", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.3.tgz", - "integrity": "sha512-OvwMLqNXkCXSz1kSm58sEsNuhqOx/fKpnUnKnFB5v8uDda5bLNEHNgKPvhDN6IU0LDcnHQ90LlJ0Q6jnyBSIBA==", - "dev": true, + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, + "@babel/runtime-corejs2": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime-corejs2/-/runtime-corejs2-7.17.9.tgz", + "integrity": "sha512-+QThIsnjVY12uURTvmnW33risFZ7ulq6OWw0VJL08UwiYiWVp9PM63s+W1L2ppajYyKAYKb7afcGYSHzA0k04Q==", "requires": { + "core-js": "^2.6.5", "regenerator-runtime": "^0.13.4" } }, @@ -15343,52 +17115,363 @@ "version": "7.14.5", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.14.5.tgz", "integrity": "sha512-6Z3Po85sfxRGachLULUhOmvAaOo7xCvqGQtxINai2mEGPFm6pQ4z5QInFnUrRpfoSV60BnjyF5F3c+15fxFV1g==", - "dev": true, "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/parser": "^7.14.5", - "@babel/types": "^7.14.5" + "@babel/code-frame": "^7.14.5", + "@babel/parser": "^7.14.5", + "@babel/types": "^7.14.5" + } + }, + "@babel/traverse": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", + "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", + "requires": { + "@babel/code-frame": "^7.14.5", + "@babel/generator": "^7.15.0", + "@babel/helper-function-name": "^7.14.5", + "@babel/helper-hoist-variables": "^7.14.5", + "@babel/helper-split-export-declaration": "^7.14.5", + "@babel/parser": "^7.15.0", + "@babel/types": "^7.15.0", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.15.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", + "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", + "requires": { + "@babel/helper-validator-identifier": "^7.14.9", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@discoveryjs/json-ext": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", + "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", + "dev": true + }, + "@emotion/babel-plugin": { + "version": "11.9.2", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.9.2.tgz", + "integrity": "sha512-Pr/7HGH6H6yKgnVFNEj2MVlreu3ADqftqjqwUvDy/OJzKFgxKeTQ+eeUf20FOTuHVkDON2iNa25rAXVYtWJCjw==", + "requires": { + "@babel/helper-module-imports": "^7.12.13", + "@babel/plugin-syntax-jsx": "^7.12.13", + "@babel/runtime": "^7.13.10", + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.5", + "@emotion/serialize": "^1.0.2", + "babel-plugin-macros": "^2.6.1", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.0.13" + }, + "dependencies": { + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==" + } + } + }, + "@emotion/cache": { + "version": "11.7.1", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.7.1.tgz", + "integrity": "sha512-r65Zy4Iljb8oyjtLeCuBH8Qjiy107dOYC6SJq7g7GV5UCQWMObY4SJDPGFjiiVpPrOJ2hmJOoBiYTC7hwx9E2A==", + "requires": { + "@emotion/memoize": "^0.7.4", + "@emotion/sheet": "^1.1.0", + "@emotion/utils": "^1.0.0", + "@emotion/weak-memoize": "^0.2.5", + "stylis": "4.0.13" + } + }, + "@emotion/core": { + "version": "10.3.1", + "resolved": "https://registry.npmjs.org/@emotion/core/-/core-10.3.1.tgz", + "integrity": "sha512-447aUEjPIm0MnE6QYIaFz9VQOHSXf4Iu6EWOIqq11EAPqinkSZmfymPTmlOE3QjLv846lH4JVZBUOtwGbuQoww==", + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/cache": "^10.0.27", + "@emotion/css": "^10.0.27", + "@emotion/serialize": "^0.11.15", + "@emotion/sheet": "0.9.4", + "@emotion/utils": "0.11.3" + }, + "dependencies": { + "@emotion/cache": { + "version": "10.0.29", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-10.0.29.tgz", + "integrity": "sha512-fU2VtSVlHiF27empSbxi1O2JFdNWZO+2NFHfwO0pxgTep6Xa3uGb+3pVKfLww2l/IBGLNEZl5Xf/++A4wAYDYQ==", + "requires": { + "@emotion/sheet": "0.9.4", + "@emotion/stylis": "0.8.5", + "@emotion/utils": "0.11.3", + "@emotion/weak-memoize": "0.2.5" + } + }, + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "requires": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "@emotion/sheet": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-0.9.4.tgz", + "integrity": "sha512-zM9PFmgVSqBw4zL101Q0HrBVTGmpAxFZH/pYx/cjJT5advXguvcgjHFTCaIO3enL/xr89vK2bh0Mfyj9aa0ANA==" + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + } + } + }, + "@emotion/css": { + "version": "10.0.27", + "resolved": "https://registry.npmjs.org/@emotion/css/-/css-10.0.27.tgz", + "integrity": "sha512-6wZjsvYeBhyZQYNrGoR5yPMYbMBNEnanDrqmsqS1mzDm1cOTu12shvl2j4QHNS36UaTE0USIJawCH9C8oW34Zw==", + "requires": { + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3", + "babel-plugin-emotion": "^10.0.27" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "requires": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + } + } + }, + "@emotion/hash": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.8.0.tgz", + "integrity": "sha512-kBJtf7PH6aWwZ6fka3zQ0p6SBYzx4fl1LoZXE2RrnYST9Xljm7WfKJrU4g/Xr3Beg72MLrp1AWNUmuYJTL7Cow==" + }, + "@emotion/is-prop-valid": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@emotion/is-prop-valid/-/is-prop-valid-0.8.8.tgz", + "integrity": "sha512-u5WtneEAr5IDG2Wv65yhunPSMLIpuKsbuOktRojfrEiEvRyC85LgPMZI63cr7NUqT8ZIGdSVg8ZKGxIug4lXcA==", + "requires": { + "@emotion/memoize": "0.7.4" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + } + } + }, + "@emotion/memoize": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.5.tgz", + "integrity": "sha512-igX9a37DR2ZPGYtV6suZ6whr8pTFtyHL3K/oLUotxpSVO2ASaprmAe2Dkq7tBo7CRY7MMDrAa9nuQP9/YG8FxQ==" + }, + "@emotion/react": { + "version": "11.9.0", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.9.0.tgz", + "integrity": "sha512-lBVSF5d0ceKtfKCDQJveNAtkC7ayxpVlgOohLgXqRwqWr9bOf4TZAFFyIcNngnV6xK6X4x2ZeXq7vliHkoVkxQ==", + "requires": { + "@babel/runtime": "^7.13.10", + "@emotion/babel-plugin": "^11.7.1", + "@emotion/cache": "^11.7.1", + "@emotion/serialize": "^1.0.3", + "@emotion/utils": "^1.1.0", + "@emotion/weak-memoize": "^0.2.5", + "hoist-non-react-statics": "^3.3.1" + } + }, + "@emotion/serialize": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.0.3.tgz", + "integrity": "sha512-2mSSvgLfyV3q+iVh3YWgNlUc2a9ZlDU7DjuP5MjK3AXRR0dYigCrP99aeFtaB2L/hjfEZdSThn5dsZ0ufqbvsA==", + "requires": { + "@emotion/hash": "^0.8.0", + "@emotion/memoize": "^0.7.4", + "@emotion/unitless": "^0.7.5", + "@emotion/utils": "^1.0.0", + "csstype": "^3.0.2" + } + }, + "@emotion/sheet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.1.0.tgz", + "integrity": "sha512-u0AX4aSo25sMAygCuQTzS+HsImZFuS8llY8O7b9MDRzbJM0kVJlAz6KNDqcG7pOuQZJmj/8X/rAW+66kMnMW+g==" + }, + "@emotion/styled": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled/-/styled-10.3.0.tgz", + "integrity": "sha512-GgcUpXBBEU5ido+/p/mCT2/Xx+Oqmp9JzQRuC+a4lYM4i4LBBn/dWvc0rQ19N9ObA8/T4NWMrPNe79kMBDJqoQ==", + "requires": { + "@emotion/styled-base": "^10.3.0", + "babel-plugin-emotion": "^10.0.27" + } + }, + "@emotion/styled-base": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@emotion/styled-base/-/styled-base-10.3.0.tgz", + "integrity": "sha512-PBRqsVKR7QRNkmfH78hTSSwHWcwDpecH9W6heujWAcyp2wdz/64PP73s7fWS1dIPm8/Exc8JAzYS8dEWXjv60w==", + "requires": { + "@babel/runtime": "^7.5.5", + "@emotion/is-prop-valid": "0.8.8", + "@emotion/serialize": "^0.11.15", + "@emotion/utils": "0.11.3" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "requires": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + } + } + }, + "@emotion/stylis": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/@emotion/stylis/-/stylis-0.8.5.tgz", + "integrity": "sha512-h6KtPihKFn3T9fuIrwvXXUOwlx3rfUvfZIcP5a6rh8Y7zjE3O06hT5Ss4S/YI1AYhuZ1kjaE/5EaOOI2NqSylQ==" + }, + "@emotion/unitless": { + "version": "0.7.5", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.7.5.tgz", + "integrity": "sha512-OWORNpfjMsSSUBVrRBVGECkhWcULOAJz9ZW8uK9qgxD+87M7jHRcvh/A96XXNhXTLmKcoYSQtBEX7lHMO7YRwg==" + }, + "@emotion/utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.1.0.tgz", + "integrity": "sha512-iRLa/Y4Rs5H/f2nimczYmS5kFJEbpiVvgN3XVfZ022IYhuNA1IRSHEizcof88LtCTXtl9S2Cxt32KgaXEu72JQ==" + }, + "@emotion/weak-memoize": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.2.5.tgz", + "integrity": "sha512-6U71C2Wp7r5XtFtQzYrW5iKFT67OixrSxjI4MptCHzdSVlgabczzqLe0ZSgnub/5Kp4hSbpDB1tMytZY9pwxxA==" + }, + "@fortawesome/fontawesome-common-types": { + "version": "0.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-0.2.36.tgz", + "integrity": "sha512-a/7BiSgobHAgBWeN7N0w+lAhInrGxksn13uK7231n2m8EDPE3BMCl9NZLTGrj9ZXfCmC6LM0QLqXidIizVQ6yg==" + }, + "@fortawesome/fontawesome-free": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-free/-/fontawesome-free-5.15.4.tgz", + "integrity": "sha512-eYm8vijH/hpzr/6/1CJ/V/Eb1xQFW2nnUKArb3z+yUWv7HTwj6M7SP957oMjfZjAHU6qpoNc2wQvIxBLWYa/Jg==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "1.2.36", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-1.2.36.tgz", + "integrity": "sha512-YUcsLQKYb6DmaJjIHdDWpBIGCcyE/W+p/LMGvjQem55Mm2XWVAP5kWTMKWLv9lwpCVjpLxPyOMOyUocP1GxrtA==", + "requires": { + "@fortawesome/fontawesome-common-types": "^0.2.36" } }, - "@babel/traverse": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.15.0.tgz", - "integrity": "sha512-392d8BN0C9eVxVWd8H6x9WfipgVH5IaIoLp23334Sc1vbKKWINnvwRpb4us0xtPaCumlwbTtIYNA0Dv/32sVFw==", - "dev": true, + "@fortawesome/free-regular-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-5.15.4.tgz", + "integrity": "sha512-9VNNnU3CXHy9XednJ3wzQp6SwNwT3XaM26oS4Rp391GsxVYA+0oDR2J194YCIWf7jNRCYKjUCOduxdceLrx+xw==", "requires": { - "@babel/code-frame": "^7.14.5", - "@babel/generator": "^7.15.0", - "@babel/helper-function-name": "^7.14.5", - "@babel/helper-hoist-variables": "^7.14.5", - "@babel/helper-split-export-declaration": "^7.14.5", - "@babel/parser": "^7.15.0", - "@babel/types": "^7.15.0", - "debug": "^4.1.0", - "globals": "^11.1.0" + "@fortawesome/fontawesome-common-types": "^0.2.36" } }, - "@babel/types": { - "version": "7.15.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.15.0.tgz", - "integrity": "sha512-OBvfqnllOIdX4ojTHpwZbpvz4j3EWyjkZEdmjH0/cgsd6QOdSgU8rLSk6ard/pcW7rlmjdVSX/AWOaORR1uNOQ==", - "dev": true, + "@fortawesome/free-solid-svg-icons": { + "version": "5.15.4", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-5.15.4.tgz", + "integrity": "sha512-JLmQfz6tdtwxoihXLg6lT78BorrFyCf59SAwBM6qV/0zXyVeDygJVb3fk+j5Qat+Yvcxp1buLTY5iDh1ZSAQ8w==", "requires": { - "@babel/helper-validator-identifier": "^7.14.9", - "to-fast-properties": "^2.0.0" + "@fortawesome/fontawesome-common-types": "^0.2.36" } }, - "@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true + "@fortawesome/react-fontawesome": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.1.15.tgz", + "integrity": "sha512-/HFHdcoLESxxMkqZAcZ6RXDJ69pVApwdwRos/B2kiMWxDSAX2dFK8Er2/+rG+RsrzWB/dsAyjefLmemgmfE18g==", + "requires": { + "prop-types": "^15.7.2" + } }, - "@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", "dev": true }, + "@icons/material": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz", + "integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==", + "requires": {} + }, "@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -15898,14 +17981,14 @@ } }, "@labkey/api": { - "version": "1.8.0", - "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.8.0.tgz", - "integrity": "sha1-DiGjCOphC25lFsGwX3BC7kGmhlc=" + "version": "1.10.0", + "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/api/-/@labkey/api-1.10.0.tgz", + "integrity": "sha1-+n1L8fL1dpJRP0sc0qyjxN2F6GA=" }, "@labkey/build": { - "version": "5.0.0", - "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/build/-/@labkey/build-5.0.0.tgz", - "integrity": "sha1-b1nqEvp+G6My9Q0zBWzx4/dLAJc=", + "version": "5.0.1", + "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/build/-/@labkey/build-5.0.1.tgz", + "integrity": "sha1-6eEqx45lpOjriEge9CRZXSSH1Fs=", "dev": true, "requires": { "@babel/core": "7.14.3", @@ -15924,11 +18007,11 @@ "fork-ts-checker-webpack-plugin": "6.2.10", "html-webpack-plugin": "5.3.1", "mini-css-extract-plugin": "1.6.0", - "node-sass": "6.0.1", + "node-sass": "7.0.1", "react-hot-loader": "4.12.21", "resolve-url-loader": "3.1.2", "rimraf": "3.0.2", - "sass-loader": "11.1.1", + "sass-loader": "12.6.0", "style-loader": "2.0.0", "typescript": "4.3.2", "webpack": "5.65.0", @@ -16017,6 +18100,259 @@ } } }, + "@labkey/components": { + "version": "2.157.0", + "resolved": "https://artifactory.labkey.com:443/artifactory/api/npm/libs-client/@labkey/components/-/@labkey/components-2.157.0.tgz", + "integrity": "sha1-N5gCKlitMFruewPoYB/28/8cX8A=", + "requires": { + "@fortawesome/fontawesome-free": "5.15.4", + "@fortawesome/fontawesome-svg-core": "1.2.36", + "@fortawesome/free-regular-svg-icons": "5.15.4", + "@fortawesome/free-solid-svg-icons": "5.15.4", + "@fortawesome/react-fontawesome": "0.1.15", + "@labkey/api": "1.10.0", + "bootstrap": "3.4.1", + "classnames": "2.3.1", + "font-awesome": "4.7.0", + "formsy-react": "1.1.5", + "formsy-react-components": "1.1.0", + "history": "4.7.2", + "immer": "9.0.6", + "immutable": "3.8.2", + "jquery": "3.6.0", + "moment": "2.27.0", + "moment-jdateformatparser": "1.1.0", + "moment-timezone": "0.5.31", + "normalizr": "3.6.1", + "numeral": "2.0.6", + "react": "16.14.0", + "react-beautiful-dnd": "13.1.0", + "react-bootstrap": "0.33.1", + "react-bootstrap-toggle": "2.3.2", + "react-color": "2.19.3", + "react-datepicker": "4.2.1", + "react-dom": "16.14.0", + "react-redux": "5.1.0", + "react-router": "3.2.6", + "react-select": "4.3.1", + "react-sticky": "6.0.3", + "react-treebeard": "3.2.4", + "reactn": "2.2.7", + "redux-actions": "2.3.2", + "use-immer": "0.6.0", + "vis-network": "6.5.2" + }, + "dependencies": { + "formsy-react": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/formsy-react/-/formsy-react-1.1.5.tgz", + "integrity": "sha512-nNWe4Vbp6aDQ/zSxJ7gVQgD5+avFRVbydcjA2Om42flxpQFrKE54AAbuyEj3Jvv+2b9LVl+WLMAPalyvLjwNcQ==", + "requires": { + "form-data-to-object": "^0.2.0", + "prop-types": "^15.5.10" + } + }, + "formsy-react-components": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/formsy-react-components/-/formsy-react-components-1.1.0.tgz", + "integrity": "sha512-GUgnIqXbXNPf7auP4nwk5PF6477r5UhdQoO1aNCvQajLarUu/Jj8PaxTCHu56tNGSlewACqRV44m8MrYOMzdTQ==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.5.10" + } + }, + "react": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react/-/react-16.14.0.tgz", + "integrity": "sha512-0X2CImDkJGApiAlcf0ODKIneSwBPhqJawOa5wCtKbu7ZECrmS26NvtSILynQ66cgkT/RJ4LidJOc3bUESwmU8g==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2" + } + }, + "react-dom": { + "version": "16.14.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-16.14.0.tgz", + "integrity": "sha512-1gCeQXDLoIqMgqD3IO2Ah9bnf0w9kzhwN5q4FGnHZ67hBm9yePzB5JJAIQCc8x3pFnNlwFq4RidZggNAAkzWWw==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1", + "prop-types": "^15.6.2", + "scheduler": "^0.19.1" + } + }, + "react-redux": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-5.1.0.tgz", + "integrity": "sha512-CRMpEx8+ccpoVxQrQDkG1obExNYpj6dZ1Ni7lUNFB9wcxOhy02tIqpFo4IUXc0kYvCGMu6ABj9A4imEX2VGZJQ==", + "requires": { + "@babel/runtime": "^7.1.2", + "hoist-non-react-statics": "^3.0.0", + "invariant": "^2.2.4", + "loose-envify": "^1.1.0", + "prop-types": "^15.6.1", + "react-is": "^16.6.0", + "react-lifecycles-compat": "^3.0.0" + } + }, + "react-router": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-3.2.6.tgz", + "integrity": "sha512-nlxtQE8B22hb/JxdaslI1tfZacxFU8x8BJryXOnR2RxB4vc01zuHYAHAIgmBkdk1kzXaA25hZxK6KAH/+CXArw==", + "requires": { + "create-react-class": "^15.5.1", + "history": "^3.0.0", + "hoist-non-react-statics": "^3.3.2", + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "prop-types": "^15.7.2", + "react-is": "^16.13.0", + "warning": "^3.0.0" + }, + "dependencies": { + "history": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/history/-/history-3.3.0.tgz", + "integrity": "sha1-/O3M6PEpdTcVRdc1RhAzV5ptrpw=", + "requires": { + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "query-string": "^4.2.2", + "warning": "^3.0.0" + } + } + } + }, + "scheduler": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.19.1.tgz", + "integrity": "sha512-n/zwRWRYSUj0/3g/otKDRPMh6qv2SYMWNq85IEa8iZyAv8od9zDYpGSnpBEjNgcMNq6Scbu5KfIPxNF72R/2EA==", + "requires": { + "loose-envify": "^1.1.0", + "object-assign": "^4.1.1" + } + }, + "vis-data": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/vis-data/-/vis-data-6.6.1.tgz", + "integrity": "sha512-xmujDB2Dzf8T04rGFJ9OP4OA6zRVrz8R9hb0CVKryBrZRCljCga9JjSfgctA8S7wdZu7otDtUIwX4ZOgfV/57w==", + "peer": true, + "requires": {} + }, + "vis-network": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/vis-network/-/vis-network-6.5.2.tgz", + "integrity": "sha512-Dj5oEtZMUWuhq7D7dwdmxmtJgrK3kwfV4Ov/ePSrhPZgNdJlXzpeDZU/Eq0pKGyOAPLClemgVImc0bZpZ4Yafw==", + "requires": {} + } + } + }, + "@material-ui/core": { + "version": "4.12.4", + "resolved": "https://registry.npmjs.org/@material-ui/core/-/core-4.12.4.tgz", + "integrity": "sha512-tr7xekNlM9LjA6pagJmL8QCgZXaubWUwkJnoYcMKd4gw/t4XiyvnTkjdGrUVicyB2BsdaAv1tvow45bPM4sSwQ==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/styles": "^4.11.5", + "@material-ui/system": "^4.12.2", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "@types/react-transition-group": "^4.2.0", + "clsx": "^1.0.4", + "hoist-non-react-statics": "^3.3.2", + "popper.js": "1.16.1-lts", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0", + "react-transition-group": "^4.4.0" + }, + "dependencies": { + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + } + } + }, + "@material-ui/styles": { + "version": "4.11.5", + "resolved": "https://registry.npmjs.org/@material-ui/styles/-/styles-4.11.5.tgz", + "integrity": "sha512-o/41ot5JJiUsIETME9wVLAJrmIWL3j0R0Bj2kCOLbSfqEkKf0fmaPt+5vtblUh5eXr2S+J/8J3DaCb10+CzPGA==", + "requires": { + "@babel/runtime": "^7.4.4", + "@emotion/hash": "^0.8.0", + "@material-ui/types": "5.1.0", + "@material-ui/utils": "^4.11.3", + "clsx": "^1.0.4", + "csstype": "^2.5.2", + "hoist-non-react-statics": "^3.3.2", + "jss": "^10.5.1", + "jss-plugin-camel-case": "^10.5.1", + "jss-plugin-default-unit": "^10.5.1", + "jss-plugin-global": "^10.5.1", + "jss-plugin-nested": "^10.5.1", + "jss-plugin-props-sort": "^10.5.1", + "jss-plugin-rule-value-function": "^10.5.1", + "jss-plugin-vendor-prefixer": "^10.5.1", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + } + } + }, + "@material-ui/system": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@material-ui/system/-/system-4.12.2.tgz", + "integrity": "sha512-6CSKu2MtmiJgcCGf6nBQpM8fLkuB9F55EKfbdTC80NND5wpTmKzwdhLYLH3zL4cLlK0gVaaltW7/wMuyTnN0Lw==", + "requires": { + "@babel/runtime": "^7.4.4", + "@material-ui/utils": "^4.11.3", + "csstype": "^2.5.2", + "prop-types": "^15.7.2" + }, + "dependencies": { + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + } + } + }, + "@material-ui/types": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@material-ui/types/-/types-5.1.0.tgz", + "integrity": "sha512-7cqRjrY50b8QzRSYyhSpx4WRw2YuO0KKIGQEVk5J8uoz2BanawykgZGoWEqKm7pVIbzFDN0SpPcVV4IhOFkl8A==", + "requires": {} + }, + "@material-ui/utils": { + "version": "4.11.3", + "resolved": "https://registry.npmjs.org/@material-ui/utils/-/utils-4.11.3.tgz", + "integrity": "sha512-ZuQPV4rBK/V1j2dIkSSEcH5uT6AaHuKWFfotADHsC0wVL1NLd2WkFCm4ZZbX33iO4ydl6V0GPngKm8HZQ2oujg==", + "requires": { + "@babel/runtime": "^7.4.4", + "prop-types": "^15.7.2", + "react-is": "^16.8.0 || ^17.0.0" + } + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -16043,6 +18379,50 @@ "fastq": "^1.6.0" } }, + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + }, + "dependencies": { + "semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, + "@popperjs/core": { + "version": "2.11.5", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.5.tgz", + "integrity": "sha512-9X2obfABZuDVLCgPK9aX0a/x4jaOEweTTWE2+9sr0Qqqevj2Uv5XorvusThmc9XGYpS9yI+fhh8RTafBtGposw==" + }, "@sinonjs/commons": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.3.tgz", @@ -16204,6 +18584,15 @@ "@types/node": "*" } }, + "@types/hoist-non-react-statics": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.1.tgz", + "integrity": "sha512-iMIqiko6ooLrTh1joXodJK5X9xeEALT1kM5G3ZLhD3hszxBdIEd5C75U834D9mLcINgD4OyZf5uQXjkuYydWvA==", + "requires": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "@types/html-minifier-terser": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-5.1.2.tgz", @@ -16286,8 +18675,7 @@ "@types/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true + "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==" }, "@types/prettier": { "version": "2.4.3", @@ -16298,8 +18686,7 @@ "@types/prop-types": { "version": "15.7.3", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.3.tgz", - "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==", - "dev": true + "integrity": "sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==" }, "@types/qs": { "version": "6.9.7", @@ -16313,12 +18700,46 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", "dev": true }, + "@types/react": { + "version": "16.14.25", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.25.tgz", + "integrity": "sha512-cXRVHd7vBT5v1is72mmvmsg9stZrbJO04DJqFeh3Yj2tVKO6vmxg5BI+ybI6Ls7ROXRG3aFbZj9x0WA3ZAoDQw==", + "requires": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, + "@types/react-redux": { + "version": "7.1.24", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.24.tgz", + "integrity": "sha512-7FkurKcS1k0FHZEtdbbgN8Oc6b+stGSfZYjQGicofJ0j4U0qIn/jaSvnP2pLwZKiai3/17xqqxkkrxTgN8UNbQ==", + "requires": { + "@types/hoist-non-react-statics": "^3.3.0", + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0", + "redux": "^4.0.0" + } + }, + "@types/react-transition-group": { + "version": "4.4.4", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.4.tgz", + "integrity": "sha512-7gAPz7anVK5xzbeQW9wFBDg7G++aPLAFY0QaSMOou9rJZpbuI58WAuJrgu+qR92l61grlnCUe7AFX8KGahAgug==", + "requires": { + "@types/react": "*" + } + }, "@types/retry": { "version": "0.12.1", "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz", "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g==", "dev": true }, + "@types/scheduler": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" + }, "@types/serve-index": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.1.tgz", @@ -16353,6 +18774,12 @@ "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", "dev": true }, + "@types/uuid": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-8.3.4.tgz", + "integrity": "sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==", + "dev": true + }, "@types/ws": { "version": "8.2.2", "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.2.2.tgz", @@ -16649,6 +19076,17 @@ "debug": "4" } }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, "aggregate-error": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", @@ -16707,12 +19145,6 @@ "dev": true, "requires": {} }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, "ansi-escapes": { "version": "4.3.2", "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", @@ -16738,7 +19170,6 @@ "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, "requires": { "color-convert": "^1.9.0" } @@ -16754,45 +19185,19 @@ } }, "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dev": true, "requires": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } + "readable-stream": "^3.6.0" } }, "argparse": { @@ -16857,9 +19262,9 @@ "dev": true }, "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "requires": { "safer-buffer": "~2.1.0" @@ -16872,9 +19277,9 @@ "dev": true }, "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, "requires": { "lodash": "^4.17.14" @@ -17004,6 +19409,52 @@ "object.assign": "^4.1.0" } }, + "babel-plugin-emotion": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/babel-plugin-emotion/-/babel-plugin-emotion-10.2.2.tgz", + "integrity": "sha512-SMSkGoqTbTyUTDeuVuPIWifPdUGkTk1Kf9BWRiXIOIcuyMfsdp2EjeiiFvOzX8NOBvEh/ypKYvUh2rkgAJMCLA==", + "requires": { + "@babel/helper-module-imports": "^7.0.0", + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/serialize": "^0.11.16", + "babel-plugin-macros": "^2.0.0", + "babel-plugin-syntax-jsx": "^6.18.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^1.0.5", + "find-root": "^1.1.0", + "source-map": "^0.5.7" + }, + "dependencies": { + "@emotion/memoize": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.7.4.tgz", + "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==" + }, + "@emotion/serialize": { + "version": "0.11.16", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-0.11.16.tgz", + "integrity": "sha512-G3J4o8by0VRrO+PFeSc3js2myYNOXVJ3Ya+RGVxnshRYgsvErfAOglKAiy1Eo1vhzxqtUvjCyS5gtewzkmvSSg==", + "requires": { + "@emotion/hash": "0.8.0", + "@emotion/memoize": "0.7.4", + "@emotion/unitless": "0.7.5", + "@emotion/utils": "0.11.3", + "csstype": "^2.5.7" + } + }, + "@emotion/utils": { + "version": "0.11.3", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-0.11.3.tgz", + "integrity": "sha512-0o4l6pZC+hI88+bzuaX/6BgOvQVhbt2PfmxauVaYOGgbsAw14wdKyvMCZXnsnsHys94iadcF+RG/wZyx6+ZZBw==" + }, + "csstype": { + "version": "2.6.20", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.20.tgz", + "integrity": "sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==" + } + } + }, "babel-plugin-istanbul": { "version": "6.1.1", "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", @@ -17029,6 +19480,16 @@ "@types/babel__traverse": "^7.0.6" } }, + "babel-plugin-macros": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-2.8.0.tgz", + "integrity": "sha512-SEP5kJpfGYqYKpBrj5XU3ahw5p5GOHJ0U5ssOSQ/WBVdwkD2Dzlce95exQTs3jOVWPPKLBN2rlEWkCK7dSmLvg==", + "requires": { + "@babel/runtime": "^7.7.2", + "cosmiconfig": "^6.0.0", + "resolve": "^1.12.0" + } + }, "babel-plugin-polyfill-corejs2": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.2.2.tgz", @@ -17067,6 +19528,11 @@ "@babel/helper-define-polyfill-provider": "^0.2.2" } }, + "babel-plugin-syntax-jsx": { + "version": "6.18.0", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz", + "integrity": "sha1-CvMqmm4Tyno/1QaeYtew9Y0NiUY=" + }, "babel-preset-current-node-syntax": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", @@ -17196,6 +19662,11 @@ "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", "dev": true }, + "bootstrap": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz", + "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==" + }, "bootstrap-sass": { "version": "3.4.1", "resolved": "https://registry.npmjs.org/bootstrap-sass/-/bootstrap-sass-3.4.1.tgz", @@ -17231,7 +19702,6 @@ "version": "4.16.7", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.16.7.tgz", "integrity": "sha512-7I4qVwqZltJ7j37wObBe3SoTz+nS8APaNcrBOlgoirb6/HbEU2XxW/LpUDTCngM6iauwFqmRTuOMfyKnFGY5JA==", - "dev": true, "requires": { "caniuse-lite": "^1.0.30001248", "colorette": "^1.2.2", @@ -17276,11 +19746,44 @@ "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=", "dev": true }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + } + } + }, "call-bind": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, "requires": { "function-bind": "^1.1.1", "get-intrinsic": "^1.0.2" @@ -17289,8 +19792,7 @@ "callsites": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" }, "camel-case": { "version": "4.1.2", @@ -17320,10 +19822,9 @@ } }, "caniuse-lite": { - "version": "1.0.30001251", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001251.tgz", - "integrity": "sha512-HOe1r+9VkU4TFmnU70z+r7OLmtR+/chB1rdcJUeQlAinjEeb0cKL20tlAtOagNZhbrtLnCvV19B4FmF1rgzl6A==", - "dev": true + "version": "1.0.30001332", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001332.tgz", + "integrity": "sha512-10T30NYOEQtN6C11YGg411yebhvpnC6Z102+B95eAsN0oB6KUs01ivE8u+G6FMIRtIrVlYXhL+LUwQ3/hXwDWw==" }, "caseless": { "version": "0.12.0", @@ -17335,7 +19836,6 @@ "version": "2.4.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, "requires": { "ansi-styles": "^3.2.1", "escape-string-regexp": "^1.0.5", @@ -17432,6 +19932,11 @@ "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", "dev": true }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", @@ -17456,46 +19961,29 @@ "dev": true }, "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -17511,18 +19999,17 @@ "shallow-clone": "^3.0.0" } }, + "clsx": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-1.1.1.tgz", + "integrity": "sha512-6/bPho624p3S2pMyvP5kKBPXnI3ufHLObBFCfgx+LkeR5lg2XYy2hqZqUf45ypD8COn2bhgGJSUE+l5dhNBieA==" + }, "co": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", "dev": true }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, "collect-v8-coverage": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", @@ -17533,7 +20020,6 @@ "version": "1.9.3", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, "requires": { "color-name": "1.1.3" } @@ -17541,14 +20027,18 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, "colorette": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.2.2.tgz", - "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==", - "dev": true + "integrity": "sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==" }, "combined-stream": { "version": "1.0.8", @@ -17666,7 +20156,6 @@ "version": "1.7.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz", "integrity": "sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==", - "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -17686,8 +20175,7 @@ "core-js": { "version": "2.6.12", "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", - "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", - "dev": true + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" }, "core-js-compat": { "version": "3.16.1", @@ -17717,7 +20205,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-6.0.0.tgz", "integrity": "sha512-xb3ZL6+L8b9JLLCx3ZdoZy4+2ECphCMo2PwqgP1tlfVq6M6YReyzBJtvWWtbDSpNr9hn96pkCiZqUcFEc+54Qg==", - "dev": true, "requires": { "@types/parse-json": "^4.0.0", "import-fresh": "^3.1.0", @@ -17726,6 +20213,15 @@ "yaml": "^1.7.2" } }, + "create-react-class": { + "version": "15.7.0", + "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.7.0.tgz", + "integrity": "sha512-QZv4sFWG9S5RUvkTYWbflxeZX+JG7Cz0Tn33rQBJ+WFQTqTfUTjMjiv9tnfXazjsO5r0KhPs+AqCjyrQX6h2ng==", + "requires": { + "loose-envify": "^1.3.1", + "object-assign": "^4.1.1" + } + }, "cross-env": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz", @@ -17766,6 +20262,14 @@ } } }, + "css-box-model": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/css-box-model/-/css-box-model-1.2.1.tgz", + "integrity": "sha512-a7Vr4Q/kd/aw96bnJG332W9V9LkJO69JRcaCYDUqjp6/z0w6VcZjgAcTbgFxEPfBgdnAwlh3iwu+hLopa+flJw==", + "requires": { + "tiny-invariant": "^1.0.6" + } + }, "css-loader": { "version": "5.2.6", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-5.2.6.tgz", @@ -17830,6 +20334,15 @@ "nth-check": "^2.0.0" } }, + "css-vendor": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/css-vendor/-/css-vendor-2.0.8.tgz", + "integrity": "sha512-x9Aq0XTInxrkuFeHKbYC7zWY8ai7qJ04Kxd9MnvbC1uO5DagxoHQjm4JvG+vCdXOoFtCjbL2XSZfxmoYa9uQVQ==", + "requires": { + "@babel/runtime": "^7.8.3", + "is-in-browser": "^1.0.2" + } + }, "css-what": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", @@ -17868,8 +20381,7 @@ "csstype": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.0.7.tgz", - "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==", - "dev": true + "integrity": "sha512-KxnUB0ZMlnUWCsx2Z8MUsr6qV6ja1w9ArPErJaJaF8a5SOWoHLIszeCTKGRGRgtLgYrs1E8CHkNSP1VZTTPc9g==" }, "d": { "version": "1.0.1", @@ -17901,11 +20413,15 @@ "whatwg-url": "^8.0.0" } }, + "date-fns": { + "version": "2.28.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.28.0.tgz", + "integrity": "sha512-8d35hViGYx/QH0icHYCeLmsLmMUheMmTyV9Fcm6gvNwdw31yXXH+O85sOBJ+OLnLQMKZowvpKb6FgMIQjcpvQw==" + }, "debug": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz", - "integrity": "sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==", - "dev": true, + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "requires": { "ms": "2.1.2" } @@ -17956,7 +20472,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.1.1.tgz", "integrity": "sha512-yd9c5AdiqVcR+JjcwUQb9DkhJc8ngNr0MahEBGvDiJw8puWab2yZlh+nkasOnZP+EGTAP6rRp2JzJhJZzvNF8g==", - "dev": true, "requires": { "is-arguments": "^1.0.4", "is-date-object": "^1.0.1", @@ -17997,7 +20512,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, "requires": { "object-keys": "^1.0.12" } @@ -18109,6 +20623,14 @@ "utila": "~0.4" } }, + "dom-helpers": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-3.4.0.tgz", + "integrity": "sha512-LnuPJ+dwqKDIyotW1VzmOZ5TONUN7CwkCR5hrgawTUbkBGYdeoNLZo6nNfGkCrjtE1nXXaj7iMMpDa8/d9WoIA==", + "requires": { + "@babel/runtime": "^7.1.2" + } + }, "dom-serializer": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", @@ -18197,8 +20719,7 @@ "electron-to-chromium": { "version": "1.3.803", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.803.tgz", - "integrity": "sha512-tmRK9qB8Zs8eLMtTBp+w2zVS9MUe62gQQQHjYdAc5Zljam3ZIokNb+vZLPRz9RCREp6EFRwyhOFwbt1fEriQ2Q==", - "dev": true + "integrity": "sha512-tmRK9qB8Zs8eLMtTBp+w2zVS9MUe62gQQQHjYdAc5Zljam3ZIokNb+vZLPRz9RCREp6EFRwyhOFwbt1fEriQ2Q==" }, "emittery": { "version": "0.8.1", @@ -18207,9 +20728,9 @@ "dev": true }, "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, "emojis-list": { @@ -18223,6 +20744,28 @@ "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", "dev": true }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "enhanced-resolve": { "version": "5.8.3", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.8.3.tgz", @@ -18374,11 +20917,16 @@ "object-is": "^1.1.2" } }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, "error-ex": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, "requires": { "is-arrayish": "^0.2.1" } @@ -18463,8 +21011,7 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-html": { "version": "1.0.3", @@ -18475,8 +21022,7 @@ "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, "escodegen": { "version": "2.0.0", @@ -18821,6 +21367,11 @@ "pkg-dir": "^4.1.0" } }, + "find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==" + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -18837,6 +21388,11 @@ "integrity": "sha512-1x0S9UVJHsQprFcEC/qnNzBLcIxsjAV905f/UkQxbclCsoTWlacCNOpQa/anodLl2uaEKFhfWOvM2Qg77+15zA==", "dev": true }, + "font-awesome": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha1-j6jPBBGhoxr9B7BtKQK7n8gVoTM=" + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", @@ -18946,6 +21502,11 @@ "mime-types": "^2.1.12" } }, + "form-data-to-object": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/form-data-to-object/-/form-data-to-object-0.2.0.tgz", + "integrity": "sha1-96jmjd2RChEApl4lrGpIQUP/gWg=" + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -19001,8 +21562,7 @@ "function-bind": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, "function.prototype.name": { "version": "1.1.4", @@ -19023,19 +21583,37 @@ "dev": true }, "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dev": true, "requires": { - "aproba": "^1.0.3", + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "gaze": { @@ -19050,8 +21628,7 @@ "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" }, "get-caller-file": { "version": "2.0.5", @@ -19063,7 +21640,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, "requires": { "function-bind": "^1.1.1", "has": "^1.0.3", @@ -19148,8 +21724,7 @@ "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" }, "globby": { "version": "11.1.0", @@ -19166,9 +21741,9 @@ } }, "globule": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.2.tgz", - "integrity": "sha512-7IDTQTIu2xzXkT+6mlluidnWo+BypnbSoEVVQCGfzqnl5Ik8d3e1d4wycb8Rj9tWW+Z39uPWsdlquqiqPCd/pA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.3.tgz", + "integrity": "sha512-mb1aYtDbIjTu4ShMB85m3UzjX9BVKe9WCzsnfMSZk+K5GpIbBOexgg4PPCt5eHDEG5/ZQAUX2Kct02zfiPLsKg==", "dev": true, "requires": { "glob": "~7.1.1", @@ -19214,20 +21789,10 @@ "version": "1.0.3", "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, "requires": { "function-bind": "^1.1.1" } }, - "has-ansi": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, "has-bigints": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", @@ -19237,20 +21802,17 @@ "has-flag": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=" }, "has-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true + "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, "has-tostringtag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, "requires": { "has-symbols": "^1.0.2" } @@ -19267,6 +21829,18 @@ "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", "dev": true }, + "history": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/history/-/history-4.7.2.tgz", + "integrity": "sha512-1zkBRWW6XweO0NBcjiphtVJVsIQ+SXF29z9DVkceeaSLVMFXHool+fdCZD4spDCfZJCILPILc3bm7Bc+HRi0nA==", + "requires": { + "invariant": "^2.2.1", + "loose-envify": "^1.2.0", + "resolve-pathname": "^2.2.0", + "value-equal": "^0.4.0", + "warning": "^3.0.0" + } + }, "hoist-non-react-statics": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", @@ -19401,6 +21975,12 @@ "entities": "^2.0.0" } }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "http-deceiver": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", @@ -19496,6 +22076,20 @@ "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", "dev": true }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0=", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, + "hyphenate-style-name": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.0.4.tgz", + "integrity": "sha512-ygGZLjmXfPHj+ZWh6LwbC37l43MhfztxetbFCoYTM2VjkIUpeHgSNn7QIyVFj7YQ1Wl9Cbw5sholVJPzWvC2MQ==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -19518,11 +22112,20 @@ "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", "dev": true }, + "immer": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.6.tgz", + "integrity": "sha512-G95ivKpy+EvVAnAab4fVa4YGYn24J1SpEktnJX7JJ45Bd7xqME/SCplFzYFmTbrkwZbQ4xJK1xMTUYBkN6pWsQ==" + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha1-wkOZUUVbs5kT2vKBN28VMOEErfM=" + }, "import-fresh": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "requires": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -19550,6 +22153,12 @@ "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", "dev": true }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -19583,6 +22192,14 @@ "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", "dev": true }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "requires": { + "loose-envify": "^1.0.0" + } + }, "ip": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz", @@ -19599,7 +22216,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -19608,8 +22224,7 @@ "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=" }, "is-bigint": { "version": "1.0.1", @@ -19645,7 +22260,6 @@ "version": "2.8.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, "requires": { "has": "^1.0.3" } @@ -19653,8 +22267,7 @@ "is-date-object": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true + "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==" }, "is-docker": { "version": "2.2.1", @@ -19669,13 +22282,10 @@ "dev": true }, "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true }, "is-generator-fn": { "version": "2.1.0", @@ -19692,6 +22302,17 @@ "is-extglob": "^2.1.1" } }, + "is-in-browser": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/is-in-browser/-/is-in-browser-1.1.3.tgz", + "integrity": "sha1-Vv9NtoOgeMYILrldrX3GLh0E+DU=" + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU=", + "dev": true + }, "is-negative-zero": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", @@ -19747,7 +22368,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, "requires": { "call-bind": "^1.0.2", "has-tostringtag": "^1.0.0" @@ -20041,12 +22661,6 @@ "yargs": "^16.2.0" }, "dependencies": { - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -20066,17 +22680,6 @@ "supports-color": "^7.1.0" } }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -20092,44 +22695,12 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, "has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, "supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -20139,23 +22710,6 @@ "has-flag": "^4.0.0" } }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - } - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - }, "yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", @@ -20170,12 +22724,6 @@ "y18n": "^5.0.5", "yargs-parser": "^20.2.2" } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true } } }, @@ -21264,6 +23812,11 @@ } } }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==" + }, "js-base64": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", @@ -21359,8 +23912,7 @@ "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" }, "json-parse-better-errors": { "version": "1.0.2", @@ -21371,8 +23923,7 @@ "json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" }, "json-schema": { "version": "0.4.0", @@ -21396,7 +23947,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", - "dev": true, "requires": { "minimist": "^1.2.5" } @@ -21423,6 +23973,95 @@ "verror": "1.10.0" } }, + "jss": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss/-/jss-10.9.0.tgz", + "integrity": "sha512-YpzpreB6kUunQBbrlArlsMpXYyndt9JATbt95tajx0t4MTJJcCJdd4hdNpHmOIDiUJrF/oX5wtVFrS3uofWfGw==", + "requires": { + "@babel/runtime": "^7.3.1", + "csstype": "^3.0.2", + "is-in-browser": "^1.1.3", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-camel-case": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-camel-case/-/jss-plugin-camel-case-10.9.0.tgz", + "integrity": "sha512-UH6uPpnDk413/r/2Olmw4+y54yEF2lRIV8XIZyuYpgPYTITLlPOsq6XB9qeqv+75SQSg3KLocq5jUBXW8qWWww==", + "requires": { + "@babel/runtime": "^7.3.1", + "hyphenate-style-name": "^1.0.3", + "jss": "10.9.0" + } + }, + "jss-plugin-default-unit": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-default-unit/-/jss-plugin-default-unit-10.9.0.tgz", + "integrity": "sha512-7Ju4Q9wJ/MZPsxfu4T84mzdn7pLHWeqoGd/D8O3eDNNJ93Xc8PxnLmV8s8ZPNRYkLdxZqKtm1nPQ0BM4JRlq2w==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0" + } + }, + "jss-plugin-global": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-global/-/jss-plugin-global-10.9.0.tgz", + "integrity": "sha512-4G8PHNJ0x6nwAFsEzcuVDiBlyMsj2y3VjmFAx/uHk/R/gzJV+yRHICjT4MKGGu1cJq2hfowFWCyrr/Gg37FbgQ==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0" + } + }, + "jss-plugin-nested": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-nested/-/jss-plugin-nested-10.9.0.tgz", + "integrity": "sha512-2UJnDrfCZpMYcpPYR16oZB7VAC6b/1QLsRiAutOt7wJaaqwCBvNsosLEu/fUyKNQNGdvg2PPJFDO5AX7dwxtoA==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-props-sort": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-props-sort/-/jss-plugin-props-sort-10.9.0.tgz", + "integrity": "sha512-7A76HI8bzwqrsMOJTWKx/uD5v+U8piLnp5bvru7g/3ZEQOu1+PjHvv7bFdNO3DwNPC9oM0a//KwIJsIcDCjDzw==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0" + } + }, + "jss-plugin-rule-value-function": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-rule-value-function/-/jss-plugin-rule-value-function-10.9.0.tgz", + "integrity": "sha512-IHJv6YrEf8pRzkY207cPmdbBstBaE+z8pazhPShfz0tZSDtRdQua5jjg6NMz3IbTasVx9FdnmptxPqSWL5tyJg==", + "requires": { + "@babel/runtime": "^7.3.1", + "jss": "10.9.0", + "tiny-warning": "^1.0.2" + } + }, + "jss-plugin-vendor-prefixer": { + "version": "10.9.0", + "resolved": "https://registry.npmjs.org/jss-plugin-vendor-prefixer/-/jss-plugin-vendor-prefixer-10.9.0.tgz", + "integrity": "sha512-MbvsaXP7iiVdYVSEoi+blrW+AYnTDvHTW6I6zqi7JcwXdc6I9Kbm234nEblayhF38EftoenbM+5218pidmC5gA==", + "requires": { + "@babel/runtime": "^7.3.1", + "css-vendor": "^2.0.8", + "jss": "10.9.0" + } + }, + "keycharm": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/keycharm/-/keycharm-0.2.0.tgz", + "integrity": "sha1-+m6i5DuQpoAohD0n8gddNajD5vk=", + "peer": true + }, + "keycode": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/keycode/-/keycode-2.2.1.tgz", + "integrity": "sha512-Rdgz9Hl9Iv4QKi8b0OlCRQEzp4AgVxyCtz5S/+VIHezDmrDhkp2N2TqBWOLz0/gbeREXOOiI9/4b8BY9uw2vFg==" + }, "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", @@ -21436,9 +24075,9 @@ "dev": true }, "klona": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.4.tgz", - "integrity": "sha512-ZRbnvdg/NxqzC7L9Uyqzf4psi1OM4Cuc+sJAkQPjO6XkQIJTNbfK2Rsmbw8fx1p2mkZdp2FZYo2+LwXYY/uwIA==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.5.tgz", + "integrity": "sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==", "dev": true }, "leven": { @@ -21460,8 +24099,7 @@ "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true + "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "loader-runner": { "version": "4.2.0", @@ -21501,8 +24139,12 @@ "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "dev": true + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash-es": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz", + "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==" }, "lodash.debounce": { "version": "4.0.8", @@ -21583,6 +24225,30 @@ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true }, + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, "makeerror": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", @@ -21598,6 +24264,11 @@ "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, + "material-colors": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz", + "integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg==" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -21613,6 +24284,11 @@ "fs-monkey": "1.0.3" } }, + "memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==" + }, "meow": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", @@ -21638,12 +24314,6 @@ "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true } } }, @@ -21773,9 +24443,9 @@ } }, "minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==" }, "minimist-options": { "version": "4.1.0", @@ -21789,14 +24459,62 @@ } }, "minipass": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz", - "integrity": "sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg==", + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.6.tgz", + "integrity": "sha512-rty5kpw9/z8SX9dmxblFA6edItUmwJgMeYDZRrwlIVN27i8gysGbznJwUggw2V/FVqFSDdWy040ZPS811DYAqQ==", "dev": true, "requires": { "yallist": "^4.0.0" } }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, "minizlib": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", @@ -21816,6 +24534,27 @@ "minimist": "^1.2.5" } }, + "moment": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.27.0.tgz", + "integrity": "sha512-al0MUK7cpIcglMv3YF13qSgdAIqxHTO7brRtaz3DlSULbqfazqkc5kEjNrLDOM7fsjshoFIihnU8snrP7zUvhQ==" + }, + "moment-jdateformatparser": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/moment-jdateformatparser/-/moment-jdateformatparser-1.1.0.tgz", + "integrity": "sha1-TGuuM+IJDONS05uHfpsxcJkoscc=", + "requires": { + "moment": ">=1.5.0" + } + }, + "moment-timezone": { + "version": "0.5.31", + "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.31.tgz", + "integrity": "sha512-+GgHNg8xRhMXfEbv81iDtrVeTcWt0kWmTEY1XQK14dICTXnWJnT0dxdlPspwqF3keKMVPXwayEsk1DI0AA/jdA==", + "requires": { + "moment": ">= 2.9.0" + } + }, "moo": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.1.tgz", @@ -21825,8 +24564,7 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "multicast-dns": { "version": "6.2.3", @@ -21845,15 +24583,16 @@ "dev": true }, "nan": { - "version": "2.14.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.2.tgz", - "integrity": "sha512-M2ufzIiINKCuDfBSAUr1vWQ+vuVcA9kqx8JJUsbQi6yf1uGRyb7HfpdfUr5qLXf3B/t8dPvcjhKMmlfnP47EzQ==", + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", "dev": true }, "nanoid": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.2.0.tgz", - "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==" + "integrity": "sha512-fmsZYa9lpn69Ad5eDn7FMcnnSR+8R34W9qJEijxYhTbfOWzr22n1QxCMzXLK+ODyW2973V3Fux959iQoUxzUIA==", + "dev": true }, "natural-compare": { "version": "1.4.0", @@ -21916,31 +24655,84 @@ "dev": true }, "node-gyp": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz", - "integrity": "sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ==", + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", "dev": true, "requires": { "env-paths": "^2.2.0", "glob": "^7.1.4", - "graceful-fs": "^4.2.3", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", "nopt": "^5.0.0", - "npmlog": "^4.1.2", - "request": "^2.88.2", + "npmlog": "^6.0.0", "rimraf": "^3.0.2", - "semver": "^7.3.2", - "tar": "^6.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", "which": "^2.0.2" }, "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "are-we-there-yet": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.0.tgz", + "integrity": "sha512-0GWpv50YSOcLXaN6/FAKY3vfRbllXWV2xvfA/oKJF8pzFhWXPV+yjhJXDBbjscDYowv7Yw1A3uigpzn5iEGTyw==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } } } }, @@ -21953,17 +24745,16 @@ "node-releases": { "version": "1.1.74", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.74.tgz", - "integrity": "sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==", - "dev": true + "integrity": "sha512-caJBVempXZPepZoZAPCWRTNxYQ+xtG/KAi4ozTA5A+nJ7IU+kLQCbqaUjb5Rwy14M9upBWiQ4NutcmW04LJSRw==" }, "node-sass": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-6.0.1.tgz", - "integrity": "sha512-f+Rbqt92Ful9gX0cGtdYwjTrWAaGURgaK5rZCWOgCNyGWusFYHhbqCCBoFBeat+HKETOU02AyTxNhJV0YZf2jQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.1.tgz", + "integrity": "sha512-uMy+Xt29NlqKCFdFRZyXKOTqGt+QaKHexv9STj2WeLottnlqZEEWx6Bj0MXNthmFRRdM/YwyNo/8Tr46TOM0jQ==", "dev": true, "requires": { "async-foreach": "^0.1.3", - "chalk": "^1.1.1", + "chalk": "^4.1.2", "cross-spawn": "^7.0.3", "gaze": "^1.0.0", "get-stdin": "^4.0.1", @@ -21971,38 +24762,62 @@ "lodash": "^4.17.15", "meow": "^9.0.0", "nan": "^2.13.2", - "node-gyp": "^7.1.0", - "npmlog": "^4.0.0", + "node-gyp": "^8.4.1", + "npmlog": "^5.0.0", "request": "^2.88.0", - "sass-graph": "2.2.5", + "sass-graph": "4.0.0", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" }, "dependencies": { "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, @@ -22028,9 +24843,9 @@ }, "dependencies": { "semver": { - "version": "7.3.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", - "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", "dev": true, "requires": { "lru-cache": "^6.0.0" @@ -22044,6 +24859,11 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true }, + "normalizr": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/normalizr/-/normalizr-3.6.1.tgz", + "integrity": "sha512-8iEmqXmPtll8PwbEFrbPoDxVw7MKnNvt3PZzR2Xvq9nggEEOgBlNICPXYzyZ4w4AkHUzCU998mdatER3n2VaMA==" + }, "npm-run-path": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", @@ -22054,15 +24874,15 @@ } }, "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dev": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" } }, "nth-check": { @@ -22074,11 +24894,10 @@ "boolbase": "^1.0.0" } }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true + "numeral": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/numeral/-/numeral-2.0.6.tgz", + "integrity": "sha1-StCAk21EPCVhrtnyGX7//iX05QY=" }, "nwsapi": { "version": "2.2.0", @@ -22107,7 +24926,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -22116,8 +24934,7 @@ "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" }, "object.assign": { "version": "4.1.2", @@ -22287,7 +25104,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "requires": { "callsites": "^3.0.0" } @@ -22296,7 +25112,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", - "dev": true, "requires": { "@babel/code-frame": "^7.0.0", "error-ex": "^1.3.1", @@ -22356,8 +25171,7 @@ "path-parse": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "path-to-regexp": { "version": "0.1.7", @@ -22368,14 +25182,12 @@ "path-type": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, "picomatch": { "version": "2.3.1", @@ -22398,6 +25210,11 @@ "find-up": "^4.0.0" } }, + "popper.js": { + "version": "1.16.1-lts", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1-lts.tgz", + "integrity": "sha512-Kjw8nKRl1m+VrSFCoVGPph93W/qrSO7ZkqPpTf7F4bk/sqcfWK019dWBUpE/fBOsOQY1dks/Bmcbfn1heM/IsA==" + }, "portfinder": { "version": "1.0.28", "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", @@ -22541,6 +25358,30 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "dependencies": { + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=", + "dev": true + } + } + }, "prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -22572,6 +25413,25 @@ "reflect.ownkeys": "^0.2.0" } }, + "prop-types-extra": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/prop-types-extra/-/prop-types-extra-1.1.1.tgz", + "integrity": "sha512-59+AHNnHYCdiC+vMwY52WmvP5dM3QLeoumYuEyceQDi9aEhtwN9zIQ2ZNo25sMyXnbh32h+P1ezDsUpUH3JAew==", + "requires": { + "react-is": "^16.3.2", + "warning": "^4.0.0" + }, + "dependencies": { + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -22603,11 +25463,20 @@ "dev": true }, "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true }, + "query-string": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", + "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", + "requires": { + "object-assign": "^4.1.0", + "strict-uri-encode": "^1.0.0" + } + }, "queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -22624,11 +25493,15 @@ "version": "3.4.1", "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz", "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==", - "dev": true, "requires": { "performance-now": "^2.1.0" } }, + "raf-schd": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/raf-schd/-/raf-schd-4.0.3.tgz", + "integrity": "sha512-tQkJl2GRWh83ui2DiPTJz9wEiMN20syf+5oKfB03yYP7ioZcJwsIK8FjrtLwH1m7C7e+Tt2yYBlrOpdT+dyeIQ==" + }, "railroad-diagrams": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", @@ -22689,6 +25562,76 @@ "object-assign": "^4.1.1" } }, + "react-beautiful-dnd": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/react-beautiful-dnd/-/react-beautiful-dnd-13.1.0.tgz", + "integrity": "sha512-aGvblPZTJowOWUNiwd6tNfEpgkX5OxmpqxHKNW/4VmvZTNTbeiq7bA3bn5T+QSF2uibXB0D1DmJsb1aC/+3cUA==", + "requires": { + "@babel/runtime": "^7.9.2", + "css-box-model": "^1.2.0", + "memoize-one": "^5.1.1", + "raf-schd": "^4.0.2", + "react-redux": "^7.2.0", + "redux": "^4.0.4", + "use-memo-one": "^1.1.1" + } + }, + "react-bootstrap": { + "version": "0.33.1", + "resolved": "https://registry.npmjs.org/react-bootstrap/-/react-bootstrap-0.33.1.tgz", + "integrity": "sha512-qWTRravSds87P8WC82tETy2yIso8qDqlIm0czsrduCaYAFtHuyLu0XDbUlfLXeRzqgwm5sRk2wRaTNoiVkk/YQ==", + "requires": { + "@babel/runtime-corejs2": "^7.0.0", + "classnames": "^2.2.5", + "dom-helpers": "^3.2.0", + "invariant": "^2.2.4", + "keycode": "^2.2.0", + "prop-types": "^15.6.1", + "prop-types-extra": "^1.0.1", + "react-overlays": "^0.9.0", + "react-prop-types": "^0.4.0", + "react-transition-group": "^2.0.0", + "uncontrollable": "^7.0.2", + "warning": "^3.0.0" + } + }, + "react-bootstrap-toggle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/react-bootstrap-toggle/-/react-bootstrap-toggle-2.3.2.tgz", + "integrity": "sha512-OPoPt+z0uu0Y96RXJ57Hq71VJna+RVtCviRsAMu/5OFS7bO80qVhoASuxK/kNsclSrSpHAaBfygHjpf6sd6CLQ==", + "requires": { + "classnames": "^2.2.5", + "prop-types": "^15.5.10", + "resize-observer-polyfill": "^1.5.0" + } + }, + "react-color": { + "version": "2.19.3", + "resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz", + "integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==", + "requires": { + "@icons/material": "^0.2.4", + "lodash": "^4.17.15", + "lodash-es": "^4.17.15", + "material-colors": "^1.2.1", + "prop-types": "^15.5.10", + "reactcss": "^1.2.0", + "tinycolor2": "^1.4.1" + } + }, + "react-datepicker": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/react-datepicker/-/react-datepicker-4.2.1.tgz", + "integrity": "sha512-0gcvHMnX8rS1fV90PjjsB7MQdsWNU77JeVHf6bbwK9HnFxgwjVflTx40ebKmHV+leqe+f+FgUP9Nvqbe5RGyfA==", + "requires": { + "@popperjs/core": "^2.9.2", + "classnames": "^2.2.6", + "date-fns": "^2.0.1", + "prop-types": "^15.7.2", + "react-onclickoutside": "^6.10.0", + "react-popper": "^2.2.5" + } + }, "react-dom": { "version": "17.0.2", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", @@ -22699,6 +25642,11 @@ "scheduler": "^0.20.2" } }, + "react-fast-compare": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-3.2.0.tgz", + "integrity": "sha512-rtGImPZ0YyLrscKI9xTpV8psd6I8VAtjKCzQDlzyDvqJA8XOW78TXYQwNRNd8g8JZnDu8q9Fu/1v4HPAVwVdHA==" + }, "react-hot-loader": { "version": "4.13.0", "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.13.0.tgz", @@ -22721,6 +25669,14 @@ } } }, + "react-input-autosize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", + "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "requires": { + "prop-types": "^15.5.8" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -22731,6 +25687,117 @@ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==" }, + "react-onclickoutside": { + "version": "6.12.1", + "resolved": "https://registry.npmjs.org/react-onclickoutside/-/react-onclickoutside-6.12.1.tgz", + "integrity": "sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==", + "requires": {} + }, + "react-overlays": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/react-overlays/-/react-overlays-0.9.3.tgz", + "integrity": "sha512-u2T7nOLnK+Hrntho4p0Nxh+BsJl0bl4Xuwj/Y0a56xywLMetgAfyjnDVrudLXsNcKGaspoC+t3C1V80W9QQTdQ==", + "requires": { + "classnames": "^2.2.5", + "dom-helpers": "^3.2.1", + "prop-types": "^15.5.10", + "prop-types-extra": "^1.0.1", + "react-transition-group": "^2.2.1", + "warning": "^3.0.0" + } + }, + "react-popper": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", + "integrity": "sha512-kxGkS80eQGtLl18+uig1UIf9MKixFSyPxglsgLBxlYnyDf65BiY9B3nZSc6C9XUNDgStROB0fMQlTEz1KxGddw==", + "requires": { + "react-fast-compare": "^3.0.1", + "warning": "^4.0.2" + }, + "dependencies": { + "warning": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz", + "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==", + "requires": { + "loose-envify": "^1.0.0" + } + } + } + }, + "react-prop-types": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/react-prop-types/-/react-prop-types-0.4.0.tgz", + "integrity": "sha1-+ZsL+0AGkpya8gUefBQUpcdbk9A=", + "requires": { + "warning": "^3.0.0" + } + }, + "react-redux": { + "version": "7.2.8", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.8.tgz", + "integrity": "sha512-6+uDjhs3PSIclqoCk0kd6iX74gzrGc3W5zcAjbrFgEdIjRSQObdIwfx80unTkVUYvbQ95Y8Av3OvFHq1w5EOUw==", + "requires": { + "@babel/runtime": "^7.15.4", + "@types/react-redux": "^7.1.20", + "hoist-non-react-statics": "^3.3.2", + "loose-envify": "^1.4.0", + "prop-types": "^15.7.2", + "react-is": "^17.0.2" + }, + "dependencies": { + "react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==" + } + } + }, + "react-select": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-4.3.1.tgz", + "integrity": "sha512-HBBd0dYwkF5aZk1zP81Wx5UsLIIT2lSvAY2JiJo199LjoLHoivjn9//KsmvQMEFGNhe58xyuOITjfxKCcGc62Q==", + "requires": { + "@babel/runtime": "^7.12.0", + "@emotion/cache": "^11.4.0", + "@emotion/react": "^11.1.1", + "memoize-one": "^5.0.0", + "prop-types": "^15.6.0", + "react-input-autosize": "^3.0.0", + "react-transition-group": "^4.3.0" + }, + "dependencies": { + "dom-helpers": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/dom-helpers/-/dom-helpers-5.2.1.tgz", + "integrity": "sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA==", + "requires": { + "@babel/runtime": "^7.8.7", + "csstype": "^3.0.2" + } + }, + "react-transition-group": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", + "requires": { + "@babel/runtime": "^7.5.5", + "dom-helpers": "^5.0.1", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2" + } + } + } + }, + "react-sticky": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/react-sticky/-/react-sticky-6.0.3.tgz", + "integrity": "sha512-LNH4UJlRatOqo29/VHxDZOf6fwbgfgcHO4mkEFvrie5FuaZCSTGtug5R8NGqJ0kSnX8gHw8qZN37FcvnFBJpTQ==", + "requires": { + "prop-types": "^15.5.8", + "raf": "^3.3.0" + } + }, "react-tooltip": { "version": "4.2.21", "resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-4.2.21.tgz", @@ -22747,6 +25814,58 @@ } } }, + "react-transition-group": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-2.9.0.tgz", + "integrity": "sha512-+HzNTCHpeQyl4MJ/bdE0u6XRMe9+XG/+aL4mCxVN4DnPBQ0/5bfHWPDuOZUzYdMj94daZaZdCCc1Dzt9R/xSSg==", + "requires": { + "dom-helpers": "^3.4.0", + "loose-envify": "^1.4.0", + "prop-types": "^15.6.2", + "react-lifecycles-compat": "^3.0.4" + } + }, + "react-treebeard": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/react-treebeard/-/react-treebeard-3.2.4.tgz", + "integrity": "sha512-TsvdUq2kbLavRXa8k4mmqfPse8HmSA9G9s1SZUtIpiYSccSwa0Tm6miMgx7DZ5gpKofQ+j/3Ua0rjsahM3/FQg==", + "requires": { + "@emotion/core": "^10.0.10", + "@emotion/styled": "^10.0.10", + "deep-equal": "^1.0.1", + "shallowequal": "^1.1.0", + "velocity-react": "^1.4.1" + }, + "dependencies": { + "velocity-react": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/velocity-react/-/velocity-react-1.4.3.tgz", + "integrity": "sha512-zvefGm85A88S3KdF9/dz5vqyFLAiwKYlXGYkHH2EbXl+CZUD1OT0a0aS1tkX/WXWTa/FUYqjBaAzAEFYuSobBQ==", + "requires": { + "lodash": "^4.17.5", + "prop-types": "^15.5.8", + "react-transition-group": "^2.0.0", + "velocity-animate": "^1.4.0" + } + } + } + }, + "reactcss": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz", + "integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==", + "requires": { + "lodash": "^4.0.1" + } + }, + "reactn": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/reactn/-/reactn-2.2.7.tgz", + "integrity": "sha512-cqnt23kWN/ABqEZhW3OlpqI1DgTaaNDeHpSHtyd81qk0H1jd32zPTzJ69Hpzti2WakwNYveGFPIgI6i7E7nXOA==", + "requires": { + "use-force-update": "^1.0.5" + } + }, "read-pkg": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", @@ -22843,6 +25962,30 @@ "strip-indent": "^3.0.0" } }, + "reduce-reducers": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/reduce-reducers/-/reduce-reducers-0.1.5.tgz", + "integrity": "sha512-uoVmQnZQ+BtKKDKpBdbBri5SLNyIK9ULZGOA504++VbHcwouWE+fJDIo8AuESPF9/EYSkI0v05LDEQK6stCbTA==" + }, + "redux": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.2.0.tgz", + "integrity": "sha512-oSBmcKKIuIR4ME29/AeNUnl5L+hvBq7OaJWzaptTQJAntaPvxIJqfnjbaEiCzzaIz+XmVILfqAM3Ob0aXLPfjA==", + "requires": { + "@babel/runtime": "^7.9.2" + } + }, + "redux-actions": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/redux-actions/-/redux-actions-2.3.2.tgz", + "integrity": "sha512-PPclrJFIbDzD48oNj46biisg34NTtb1VxP9MTTAxsgIFuV4mEe5UXLRNBwyqrlXrMQHUbmpnjJupxocS4mxpvA==", + "requires": { + "invariant": "^2.2.1", + "lodash": "^4.13.1", + "lodash-es": "^4.17.4", + "reduce-reducers": "^0.1.0" + } + }, "reflect.ownkeys": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/reflect.ownkeys/-/reflect.ownkeys-0.2.0.tgz", @@ -22867,8 +26010,7 @@ "regenerator-runtime": { "version": "0.13.7", "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true + "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==" }, "regenerator-transform": { "version": "0.14.5", @@ -22889,7 +26031,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", - "dev": true, "requires": { "call-bind": "^1.0.2", "define-properties": "^1.1.3" @@ -22977,6 +26118,14 @@ "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" + }, + "dependencies": { + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + } } }, "require-directory": { @@ -22991,23 +26140,21 @@ "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, "requires-port": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", "dev": true }, + "resize-observer-polyfill": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz", + "integrity": "sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==" + }, "resolve": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, "requires": { "is-core-module": "^2.2.0", "path-parse": "^1.0.6" @@ -23033,8 +26180,12 @@ "resolve-from": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + }, + "resolve-pathname": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/resolve-pathname/-/resolve-pathname-2.2.0.tgz", + "integrity": "sha512-bAFz9ld18RzJfddgrO2e/0S2O81710++chRMUxHjXOYKF6jTAMrUNZrEZ1PvV0zlhfjidm08iRPdTLPno1FuRg==" }, "resolve-url": { "version": "0.2.1", @@ -23193,8 +26344,7 @@ "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, "safer-buffer": { "version": "2.1.2", @@ -23203,21 +26353,21 @@ "dev": true }, "sass-graph": { - "version": "2.2.5", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.5.tgz", - "integrity": "sha512-VFWDAHOe6mRuT4mZRd4eKE+d8Uedrk6Xnh7Sh9b4NGufQLQjOrvf/MQoOdx+0s92L89FeyUUNfU597j/3uNpag==", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.0.tgz", + "integrity": "sha512-WSO/MfXqKH7/TS8RdkCX3lVkPFQzCgbqdGsmSKq6tlPU+GpGEsa/5aW18JqItnqh+lPtcjifqdZ/VmiILkKckQ==", "dev": true, "requires": { "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^13.3.2" + "lodash": "^4.17.11", + "scss-tokenizer": "^0.3.0", + "yargs": "^17.2.1" } }, "sass-loader": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-11.1.1.tgz", - "integrity": "sha512-fOCp/zLmj1V1WHDZbUbPgrZhA7HKXHEqkslzB+05U5K9SbSbcmH91C7QLW31AsXikxUMaxXRhhcqWZAxUMLDyA==", + "version": "12.6.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-12.6.0.tgz", + "integrity": "sha512-oLTaH0YCtX4cfnJZxKSLAyglED0naiYfNG1iXfU5w1LNZ+ukoA5DtyDIN5zmKVZwYNJP4KRc5Y3hkWga+7tYfA==", "dev": true, "requires": { "klona": "^2.0.4", @@ -23254,23 +26404,20 @@ } }, "scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.3.0.tgz", + "integrity": "sha512-14Zl9GcbBvOT9057ZKjpz5yPOyUWG2ojd9D5io28wHRYsOrs7U95Q+KNL87+32p8rc+LvDpbu/i9ZYjM9Q+FsQ==", "dev": true, "requires": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" + "js-base64": "^2.4.3", + "source-map": "^0.7.1" }, "dependencies": { "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true } } }, @@ -23471,9 +26618,9 @@ } }, "signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, "sisteransi": { @@ -23488,6 +26635,12 @@ "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", "dev": true }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true + }, "sockjs": { "version": "0.3.24", "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", @@ -23497,14 +26650,27 @@ "faye-websocket": "^0.11.3", "uuid": "^8.3.2", "websocket-driver": "^0.7.4" - }, - "dependencies": { - "uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true - } + } + }, + "socks": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.6.2.tgz", + "integrity": "sha512-zDZhHhZRY9PxRruRMR7kMhnf3I8hDs4S3f9RecfnGxvcBHQcKcIH/oUcEWffsfl1XxdYlA7nnlGbbTvPz9D8gA==", + "dev": true, + "requires": { + "ip": "^1.1.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.0.tgz", + "integrity": "sha512-wWqJhjb32Q6GsrUqzuFkukxb/zzide5quXYcMVpIjxalDBBYy2nqKCFQ/9+Ie4dvOYSQdOk3hUlZSdzZOd3zMQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" } }, "source-list-map": { @@ -23516,8 +26682,7 @@ "source-map": { "version": "0.5.7", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" }, "source-map-js": { "version": "0.6.2", @@ -23628,9 +26793,9 @@ "dev": true }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -23644,6 +26809,15 @@ "tweetnacl": "~0.14.0" } }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, "stack-utils": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.5.tgz", @@ -23702,6 +26876,11 @@ } } }, + "strict-uri-encode": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", + "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=" + }, "string_decoder": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", @@ -23747,14 +26926,31 @@ } }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + } } }, "string.prototype.trim": { @@ -23852,11 +27048,15 @@ } } }, + "stylis": { + "version": "4.0.13", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.0.13.tgz", + "integrity": "sha512-xGPXiFVl4YED9Jh7Euv2V220mriG9u4B2TA6Ybjc1catrstKD2PpIdU3U0RKpkVBC2EhmL/F0sPCr9vrFTNRag==" + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, "requires": { "has-flag": "^3.0.0" } @@ -24037,6 +27237,21 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "tiny-invariant": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.2.0.tgz", + "integrity": "sha512-1Uhn/aqw5C6RI4KejVeTg6mIS7IqxnLJ8Mv2tV5rTc0qWobay7pDUz6Wi392Cnc8ak1H0F2cjoRzb2/AW4+Fvg==" + }, + "tiny-warning": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-warning/-/tiny-warning-1.0.3.tgz", + "integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==" + }, + "tinycolor2": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.4.2.tgz", + "integrity": "sha512-vJhccZPs965sV/L2sU4oRQVAos0pQXwsvTLkWYdqJ+a8Q5kPFzJTuOFwy7UniPli44NKQGAglksjvOcpo95aZA==" + }, "tmpl": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", @@ -24046,8 +27261,7 @@ "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=" }, "to-regex-range": { "version": "5.0.1", @@ -24122,12 +27336,6 @@ "requires": { "lru-cache": "^6.0.0" } - }, - "yargs-parser": { - "version": "20.2.7", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", - "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", - "dev": true } } }, @@ -24216,6 +27424,17 @@ "which-boxed-primitive": "^1.0.2" } }, + "uncontrollable": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/uncontrollable/-/uncontrollable-7.2.1.tgz", + "integrity": "sha512-svtcfoTADIB0nT9nltgjujTi7BzVmwjZClOmskKu/E8FW9BXzg9os8OLr4f8Dlnk0rYWJIWr4wv9eKUXiQvQwQ==", + "requires": { + "@babel/runtime": "^7.6.3", + "@types/react": ">=16.9.11", + "invariant": "^2.2.4", + "react-lifecycles-compat": "^3.0.4" + } + }, "unicode-canonical-property-names-ecmascript": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz", @@ -24244,6 +27463,24 @@ "integrity": "sha512-PqSoPh/pWetQ2phoj5RLiaqIk4kCNwoV3CI+LfGmWLKI3rE3kl1h59XpX2BjgDrmbxD9ARtQobPGU1SguCYuQg==", "dev": true }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, "universalify": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", @@ -24271,6 +27508,23 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, + "use-force-update": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/use-force-update/-/use-force-update-1.0.7.tgz", + "integrity": "sha512-k5dppYhO+I5X/cd7ildbrzeMZJkWwdAh5adaIk0qKN2euh7J0h2GBGBcB4QZ385eyHHnp7LIygvebdRx3XKdwA==" + }, + "use-immer": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/use-immer/-/use-immer-0.6.0.tgz", + "integrity": "sha512-dFGRfvWCqPDTOt/S431ETYTg6+uxbpb7A1pptufwXVzGJY3RlXr38+3wyLNpc6SbbmAKjWl6+EP6uW74fkEsXQ==", + "requires": {} + }, + "use-memo-one": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/use-memo-one/-/use-memo-one-1.1.2.tgz", + "integrity": "sha512-u2qFKtxLsia/r8qG0ZKkbytbztzRb317XCkT7yP8wxL0tZ/CzK2G+WWie5vWvpyeP7+YoPIwbJoIHJ4Ba4k0oQ==", + "requires": {} + }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", @@ -24290,10 +27544,9 @@ "dev": true }, "uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "dev": true + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" }, "v8-to-istanbul": { "version": "8.1.1", @@ -24324,12 +27577,22 @@ "spdx-expression-parse": "^3.0.0" } }, + "value-equal": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/value-equal/-/value-equal-0.4.0.tgz", + "integrity": "sha512-x+cYdNnaA3CxvMaTX0INdTCN8m8aF2uY9BvEqmxuYp8bL09cs/kWVQPVGcA35fMktdOsP69IgU7wFj/61dJHEw==" + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", "dev": true }, + "velocity-animate": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/velocity-animate/-/velocity-animate-1.5.2.tgz", + "integrity": "sha512-m6EXlCAMetKztO1ppBhGU1/1MR3IiEevO6ESq6rcrSQ3Q77xYSW13jkfXW88o4xMrkXJhy/U7j4wFR/twMB0Eg==" + }, "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", @@ -24341,6 +27604,12 @@ "extsprintf": "^1.2.0" } }, + "vis-util": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/vis-util/-/vis-util-4.3.4.tgz", + "integrity": "sha512-hJIZNrwf4ML7FYjs+m+zjJfaNvhjk3/1hbMdQZVnwwpOFJS/8dMG8rdbOHXcKoIEM6U5VOh3HNpaDXxGkOZGpw==", + "peer": true + }, "w3c-hr-time": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz", @@ -24368,6 +27637,14 @@ "makeerror": "1.0.12" } }, + "warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/warning/-/warning-3.0.0.tgz", + "integrity": "sha1-MuU3fLVy3kqwR1O9+IIcAe1gW3w=", + "requires": { + "loose-envify": "^1.0.0" + } + }, "watchpack": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", @@ -24743,19 +28020,13 @@ "is-symbol": "^1.0.3" } }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "wildcard": { @@ -24771,46 +28042,53 @@ "dev": true }, "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "dependencies": { "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" + "color-name": "~1.1.4" } }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "ansi-regex": "^4.1.0" + "ansi-regex": "^5.0.1" } } } @@ -24853,9 +28131,9 @@ "dev": true }, "y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { @@ -24867,104 +28145,36 @@ "yaml": { "version": "1.10.2", "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==" }, "yargs": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", - "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "version": "17.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.4.1.tgz", + "integrity": "sha512-WSZD9jgobAg3ZKuCQZSa3g9QOJeCCqLoLAykiWgmXnDo9EPnn4RPf5qVTtzgOx66o6/oqhcA5tHtJXpG8pMt3g==", "dev": true, "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.2" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" }, "dependencies": { - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "yargs-parser": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.1.tgz", + "integrity": "sha512-9BK1jFpLzJROCI5TzwZL/TU4gqjK5xiHV/RfWLOahrjAko/e4DJkRDZQXfvqAsiZzzYhgAzbgz6lg48jcm4GLg==", "dev": true - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } } } }, "yargs-parser": { - "version": "13.1.2", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", - "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } } diff --git a/mcc/package.json b/mcc/package.json index 5640dced8..ab785410c 100644 --- a/mcc/package.json +++ b/mcc/package.json @@ -12,16 +12,20 @@ }, "dependencies": { "@labkey/api": "^1.8.0", + "@labkey/components": "2.157.0", "chart.js": "^3.7.0", - "nanoid": "^3.2.0", + "uuid": "^8.3.2", "react": "^17.0.2", "react-dom": "^17.0.2", + "react-hot-loader": "^4.13.0", "react-tooltip": "^4.2.21", - "react-hot-loader": "^4.13.0" + "@material-ui/core": "^4.12.4", + "@material-ui/styles": "^4.11.5" }, "devDependencies": { "@labkey/build": "^5.0.0", "@types/jest": "^27.4.0", + "@types/uuid": "^8.3.4", "enzyme": "^3.11.0", "enzyme-adapter-react-16": "^1.15.6", "jest": "^27.4.7", diff --git a/mcc/resources/folderTypes/MCC.folderType.xml b/mcc/resources/folderTypes/MCC.folderType.xml index dc2f8a18d..ff45df62e 100644 --- a/mcc/resources/folderTypes/MCC.folderType.xml +++ b/mcc/resources/folderTypes/MCC.folderType.xml @@ -1,6 +1,12 @@ MCC The default folder layout for MCC + + + MCC Menu + menu + + mcc diff --git a/mcc/resources/queries/mcc/aggregatedDemographics.sql b/mcc/resources/queries/mcc/aggregatedDemographics.sql index b2b9e4a19..49d451ca4 100644 --- a/mcc/resources/queries/mcc/aggregatedDemographics.sql +++ b/mcc/resources/queries/mcc/aggregatedDemographics.sql @@ -7,13 +7,15 @@ SELECT d.birth, d.death, d.colony, - d.dam, - d.sire, + d.damMccAlias.externalAlias as dam, + d.sireMccAlias.externalAlias as sire, + d.dam as originalDam, + d.sire as originalSire, d.Id.mostRecentWeight.mostRecentWeight as mostRecentWeight, d.objectid, d.calculated_status, CASE - WHEN (SELECT COUNT(f.flag.value) as total FROM "/data/Colonies/SNPRC/".study.flags f WHERE f.Id = d.Id AND f.isActive = true) > 0 THEN true + WHEN d.calculated_status = 'Alive' AND (SELECT COUNT(f.flag.value) as total FROM "/data/Colonies/SNPRC/".study.flags f WHERE f.Id = d.Id AND f.isActive = true) > 0 THEN true ELSE false END as u24_status, d.container @@ -31,13 +33,15 @@ SELECT d.birth, d.death, d.colony, - d.dam, - d.sire, + d.damMccAlias.externalAlias as dam, + d.sireMccAlias.externalAlias as sire, + d.dam as originalDam, + d.sire as originalSire, d.Id.mostRecentWeight.mostRecentWeight as mostRecentWeight, d.objectid, d.calculated_status, CASE - WHEN (SELECT COUNT(f.flag.value) as total FROM "/data/Colonies/WNPRC/".study.flags f WHERE f.Id = d.Id AND f.isActive = true) > 0 THEN true + WHEN d.calculated_status = 'Alive' AND (SELECT COUNT(f.flag.value) as total FROM "/data/Colonies/WNPRC/".study.flags f WHERE f.Id = d.Id AND f.isActive = true) > 0 THEN true ELSE false END as u24_status, d.container @@ -55,8 +59,10 @@ SELECT d.birth, d.death, 'U NEB' as colony, - d.dam, - d.sire, + d.damMccAlias.externalAlias as dam, + d.sireMccAlias.externalAlias as sire, + d.dam as originalDam, + d.sire as originalSire, d.Id.mostRecentWeight.mostRecentWeight as mostRecentWeight, d.objectid, d.calculated_status, @@ -76,8 +82,10 @@ SELECT d.birth, d.death, d.center as colony, - d.dam, - d.sire, + d.damMccAlias.externalAlias as dam, + d.sireMccAlias.externalAlias as sire, + d.dam as originalDam, + d.sire as originalSire, d.Id.mostRecentWeight.mostRecentWeight as mostRecentWeight, d.objectid, d.calculated_status, @@ -97,8 +105,10 @@ SELECT d.birth, d.death, d.colony, - d.dam, - d.sire, + d.damMccAlias.externalAlias as dam, + d.sireMccAlias.externalAlias as sire, + d.dam as originalDam, + d.sire as originalSire, d.Id.mostRecentWeight.mostRecentWeight as mostRecentWeight, d.objectid, d.calculated_status, diff --git a/mcc/resources/queries/mcc/animalRequests.js b/mcc/resources/queries/mcc/animalRequests.js index 3d00815a7..d67674ccf 100644 --- a/mcc/resources/queries/mcc/animalRequests.js +++ b/mcc/resources/queries/mcc/animalRequests.js @@ -12,7 +12,34 @@ function beforeUpdate(row, oldRow, errors){ } function beforeUpsert(row, oldRow, errors) { - row.status = row.status || 'draft' + if (!row.objectid && row.rowid) { + row.objectid = triggerHelper.resolveObjectId(row.rowid) + } + + if (!row.objectid) { + errors._form = 'Unable to resolve record with rowid: ' + row.rowid + return + } + else { + row.objectid = row.objectid.toUpperCase(); + } + + if (!row.status && oldRow) { + row.status = oldRow.status; + } + + if (!row.status) { + console.error('Request row being submitted without a status: ' + row.objectid) + console.error(row) + console.error(oldRow) + } + + row.status = row.status || 'Draft' + + if (!triggerHelper.hasPermission(row.status)) { + errors._form = 'Insufficient permissions to update request with status: ' + row.status; + return; + } } function afterInsert(row, errors){ @@ -24,9 +51,91 @@ function afterUpdate(row, oldRow, errors){ } function afterUpsert(row, oldRow, errors) { - if (row.status === 'submitted') { - if (!oldRow || oldRow.status !== 'submitted') { - triggerHelper.sendNotification(row.rowid); + if (row.status && row.status !== 'Draft') { + try { + triggerHelper.ensureReviewRecordsCreated(row.objectId, row.status, oldRow ? oldRow.status : null, calculatePreliminaryScore(row, oldRow)); + } + catch(e) { + console.error('Error in animalRequest.afterUpsert') + console.error(e) + console.error(row) + console.error(oldRow) + errors._form = 'Error saving record' + } + } +} + +// cascade delete co-i, cohorts: +function beforeDelete(row, errors){ + if (!row.status) { + errors._form = 'Request lacks a status, cannot delete'; + return; + } + + if (!triggerHelper.hasPermission(row.status)) { + errors._form = 'Insufficient permissions to delete this request'; + return; + } + + if (row.objectid) { + triggerHelper.cascadeDelete('mcc', 'coinvestigators', 'requestid', row.objectid); + triggerHelper.cascadeDelete('mcc', 'requestcohorts', 'requestid', row.objectid); + + triggerHelper.cascadeDelete('mcc', 'requestreviews', 'requestid', row.objectid); + triggerHelper.cascadeDelete('mcc', 'requestscores', 'requestid', row.objectid); + } + else { + console.error('MCC animalRequests row lacks objectid. row ID: ' + row.rowid); + } +} + +function calculatePreliminaryScore(row, oldRow) { + var fields = ['institutiontype', 'earlystageinvestigator', 'fundingsource', 'existingnhpfacilities', 'existingmarmosetcolony', 'isbreedinganimals']; + if (oldRow) { + fields.forEach(function(fieldName){ + if (row[fieldName] === undefined) { + row[fieldName] = oldRow[fieldName] + } + }, this); + } + + fields.forEach(function(fieldName){ + if (row[fieldName] === undefined || row[fieldName] === null || row[fieldName] === '') { + console.error('Missing field ' + fieldName + ' in calculatePreliminaryScore: [' + row[fieldName] + ']') + console.error(row) + console.error(oldRow) } + }, this); + + // NOTE: the initial score is two, such that the final range is 0-10 + var score = 2; + + score += row.earlystageinvestigator ? 1 : 0; + if (row.institutiontype === 'minorityServing' || row.institutiontype === 'university') { + score += 1; } + else if (row.institutiontype === 'commercial') { + score -= 1; + } + else { + console.error('Unknown MCC institutiontype: ' + row.institutiontype) + } + + if (['nih', 'other-federal', 'start-up', 'foundation'].indexOf(row.fundingsource) !== -1) { + score += 1; + } + else if (row.fundingsource === 'private' || row.fundingsource === 'no-funding') { + // no score change + } + else { + console.error('Unknown MCC fundingsource: ' + row.fundingsource) + } + + score += row.existingnhpfacilities === 'existing' ? 1 : -1; + score += row.existingmarmosetcolony === 'existing' ? 1 : 0; + + //TODO: verify values + score += row.isbreedinganimals ? 1 : 0; + + return score; } \ No newline at end of file diff --git a/mcc/resources/queries/mcc/animalRequests/.qview.xml b/mcc/resources/queries/mcc/animalRequests/.qview.xml index b87e37920..9f5fc4327 100644 --- a/mcc/resources/queries/mcc/animalRequests/.qview.xml +++ b/mcc/resources/queries/mcc/animalRequests/.qview.xml @@ -7,6 +7,7 @@ + diff --git a/mcc/resources/queries/mcc/animalRequests/Detailed.qview.xml b/mcc/resources/queries/mcc/animalRequests/Detailed.qview.xml deleted file mode 100644 index ae436edec..000000000 --- a/mcc/resources/queries/mcc/animalRequests/Detailed.qview.xml +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/mcc/resources/queries/mcc/myRequests.query.xml b/mcc/resources/queries/mcc/myRequests.query.xml index e5bdacb69..37a91ba90 100644 --- a/mcc/resources/queries/mcc/myRequests.query.xml +++ b/mcc/resources/queries/mcc/myRequests.query.xml @@ -3,6 +3,8 @@ + /mcc/animalRequest.view + /mcc/animalRequest.view?requestId=${objectid} rowid diff --git a/mcc/resources/queries/mcc/myRequests.sql b/mcc/resources/queries/mcc/myRequests.sql index f17e699ff..e05514bea 100644 --- a/mcc/resources/queries/mcc/myRequests.sql +++ b/mcc/resources/queries/mcc/myRequests.sql @@ -3,8 +3,10 @@ SELECT t.lastname, t.firstname, t.created, + t.createdby, t.status, - t.objectid + t.objectid, + t.actions FROM mcc.animalRequests t WHERE ISMEMBEROF(t.createdby) diff --git a/mcc/resources/queries/mcc/requestReviews.js b/mcc/resources/queries/mcc/requestReviews.js new file mode 100644 index 000000000..8dcbdb027 --- /dev/null +++ b/mcc/resources/queries/mcc/requestReviews.js @@ -0,0 +1,42 @@ +var console = require("console"); +var LABKEY = require("labkey"); + +var triggerHelper = new org.labkey.mcc.query.TriggerHelper(LABKEY.Security.currentUser.id, LABKEY.Security.currentContainer.id); + +function beforeInsert(row, errors){ + beforeUpsert(row, null, errors); +} + +function beforeUpdate(row, oldRow, errors){ + beforeUpsert(row, oldRow, errors); +} + +function beforeUpsert(row, oldRow, errors) { + if (row.requestId) { + row.requestId = row.requestId.toUpperCase(); + } +} + +function afterInsert(row, errors){ + afterUpsert(row, null, errors); +} + +function afterUpdate(row, oldRow, errors){ + afterUpsert(row, oldRow, errors); +} + +function afterUpsert(row, oldRow, errors) { + if (row.review) { + var requestId = row.requestId || oldRow.requestId + if (!requestId) { + console.error('No requestId for requestScore update') + console.error(row) + return + } + + // Only perform this test the first time the review is added + if (!oldRow || !oldRow.review) { + triggerHelper.possiblySetRabComplete(requestId); + } + } +} \ No newline at end of file diff --git a/mcc/resources/queries/mcc/requestReviews/.qview.xml b/mcc/resources/queries/mcc/requestReviews/.qview.xml new file mode 100644 index 000000000..55fa5feb2 --- /dev/null +++ b/mcc/resources/queries/mcc/requestReviews/.qview.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/queries/mcc/requestReviews/Pending Reviews.qview.xml b/mcc/resources/queries/mcc/requestReviews/Pending Reviews.qview.xml new file mode 100644 index 000000000..011014440 --- /dev/null +++ b/mcc/resources/queries/mcc/requestReviews/Pending Reviews.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/queries/mcc/requestScores.js b/mcc/resources/queries/mcc/requestScores.js new file mode 100644 index 000000000..af4906f3f --- /dev/null +++ b/mcc/resources/queries/mcc/requestScores.js @@ -0,0 +1,18 @@ +var console = require("console"); +var LABKEY = require("labkey"); + +var triggerHelper = new org.labkey.mcc.query.TriggerHelper(LABKEY.Security.currentUser.id, LABKEY.Security.currentContainer.id); + +function beforeInsert(row, errors){ + beforeUpsert(row, null, errors); +} + +function beforeUpdate(row, oldRow, errors){ + beforeUpsert(row, oldRow, errors); +} + +function beforeUpsert(row, oldRow, errors) { + if (row.requestId) { + row.requestId = row.requestId.toUpperCase(); + } +} \ No newline at end of file diff --git a/mcc/resources/queries/mcc/requestScores/.qview.xml b/mcc/resources/queries/mcc/requestScores/.qview.xml new file mode 100644 index 000000000..947e4dd6b --- /dev/null +++ b/mcc/resources/queries/mcc/requestScores/.qview.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/queries/mcc/requestScores/Pending Decision.qview.xml b/mcc/resources/queries/mcc/requestScores/Pending Decision.qview.xml new file mode 100644 index 000000000..2732aa402 --- /dev/null +++ b/mcc/resources/queries/mcc/requestScores/Pending Decision.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/queries/mcc/requestScores/Pending Requests.qview.xml b/mcc/resources/queries/mcc/requestScores/Pending Requests.qview.xml new file mode 100644 index 000000000..9a0b82fa5 --- /dev/null +++ b/mcc/resources/queries/mcc/requestScores/Pending Requests.qview.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/queries/mcc/userRequests/.qview.xml b/mcc/resources/queries/mcc/userRequests/.qview.xml new file mode 100644 index 000000000..5fff46319 --- /dev/null +++ b/mcc/resources/queries/mcc/userRequests/.qview.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/queries/study/demographics.js b/mcc/resources/queries/study/demographics.js index f514db4fa..3b39ec58e 100644 --- a/mcc/resources/queries/study/demographics.js +++ b/mcc/resources/queries/study/demographics.js @@ -26,6 +26,10 @@ function onUpsert(helper, scriptErrors, row, oldRow){ row.calculated_status = row.status; } + if (row.calculated_status === 'alive') { + row.calculated_status = 'Alive'; + } + if (row.death) { row.calculated_status = 'Dead'; } @@ -42,6 +46,9 @@ function onUpsert(helper, scriptErrors, row, oldRow){ case 'Female': row.gender = 'f'; break; + case 'U': + case 'u': + case 'Other': case 'Undetermined': row.gender = 'Unknown'; break; diff --git a/mcc/resources/queries/study/demographics.query.xml b/mcc/resources/queries/study/demographics.query.xml index e5e0a932b..d2be9bc01 100644 --- a/mcc/resources/queries/study/demographics.query.xml +++ b/mcc/resources/queries/study/demographics.query.xml @@ -9,7 +9,7 @@ - + true @@ -85,6 +85,9 @@ code + + Alternate IDs + @@ -113,21 +116,23 @@ Dam - - - - - - /ehr/participantView.view?participantId=${dam} + + study + animal + id + + + Sire - - - - - - /ehr/participantView.view?participantId=${sire} + + study + animal + id + + + Origin diff --git a/mcc/resources/referenceStudy/study/datasets/datasets_metadata.xml b/mcc/resources/referenceStudy/study/datasets/datasets_metadata.xml index 5ae113419..57c9fc814 100644 --- a/mcc/resources/referenceStudy/study/datasets/datasets_metadata.xml +++ b/mcc/resources/referenceStudy/study/datasets/datasets_metadata.xml @@ -655,6 +655,9 @@ varchar + + varchar + Demographics
diff --git a/mcc/resources/schemas/dbscripts/postgresql/mcc-20.008-20.009.sql b/mcc/resources/schemas/dbscripts/postgresql/mcc-20.008-20.009.sql new file mode 100644 index 000000000..2a8da5896 --- /dev/null +++ b/mcc/resources/schemas/dbscripts/postgresql/mcc-20.008-20.009.sql @@ -0,0 +1,38 @@ +CREATE TABLE mcc.requestReviews ( + rowid SERIAL, + reviewerId int, + review varchar(1000), + score int, + comments varchar(4000), + status varchar(1000), + requestid ENTITYID, + + container entityid, + created timestamp, + createdby userid, + modified timestamp, + modifiedby userid, + + CONSTRAINT PK_requestReviews PRIMARY KEY (rowid) +); + +CREATE TABLE mcc.requestScores ( + rowid SERIAL, + preliminaryScore int, + resourceAvailabilityScore varchar(200), + researchAreaPriorityScore varchar(200), + + proposalScore varchar(200), + comments varchar(4000), + requestid ENTITYID, + + container entityid, + created timestamp, + createdby userid, + modified timestamp, + modifiedby userid, + + CONSTRAINT PK_requestScores PRIMARY KEY (rowid) +); + +ALTER TABLE mcc.animalRequests add earlystageinvestigator boolean; \ No newline at end of file diff --git a/mcc/resources/schemas/dbscripts/postgresql/mcc-20.009-20.010.sql b/mcc/resources/schemas/dbscripts/postgresql/mcc-20.009-20.010.sql new file mode 100644 index 000000000..8c3ff857f --- /dev/null +++ b/mcc/resources/schemas/dbscripts/postgresql/mcc-20.009-20.010.sql @@ -0,0 +1,4 @@ +ALTER TABLE mcc.animalRequests drop column isprincipalinvestigator; + +ALTER TABLE mcc.animalRequests DROP COLUMN certify; +ALTER TABLE mcc.animalRequests ADD COLUMN certify boolean; \ No newline at end of file diff --git a/mcc/resources/schemas/dbscripts/postgresql/mcc-20.010-20.011.sql b/mcc/resources/schemas/dbscripts/postgresql/mcc-20.010-20.011.sql new file mode 100644 index 000000000..584ee01c4 --- /dev/null +++ b/mcc/resources/schemas/dbscripts/postgresql/mcc-20.010-20.011.sql @@ -0,0 +1,4 @@ +ALTER TABLE mcc.requestScores drop column researchAreaPriorityScore; + +ALTER TABLE mcc.animalrequests drop column otherjustification; +ALTER TABLE mcc.animalrequests drop column researcharea; diff --git a/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.008-20.009.sql b/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.008-20.009.sql new file mode 100644 index 000000000..b0e079107 --- /dev/null +++ b/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.008-20.009.sql @@ -0,0 +1,38 @@ +CREATE TABLE mcc.requestReviews ( + rowid int IDENTITY(1,1), + reviewerId int, + review varchar(1000), + score int, + comments varchar(4000), + status varchar(1000), + requestid ENTITYID, + + container entityid, + created datetime, + createdby userid, + modified datetime, + modifiedby userid, + + CONSTRAINT PK_requestReviews PRIMARY KEY (rowid) +); + +CREATE TABLE mcc.requestScores ( + rowid int IDENTITY(1,1), + preliminaryScore int, + resourceAvailabilityScore varchar(200), + researchAreaPriorityScore varchar(200), + + proposalScore varchar(200), + comments varchar(4000), + requestid ENTITYID, + + container entityid, + created datetime, + createdby userid, + modified datetime, + modifiedby userid, + + CONSTRAINT PK_requestScores PRIMARY KEY (rowid) +); + +ALTER TABLE mcc.animalRequests add earlystageinvestigator bit; diff --git a/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.009-20.010.sql b/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.009-20.010.sql new file mode 100644 index 000000000..6ca156d1b --- /dev/null +++ b/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.009-20.010.sql @@ -0,0 +1,4 @@ +ALTER TABLE mcc.animalRequests drop column isprincipalinvestigator; + +ALTER TABLE mcc.animalRequests DROP COLUMN certify; +ALTER TABLE mcc.animalRequests ADD certify bit; \ No newline at end of file diff --git a/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.010-20.011.sql b/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.010-20.011.sql new file mode 100644 index 000000000..33a1c61ef --- /dev/null +++ b/mcc/resources/schemas/dbscripts/sqlserver/mcc-20.010-20.011.sql @@ -0,0 +1,4 @@ +ALTER TABLE mcc.requestScores drop column researchAreaPriorityScore; + +ALTER TABLE mcc.animalrequests drop column otherjustification; +ALTER TABLE mcc.animalrequests drop column researcharea; \ No newline at end of file diff --git a/mcc/resources/schemas/mcc.xml b/mcc/resources/schemas/mcc.xml index 64770504b..9c0527cd2 100644 --- a/mcc/resources/schemas/mcc.xml +++ b/mcc/resources/schemas/mcc.xml @@ -214,8 +214,10 @@ MCC Animal Requestsmcc/animalRequest.view - + mcc/animalRequest.viewmcc/animalRequest.view?requestId=${objectid} + mcc/requestReview.view?requestId=${objectid}&mode=details + DETAILEDrowid @@ -226,6 +228,7 @@ Object Id true false + false Last Name @@ -239,8 +242,8 @@ Middle Initial true - - Is Principal Investigator + + Is Early Stage Investigator? true @@ -307,14 +310,6 @@ Detail on Breeding true - - Research Area - true - - - Justification (If other picked on Research Area) - true - Existing marmoset colony? true @@ -379,11 +374,19 @@ 29 true + + Actions + 200 + + org.labkey.mcc.query.AnimalRequestActionsDisplayColumnFactory + +
Co-investigatorsrowid + DETAILED Row ID @@ -397,6 +400,7 @@ mcc animalrequests objectid + rowId @@ -445,6 +449,7 @@
Request Cohortsrowid + DETAILED Cohort Id @@ -457,6 +462,7 @@ mcc animalrequests objectid + rowId @@ -503,6 +509,7 @@ rowid Animal ID Mapping DETAILED + externalAlias true @@ -516,7 +523,7 @@ false - mGAP Alias + MCC Alias false true false @@ -557,4 +564,179 @@
+ + + Request Reviews + DETAILED + + + + + + rowid + + + Row ID + false + + + Assigned Reviewer + false + + core + users + userid + + + + Review + true + + + Score + true + + + Comments + true + + + Status + true + + + Request ID + false + + mcc + animalrequests + objectid + rowId + + + + true + + + true + + + false + false + false + true + 29 + true + + + true + + + false + false + false + true + 29 + true + + + Actions + + org.labkey.mcc.query.RequestReviewActionsDisplayColumnFactory + + + + + ldk.context + + + +
+ + + + + /mcc/requestReview.view?requestId=${requestId}&mode=details + + Animal Request Reviews + DETAILED + rowid + + + Row ID + false + + + Preliminary Score + true + + + Resource Availability Score + true + + + Proposal Score + true + + + Comments + true + + + Request ID + false + + mcc + animalrequests + objectid + rowId + + + + true + + + true + + + false + false + false + true + 29 + true + + + true + + + false + false + false + true + 29 + true + + + Actions + 200 + + org.labkey.mcc.query.RequestScoreActionsDisplayColumnFactory + + + + + ldk.context + + + +
diff --git a/mcc/resources/views/mccAdmin.html b/mcc/resources/views/mccAdmin.html index 892620707..f2a8f3472 100644 --- a/mcc/resources/views/mccAdmin.html +++ b/mcc/resources/views/mccAdmin.html @@ -1,24 +1,64 @@ \ No newline at end of file diff --git a/mcc/resources/views/mccAdmin.view.xml b/mcc/resources/views/mccAdmin.view.xml index 4ed342d30..d3a353e12 100644 --- a/mcc/resources/views/mccAdmin.view.xml +++ b/mcc/resources/views/mccAdmin.view.xml @@ -1,7 +1,7 @@ - - - - + + + + diff --git a/mcc/resources/views/mccFolderInit.html b/mcc/resources/views/mccFolderInit.html new file mode 100644 index 000000000..892620707 --- /dev/null +++ b/mcc/resources/views/mccFolderInit.html @@ -0,0 +1,24 @@ + \ No newline at end of file diff --git a/mcc/resources/views/mccFolderInit.view.xml b/mcc/resources/views/mccFolderInit.view.xml new file mode 100644 index 000000000..c421b1d0f --- /dev/null +++ b/mcc/resources/views/mccFolderInit.view.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/views/mccMenu.html b/mcc/resources/views/mccMenu.html index b6db857d7..8627dd31e 100644 --- a/mcc/resources/views/mccMenu.html +++ b/mcc/resources/views/mccMenu.html @@ -17,57 +17,129 @@ if(!ctx) return; - var panel = Ext4.create('Ext.view.View', { - renderTo: div.id, - cls: 'labkey-iconpanel', - width: 300, - itemId: 'menuPanel', - style: { - padding: '10px' - }, - defaults: { - overItemCls: 'x4-item-over', - trackOver: true - }, - tpl: [ + var menuItemsData = [{ + label: 'Site Home', + name: 'siteHome', + url: LABKEY.ActionURL.buildURL('project', 'begin', 'home'), + visible: true + }, { + label: 'Animal Data', + name: 'animalData', + url: LABKEY.ActionURL.buildURL('project', 'begin', ctx['MCCContainer']), + visible: true + }, { + label: 'Request Help / Contact', + name: 'help', + url: LABKEY.ActionURL.buildURL('mcc', 'contact', 'home'), + visible: true + }]; + + if (MCC.Utils.isRequestAdmin()) { + menuItemsData.push({ + label: 'MCC Site Admin', + name: 'siteAdmin', + url: LABKEY.ActionURL.buildURL('mcc', 'mccAdmin', ctx['MCCContainer']), + visible: true + }) + } + + var menuItemsRequest = [{ + label: 'Submit/Manage Requests', + name: 'requests', + url: LABKEY.ActionURL.buildURL('mcc', 'mccRequests', ctx['MCCRequestContainer']), + visible: true + }] + + if (MCC.Utils.hasRabPermission()) { + menuItemsRequest.push({ + label: 'RAB Reviewer Dashboard', + name: 'reviewerDashboard', + url: LABKEY.ActionURL.buildURL('mcc', 'rabRequestReview', ctx['MCCRequestContainer']), + visible: true + }) + } + + if (MCC.Utils.hasFinalDecisionPermission()) { + menuItemsRequest.push({ + label: 'NIH Review Dashboard', + name: 'nihReview', + url: LABKEY.ActionURL.buildURL('mcc', 'nihReview', ctx['MCCRequestContainer']), + visible: true + }) + } + + if (MCC.Utils.isRequestAdmin()) { + menuItemsRequest.push({ + label: 'Animal Request Administration', + name: 'requestAdmin', + url: LABKEY.ActionURL.buildURL('mcc', 'mccRequestAdmin', ctx['MCCRequestContainer']), + visible: true + }) + } + + var getTemplate = function(title) { + return [ + '' + title + '', '', '', - '', + '', '', '', '
' - ], - store: { - type: 'store', - fields: ['label', 'name', 'url', 'visible'], - data: [{ - label: 'Site Home', - name: 'siteHome', - url: LABKEY.ActionURL.buildURL('project', 'begin', 'home'), - visible: true - }, { - label: 'Animal Requests', - name: 'requests', - url: LABKEY.ActionURL.buildURL('mcc', 'mccRequests', ctx['MCCRequestContainer']), - visible: true - }, { - label: 'Animal Data', - name: 'animalData', - url: LABKEY.ActionURL.buildURL('project', 'begin', ctx['MCCContainer']), - visible: true - }, { - label: 'Request Help / Contact', - name: 'help', - url: LABKEY.ActionURL.buildURL('mcc', 'contact', 'home'), - visible: true + ] + } + + Ext4.create('Ext.panel.Panel', { + renderTo: div.id, + cls: 'labkey-iconpanel', + style: 'padding: 10px;', + border: false, + width: 300, + itemId: 'menuPanel', + minHeight: 50, + items: [{ + xtype: 'panel', + border: false, + style: 'padding-bottom: 10px;', + items: [{ + xtype: 'dataview', + style: 'padding-left: 5px;', + overItemCls: 'x4-item-over', + trackOver: true, + itemSelector: 'div.thumb-wrap', + cls: 'labkey-iconpanel', + tpl: getTemplate('General Items:'), + border: false, + store: { + type: 'store', + fields: ['label', 'name', 'url', 'visible'], + data: menuItemsData + } + }] + },{ + xtype: 'panel', + border: false, + hidden: !menuItemsRequest.length, + items: [{ + xtype: 'dataview', + style: 'padding-left: 5px;', + overItemCls: 'x4-item-over', + trackOver: true, + itemSelector: 'div.thumb-wrap', + cls: 'labkey-iconpanel', + tpl: getTemplate('Animal Requests:'), + border: false, + store: { + type: 'store', + fields: ['label', 'name', 'url', 'visible'], + data: menuItemsRequest + } }] - }, - border: true, - minHeight: 50 + }] }); }); diff --git a/mcc/resources/views/mccRequestAdmin.html b/mcc/resources/views/mccRequestAdmin.html index fbeb00caa..f5f659231 100644 --- a/mcc/resources/views/mccRequestAdmin.html +++ b/mcc/resources/views/mccRequestAdmin.html @@ -6,23 +6,57 @@ if(!ctx) return; + //TODO: + // Review advisory board table + // figure with workflow + Ext4.get(webpart.wrapperDivId).update( 'Below are all pending and historic animal requests to MCC. You can use the edit link to view/update any request. You can also use the left-hand \'Views\' button to toggle between submitted requests, all requests, etc.' + '

' + 'Click Here to View Documentation on the Request Process and Scoring Criteria' + + '
' + + 'Outline of Request Workflow' + + '
' + + 'Manage RAB Members (admin permission needed)' + + '
' + + 'View All Requests' + + '

' + + '
' + + '

' + + '
' + '

' + - '
' + '
' ); LDK.Utils.getBasicQWP({ - title: 'MCC Animal Requests', + title: 'All Pending RAB Reviews', + schemaName: 'mcc', + queryName: 'requestReviews', + viewName: 'Pending Reviews', + showRecordSelectors: false, + showDetailsColumn: false + }).render(webpart.wrapperDivId + '-webpartAssignments'); + + LDK.Utils.getBasicQWP({ + title: 'All Pending MCC Requests', frame: 'left-nav', schemaName: 'mcc', - queryName: 'animalRequests', - viewName: 'Submitted', + queryName: 'requestScores', + //viewName: 'Pending Requests', showRecordSelectors: true, - showDetailsColumn: true, - buttonBar: {position: 'top', includeStandardButtons: true, items: []} + showDetailsColumn: true }).render(webpart.wrapperDivId + '-webpartPending'); + + LDK.Utils.getBasicQWP({ + title: 'Current RAB Members', + //frame: 'none', + schemaName: 'core', + queryName: 'Members', + columns: 'UserId,UserId/FirstName,UserId/LastName,UserId/Email', + filterArray: [LABKEY.Filter.create('GroupId/Name', 'MCC RAB Members')], + showRecordSelectors: false, + showDetailsColumn: false, + buttonBar: {position: 'top', includeStandardButtons: true, items: []} + }).render(webpart.wrapperDivId + '-webpartRAB'); }); \ No newline at end of file diff --git a/mcc/resources/views/mccRequests.html b/mcc/resources/views/mccRequests.html index 84037736d..e7652b3b6 100644 --- a/mcc/resources/views/mccRequests.html +++ b/mcc/resources/views/mccRequests.html @@ -7,7 +7,7 @@ return; Ext4.get(webpart.wrapperDivId).update( - 'Investigators interested in requesting marmosets for their research can submit applications via the animal request portal. Investigators must already have user access to the password protected MCC site to submit these applications. The animal request review process (submission to approval) takes about 10 business days. (Please note that applications are not being accepted yet).' + + 'The MCC is now accepting animal requests! Investigators interested in requesting marmosets for their research can submit applications via the animal request portal. Please note, while you are encouraged to submit your requests now, the review process will not begin until June 2022, and the first animals will not be available until at least September 2022.' + '

' + 'Submit New Animal Request
' + 'Click Here to View Documentation on the Request Process and Scoring Criteria' + diff --git a/mcc/resources/views/nihReview.html b/mcc/resources/views/nihReview.html new file mode 100644 index 000000000..007019081 --- /dev/null +++ b/mcc/resources/views/nihReview.html @@ -0,0 +1,29 @@ + \ No newline at end of file diff --git a/mcc/resources/views/nihReview.view.xml b/mcc/resources/views/nihReview.view.xml new file mode 100644 index 000000000..02b85efcb --- /dev/null +++ b/mcc/resources/views/nihReview.view.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/views/rabRequestReview.html b/mcc/resources/views/rabRequestReview.html new file mode 100644 index 000000000..459fbe186 --- /dev/null +++ b/mcc/resources/views/rabRequestReview.html @@ -0,0 +1,32 @@ + \ No newline at end of file diff --git a/mcc/resources/views/rabRequestReview.view.xml b/mcc/resources/views/rabRequestReview.view.xml new file mode 100644 index 000000000..7e62677d0 --- /dev/null +++ b/mcc/resources/views/rabRequestReview.view.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/mcc/resources/views/requestLogin.html b/mcc/resources/views/requestLogin.html index 6c3b1fb7f..90c7565ad 100644 --- a/mcc/resources/views/requestLogin.html +++ b/mcc/resources/views/requestLogin.html @@ -42,7 +42,7 @@ },{ xtype: 'textfield', labelWidth: 130, - fieldLabel: 'Title', + fieldLabel: 'Job Title', name: 'title', width: 500, allowBlank: false diff --git a/mcc/resources/web/mcc/Utils.js b/mcc/resources/web/mcc/Utils.js index ca9b72c64..95636656b 100644 --- a/mcc/resources/web/mcc/Utils.js +++ b/mcc/resources/web/mcc/Utils.js @@ -12,8 +12,18 @@ MCC.Utils = new function() { var requiredProps = requiredProps || ['MCCContainer', 'MCCRequestContainer']; var missingProps = []; for (var i=0;i 0){ @@ -23,6 +33,24 @@ MCC.Utils = new function() { } return ctx; + }, + + isRequestAdmin: function(){ + var ctx = LABKEY.getModuleContext('mcc'); + + return !!ctx.hasRequestAdminPermission; + }, + + hasRabPermission: function(){ + var ctx = LABKEY.getModuleContext('mcc'); + + return !!ctx.hasRabPermission; + }, + + hasFinalDecisionPermission: function(){ + var ctx = LABKEY.getModuleContext('mcc'); + + return !!ctx.hasFinalDecisionPermission; } } }; \ No newline at end of file diff --git a/mcc/resources/web/mcc/img/mccRequest.png b/mcc/resources/web/mcc/img/mccRequest.png new file mode 100644 index 000000000..adc667f00 Binary files /dev/null and b/mcc/resources/web/mcc/img/mccRequest.png differ diff --git a/mcc/resources/web/mcc/window/ReviewerNotifyWindow.js b/mcc/resources/web/mcc/window/ReviewerNotifyWindow.js new file mode 100644 index 000000000..52505da8d --- /dev/null +++ b/mcc/resources/web/mcc/window/ReviewerNotifyWindow.js @@ -0,0 +1,63 @@ +Ext4.define('MCC.window.ReviewerNotifyWindow', { + extend: 'Ext.window.Window', + + statics: { + buttonHandler: function (dataRegionName) { + var dataRegion = LABKEY.DataRegions[dataRegionName]; + var checked = dataRegion.getChecked(); + if (!checked || !checked.length) { + Ext4.Msg.alert('Error', 'No records selected'); + return; + } + + Ext4.create('MCC.window.ReviewerNotifyWindow', { + dataRegionName: dataRegionName, + rowIds: checked + }).show(); + } + }, + + initComponent: function(){ + Ext4.apply(this, { + bodyStyle: 'padding: 5px;', + width: 500, + modal: true, + title: 'Send Reviewer Notifications', + items: [{ + html: 'This will send a notification email to the reviewers assigned to the ' + this.rowIds.length + ' selected records.', + border: false, + style: 'padding-bottom: 10px;' + }], + buttons: [{ + text: 'Submit', + handler: this.onSubmit, + scope: this + },{ + text: 'Cancel', + handler: function(btn){ + btn.up('window').close(); + } + }] + }); + + this.callParent(arguments); + }, + + onSubmit: function(btn){ + Ext4.Msg.wait('Loading...'); + + LABKEY.Ajax.request({ + url: LABKEY.ActionURL.buildURL('mcc', 'notifyReviewers'), + scope: this, + failure: LDK.Utils.getErrorCallback(), + success: LABKEY.Utils.getCallbackWrapper(function (results) { + Ext4.Msg.hide(); + Ext4.Msg.alert('Success', 'Notification Emails Sent'); + btn.up('window').close(); + }, this), + jsonData: { + rowIds: this.rowIds + } + }); + } +}); \ No newline at end of file diff --git a/mcc/src/client/AnimalRequest/animal-request.tsx b/mcc/src/client/AnimalRequest/animal-request.tsx index 3e76fa3a8..309fa4d05 100644 --- a/mcc/src/client/AnimalRequest/animal-request.tsx +++ b/mcc/src/client/AnimalRequest/animal-request.tsx @@ -1,135 +1,118 @@ -import React, { useState, FormEvent } from 'react' -import { Query, ActionURL, Filter, getServerContext } from '@labkey/api'; -import { nanoid } from 'nanoid' - -import Tooltip from './tooltip' -import Title from './title' -import Input from './input' -import Select from './select' -import CoInvestigators from './co-investigators' -import TextArea from './text-area' -import YesNoRadio from './yes-no-radio' -import AnimalBreeding from './animal-breeding' -import IACUCProtocol from './iacuc-protocol' -import Funding from './funding' -import ResearchArea from './research-area' -import AnimalCohorts from './animal-cohort' -import Button from './button' -import SavingOverlay from './saving-overlay' -import ErrorMessageHandler from './error-message-handler' +import React, { FormEvent, useState } from 'react'; +import { ActionURL, getServerContext, Query } from '@labkey/api'; +import { + AnimalCohort, + AnimalRequestModel, + CoInvestigatorModel, + queryRequestInformation +} from '../components/RequestUtils'; + +import Tooltip from './components/tooltip'; +import Title from './components/title'; +import Input from './components/input'; +import Select from './components/select'; +import CoInvestigators from './components/co-investigators'; +import TextArea from './components/text-area'; +import YesNoRadio from './components/yes-no-radio'; +import AnimalBreeding from './components/animal-breeding'; +import IACUCProtocol from './components/iacuc-protocol'; +import Funding from './components/funding'; +import AnimalCohorts from './components/animal-cohort'; +import Button from './components/button'; +import SavingOverlay from './saving-overlay'; +import ErrorMessageHandler from './components/error-message-handler'; import { + animalWellfarePlaceholder, + certificationLabel, + collaborationsPlaceholder, earlyInvestigatorTooltip, - experimentalRationalePlaceholder, - methodsProposedPlaceholder, collaborationsPlaceholder, - animalWellfarePlaceholder, signingOfficialTooltip, - certificationLabel, existingMarmosetColonyOptions, + existingMarmosetColonyOptions, existingNHPFacilityOptions, - researchUseStatementTooltip -} from './values' - + experimentalRationalePlaceholder, + institutionTypeOptions, + methodsProposedPlaceholder, + signingOfficialTooltip +} from './components/values'; export function AnimalRequest() { const requestId = (new URLSearchParams(window.location.search)).get("requestId") + const [isSubmitting, setIsSubmitting] = useState(false) const [displayOverlay, setDisplayOverlay] = useState(false) - const [stateRollbackOnFailure, setStateRollbackOnFailure] = useState({ - "returned": false, - "data": {"status": "draft", - middleinitial: undefined, - lastname: undefined, - firstname: undefined, - isprincipalinvestigator: undefined, - institutionname: undefined, - institutioncity: undefined, - institutionstate: undefined, - institutioncountry: undefined, - officiallastname: undefined, - officialfirstname: undefined, - officialemail: undefined, - experimentalrationale: undefined, - methodsproposed: undefined, - collaborations: undefined, - existingmarmosetcolony: undefined, - existingnhpfacilities: undefined, - rowid: undefined, - certify: false, - animalwelfare: undefined, - vetlastname: undefined, - vetemail: undefined, - vetfirstname: undefined + const [requestData, setRequestData] = useState(null) + const [stateRollbackOnFailure, setStateRollbackOnFailure] = useState(requestData?.request?.status) + + const [ deletedCohortRecords, setDeletedCohortRecords ] = useState(new Set()) + const [ deletedCoIRecords, setDeletedCoIRecords ] = useState(new Set()) + + function onAddCohort() { + requestData.cohorts.push(new AnimalCohort()) + setRequestData({...requestData}) + } + + function onRemoveCohort(cohort: AnimalCohort) { + // NOTE: dont allow removing all cohorts + if (requestData.cohorts.length > 1) { + requestData.cohorts = [...requestData.cohorts.filter(item => item.uuid !== cohort.uuid)] + + if (cohort.rowid) { + deletedCohortRecords.add(cohort.rowid) + setDeletedCohortRecords(new Set(deletedCohortRecords)) + } + + setRequestData({...requestData}) } - }) - - // On submit, state is managed by the FormData object in handleSubmit. These hooks are only used to propagate values - // from the database into the form via fillForm if there is a requestId - const [isFormQueried, setIsFormQueried] = useState(false) - const [animalRequests, setAnimalRequests] = useState({ - "returned": false, - "data": {"status": "draft", - middleinitial: undefined, - lastname: undefined, - firstname: undefined, - isprincipalinvestigator: undefined, - institutionname: undefined, - institutioncity: undefined, - institutionstate: undefined, - institutioncountry: undefined, - officiallastname: undefined, - officialfirstname: undefined, - officialemail: undefined, - experimentalrationale: undefined, - methodsproposed: undefined, - collaborations: undefined, - existingmarmosetcolony: undefined, - existingnhpfacilities: undefined, - rowid: undefined, - certify: false, - animalwelfare: undefined, - vetlastname: undefined, - vetemail: undefined, - vetfirstname: undefined + } + + function onAddInvestigator() { + requestData.coinvestigators.push(new CoInvestigatorModel()) + setRequestData({...requestData}) + } + + function onRemoveCoInvestigator(coInvestigator: CoInvestigatorModel) { + if (requestData.coinvestigators.length) { + requestData.coinvestigators = [...requestData.coinvestigators.filter(item => item.uuid !== coInvestigator.uuid)] + + if (coInvestigator.rowid) { + deletedCoIRecords.add(coInvestigator.rowid) + setDeletedCoIRecords(new Set(deletedCoIRecords)) + } + + setRequestData({...requestData}) } - }) - const [coinvestigators, setCoinvestigators] = useState({ - "returned": false, - "data": [] - }) - const [animalCohorts, setAnimalCohorts] = useState({ - "returned": false, - "data": [{uuid: nanoid(), rowid: undefined, othercharacteristics: undefined}] - }) - + } + + if (!requestData) { + queryRequestInformation(requestId, handleFailure).then((model) => { + setRequestData(model) + setStateRollbackOnFailure(requestData?.request.status) + }) + } + + if (!requestData || !requestData?.dataLoaded) { + return ( +
+
+
+ ) + } + else if (requestData.dataLoaded === true && !requestData.request) { + return(
There is no request with id: {requestId}
) + } function handleFailure(response) { + console.error(response.exception) + console.error(response) alert(response.exception) //this is probably what you want to show. An example would be to submit data with a long value for middle initial (>14 characters) setDisplayOverlay(false) - setAnimalRequests({ - "returned": stateRollbackOnFailure.returned, - "data": { ...stateRollbackOnFailure.data, status: stateRollbackOnFailure.data.status } - }) + + requestData.request.status = stateRollbackOnFailure + setRequestData({...requestData}) } - - function getRequired() { - switch (animalRequests.data.status) { - case "draft": - return false - case "submitting": - return true - case "submitted": - return false - case "approving": - return true - case "under-review": - return true - case "approving-final": - return true - case "rejecting": - return true - default: - return false - } + function doEnforceRequiredFields() { + return isSubmitting || requestData.request.status !== "Draft" } // The general idea is that users with MCCRequestAdminPermission can edit all states. @@ -140,215 +123,155 @@ export function AnimalRequest() { return true } - if (!animalRequests.data.status) { + if (!requestData.request.status) { return true } - return "draft" === animalRequests.data.status || "submitting" === animalRequests.data.status + return "Draft" === requestData.request.status } - function handleNextStateSubmitButton() { - setIsSubmitting(true); - - if (animalRequests.data.status === "draft") { - setAnimalRequests({ - "returned": true, - "data": { ...animalRequests.data, status:"submitting" } - }); - } else if (animalRequests.data.status === "submitted") { - setAnimalRequests({ - "returned": true, - "data": { ...animalRequests.data, status:"approving" } - }); - } else if (animalRequests.data.status === "under-review") { - setAnimalRequests({ - "returned": true, - "data": { ...animalRequests.data, status:"approving-final" } - }); + function handleSubmitButton(e, isSubmitting) { + setIsSubmitting(isSubmitting); + + if (!isSubmitting) { + // Use this to reset each field's error state + e.target.form.querySelectorAll('input, select, textarea').forEach(function(e){ + e.checkValidity() + }) } } function getSubmitButtonText() { - switch (animalRequests.data.status) { - case "draft": - return "Submit" - case "submitting": + switch (requestData.request.status) { + case "Draft": return "Submit" - case "submitted": - return "Approve Request" - case "approving": - return "Approve Request" - case "under-review": - return "Approve" - case "approving-final": - return "Approve" - case "rejecting": - return "Approve" default: - "Submit" + return "Update Request" } } - - function handleNextStateSaveButton() { - setIsSubmitting(false) - - if (animalRequests.data.status === "submitting") { - setAnimalRequests({ - "returned": true, - "data": { ...animalRequests.data, status:"draft" } - }); - } else if (animalRequests.data.status === "approving") { - setAnimalRequests({ - "returned": true, - "data": { ...animalRequests.data, status:"submitted" } - }); - } else if (animalRequests.data.status === "under-review") { - setIsSubmitting(true) - setAnimalRequests({ - "returned": true, - "data": { ...animalRequests.data, status:"rejecting" } - }); - } - } - function getSaveButtonText() { - switch (animalRequests.data.status) { - case "draft": - return "Save" - case "submitting": - return "Save" - case "submitted": - return "Save" - case "approving": - return "Save" - case "under-review": - return "Reject" - case "approving-final": - return "Reject" - case "rejecting": - return "Reject" - default: - "Save" - } + return "Save" } - - function get_coinvestigator_commands(data, objectId) { + function getCoinvestigatorCommands(data) { let commands = [] - let i = 0 - if(requestId && coinvestigators.data.length > 0) { - for(const coinvestigator of coinvestigators.data) { + if (requestData.coinvestigators.length) { + requestData.coinvestigators.forEach((rec, i) => { commands.push({ - command: "delete", + command: rec.rowid ? "update" : "insert", schemaName: "mcc", queryName: "coinvestigators", rows: [{ - "rowid": coinvestigator.rowid, + "rowid": rec.rowid, + "requestId": requestData.request.objectid, + "lastname": data.get("coinvestigators-" + i + "-lastName"), + "firstname": data.get("coinvestigators-" + i + "-firstName"), + "middleinitial": data.get("coinvestigators-" + i + "-middleInitial"), + "institutionname": data.get("coinvestigators-" + i + "-institution"), }] }) - } + }) } - while(data.get("coinvestigators-" + i + "-lastName") || data.get("coinvestigators-" + i + "-firstName") || - data.get("coinvestigators-" + i + "-middleInitial") || data.get("coinvestigators-" + i + "-institution")) { - commands.push({ - command: "insert", - schemaName: "mcc", - queryName: "coinvestigators", - rows: [{ - "requestId": objectId, - "lastname": data.get("coinvestigators-" + i + "-lastName"), - "firstname": data.get("coinvestigators-" + i + "-firstName"), - "middleinitial": data.get("coinvestigators-" + i + "-middleInitial"), - "institutionname": data.get("coinvestigators-" + i + "-institution"), - }] + if (deletedCoIRecords.size) { + deletedCoIRecords.forEach(rowId => { + commands.push({ + command: "delete", + schemaName: "mcc", + queryName: "coinvestigators", + rows: [{ + "rowid": rowId, + }] + }) }) - - i++ } return commands } - - function get_animal_cohort_commands(data, objectId) { + function getAnimalCohortCommands(data) { let commands = [] - let i = 0 - if(requestId && animalCohorts.data.length > 0) { - for(const cohort of animalCohorts.data) { + if (requestData.cohorts.length) { + requestData.cohorts.forEach((rec, i) => { commands.push({ - command: "delete", + command: rec.rowid ? "update" : "insert", schemaName: "mcc", queryName: "requestcohorts", rows: [{ - "rowid": cohort.rowid, + "rowid": rec.rowid, + "requestId": requestData.request.objectid, + "numberofanimals": data.get("animal-cohorts-" + i + "-numberofanimals"), + "sex": data.get("animal-cohorts-" + i + "-sex"), + "othercharacteristics": data.get("animal-cohorts-" + i + "-othercharacteristics"), }] }) - } + }) } - while(data.get("animal-cohorts-" + i + "-numberofanimals") || data.get("animal-cohorts-" + i + "-sex") || - data.get("animal-cohorts-" + i + "-othercharacteristics")) { - commands.push({ - command: "insert", - schemaName: "mcc", - queryName: "requestcohorts", - rows: [{ - "requestId": objectId, - "numberofanimals": data.get("animal-cohorts-" + i + "-numberofanimals"), - "sex": data.get("animal-cohorts-" + i + "-sex"), - "othercharacteristics": data.get("animal-cohorts-" + i + "-othercharacteristics"), - }] + if (deletedCohortRecords.size) { + deletedCohortRecords.forEach(rowId => { + commands.push({ + command: "delete", + schemaName: "mcc", + queryName: "requestcohorts", + rows: [{ + "rowid": rowId, + }] + }) }) - - i++ } return commands } - function handleSubmit(e: FormEvent) { e.preventDefault() setDisplayOverlay(true) - setStateRollbackOnFailure({ - "returned": animalRequests.returned, - "data": { ...animalRequests.data, status: animalRequests.data.status } - }) - if(animalRequests.data.status === "submitting") { - animalRequests.data.status = "submitted" - } else if(animalRequests.data.status === "approving") { - animalRequests.data.status = "under-review" - } else if(animalRequests.data.status === "approving-final") { - animalRequests.data.status = "approved" - } else if(animalRequests.data.status === "rejecting") { - animalRequests.data.status = "rejected" + // NOTE: the idea is that when the user hits 'submit', this changes Draft to Submitted. + // Any other action preserved the status as-is + if (isSubmitting) { + setStateRollbackOnFailure(requestData.request.status) + if (requestData.request.status === 'Draft') { + requestData.request.status = 'Submitted' + + setRequestData({...requestData}) + } } + + const el = e.currentTarget as HTMLFormElement + const data = new FormData(el) + el.querySelectorAll('select[multiple]').forEach(function(x){ + data.set(x.id, Array.from(x.selectedOptions, option => option.value).join(',')) + }) - const data = new FormData(e.currentTarget as HTMLFormElement) + if (!requestData.request.status) { + console.error('Request being submitted without a status!') + } - const objectId = requestId || nanoid() - let coinvestigatorCommands = get_coinvestigator_commands(data, objectId) - let cohortCommands = get_animal_cohort_commands(data, objectId) + if (!requestData.request.objectid) { + console.error('Request being submitted without an objectId!') + } - let rowId = requestId ? {"rowid": animalRequests.data.rowid} : {} + // NOTE: use a proper v4 UUID so this is compatible with the sqlserver ENTITYID datatype + let coinvestigatorCommands = getCoinvestigatorCommands(data) + let cohortCommands = getAnimalCohortCommands(data) Query.saveRows({ - commands: [ - { - command: requestId ? "update" : "insert", + commands: [{ + command: requestData.request.rowid ? "update" : "insert", schemaName: "mcc", queryName: "animalrequests", rows: [{ - "objectId": objectId, + "rowid": requestData.request.rowid, + "objectId": requestData.request.objectid, "lastname": data.get("investigator-last-name"), "firstname": data.get("investigator-first-name"), "middleinitial": data.get("investigator-middle-initial"), - "isprincipalinvestigator": data.get("is-principal-investigator"), + "earlystageinvestigator": data.get("is-early-stage-investigator"), "institutionname": data.get("institution-name"), "institutioncity": data.get("institution-city"), "institutionstate": data.get("institution-state"), @@ -363,12 +286,10 @@ export function AnimalRequest() { "collaborations": data.get("collaborations"), "isbreedinganimals": data.get("animal-breeding-is-planning-to-breed-animals"), "breedingpurpose": data.get("animal-breeding-purpose"), - "researcharea": data.get("research-area"), - "otherjustification": data.get("research-area-other-specify"), "existingmarmosetcolony": data.get("existing-marmoset-colony"), "existingnhpfacilities": data.get("existing-nhp-facilities"), "animalwelfare": data.get("animal-welfare"), - "certify": data.get("certify"), + "certify": !!data.get("certify"), "vetlastname": data.get("vet-last-name"), "vetfirstname": data.get("vet-first-name"), "vetemail": data.get("vet-email"), @@ -376,352 +297,356 @@ export function AnimalRequest() { "iacucprotocol": data.get("iacuc-protocol"), "grantnumber" : data.get("funding-grant-number"), "applicationduedate": data.get("funding-application-due-date"), - "status": animalRequests.data.status, - ...rowId + "status": requestData.request.status, }] }, ...coinvestigatorCommands, ...cohortCommands ], success: function(response) { - window.location.href = ActionURL.buildURL('mcc', 'mccRequests.view') - }, - failure: handleFailure - }) - } + // set RowIDs: + if (response.result[0].queryName !== 'animalrequests') { + console.error('The first command was not animal requests! This is not expected.') + } + + const rowId = response.result[0].rows[0].rowid + if (!rowId) { + console.error('No rowId found for the animalrequest row after save. This is not expected.') + } + else { + requestData.request.rowid = rowId + } + + if (response.result[0].rows[0].rowid.status) { + requestData.request.status = response.result[0].rows[0].rowid.status + } + else { + console.error('Status was null for the animalrequest row after save. This is not expected.') + } + + response.result.filter(x => x.command !== 'delete' && x.queryName === 'requestcohorts').forEach((x, idx) => { + if (requestData.cohorts.length < idx) { + console.error('There are more cohort saveRows commands than client-side records') + return + } + + if (x.rows.length != 1) { + console.error('Expected a single row per cohort saveRows command, found: ' + x.rows.length) + return + } + + if (requestData.cohorts[idx].rowid && requestData.cohorts[idx].rowid != x.rows[0].rowid) { + console.error('Cohort row has existing rowId but doesnt match the server: ' + requestData.cohorts[idx].rowid + ' / ' + x.rows[0].rowid) + return + } + + requestData.cohorts[idx].rowid = x.rows[0].rowid + }) + response.result.filter(x => x.command !== 'delete' && x.queryName === 'coinvestigators').forEach((x, idx) => { + if (requestData.coinvestigators.length < idx) { + console.error('There are more coinvestigators saveRows commands than client-side records') + return + } - function fillForm() { - setIsFormQueried(true) - - Query.selectRows({ - schemaName: "mcc", - queryName: "animalrequests", - columns: [ - "rowid", - "objectId", - "lastname", - "firstname", - "middleinitial", - "isprincipalinvestigator", - "institutionname", - "institutioncity", - "institutionstate", - "institutioncountry", - "institutiontype", - "officiallastname", - "officialfirstname", - "officialemail", - "fundingsource", - "experimentalrationale", - "methodsproposed", - "collaborations", - "isbreedinganimals", - "breedingpurpose", - "researcharea", - "otherjustification", - "existingmarmosetcolony", - "existingnhpfacilities", - "animalwelfare", - "certify", - "vetlastname", - "vetfirstname", - "vetemail", - "iacucapproval", - "iacucprotocol", - "grantnumber", - "applicationduedate", - "status" - ], - filterArray: [ - Filter.create('objectId', requestId) - ], - success: function(resp) { - let returnedData = resp.rows[0] + if (x.rows.length != 1) { + console.error('Expected a single row per coinvestigators saveRows command, found: ' + x.rows.length) + return + } - setAnimalRequests({ - "returned": true, - "data": returnedData - }) - }, - failure: handleFailure - }) + if (requestData.coinvestigators[idx].rowid && requestData.coinvestigators[idx].rowid != x.rows[0].rowid) { + console.error('Coinvestigators row has existing rowId but doesnt match the server: ' + requestData.coinvestigators[idx].rowid + ' / ' + x.rows[0].rowid) + return + } + requestData.coinvestigators[idx].rowid = x.rows[0].rowid + }) - Query.selectRows({ - schemaName: "mcc", - queryName: "coinvestigators", - columns: [ - "rowid", - "requestId", - "lastname", - "firstname", - "middleinitial", - "institutionname", - ], - filterArray: [ - Filter.create('requestId', requestId) - ], - success: function(resp) { - let returnedData = resp.rows - setCoinvestigators({ - "returned": true, - "data": returnedData + response.result.filter(x => x.command === 'delete').forEach((x, idx) => { + if (x.rows.length != 1) { + console.error('Expected a single row per saveRows delete command, found: ' + x.rows.length) + return + } + + const rowId = x.rows[0].rowid + if (x.queryName === 'requestcohorts') { + deletedCohortRecords.delete(rowId) + setDeletedCohortRecords(new Set(deletedCohortRecords)) + } + else if (x.queryName === 'coinvestigators') { + deletedCoIRecords.delete(rowId) + setDeletedCoIRecords(new Set(deletedCoIRecords)) + } }) - }, - failure: handleFailure - }) + if (deletedCoIRecords.size) { + console.log('there are still records in deletedCoIRecords: ' + deletedCoIRecords.size) + } - Query.selectRows({ - schemaName: "mcc", - queryName: "requestcohorts", - columns: [ - "rowid", - "requestId", - "numberofanimals", - "sex", - "othercharacteristics", - ], - filterArray: [ - Filter.create('requestId', requestId) - ], - success: function(resp) { - let returnedData = resp.rows - setAnimalCohorts({ - "returned": true, - "data": returnedData + if (deletedCohortRecords.size) { + console.log('there are still records in deletedCohortRecords: ' + deletedCohortRecords.size) + } + + setRequestData({...requestData}) + setStateRollbackOnFailure(requestData.request.status) + + if (!requestData.request.rowid) { + console.error("Missing request rowid after save") + } + + requestData.cohorts.forEach(x => { + if (!x.rowid) { + console.error("Missing cohort rowid after save") + } + }) + + requestData.coinvestigators.forEach(x => { + if (!x.rowid) { + console.error("Missing coinvestigator rowid after save") + } }) + + setDisplayOverlay(false) + if (isSubmitting) { + const returnURL = (new URLSearchParams(window.location.search)).get("requestId") + let dest = ActionURL.buildURL('mcc', 'mccRequests.view') + if (returnURL) { + try { + dest = new URL(returnURL).href + } + catch (e) { + + } + } + + window.location.href = dest + } }, failure: handleFailure }) - } + return ( + <> +
+

General Information

+ +
+ - if (requestId && (animalRequests.returned === false || coinvestigators.returned === false || animalCohorts.returned === false)) { - if (isFormQueried === false) { - fillForm() - } + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="investigator-last-name" ariaLabel="Last Name" isSubmitting={isSubmitting} required={doEnforceRequiredFields()} placeholder="Last Name" defaultValue={requestData.request.lastname}/> + </div> - return ( - <div className="tw-flex tw-justify-center tw-items-center"> - <div style={{ borderBottom: "2px solid #3495d2" }} className="tw-animate-spin tw-rounded-full tw-h-32 tw-w-32"></div> - </div> - ) - } else if (requestId && animalRequests.returned === true && animalRequests.data === undefined) { - return(<Title text="No such request."/>) - } else { - return ( - <> - <form className="tw-w-full tw-max-w-4xl" onSubmit={handleSubmit} autoComplete="off"> - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <Title text="Principal Investigator*"/> + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="investigator-first-name" ariaLabel="First Name" isSubmitting={isSubmitting} required={doEnforceRequiredFields()} placeholder="First Name" defaultValue={requestData.request.firstname}/> + </div> - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="investigator-last-name" ariaLabel="Last Name" isSubmitting={isSubmitting} required={getRequired()} placeholder="Last Name" defaultValue={animalRequests.data.lastname}/> - </div> + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="investigator-middle-initial" isSubmitting={isSubmitting} required={false} placeholder="Middle Initial" defaultValue={requestData.request.middleinitial} maxLength="8"/> + </div> + </div> + </ErrorMessageHandler> + + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> + <div className="tw-relative tw-w-full tw-mb-6 md:tw-mb-0"> + <Title text="2. Are you an early-stage investigator? "/> + <Tooltip id="early-stage-investigator-helper" + text={earlyInvestigatorTooltip} + /> + </div> - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="investigator-first-name" ariaLabel="First Name" isSubmitting={isSubmitting} required={getRequired()} placeholder="First Name" defaultValue={animalRequests.data.firstname}/> - </div> + <div className="tw-w-full tw-px-3 tw-mt-6"> + <YesNoRadio id="is-early-stage-investigator" ariaLabel="Early Stage Investigator" isSubmitting={isSubmitting} required={doEnforceRequiredFields()} defaultValue={requestData.request.earlystageinvestigator}/> + </div> + </div> + </ErrorMessageHandler> - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="investigator-middle-initial" isSubmitting={isSubmitting} required={false} placeholder="Middle Initial" defaultValue={animalRequests.data.middleinitial} maxLength="8"/> - </div> + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> + <Title text="3. Affiliated research institution*"/> + + <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="institution-name" ariaLabel="Institution Name" isSubmitting={isSubmitting} placeholder="Name" required={doEnforceRequiredFields()} defaultValue={requestData.request.institutionname}/> </div> - </ErrorMessageHandler> - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <div className="tw-relative tw-w-full tw-mb-6 md:tw-mb-0"> - <Title text="Are you an early-stage investigator? "/> - <Tooltip id="early-stage-investigator-helper" - text={earlyInvestigatorTooltip} - /> - </div> + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="institution-city" ariaLabel="Institution City" isSubmitting={isSubmitting} placeholder="City" required={doEnforceRequiredFields()} defaultValue={requestData.request.institutioncity}/> + </div> - <div className="tw-w-full tw-px-3 tw-mt-6"> - <YesNoRadio id="is-principal-investigator" ariaLabel="Principal Investigator" isSubmitting={isSubmitting} required={getRequired()} defaultValue={animalRequests.data.isprincipalinvestigator}/> - </div> + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="institution-state" ariaLabel="Institution State" isSubmitting={isSubmitting} placeholder="State" required={doEnforceRequiredFields()} defaultValue={requestData.request.institutionstate}/> </div> - </ErrorMessageHandler> - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <Title text="Affiliated research institution*"/> + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="institution-country" ariaLabel="Institution Country" isSubmitting={isSubmitting} placeholder="Country" required={doEnforceRequiredFields()} defaultValue={requestData.request.institutioncountry}/> + </div> - <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="institution-name" ariaLabel="Institution Name" isSubmitting={isSubmitting} placeholder="Name" required={getRequired()} defaultValue={animalRequests.data.institutionname}/> - </div> + <Title text="4. Affiliated Research Institution Type*"/> - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="institution-city" ariaLabel="Institution City" isSubmitting={isSubmitting} placeholder="City" required={getRequired()} defaultValue={animalRequests.data.institutioncity}/> - </div> + <div className="tw-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Select id="institution-type" ariaLabel="Institution Type" isSubmitting={isSubmitting} placeholder="Type" required={doEnforceRequiredFields()} defaultValue={requestData.request.institutiontype} options={institutionTypeOptions}/> + </div> + </div> + </ErrorMessageHandler> + + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> + <div className="tw-relative tw-w-full tw-mb-6 md:tw-mb-0"> + <Title text="5. Institution Signing Official* "/> + <Tooltip id="signing-official-helper" + text={signingOfficialTooltip} + /> + </div> - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="institution-state" ariaLabel="Institution State" isSubmitting={isSubmitting} placeholder="State" required={getRequired()} defaultValue={animalRequests.data.institutionstate}/> + + <div className="tw-flex tw-flex-wrap tw-mt-6"> + <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="official-last-name" ariaLabel="Last Name" isSubmitting={isSubmitting} placeholder="Last Name" required={doEnforceRequiredFields()} defaultValue={requestData.request.officiallastname}/> </div> - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="institution-country" ariaLabel="Institution Country" isSubmitting={isSubmitting} placeholder="Country" required={getRequired()} defaultValue={animalRequests.data.institutioncountry}/> + <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="official-first-name" ariaLabel="First Name" isSubmitting={isSubmitting} placeholder="First Name" required={doEnforceRequiredFields()} defaultValue={requestData.request.officialfirstname}/> </div> - </div> - </ErrorMessageHandler> - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <div className="tw-relative tw-w-full tw-mb-6 md:tw-mb-0"> - <Title text="Institution Signing Official* "/> - <Tooltip id="signing-official-helper" - text={signingOfficialTooltip} - /> + <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="official-email" ariaLabel="Email Address" isSubmitting={isSubmitting} placeholder="Email Address" required={doEnforceRequiredFields()} defaultValue={requestData.request.officialemail}/> </div> + </div> + </div> + </ErrorMessageHandler> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-10"> + <Title text="6. Co-Investigators"/> - <div className="tw-flex tw-flex-wrap tw-mt-6"> - <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="official-last-name" ariaLabel="Last Name" isSubmitting={isSubmitting} placeholder="Last Name" required={getRequired()} defaultValue={animalRequests.data.officiallastname}/> - </div> + <CoInvestigators isSubmitting={isSubmitting} required={doEnforceRequiredFields()} coinvestigators={requestData.coinvestigators} onAddRecord={onAddInvestigator} onRemoveRecord={onRemoveCoInvestigator} /> + </div> - <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="official-first-name" ariaLabel="First Name" isSubmitting={isSubmitting} placeholder="First Name" required={getRequired()} defaultValue={animalRequests.data.officialfirstname}/> - </div> + <Title text="7. Existing or proposed funding source (select all that apply)"/> + {/* TODO: Make into checkbox group*/} + <Funding id="funding" isSubmitting={isSubmitting} defaultValue={requestData.request} required={doEnforceRequiredFields()}/> - <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="official-email" ariaLabel="Email Address" isSubmitting={isSubmitting} placeholder="Email Address" required={getRequired()} defaultValue={animalRequests.data.officialemail}/> - </div> + <h3>Institutional Animal Facilities and Capabilities</h3> + <div className="tw-w-full tw-px-3"> + <Title text="1. Does your institution have existing NHP facilities?"/> + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> + <Select id="existing-nhp-facilities" ariaLabel="Existing NHP Facilities" isSubmitting={isSubmitting} options={existingNHPFacilityOptions} defaultValue={requestData.request.existingnhpfacilities} required={doEnforceRequiredFields()}/> </div> - </div> </ErrorMessageHandler> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-10"> - <Title text="Co-investigators"/> + <Title text="2. Does your institution have an existing marmoset colony?"/> + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> + <Select id="existing-marmoset-colony" ariaLabel="Existing Marmoset Colony" isSubmitting={isSubmitting} options={existingMarmosetColonyOptions} defaultValue={requestData.request.existingmarmosetcolony} required={doEnforceRequiredFields()}/> + </div> + </ErrorMessageHandler> - <CoInvestigators isSubmitting={isSubmitting} defaultValue={coinvestigators.data} required={getRequired()}/> + <Title text="3. Do you plan to breed marmosets?"/> + <div className="tw-w-full tw-px-3 tw-mb-4"> + <AnimalBreeding id="animal-breeding" isSubmitting={isSubmitting} request={requestData.request} required={doEnforceRequiredFields()}/> </div> + </div> - <Funding id="funding" isSubmitting={isSubmitting} defaultValue={animalRequests.data} required={getRequired()}/> + <h3>Research Details</h3> - <div className="tw-flex tw-flex-wrap tw-mx-2"> - <div className="tw-relative tw-w-full tw-mb-6 md:tw-mb-0"> - <Title text="Research Use Statement* "/> - <Tooltip id="research-use-statement-helper" - text={experimentalRationalePlaceholder} - /> - </div> + <div className="tw-flex tw-flex-wrap tw-mx-2"> + <div className="tw-w-full tw-px-3 tw-mb-4"> + <Title text={"1. " + experimentalRationalePlaceholder}/> + <Tooltip id="research-use-statement-helper" + text={experimentalRationalePlaceholder} + /> <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-w-full tw-px-3 tw-mb-6 tw-mt-6"> - <TextArea id="experiment-rationale" ariaLabel="Experimental rationale" isSubmitting={isSubmitting} placeholder={experimentalRationalePlaceholder} required={getRequired()} defaultValue={animalRequests.data.experimentalrationale}/> - </div> + <TextArea id="experiment-rationale" ariaLabel="Experimental rationale" isSubmitting={isSubmitting} placeholder={experimentalRationalePlaceholder} required={doEnforceRequiredFields()} defaultValue={requestData.request.experimentalrationale}/> </ErrorMessageHandler> + </div> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-6"> - <Title text="Animal Cohorts"/> - - <AnimalCohorts isSubmitting={isSubmitting} defaultValue={animalCohorts.data} required={getRequired()}/> - </div> + <Title text="2. Animal Cohorts"/> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-6"> + <AnimalCohorts isSubmitting={isSubmitting} cohorts={requestData.cohorts} required={doEnforceRequiredFields()} onAddCohort={onAddCohort} onRemoveCohort={onRemoveCohort}/> + </div> + <Title text={"3. " + methodsProposedPlaceholder}/> + <div className="tw-w-full tw-px-3 tw-mb-6"> <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-w-full tw-px-3 tw-mb-4"> - <TextArea id="methods-proposed" ariaLabel="Methods Proposed" isSubmitting={isSubmitting} placeholder={methodsProposedPlaceholder} required={getRequired()} defaultValue={animalRequests.data.methodsproposed}/> + <div className="tw-w-full tw-px-3 tw-mb-6"> + <TextArea id="methods-proposed" ariaLabel="Methods Proposed" isSubmitting={isSubmitting} placeholder={methodsProposedPlaceholder} required={doEnforceRequiredFields()} defaultValue={requestData.request.methodsproposed}/> </div> </ErrorMessageHandler> + </div> + <Title text={"4. " + collaborationsPlaceholder}/> + <div className="tw-w-full tw-px-3 tw-mb-6"> <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-w-full tw-px-3 tw-mb-4"> - <TextArea id="collaborations" ariaLabel="Collaborations" isSubmitting={isSubmitting} placeholder={collaborationsPlaceholder} required={getRequired()} defaultValue={animalRequests.data.collaborations}/> + <div className="tw-w-full tw-px-3 tw-mb-6"> + <TextArea id="collaborations" ariaLabel="Collaborations" isSubmitting={isSubmitting} placeholder={collaborationsPlaceholder} required={doEnforceRequiredFields()} defaultValue={requestData.request.collaborations}/> </div> </ErrorMessageHandler> + </div> - <div className="tw-w-full tw-px-3 tw-mb-4"> - <div className="tw-mb-6"> - <Title text="Do you plan to breed animals?"/> - </div> - <AnimalBreeding id="animal-breeding" isSubmitting={isSubmitting} defaultValue={animalRequests.data} required={getRequired()}/> - </div> - - <ResearchArea id="research-area" isSubmitting={isSubmitting} defaultValue={animalRequests.data} required={getRequired()}/> - - <div className="tw-w-full tw-px-3"> - <div className="tw-mb-6"> - <Title text="Institutional Animal Facilities and Capabilities"/> - </div> - - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <Title text="Does your institution have an existing marmoset colony?"/> - <Select id="existing-marmoset-colony" ariaLabel="Existing Marmoset Colony" isSubmitting={isSubmitting} options={existingMarmosetColonyOptions} defaultValue={animalRequests.data.existingmarmosetcolony} required={getRequired()}/> - </div> - </ErrorMessageHandler> - - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <Title text="Does your institution have existing NHP facilities?"/> - <Select id="existing-nhp-facilities" ariaLabel="Existing NHP Facilities" isSubmitting={isSubmitting} options={existingNHPFacilityOptions} defaultValue={animalRequests.data.existingnhpfacilities} required={getRequired()}/> - </div> - </ErrorMessageHandler> + <Title text={"5. " + animalWellfarePlaceholder}/> + <div className="tw-w-full tw-px-3 tw-mb-6"> + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-w-full tw-px-3 tw-mb-6"> + <TextArea id="animal-welfare" ariaLabel="Animal Welfare" isSubmitting={isSubmitting} placeholder={animalWellfarePlaceholder} required={doEnforceRequiredFields()} defaultValue={requestData.request.animalwelfare}/> </div> + </ErrorMessageHandler> + <ErrorMessageHandler isSubmitting={isSubmitting}> <div className="tw-w-full tw-px-3 tw-mb-6"> - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-w-full tw-px-3 tw-mb-6"> - <TextArea id="animal-welfare" ariaLabel="Animal Welfare" isSubmitting={isSubmitting} placeholder={animalWellfarePlaceholder} required={getRequired()} defaultValue={animalRequests.data.animalwelfare}/> - </div> - </ErrorMessageHandler> - - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-w-full tw-px-3 tw-mb-6"> - <input type="checkbox" name="certify" id="certify" aria-label="Certify" className={(isSubmitting ? "custom-invalid" : "")} required={getRequired()} defaultChecked={animalRequests.data.certify}/> - <label className="tw-text-gray-700 ml-1">{certificationLabel}</label> - </div> - </ErrorMessageHandler> + <input type="checkbox" name="certify" id="certify" aria-label="Certify" className={(isSubmitting ? "custom-invalid" : "")} required={doEnforceRequiredFields()} defaultChecked={requestData.request.certify}/> + <label className="tw-text-gray-700 ml-1">{certificationLabel}</label> </div> + </ErrorMessageHandler> + </div> - <ErrorMessageHandler isSubmitting={isSubmitting}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <Title text="Attending veterinarian"/> + <ErrorMessageHandler isSubmitting={isSubmitting}> + <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> + <Title text="6. Attending veterinarian"/> - <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="vet-last-name" ariaLabel="Last Name" isSubmitting={isSubmitting} placeholder="Last Name" required={getRequired()} defaultValue={animalRequests.data.vetlastname}/> - </div> + <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="vet-last-name" ariaLabel="Last Name" isSubmitting={isSubmitting} placeholder="Last Name" required={doEnforceRequiredFields()} defaultValue={requestData.request.vetlastname}/> + </div> - <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="vet-first-name" ariaLabel="First Name" isSubmitting={isSubmitting} placeholder="First Name" required={getRequired()} defaultValue={animalRequests.data.vetfirstname}/> - </div> + <div className="tw-w-full md:tw-w-1/2 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="vet-first-name" ariaLabel="First Name" isSubmitting={isSubmitting} placeholder="First Name" required={doEnforceRequiredFields()} defaultValue={requestData.request.vetfirstname}/> + </div> - <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id="vet-email" ariaLabel="Email" isSubmitting={isSubmitting} placeholder="Email Address" required={getRequired()} defaultValue={animalRequests.data.vetemail}/> - </div> + <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id="vet-email" ariaLabel="Email" isSubmitting={isSubmitting} placeholder="Email Address" required={doEnforceRequiredFields()} defaultValue={requestData.request.vetemail}/> </div> - </ErrorMessageHandler> </div> - - <IACUCProtocol id="iacuc" isSubmitting={isSubmitting} required={getRequired()} defaultValue={animalRequests.data}/> + </ErrorMessageHandler> + </div> - <div className="tw-flex tw-flex-wrap tw-mx-2"> - <button className="tw-ml-auto tw-bg-red-500 hover:tw-bg-red-400 tw-text-white tw-font-bold tw-py-4 tw-mt-2 tw-px-6 tw-border-none tw-rounded" onClick={(e) => { - e.preventDefault() + <IACUCProtocol id="iacuc" isSubmitting={isSubmitting} required={doEnforceRequiredFields()} request={requestData.request}/> - if (confirm("You are about to leave this page.")) { - window.location.href = ActionURL.buildURL('mcc', 'mccRequests.view'); - } - }}>Cancel</button> + <div className="tw-flex tw-flex-wrap tw-mx-2"> + <Title text="Request Status: "/>{requestData.request.status} + </div> - <Button onClick={() => { - handleNextStateSaveButton(); - }} text={getSaveButtonText()} display={hasEditPermission() && animalRequests.data.status != "rejected"}/> + <div className="tw-flex tw-flex-wrap tw-mx-2"> + <button className="tw-ml-auto tw-bg-red-500 hover:tw-bg-red-400 tw-text-white tw-font-bold tw-py-4 tw-mt-2 tw-px-6 tw-border-none tw-rounded" onClick={(e) => { + e.preventDefault() - <Button onClick={() => { - handleNextStateSubmitButton(); - }} text={getSubmitButtonText()} display={hasEditPermission() && animalRequests.data.status != "rejected"}/> - </div> - </form> + if (confirm("You are about to leave this page.")) { + window.location.href = ActionURL.buildURL('mcc', 'mccRequests.view'); + } + }}>Cancel</button> + + <Button onClick={(e) => { + handleSubmitButton(e, false); + }} text={getSaveButtonText()} display={hasEditPermission()}/> + + <Button onClick={(e) => { + handleSubmitButton(e, true); + }} text={getSubmitButtonText()} display={hasEditPermission()}/> + </div> + </form> - <SavingOverlay display={displayOverlay} /> - </> - ) - } + <SavingOverlay display={displayOverlay} /> + </> + ) } diff --git a/mcc/src/client/AnimalRequest/app.tsx b/mcc/src/client/AnimalRequest/app.tsx index 54fcf9081..a7fdfdd8d 100644 --- a/mcc/src/client/AnimalRequest/app.tsx +++ b/mcc/src/client/AnimalRequest/app.tsx @@ -1,11 +1,15 @@ import React from 'react' import ReactDOM from 'react-dom' +import { ErrorBoundary } from '@labkey/components'; -import './tailwind.css'; +import '../tailwind.css'; import { AnimalRequest } from './animal-request' // Need to wait for container element to be available in labkey wrapper before render window.addEventListener('DOMContentLoaded', (event) => { - ReactDOM.render(<AnimalRequest />, document.getElementById('app')); + ReactDOM.render( + <ErrorBoundary> + <AnimalRequest/> + </ErrorBoundary>, document.getElementById('app')); }); diff --git a/mcc/src/client/AnimalRequest/co-investigators.tsx b/mcc/src/client/AnimalRequest/co-investigators.tsx deleted file mode 100644 index 16d939395..000000000 --- a/mcc/src/client/AnimalRequest/co-investigators.tsx +++ /dev/null @@ -1,67 +0,0 @@ -import React, { useState, Fragment } from 'react' -import { nanoid } from 'nanoid' - -import Input from './input' -import Title from './title' -import ErrorMessageHandler from './error-message-handler' - -export default function CoInvestigators(props) { - const [coInvestigators, setCoInvestigators] = useState(new Set( - props.defaultValue.map((coInvestigator) => ({ - ...coInvestigator, - "uuid": nanoid() - })) - )) - - function addInvestigator() { - coInvestigators.add({ - "uuid": nanoid() - }) - setCoInvestigators(new Set(coInvestigators)) - } - - function removeCoInvestigator(coInvestigator) { - coInvestigators.delete(coInvestigator) - setCoInvestigators(new Set(coInvestigators)) - } - - return ( - <> - {[...coInvestigators].map((coInvestigator, index) => ( - <ErrorMessageHandler isSubmitting={props.isSubmitting} keyInternal={coInvestigator.uuid} key={coInvestigator.uuid + "-errorHandler"}> - <div className="tw-flex tw-flex-wrap tw-w-full tw-mx-2 tw-mb-4" key={coInvestigator.uuid}> - <div className="tw-flex tw-flex-wrap tw-w-full tw-mb-6"> - <div className="tw-w-1/2 md:tw-mb-0"> - <Title text={ "Co-Investigator " + (index + 1)} /> - </div> - - <div className="tw-flex tw-flex-wrap tw-w-full md:tw-w-1/2 md:tw-mb-0"> - <input type="button" className="tw-ml-auto tw-bg-red-500 hover:tw-bg-red-400 tw-text-white tw-font-bold tw-py-2 tw-px-4 tw-border-none tw-rounded" onClick={() => removeCoInvestigator(coInvestigator)} value="Remove" /> - </div> - </div> - - <div className="tw-w-full md:tw-w-1/3 tw-px-3 md:tw-mb-0"> - <Input id={"coinvestigators-" + index + "-" + "lastName"} ariaLabel={"Last Name" + "#" + index} isSubmitting={props.isSubmitting} placeholder="Last Name" required={props.required} defaultValue={coInvestigator.lastname}/> - </div> - - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id={"coinvestigators-" + index + "-" + "firstName"} ariaLabel={"First Name" + "#" + index} isSubmitting={props.isSubmitting} placeholder="First Name" required={props.required} defaultValue={coInvestigator.firstname}/> - </div> - - <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id={"coinvestigators-" + index + "-" + "middleInitial"} ariaLabel={"Middle Initial" + "#" + index} isSubmitting={props.isSubmitting} placeholder="Middle Initial" required={false} defaultValue={coInvestigator.middleinitial} maxLength="8"/> - </div> - - <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> - <Input id={"coinvestigators-" + index + "-" + "institution"} ariaLabel={"Institution" + "#" + index} isSubmitting={props.isSubmitting} placeholder="Institution" required={props.required} defaultValue={coInvestigator.institutionname}/> - </div> - </div> - </ErrorMessageHandler> - ))} - - <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> - <input type="button" className="tw-bg-blue-500 hover:tw-bg-blue-400 tw-text-white tw-font-bold tw-py-2 tw-mt-2 tw-px-4 tw-border-none tw-rounded" onClick={addInvestigator} value="Add Co-investigator" /> - </div> - </> - ) -} diff --git a/mcc/src/client/AnimalRequest/animal-breeding.tsx b/mcc/src/client/AnimalRequest/components/animal-breeding.tsx similarity index 74% rename from mcc/src/client/AnimalRequest/animal-breeding.tsx rename to mcc/src/client/AnimalRequest/components/animal-breeding.tsx index 05066f3be..0be59f075 100644 --- a/mcc/src/client/AnimalRequest/animal-breeding.tsx +++ b/mcc/src/client/AnimalRequest/components/animal-breeding.tsx @@ -5,10 +5,11 @@ import TextArea from './text-area' import ErrorMessageHandler from './error-message-handler' import { animalBreedingPlaceholder } from './values' +import { AnimalRequestProps } from '../../components/RequestUtils'; -export default function AnimalBreeding(props) { +export default function AnimalBreeding(props: {request: AnimalRequestProps, isSubmitting: boolean, required: boolean, id: string}) { - const [displayPurpose, setDisplayPurpose] = useState(props.defaultValue.isbreedinganimals === true ? true : false) + const [displayPurpose, setDisplayPurpose] = useState(props.request.isbreedinganimals === true) function setDisplayPurposeField(value) { if(value == "yes") { @@ -21,13 +22,13 @@ export default function AnimalBreeding(props) { return ( <ErrorMessageHandler isSubmitting={props.isSubmitting}> <div className="tw-mb-6"> - <YesNoRadio id={props.id + "-is-planning-to-breed-animals"} ariaLabel="Planning to breed animals" isSubmitting={props.isSubmitting} required={props.required} defaultValue={props.defaultValue.isbreedinganimals} + <YesNoRadio id={props.id + "-is-planning-to-breed-animals"} ariaLabel="Planning to breed animals" isSubmitting={props.isSubmitting} required={props.required} defaultValue={props.request.isbreedinganimals} onChange={(e) => setDisplayPurposeField(e.currentTarget.value)}/> </div> <div className="tw-mb-6"> <TextArea id={props.id + "-purpose"} ariaLabel="Breeding Program Purpose" isSubmitting={props.isSubmitting} placeholder={animalBreedingPlaceholder} - display={displayPurpose} required={displayPurpose && props.required} defaultValue={props.defaultValue.breedingpurpose}/> + display={displayPurpose} required={displayPurpose && props.required} defaultValue={props.request.breedingpurpose}/> </div> </ErrorMessageHandler> ) diff --git a/mcc/src/client/AnimalRequest/animal-cohort.tsx b/mcc/src/client/AnimalRequest/components/animal-cohort.tsx similarity index 70% rename from mcc/src/client/AnimalRequest/animal-cohort.tsx rename to mcc/src/client/AnimalRequest/components/animal-cohort.tsx index 85c1d9b58..77aa95ca4 100644 --- a/mcc/src/client/AnimalRequest/animal-cohort.tsx +++ b/mcc/src/client/AnimalRequest/components/animal-cohort.tsx @@ -1,39 +1,18 @@ -import React, { useState, Fragment } from 'react' -import { nanoid } from 'nanoid' +import React from 'react'; -import InputNumber from './input-number' -import Select from './select' -import Title from './title' -import TextArea from './text-area' -import ErrorMessageHandler from './error-message-handler' +import InputNumber from './input-number'; +import Select from './select'; +import Title from './title'; +import TextArea from './text-area'; +import ErrorMessageHandler from './error-message-handler'; -import { animalSexes, otherCharacteristicsPlaceholder } from './values' - -export default function AnimalCohorts(props) { - const [cohorts, setCohorts] = useState(new Set( - props.defaultValue.map((cohort) => ({ - ...cohort, - "uuid": nanoid() - })) - )) - - function addCohort() { - cohorts.add({ - "uuid": nanoid() - }) - setCohorts(new Set(cohorts)) - } - - function removeCohort(cohort) { - if(cohorts.size > 1) { - cohorts.delete(cohort) - setCohorts(new Set(cohorts)) - } - } +import { animalSexes, otherCharacteristicsPlaceholder } from './values'; +import { AnimalCohort } from '../../components/RequestUtils'; +export default function AnimalCohorts(props: { cohorts: AnimalCohort[], required: boolean, isSubmitting: boolean, onAddCohort: () => void, onRemoveCohort: (x: AnimalCohort) => void}) { return ( <> - {[...cohorts].map((cohort, index) => ( + {[...props.cohorts].map((cohort, index) => ( <ErrorMessageHandler isSubmitting={props.isSubmitting} keyInternal={cohort.uuid} key={cohort.uuid + "-errorHandler"}> <div className="tw-flex tw-flex-wrap tw-w-full tw-mx-2 tw-mb-10" key={cohort.uuid}> <div className="tw-flex tw-flex-wrap tw-w-full tw-mb-6"> @@ -43,7 +22,7 @@ export default function AnimalCohorts(props) { <div className="tw-flex tw-flex-wrap tw-w-full md:tw-w-1/2 md:tw-mb-0"> <input type="button" className="tw-ml-auto tw-bg-red-500 hover:tw-bg-red-400 tw-text-white tw-font-bold tw-py-2 tw-px-4 tw-border-none tw-rounded" - onClick={() => removeCohort(cohort)} value="Remove" style={{display: cohorts.size > 1 ? null : "none"}}/> + onClick={() => props.onRemoveCohort(cohort)} value="Remove" style={{display: index > 0 ? null : "none"}}/> </div> </div> @@ -70,7 +49,7 @@ export default function AnimalCohorts(props) { ))} <div className="tw-w-full tw-px-3 tw-mb-10 md:tw-mb-0"> - <input type="button" className="tw-bg-blue-500 hover:tw-bg-blue-400 tw-text-white tw-font-bold tw-py-2 tw-mt-2 tw-px-4 tw-border-none tw-rounded" onClick={addCohort} value="Add Cohort" /> + <input type="button" className="tw-bg-blue-500 hover:tw-bg-blue-400 tw-text-white tw-font-bold tw-py-2 tw-mt-2 tw-px-4 tw-border-none tw-rounded" onClick={props.onAddCohort} value="Add Cohort" /> </div> </> ) diff --git a/mcc/src/client/AnimalRequest/button.tsx b/mcc/src/client/AnimalRequest/components/button.tsx similarity index 72% rename from mcc/src/client/AnimalRequest/button.tsx rename to mcc/src/client/AnimalRequest/components/button.tsx index f410b1b0d..0ec1c1e27 100644 --- a/mcc/src/client/AnimalRequest/button.tsx +++ b/mcc/src/client/AnimalRequest/components/button.tsx @@ -1,9 +1,9 @@ -import React from 'react' +import React from 'react'; export default function Button(props) { - function onClick() { + function onClick(e) { if(props.onClick) { - props.onClick() + props.onClick(e) } } if(props.display === false) { @@ -14,7 +14,7 @@ export default function Button(props) { } else { return ( <button className="tw-ml-16 tw-bg-blue-500 hover:tw-bg-blue-400 tw-text-white tw-font-bold tw-py-4 tw-mt-2 tw-px-6 tw-border-none tw-rounded" - onClick={() => onClick()}>{props.text}</button> + onClick={(e) => onClick(e)}>{props.text}</button> ) } } diff --git a/mcc/src/client/AnimalRequest/components/co-investigators.tsx b/mcc/src/client/AnimalRequest/components/co-investigators.tsx new file mode 100644 index 000000000..2561d3f1d --- /dev/null +++ b/mcc/src/client/AnimalRequest/components/co-investigators.tsx @@ -0,0 +1,49 @@ +import React from 'react'; + +import Input from './input'; +import Title from './title'; +import ErrorMessageHandler from './error-message-handler'; +import { CoInvestigatorModel } from '../../components/RequestUtils'; + +export default function CoInvestigators(props: {coinvestigators: CoInvestigatorModel[], required: boolean, isSubmitting: boolean, onAddRecord: () => void, onRemoveRecord: (x: CoInvestigatorModel) => void}) { + + return ( + <> + {[...props.coinvestigators].map((coInvestigator, index) => ( + <ErrorMessageHandler isSubmitting={props.isSubmitting} keyInternal={coInvestigator.uuid} key={coInvestigator.uuid + "-errorHandler"}> + <div className="tw-flex tw-flex-wrap tw-w-full tw-mx-2 tw-mb-4" key={coInvestigator.uuid}> + <div className="tw-flex tw-flex-wrap tw-w-full tw-mb-6"> + <div className="tw-w-1/2 md:tw-mb-0"> + <Title text={ "Co-Investigator " + (index + 1)} /> + </div> + + <div className="tw-flex tw-flex-wrap tw-w-full md:tw-w-1/2 md:tw-mb-0"> + <input type="button" className="tw-ml-auto tw-bg-red-500 hover:tw-bg-red-400 tw-text-white tw-font-bold tw-py-2 tw-px-4 tw-border-none tw-rounded" onClick={() => props.onRemoveRecord(coInvestigator)} value="Remove" /> + </div> + </div> + + <div className="tw-w-full md:tw-w-1/3 tw-px-3 md:tw-mb-0"> + <Input id={"coinvestigators-" + index + "-" + "lastName"} ariaLabel={"Last Name" + "#" + index} isSubmitting={props.isSubmitting} placeholder="Last Name" required={props.required} defaultValue={coInvestigator.lastname}/> + </div> + + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id={"coinvestigators-" + index + "-" + "firstName"} ariaLabel={"First Name" + "#" + index} isSubmitting={props.isSubmitting} placeholder="First Name" required={props.required} defaultValue={coInvestigator.firstname}/> + </div> + + <div className="tw-w-full md:tw-w-1/3 tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id={"coinvestigators-" + index + "-" + "middleInitial"} ariaLabel={"Middle Initial" + "#" + index} isSubmitting={props.isSubmitting} placeholder="Middle Initial" required={false} defaultValue={coInvestigator.middleinitial} maxLength="8"/> + </div> + + <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> + <Input id={"coinvestigators-" + index + "-" + "institution"} ariaLabel={"Institution" + "#" + index} isSubmitting={props.isSubmitting} placeholder="Institution" required={props.required} defaultValue={coInvestigator.institutionname}/> + </div> + </div> + </ErrorMessageHandler> + ))} + + <div className="tw-w-full tw-px-3 tw-mb-6 md:tw-mb-0"> + <input type="button" className="tw-bg-blue-500 hover:tw-bg-blue-400 tw-text-white tw-font-bold tw-py-2 tw-mt-2 tw-px-4 tw-border-none tw-rounded" onClick={props.onAddRecord} value="Add Co-investigator" /> + </div> + </> + ) +} diff --git a/mcc/src/client/AnimalRequest/date.tsx b/mcc/src/client/AnimalRequest/components/date.tsx similarity index 100% rename from mcc/src/client/AnimalRequest/date.tsx rename to mcc/src/client/AnimalRequest/components/date.tsx diff --git a/mcc/src/client/AnimalRequest/error-message-handler.tsx b/mcc/src/client/AnimalRequest/components/error-message-handler.tsx similarity index 50% rename from mcc/src/client/AnimalRequest/error-message-handler.tsx rename to mcc/src/client/AnimalRequest/components/error-message-handler.tsx index 018d79bd1..9e47d0a4a 100644 --- a/mcc/src/client/AnimalRequest/error-message-handler.tsx +++ b/mcc/src/client/AnimalRequest/components/error-message-handler.tsx @@ -2,40 +2,45 @@ import React from 'react' import { nanoid } from 'nanoid' export default function ErrorMessageHandler(props) { - const ref = React.useRef() - const [errors, setErrors] = React.useState(new Set()) + const ref = React.useRef(null) + const [errors, setErrors] = React.useState(new Set()) + + React.useEffect(() => { + if (ref && ref.current && props.isSubmitting) { + const el = ref.current as HTMLElement + if (!el) { + return + } - React.useEffect(() => { - if (ref.current && props.isSubmitting) { - const el = ref.current - const handleValidationMessages = () => { const tmp = new Set() - - for (const e of el.querySelectorAll('input, select, textarea')) { + el.querySelectorAll<HTMLSelectElement>('input, select, textarea').forEach(function(e){ if (!e.checkValidity()) { const name = e.getAttribute("aria-label").split("#")[0] const message = e.validationMessage tmp.add(`${name}: ${message}`) } - } - + }) + setErrors(tmp) } - + el.addEventListener('input', handleValidationMessages) handleValidationMessages() + } else { + // NOTE: if we're not actively submitting, reset the errors + setErrors(new Set()) } }, [props.isSubmitting, props.rerender]); return ( - <> + <> <span ref={ref} key={props.id + "-error-message-handler-children"}> {props.children} </span> - <ul className="tw-mx-2 tw-mb-6" key={props.id + "-error-message-handler-errors"}> - {[...errors].map(txt => <li className="tw-tracking-wide tw-text-red-500" key={nanoid()}>{txt}</li>)} - </ul> - </> + <ul className="tw-mx-2 tw-mb-6" key={props.id + "-error-message-handler-errors"}> + {[...errors].map(txt => <li className="tw-tracking-wide tw-text-red-500" key={nanoid()}>{txt}</li>)} + </ul> + </> ) } diff --git a/mcc/src/client/AnimalRequest/funding.tsx b/mcc/src/client/AnimalRequest/components/funding.tsx similarity index 82% rename from mcc/src/client/AnimalRequest/funding.tsx rename to mcc/src/client/AnimalRequest/components/funding.tsx index 6c9d678c1..a8cc6fb1a 100644 --- a/mcc/src/client/AnimalRequest/funding.tsx +++ b/mcc/src/client/AnimalRequest/components/funding.tsx @@ -22,10 +22,9 @@ export default function Funding(props) { return ( <ErrorMessageHandler isSubmitting={props.isSubmitting} rerender={displayApplicationDate}> - <div className="tw-flex tw-flex-wrap tw-mx-2 tw-mb-4"> - <Title text="Existing or proposed funding source*"/> + <div className="tw-w-full tw-mx-2 tw-mb-4"> <div className="tw-w-full tw-px-3 tw-mb-6"> - <Select id={props.id + "-source"} ariaLabel="Proposed Funding Source" isSubmitting={props.isSubmitting} options={fundingSourceOptions} onChange={(e) => setDisplayApplicationDateField(e.currentTarget.value)} required={props.required} defaultValue={props.defaultValue.fundingsource} /> + <Select id={props.id + "-source"} ariaLabel="Proposed Funding Source(s)" isSubmitting={props.isSubmitting} options={fundingSourceOptions} onChange={(e) => setDisplayApplicationDateField(e.currentTarget.value)} multiSelect={true} required={props.required} defaultValue={props.defaultValue.fundingsource} /> </div> <div className="tw-w-full tw-px-3"> diff --git a/mcc/src/client/AnimalRequest/iacuc-protocol.tsx b/mcc/src/client/AnimalRequest/components/iacuc-protocol.tsx similarity index 70% rename from mcc/src/client/AnimalRequest/iacuc-protocol.tsx rename to mcc/src/client/AnimalRequest/components/iacuc-protocol.tsx index 2e775c5a2..808641b44 100644 --- a/mcc/src/client/AnimalRequest/iacuc-protocol.tsx +++ b/mcc/src/client/AnimalRequest/components/iacuc-protocol.tsx @@ -6,13 +6,14 @@ import Title from './title' import ErrorMessageHandler from './error-message-handler' import { IACUCApprovalOptions } from './values' +import { AnimalRequestProps } from '../../components/RequestUtils'; -export default function IACUCProtocol(props) { +export default function IACUCProtocol(props: {request: AnimalRequestProps, isSubmitting: boolean, required: boolean, id: string}) { - const [displayProtocol, setDisplayProtocol] = useState(props.defaultValue.iacucapproval == "approved" ? true : false) + const [displayProtocol, setDisplayProtocol] = useState(props.request.iacucapproval === "approved") function setDisplayProtocolField(value) { - if(value == "approved") { + if (value == "approved") { setDisplayProtocol(true) } else { setDisplayProtocol(false) @@ -22,18 +23,18 @@ export default function IACUCProtocol(props) { return ( <ErrorMessageHandler isSubmitting={props.isSubmitting} rerender={displayProtocol}> <div className="tw-flex tw-flex-wrap tw-mx-2"> - <Title text="IACUC Approval"/> + <Title text="7. IACUC Approval"/> <div className="tw-w-full tw-px-3 md:tw-mb-0"> <div className="tw-w-full tw-mb-6"> <Select id={props.id + "-approval"} ariaLabel="IACUC Approval Status" isSubmitting={props.isSubmitting} options={IACUCApprovalOptions} required={props.required} - defaultValue={props.defaultValue.iacucapproval} onChange={(e) => setDisplayProtocolField(e.currentTarget.value)}/> + defaultValue={props.request.iacucapproval} onChange={(e) => setDisplayProtocolField(e.currentTarget.value)}/> </div> <div className="tw-mb-6"> <Input id={props.id + "-protocol"} ariaLabel="IACUC Protocol" isSubmitting={props.isSubmitting} placeholder={"IACUC Protocol Number"} - display={displayProtocol} required={displayProtocol && props.required} defaultValue={props.defaultValue.iacucprotocol}/> + display={displayProtocol} required={displayProtocol && props.required} defaultValue={props.request.iacucprotocol}/> </div> </div> </div> diff --git a/mcc/src/client/AnimalRequest/input-number.tsx b/mcc/src/client/AnimalRequest/components/input-number.tsx similarity index 100% rename from mcc/src/client/AnimalRequest/input-number.tsx rename to mcc/src/client/AnimalRequest/components/input-number.tsx diff --git a/mcc/src/client/AnimalRequest/input.tsx b/mcc/src/client/AnimalRequest/components/input.tsx similarity index 100% rename from mcc/src/client/AnimalRequest/input.tsx rename to mcc/src/client/AnimalRequest/components/input.tsx diff --git a/mcc/src/client/AnimalRequest/select.tsx b/mcc/src/client/AnimalRequest/components/select.tsx similarity index 59% rename from mcc/src/client/AnimalRequest/select.tsx rename to mcc/src/client/AnimalRequest/components/select.tsx index 27245fab3..03d43ee5a 100644 --- a/mcc/src/client/AnimalRequest/select.tsx +++ b/mcc/src/client/AnimalRequest/components/select.tsx @@ -11,11 +11,20 @@ export default function Select(props) { } } + const isMultiple = props.multiSelect || false + let defaultValue = props.defaultValue + if (isMultiple && !Array.isArray(defaultValue)) { + defaultValue = defaultValue ? defaultValue.split(',') : [] + } + else { + defaultValue = defaultValue || "" + } + return ( <select className={"tw-block tw-border tw-border-gray-300" + (props.isSubmitting && " tw-invalid ") + "tw-text-gray-700 tw-py-3 tw-pr-8 tw-rounded tw-leading-tight focus:tw-outline-none"} - name={props.id} aria-label={props.ariaLabel} id={props.id} required={props.required} defaultValue={props.defaultValue || ""} onChange={(e) => onChange(e)}> + name={props.id} aria-label={props.ariaLabel} id={props.id} multiple={isMultiple} required={props.required} defaultValue={defaultValue} onChange={(e) => onChange(e)}> - <option disabled value=""> -- </option> + {isMultiple ? null : (<option disabled value=""> -- </option>)} {props.options.map(({ value, label }, _) => <option key={value} value={value}>{label}</option>)} </select> ) diff --git a/mcc/src/client/AnimalRequest/text-area.tsx b/mcc/src/client/AnimalRequest/components/text-area.tsx similarity index 93% rename from mcc/src/client/AnimalRequest/text-area.tsx rename to mcc/src/client/AnimalRequest/components/text-area.tsx index d7e7b4845..d609f42a7 100644 --- a/mcc/src/client/AnimalRequest/text-area.tsx +++ b/mcc/src/client/AnimalRequest/components/text-area.tsx @@ -11,7 +11,6 @@ export default function TextArea(props) { } else { return ( <div className="tw-flex tw-flex-wrap"> - <Title text={props.placeholder}/> <textarea className={"tw-w-full tw-h-36 tw-px-3 tw-py-2 tw-text-base" + (props.isSubmitting && " tw-invalid ") + "tw-text-gray-700 tw-placeholder-gray-600 tw-border tw-rounded-lg focus:tw-shadow-outline"} name={props.id} aria-label={props.ariaLabel} id={props.id} placeholder={props.placeholder} required={props.required} defaultValue={props.defaultValue}/> </div> diff --git a/mcc/src/client/AnimalRequest/title.tsx b/mcc/src/client/AnimalRequest/components/title.tsx similarity index 100% rename from mcc/src/client/AnimalRequest/title.tsx rename to mcc/src/client/AnimalRequest/components/title.tsx diff --git a/mcc/src/client/AnimalRequest/tooltip.tsx b/mcc/src/client/AnimalRequest/components/tooltip.tsx similarity index 91% rename from mcc/src/client/AnimalRequest/tooltip.tsx rename to mcc/src/client/AnimalRequest/components/tooltip.tsx index a9982718f..50f5fdb6f 100644 --- a/mcc/src/client/AnimalRequest/tooltip.tsx +++ b/mcc/src/client/AnimalRequest/components/tooltip.tsx @@ -4,7 +4,7 @@ import ReactTooltip from 'react-tooltip'; export default function Tooltip(props) { return ( <> - <svg data-tip={props.text} data-for={props.id} xmlns="http://www.w3.org/2000/svg" className="tw-h-6 tw-w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" tabIndex="-1"> + <svg data-tip={props.text} data-for={props.id} xmlns="http://www.w3.org/2000/svg" className="tw-h-6 tw-w-6" fill="none" viewBox="0 0 24 24" stroke="currentColor" tabIndex={-1}> <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M8.228 9c.549-1.165 2.03-2 3.772-2 2.21 0 4 1.343 4 3 0 1.4-1.278 2.575-3.006 2.907-.542.104-.994.54-.994 1.093m0 3h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z" /> </svg> diff --git a/mcc/src/client/AnimalRequest/values.ts b/mcc/src/client/AnimalRequest/components/values.ts similarity index 92% rename from mcc/src/client/AnimalRequest/values.ts rename to mcc/src/client/AnimalRequest/components/values.ts index 416f7c59d..0f187d560 100644 --- a/mcc/src/client/AnimalRequest/values.ts +++ b/mcc/src/client/AnimalRequest/components/values.ts @@ -5,7 +5,7 @@ export const researchUseStatementTooltip = "This will hold an explanation of the export const signingOfficialTooltip = "An SO has institutional authority to legally bind the institution in grant-administration matters by providing signature approval on grant application submissions. The SO monitors grant related activities within the extramural organization and may have a number of titles. The SO can also create additional accounts for personnel at their institution, including new signing official accounts." export const experimentalRationalePlaceholder = "Experimental rationale and justification for the selection of marmosets" -export const otherCharacteristicsPlaceholder = "Other characteristics (ie. Sex, age, disease state, genotype...)" +export const otherCharacteristicsPlaceholder = "Other characteristics (ie. age, disease state, genotype...)" export const methodsProposedPlaceholder = "Methods proposed and investigators' experience in the methods" export const animalBreedingPlaceholder = "Purpose of the animal breeding program" export const collaborationsPlaceholder = "Any collaborations, pilot studies, and/or publications" @@ -13,11 +13,6 @@ export const animalWellfarePlaceholder = "Animal welfare (proposed care and use) export const certificationLabel = "I certify and I have obtained approval for this study from my institution." -export const isPrincipalInvestigatorOptions = [ - { value: 'yes', label: 'Yes' }, - { value: 'no', label: 'No' }, -] - export const fundingSourceOptions = [ {value: 'nih', label: 'NIH-supported research'}, {value: 'other-federal', label: 'Other federal agency support'}, @@ -32,12 +27,17 @@ export const researchAreaOptions = [ {value: 'public-health', label: 'Public health emergency response (COVID or other)'}, {value: 'rare-disease', label: 'Rare disease research'}, {value: 'no-models', label: 'Paucity of existing disease animal models'}, - {value: 'nih-ic-interest', label: 'NIH IC interest'}, {value: 'new-colony-trans', label: 'Set up new breeding colony—transgenics'}, {value: 'new-colony-non-trans', label: 'Set up new breeding colony—not transgenics'}, {value: 'other', label: 'Other (specify)'}, ] +export const institutionTypeOptions = [ + {value: 'minorityServing', label: 'Minority serving'}, + {value: 'university', label: 'University/Non-profit'}, + {value: 'commercial', label: 'Commercial entity'} +] + export const existingMarmosetColonyOptions = [ {value: 'existing', label: 'Existing marmoset colony'}, {value: 'no-existing', label: 'No existing marmoset colony'}, diff --git a/mcc/src/client/AnimalRequest/yes-no-radio.tsx b/mcc/src/client/AnimalRequest/components/yes-no-radio.tsx similarity index 100% rename from mcc/src/client/AnimalRequest/yes-no-radio.tsx rename to mcc/src/client/AnimalRequest/components/yes-no-radio.tsx diff --git a/mcc/src/client/AnimalRequest/research-area.tsx b/mcc/src/client/AnimalRequest/research-area.tsx deleted file mode 100644 index 27415e873..000000000 --- a/mcc/src/client/AnimalRequest/research-area.tsx +++ /dev/null @@ -1,38 +0,0 @@ -import React, { useState } from 'react'; - -import Select from './select' -import Input from './input' -import Title from './title' -import ErrorMessageHandler from './error-message-handler' - -import { researchAreaOptions } from './values' - -export default function ResearchArea(props) { - - const [displayOther, setDisplayOther] = useState(props.defaultValue.researcharea == "other" ? true : false) - - function setDisplayOtherField(value) { - if(value == "other") { - setDisplayOther(true) - } else { - setDisplayOther(false) - } - } - - return ( - <ErrorMessageHandler isSubmitting={props.isSubmitting} rerender={displayOther}> - <div className="tw-w-full tw-px-3 tw-mb-10"> - <div className="tw-mb-6"> - <Title text="Research Area"/> - </div> - <div className="tw-w-full tw-mb-6"> - <Select id={props.id} options={researchAreaOptions} ariaLabel="Research Area" isSubmitting={props.isSubmitting} onChange={(e) => setDisplayOtherField(e.currentTarget.value)} defaultValue={props.defaultValue.researcharea} required={props.required}/> - </div> - - <div className="tw-w-full tw-mb-6"> - <Input id={props.id + "-other-specify"} ariaLabel="Other" isSubmitting={props.isSubmitting} placeholder="Please specify" display={displayOther} required={displayOther && props.required} defaultValue={props.defaultValue.otherjustification}/> - </div> - </div> - </ErrorMessageHandler> - ) -} diff --git a/mcc/src/client/Dashboard/Dashboard.tsx b/mcc/src/client/Dashboard/Dashboard.tsx index a898c5c26..bdf772750 100644 --- a/mcc/src/client/Dashboard/Dashboard.tsx +++ b/mcc/src/client/Dashboard/Dashboard.tsx @@ -29,7 +29,7 @@ export function Dashboard() { queryName: 'demographics', columns: 'Id,birth,death,gender/meaning,species,colony,calculated_status,u24_status,Id/age/AgeFriendly,Id/ageClass/label', success: function(results) { - setLiving(results.rows.filter(row => row.calculated_status === 'Alive')); + setLiving(results.rows.filter(row => row.calculated_status === 'Alive' || row.calculated_status === 'alive')); setu24Assigned(results.rows.filter(row => row.u24_status === true)); setDemographics(results.rows); }, diff --git a/mcc/src/client/RequestReview/app.tsx b/mcc/src/client/RequestReview/app.tsx new file mode 100644 index 000000000..1709dc8cb --- /dev/null +++ b/mcc/src/client/RequestReview/app.tsx @@ -0,0 +1,11 @@ +import React from 'react' +import ReactDOM from 'react-dom' + +import '../tailwind.css'; + +import { RequestView } from './request-review' + +// Need to wait for container element to be available in labkey wrapper before render +window.addEventListener('DOMContentLoaded', (event) => { + ReactDOM.render(<RequestView />, document.getElementById('app')); +}); diff --git a/mcc/src/client/RequestReview/components/FinalReviewForm.tsx b/mcc/src/client/RequestReview/components/FinalReviewForm.tsx new file mode 100644 index 000000000..a6349c861 --- /dev/null +++ b/mcc/src/client/RequestReview/components/FinalReviewForm.tsx @@ -0,0 +1,191 @@ +import React, { FormEvent, useEffect, useState } from 'react'; +import { ActionURL, Filter, getServerContext, Query } from '@labkey/api'; +import { + Box, + Button, + makeStyles, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + TextField +} from '@material-ui/core'; +import { AnimalRequestModel } from '../../components/RequestUtils'; +import SavingOverlay from '../../AnimalRequest/saving-overlay'; + +export default function FinalReviewForm(props: {requestData: AnimalRequestModel}) { + const { requestData } = props + const [ recordData, setRecordData ] = useState(null) + const [ reviewData, setReviewData ] = useState(null) + const [ displayOverlay, setDisplayOverlay ] = useState(false) + const [ hasSubmitted, setHasSubmitted ] = useState(false) + const [ pendingStatus, setPendingStatus ] = useState<string>(null) + + const styles = makeStyles({ + tableHead: { + fontWeight: "bold", + padding: 5, + paddingTop: 0 + }, + tableCell: { + border: 1, + borderColor: "black", + borderStyle: "solid", + padding: 5 + } + })() + + useEffect(() => { + Query.selectRows({ + schemaName: "mcc", + queryName: "requestScores", + columns: [ + "rowid", + "preliminaryScore", + "resourceAvailabilityScore", + "proposalScore", + "comments", + "requestid" + ], + filterArray: [ + Filter.create('requestId', requestData.request.objectid) + ], + success: function (resp) { + setRecordData(resp.rows[0] ? {...resp.rows[0]} : {}) + }, + failure: function (response) { + console.error(response) + alert(response.exception) + } + }) + + Query.selectRows({ + schemaName: "mcc", + queryName: "requestReviews", + columns: [ + "rowid", + "reviewerid", + "reviewerid/displayName", + "reviewerid/email", + "review", + "score", + "comments", + "requestid" + ], + filterArray: [ + Filter.create('requestId', requestData.request.objectid) + ], + success: function (resp) { + setReviewData([...resp.rows]) + }, + failure: function (response) { + alert(response.exception) + } + }) + }, [requestData]) + + if (!recordData || !reviewData) { + return(<div>Loading...</div>) + } + + const handleChange = (e) => { + setRecordData({...recordData, [e.target.name]: e.target.value ? e.target.value.trim() : null}) + }; + + const updateRequestStatus = (status: string) => { + setDisplayOverlay(true) + Query.updateRows({ + schemaName: "mcc", + queryName: "animalRequests", + rows: [{ + rowid: requestData.request.rowid, + objectid: requestData.request.objectid, + status: status + }], + success: function (resp) { + requestData.request.status = status + setDisplayOverlay(false) + window.location.href = ActionURL.buildURL("mcc", "mccRequestAdmin") + }, + failure: function (response) { + setDisplayOverlay(false) + console.error(response) + alert(response.exception) + } + }) + } + + const onFormSubmit = (e: React.SyntheticEvent<HTMLFormElement>) => { + setHasSubmitted(true) + e.preventDefault() + if (!e.currentTarget.reportValidity()) { + return + } + + setDisplayOverlay(true) + Query.updateRows({ + schemaName: "mcc", + queryName: "requestScores", + rows: [recordData], + success: function (resp) { + updateRequestStatus(pendingStatus) + }, + failure: function (response) { + setDisplayOverlay(false) + console.error(response) + alert(response.exception) + } + }) + } + + return( + <> + <h2>RAB Reviews</h2> + <Table style={{display: "inline-block", padding: 5}}> + <TableHead> + <TableRow key={"header"}> + <TableCell className={styles.tableHead}>Reviewer</TableCell> + <TableCell className={styles.tableHead}>Review</TableCell> + <TableCell className={styles.tableHead}>Comments</TableCell> + </TableRow> + </TableHead> + <TableBody> + {reviewData.map((row, idx) => { + return( + <TableRow key={"review-" + row.reviewerid} style = { idx % 2 ? { background : "#fdffe0" }:{ background : "white" }}> + <TableCell className={styles.tableCell}>{row['reviewerid/displayName']}</TableCell> + <TableCell className={styles.tableCell}>{row.review}</TableCell> + <TableCell className={styles.tableCell}>{row.comments}</TableCell> + </TableRow> + ) + })} + </TableBody> + </Table> + <h2>Enter MCC Review</h2> + <Box key={"mccReviewBox"} style={{display: 'inline-block'}}> + <form key={"internalReviewForm"} noValidate autoComplete='off' onSubmit={onFormSubmit}> + <Table width={500}> + <TableBody> + <TableRow> + <TableCell><TextField key={"preliminaryScore"} name={"preliminaryScore"} label={"Preliminary Score"} onChange={handleChange} variant={'outlined'} value={recordData.preliminaryScore || ''} disabled={true} fullWidth={true}/></TableCell> + </TableRow> + <TableRow> + <TableCell><TextField key={"resourceAvailabilityScore"} name={"resourceAvailabilityScore"} label={"Resource Availability Score"} onChange={handleChange} variant={'outlined'} defaultValue={recordData.resourceAvailabilityScore || ''} fullWidth={true} /></TableCell> + </TableRow> + {/*<TableRow>*/} + {/* <TableCell><TextField key={"proposalScore"} name={"proposalScore"} required={true} error={hasSubmitted && !recordData.proposalScore} label={"Final Proposal Score"} onChange={handleChange} variant={'outlined'} defaultValue={recordData.proposalScore || ''} fullWidth={true} /></TableCell>*/} + {/*</TableRow>*/} + <TableRow> + <TableCell><TextField key={"comments"} name={"comments"} label={"NIH Comments"} minRows={4} multiline={true} onChange={handleChange} variant={'outlined'} defaultValue={recordData.comments || ''} fullWidth={true} /></TableCell> + </TableRow> + </TableBody> + </Table> + <Button key={"approveBtn"} variant={"contained"} style={{marginRight: 10}} type={'submit'} onClick={() => setPendingStatus("Approved")}>Approve Request</Button> + <Button key={"rejectBtn"} variant={"contained"} style={{marginRight: 10}} type={'submit'} onClick={() => setPendingStatus("Rejected")}>Reject Request</Button> + </form> + </Box> + <SavingOverlay display={displayOverlay} /> + </> + ) +} \ No newline at end of file diff --git a/mcc/src/client/RequestReview/components/InternalReviewForm.tsx b/mcc/src/client/RequestReview/components/InternalReviewForm.tsx new file mode 100644 index 000000000..2ac5b486a --- /dev/null +++ b/mcc/src/client/RequestReview/components/InternalReviewForm.tsx @@ -0,0 +1,182 @@ +import React, { useEffect, useState } from 'react'; +import { ActionURL, Filter, Query } from '@labkey/api'; +import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, Typography } from '@material-ui/core'; +import { AnimalRequestModel } from '../../components/RequestUtils'; +import SavingOverlay from '../../AnimalRequest/saving-overlay'; + +export default function InternalReviewForm(props: {requestData: AnimalRequestModel}) { + const { requestData } = props + const [ recordData, setRecordData ] = useState(null) + const [ rabMembers, setRabMembers ] = useState(null) + const [ existingAssignments, setExistingAssignments ] = useState(null) + const [ displayOverlay, setDisplayOverlay ] = useState(false) + + const [ showReturnToInvestigator, setShowReturnToInvestigator ] = useState(false) + const [ showSendToRab, setShowSendToRab ] = useState(false) + + useEffect(() => { + Query.selectRows({ + schemaName: "mcc", + queryName: "requestScores", + columns: [ + "rowid", + "preliminaryScore", + "resourceAvailabilityScore", + "proposalScore", + "comments", + "requestid", + "requestid/createdby/email" + + ], + filterArray: [ + Filter.create('requestId', requestData.request.objectid) + ], + success: function (resp) { + setRecordData(resp.rows[0] ? {...resp.rows[0]} : {}) + }, + failure: function (response) { + console.error(response) + alert(response.exception) + } + }) + + Query.selectRows({ + schemaName: 'core', + queryName: 'Members', + columns: 'UserId,UserId/DisplayName', + filterArray: [ + Filter.create('GroupId/Name', 'MCC RAB Members') + ], + success: function (resp) { + setRabMembers(resp.rows) + }, + failure: function (response) { + console.error(response) + alert(response.exception) + } + }) + + Query.selectRows({ + schemaName: "mcc", + queryName: "requestReviews", + columns: 'reviewerId', + filterArray: [ + Filter.create('requestId', requestData.request.objectid) + ], + success: function (resp) { + setExistingAssignments(resp.rows?.map(r => r.reviewerId)) + }, + failure: function (response) { + console.error(response) + alert(response.exception) + } + }) + }, [requestData]) + + if (!recordData || !rabMembers || !existingAssignments || !requestData) { + return(<div>Loading...</div>) + } + + const onReturnToInvestigatorSubmit = (e) => { + updateRequestStatus('Draft') + setShowReturnToInvestigator(false) + } + + const updateRequestStatus = (status: string) => { + setDisplayOverlay(true) + Query.updateRows({ + schemaName: "mcc", + queryName: "animalRequests", + rows: [{ + rowid: requestData.request.rowid, + objectid: requestData.request.objectid, + status: status + }], + success: function (resp) { + requestData.request.status = status + setDisplayOverlay(false) + window.location.href = ActionURL.buildURL("mcc", "mccRequestAdmin") + }, + failure: function (response) { + setDisplayOverlay(false) + console.error(response) + alert(response.exception) + } + }) + } + + const onRabReviewSubmit = (e) => { + setDisplayOverlay(true) + const toInsert = rabMembers.filter(r => !existingAssignments.includes(r.UserId)).map(r => { + return { + reviewerId: r.UserId, + requestId: requestData.request.objectid + } + }) + + if (!toInsert.length) { + updateRequestStatus('RAB Review') + } + else { + Query.insertRows({ + schemaName: "mcc", + queryName: "requestReviews", + rows: toInsert, + success: function (resp) { + updateRequestStatus('RAB Review') + }, + failure: function (response) { + setDisplayOverlay(false) + console.error(response) + alert(response.exception) + } + }) + } + + setShowSendToRab(false) + } + + const emailHref = recordData['requestid/createdby/email'] ? ("mailto:" + recordData['requestid/createdby/email'] + "?subject=MCC Request: " + recordData.rowid) : null + + return ( + <> + <h2>MCC Internal Review</h2> + <Typography style={{paddingBottom: 20}}>After reviewing the request above for completeness and accuracy, please either return to the investigator or assign for RAB Review</Typography> + <Box key={"mccReviewBox"} style={{display: 'inline-block'}}> + <Button href={emailHref} variant={"contained"} style={{marginRight: 10}} disabled={!emailHref}>Contact Investigator</Button> + <Button key={"returnToPiBtn"} variant={"contained"} style={{marginRight: 10}} onClick={(e) => setShowReturnToInvestigator(true)}>Return to Investigator</Button> + <Button key={"rabAssignBtn"} variant={"contained"} style={{marginRight: 10}} onClick={(e) => setShowSendToRab(true)}>Assign to RAB Reviewers</Button> + </Box> + <Dialog open={showReturnToInvestigator}> + <DialogTitle>Return To Investigator</DialogTitle> + <DialogContent> + Hitting submit will change the status of this request back to draft. Please use the button below to contact the investigator with questions or concerns. + </DialogContent> + <DialogActions> + <Box mr="5px"> + <Button onClick={onReturnToInvestigatorSubmit} disabled={false}>Submit</Button> + <Button onClick={(e) => setShowReturnToInvestigator(false)}>Close</Button> + </Box> + </DialogActions> + </Dialog> + <Dialog open={showSendToRab}> + <DialogTitle>Assign for RAB Review</DialogTitle> + <DialogContent> + This will assign this review to review by the RAB, which includes: + { + rabMembers.map(r => { + return(<Typography key={'rab-' + r.UserId} style={{paddingTop: 20}}>{r['UserId/DisplayName'] + (existingAssignments.includes(r.UserId) ? ' (already assigned)' : '')}</Typography>) + }) + } + </DialogContent> + <DialogActions> + <Box mr="5px"> + <Button onClick={onRabReviewSubmit} disabled={false}>Submit</Button> + <Button onClick={(e) => setShowSendToRab(false)}>Close</Button> + </Box> + </DialogActions> + </Dialog> + <SavingOverlay display={displayOverlay} /> + </> + ) +} \ No newline at end of file diff --git a/mcc/src/client/RequestReview/components/RabReviewForm.tsx b/mcc/src/client/RequestReview/components/RabReviewForm.tsx new file mode 100644 index 000000000..9bf1f47a5 --- /dev/null +++ b/mcc/src/client/RequestReview/components/RabReviewForm.tsx @@ -0,0 +1,134 @@ +import { ActionURL, Filter, getServerContext, Query } from '@labkey/api'; +import React, { useEffect, useState } from 'react'; +import { Box, Button, MenuItem, Select, Table, TableBody, TableCell, TableRow, TextField } from '@material-ui/core'; +import SavingOverlay from '../../AnimalRequest/saving-overlay'; + +export default function RabReviewForm(props: {requestId: string}) { + const [ recordData, setRecordData ] = useState(null) + const [displayOverlay, setDisplayOverlay] = useState(false) + const [hasSubmitted, setHasSubmitted] = useState(false) + + useEffect(() => { + Query.selectRows({ + schemaName: "mcc", + queryName: "requestReviews", + columns: [ + "rowid", + "reviewerid", + "reviewerid/displayName", + "reviewerid/email", + "review", + "score", + "comments", + "requestid" + ], + filterArray: [ + Filter.create('requestId', props.requestId), + Filter.create('reviewerId', getServerContext().user.id) + ], + success: function (resp) { + if (resp.rows.length > 1) { + console.error("More than one MCC review record returned for the user: " + getServerContext().user.id + ". this should never happen") + } + + setRecordData([...resp.rows]) + }, + failure: function (response) { + alert(response.exception) + } + }) + }, [props.requestId]) + + if (!recordData) { + return(<div>Loading...</div>) + } + + if (!recordData?.length) { + return(<div style={{paddingTop: 20}}>You have not been assigned to review this request</div>) + } + + const handleChange = (e) => { + recordData[0][e.target.name] = e.target.value ? e.target.value.trim() : null + setRecordData([...recordData]) + }; + + const onFormSubmit = (e: React.SyntheticEvent<HTMLFormElement>) => { + setHasSubmitted(true) + e.preventDefault() + if (!e.currentTarget.reportValidity()) { + return + } + + setDisplayOverlay(true) + const row = recordData[0] + if (row.rowid) { + Query.updateRows({ + schemaName: "mcc", + queryName: "requestReviews", + rows: [{ + rowid: row.rowid, + review: row.review, + comments: row.comments + }], + success: function (resp) { + window.location.href = ActionURL.buildURL('mcc', 'rabRequestReview') + }, + failure: function (response) { + setDisplayOverlay(false) + console.error(response) + alert(response.exception) + } + }) + } + else { + Query.insertRows({ + schemaName: "mcc", + queryName: "requestReviews", + rows: [{ + review: row.review, + comments: row.comments + }], + success: function (resp) { + window.location.href = ActionURL.buildURL('mcc', 'rabRequestReview') + }, + failure: function (response) { + setDisplayOverlay(false) + console.error(response) + alert(response.exception) + } + }) + } + + } + + return ( + <> + <h2>Enter RAB Review</h2> + <form noValidate autoComplete='off' onSubmit={onFormSubmit}> + <Box style={{display: 'inline-block'}}> + After reviewing the request, please fill out the section below and provide a 2-3 sentence justification for your choice. + <Table width={500}> + <TableBody> + <TableRow> + <TableCell> + <Select id={"review"} variant={"outlined"} name={"review"} aria-label="Review" label={"Review"} error={hasSubmitted && !recordData[0].review} onChange={handleChange} required={true} value={recordData[0].review ?? ''} fullWidth={true} displayEmpty={true} placeholder={"Enter review..."}> + <MenuItem value={""}>Not Decided</MenuItem> + <MenuItem value={"I recommend this proposal"}>I recommend this proposal</MenuItem> + <MenuItem value={"I recommend this proposal with conditions"}>I recommend this proposal with conditions</MenuItem> + <MenuItem value={"I do not recommend this proposal"}>I do not recommend this proposal</MenuItem> + </Select> + </TableCell> + </TableRow> + <TableRow> + <TableCell><TextField key={"comments"} name={"comments"} label={"Justification"} minRows={4} multiline={true} onChange={handleChange} variant={'outlined'} defaultValue={recordData[0].comments || ''} fullWidth={true} /></TableCell> + </TableRow> + </TableBody> + </Table> + <p /> + <Button variant={"contained"} style={{marginRight: 10}} type={'submit'}>Submit Review</Button> + </Box> + </form> + <SavingOverlay display={displayOverlay} /> + </> + ) +} \ No newline at end of file diff --git a/mcc/src/client/RequestReview/components/ReadOnlyRequest.tsx b/mcc/src/client/RequestReview/components/ReadOnlyRequest.tsx new file mode 100644 index 000000000..e5d9e3a19 --- /dev/null +++ b/mcc/src/client/RequestReview/components/ReadOnlyRequest.tsx @@ -0,0 +1,231 @@ +import React from 'react'; +import { AnimalRequestModel, AnimalRequestProps } from '../../components/RequestUtils'; +import { + existingMarmosetColonyOptions, + existingNHPFacilityOptions, + IACUCApprovalOptions, + institutionTypeOptions, + researchAreaOptions +} from '../../AnimalRequest/components/values'; +import { + Box, + Button, + Grid, + makeStyles, + Table, + TableBody, + TableCell, + TableHead, + TableRow, + Typography +} from '@material-ui/core'; +import { ActionURL } from '@labkey/api'; + +function formatPIName(request: AnimalRequestProps) { + return(formatName(request.lastname, request.firstname, request.middleinitial)) +} + +function formatName(lastname, firstname, middleinitial) { + if (!lastname) { + return('NOT ENTERED') + } + + return(lastname + ', ' + (firstname || 'NOT_ENTERED') + (middleinitial ? ' ' + middleinitial : '')) +} + +function findDisplayValue(value, translationMap) { + if (!value) { + return '' + } + + return translationMap.filter((rec) => rec.value == value).map((rec) => rec.label).join(', ') +} + +function translateRawToDisplayValue(value, translationMap: any[], isMulti = false) { + if (isMulti) { + return value.split(',').map((value) => findDisplayValue(value, translationMap)) + } + else { + return findDisplayValue(value, translationMap) + } +} +export default function ReadOnlyRequest(props: {requestData: AnimalRequestModel}) { + const { requestData } = props + const styles = makeStyles({ + fieldLabel: { + fontSize: "14px", + fontWeight: "bold" + }, + tableHead: { + fontWeight: "bold", + padding: 5, + paddingTop: 0 + }, + tableCell: { + border: 1, + borderColor: "black", + borderStyle: "solid", + padding: 5 + } + })() + + if (!requestData?.dataLoaded) { + return null + } + + return( + <> + <h2>Request Details</h2> + <Box display={"inline-block"} style={{marginBottom: 30}}> + <h4 style={{marginTop: 10}}>General Information</h4> + <Grid container spacing={1} style={{marginLeft: 10}}> + <Grid item xs={2} className={styles.fieldLabel}> + PI Name: + </Grid> + <Grid item xs={10}> + {formatPIName(requestData.request)} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Early State Investigator: + </Grid> + <Grid item xs={10}> + {requestData.request.earlystageinvestigator ? 'Yes' : 'No'} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + <div>Institution: </div> + </Grid> + <Grid item xs={10}> + {requestData.request.institutionname || ''} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + <div>Institution City: </div> + </Grid> + <Grid item xs={10}> + {requestData.request.institutioncity}, {requestData.request.institutionstate} {requestData.request.institutioncountry} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + <div>Institution Type: </div> + </Grid> + <Grid item xs={10}> + {translateRawToDisplayValue(requestData.request.institutiontype, institutionTypeOptions)} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + <div>Signing Official: </div> + </Grid> + <Grid item xs={10}> + {formatName(requestData.request.officiallastname, requestData.request.officialfirstname, null)} + {requestData.request.officialemail ? ' (' + requestData.request.officialemail + ')' : ''} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + <div>Co-Investigators: </div> + </Grid> + <Grid item xs={10}> + {requestData.coinvestigators.length ? requestData.coinvestigators.map((coi, idx) => { + return([ + <Typography key={'coi-' + idx}>{formatName(coi.lastname, coi.firstname, coi.middleinitial) + ': ' +coi.institutionname}</Typography> + ]) + }) : 'N/A'} + </Grid> + </Grid> + + <p /> + <h4 style={{marginTop: 20}}>Institutional Animal Facilities and Capabilities</h4> + <Grid container spacing={1} style={{marginLeft: 10}}> + <Grid item xs={2} className={styles.fieldLabel}> + Has Existing NHP Facilities: + </Grid> + <Grid item xs={10}> + {translateRawToDisplayValue(requestData.request.existingnhpfacilities, existingNHPFacilityOptions)} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Has Existing Marmoset Colony: + </Grid> + <Grid item xs={10}> + {translateRawToDisplayValue(requestData.request.existingmarmosetcolony, existingMarmosetColonyOptions)} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Plans to Breed Marmosets: + </Grid> + <Grid item xs={10}> + {requestData.request.isbreedinganimals ? 'Yes' : 'No'} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Breeding Purpose: + </Grid> + <Grid item xs={10}> + {requestData.request.breedingpurpose || 'N/A'} + </Grid> + </Grid> + + <p /> + <h4 style={{marginTop: 20}}>Research Details</h4> + <Grid container spacing={1} style={{marginLeft: 10}}> + <Grid item xs={2} className={styles.fieldLabel}> + Animal Cohorts: + </Grid> + <Grid item xs={10}> + {requestData.cohorts.length ? ( + <Table style={{display: "inline-block", padding: 5}}> + <TableHead><TableRow key={"cohorts-header"}> + <TableCell className={styles.tableHead}>Number of Animals</TableCell><TableCell className={styles.tableHead}>Sex</TableCell><TableCell className={styles.tableHead}>Other Characteristics</TableCell> + </TableRow> + </TableHead> + <TableBody style={{border: 1, borderColor: 'black'}}> + {requestData.cohorts.map((cohort, idx) => { + return( + <TableRow key={cohort.rowid} style = { idx % 2 ? { background : "#fdffe0" }:{ background : "white" }}> + <TableCell className={styles.tableCell}>{cohort.numberofanimals}</TableCell> + <TableCell className={styles.tableCell}>{cohort.sex}</TableCell> + <TableCell className={styles.tableCell}>{cohort.othercharacteristics}</TableCell> + </TableRow> + ) + })} + </TableBody> + </Table> + ) : 'No cohorts entered'} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Methods Proposed: + </Grid> + <Grid item xs={10}> + {requestData.request.methodsproposed} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Collaborations: + </Grid> + <Grid item xs={10}> + {requestData.request.collaborations || 'N/A'} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Animal Welfare: + </Grid> + <Grid item xs={10}> + {requestData.request.animalwelfare} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Attending Veterinarian: + </Grid> + <Grid item xs={10}> + {requestData.request.vetlastname ? (requestData.request.vetlastname + (requestData.request.vetfirstname ? ', ' + requestData.request.vetfirstname : '')) : ''} + {requestData.request.vetemail ? ' (' + requestData.request.vetemail + ')' : ''} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + IACUC Approval: + </Grid> + <Grid item xs={10}> + {translateRawToDisplayValue(requestData.request.iacucapproval, IACUCApprovalOptions)} + {requestData.request.iacucprotocol ? ' (' + requestData.request.iacucprotocol + ')' : ''} + </Grid> + <Grid item xs={2} className={styles.fieldLabel}> + Status: + </Grid> + <Grid item xs={10}> + {requestData.request.status} + </Grid> + </Grid> + <p /> + <Button variant={"contained"} style={{marginLeft: 10}} href={ActionURL.buildURL('mcc', 'animalRequest', null, {requestId: requestData.request.objectid})}>Edit Request</Button> + </Box> + </> + ) +} \ No newline at end of file diff --git a/mcc/src/client/RequestReview/request-review.tsx b/mcc/src/client/RequestReview/request-review.tsx new file mode 100644 index 000000000..29f8147e3 --- /dev/null +++ b/mcc/src/client/RequestReview/request-review.tsx @@ -0,0 +1,96 @@ +import React, { useState } from 'react'; +import { AnimalRequestModel, queryRequestInformation } from '../components/RequestUtils'; +import { default as ReadOnlyRequest } from './components/ReadOnlyRequest'; +import Title from '../AnimalRequest/components/title'; +import RabReviewForm from './components/RabReviewForm'; +import InternalReviewForm from './components/InternalReviewForm'; + +import { ThemeProvider } from '@material-ui/styles'; +import { createTheme } from '@material-ui/core/styles'; +import '../labkeyOverrides.css'; +import FinalReviewForm from './components/FinalReviewForm'; +import { ErrorBoundary } from '@labkey/components'; + +export function RequestView() { + const mode = (new URLSearchParams(window.location.search)).get("mode") + const requestId = (new URLSearchParams(window.location.search)).get("requestId") + + const [requestData, setRequestData] = useState<AnimalRequestModel>(null) + + if (!requestId) { + return(<div>No request Id provided</div>) + } + + if (!mode) { + return(<div>Must provide the mode parameter for this page on the URL</div>) + } + + if (!requestData) { + queryRequestInformation(requestId, handleFailure).then((model) => { + setRequestData(model) + }) + } + + if (!requestData || !requestData?.dataLoaded) { + return ( + <div className="tw-flex tw-justify-center tw-items-center"> + <div style={{ borderBottom: "2px solid #3495d2" }} className="tw-animate-spin tw-rounded-full tw-h-32 tw-w-32"></div> + </div> + ) + } + else if (requestData.dataLoaded === true && !requestData.request) { + return(<Title text="No such request."/>) + } + + function handleFailure(response) { + alert(response.exception) //this is probably what you want to show. An example would be to submit data with a long value for middle initial (>14 characters) + + setRequestData(requestData) + } + + let reviewForms = null + switch (mode) { + case "details": + break + case "primaryReview": + reviewForms = [ + <InternalReviewForm key={"internalReviewForm"} requestData={requestData}/> + ] + break + case "rabReview": + reviewForms = ( + <> + <RabReviewForm key={"rabReviewForm"} requestId={requestId}/> + </> + ) + break + case "finalReview": + reviewForms = ( + <> + <FinalReviewForm key={"finalReviewForm"} requestData={requestData}/> + </> + ) + break + } + + const theme = createTheme({ + overrides: { + MuiTableCell: { + root: { + borderBottom: "none" + } + } + } + }); + + return( + <> + <ErrorBoundary> + <ThemeProvider theme={theme}> + <ReadOnlyRequest requestData={requestData} /> + {reviewForms} + </ThemeProvider> + </ErrorBoundary> + </> + ) +} \ No newline at end of file diff --git a/mcc/src/client/components/RequestUtils.tsx b/mcc/src/client/components/RequestUtils.tsx new file mode 100644 index 000000000..ece52cde9 --- /dev/null +++ b/mcc/src/client/components/RequestUtils.tsx @@ -0,0 +1,187 @@ +import React from 'react'; +import { Filter, Query } from '@labkey/api'; +import { v4 as uuidv4 } from 'uuid'; + +export class AnimalRequestModel { + request: AnimalRequestProps = new AnimalRequestProps(); + coinvestigators: CoInvestigatorModel[] = []; + cohorts: AnimalCohort[] = []; + dataLoaded: boolean = false; +} + +export class AnimalRequestProps { + status: string = 'Draft'; + middleinitial: string; + lastname: string; + firstname: string; + earlystageinvestigator: string; + institutionname: string; + institutioncity: string; + institutionstate: string; + institutioncountry: string; + institutiontype: string; + officiallastname: string; + officialfirstname: string; + officialemail: string; + experimentalrationale: string; + isbreedinganimals: boolean; + breedingpurpose: string; + methodsproposed: string; + collaborations: string; + iacucprotocol: string; + iacucapproval: string; + existingmarmosetcolony: string; + existingnhpfacilities: string; + rowid: number; + certify: boolean; + animalwelfare: string; + vetlastname: string; + vetemail: string; + vetfirstname: string; + objectid: string; +} + +export class CoInvestigatorModel { + rowid: number; + requestId: string; + lastname: string; + firstname: string; + middleinitial: string; + institutionname: string; + uuid: string = uuidv4().toUpperCase(); +} + +export class AnimalCohort { + rowid: number; + requestId: string; + numberofanimals: number; + sex: string; + othercharacteristics: string; + uuid: string = uuidv4().toUpperCase(); +} + +export async function queryRequestInformation(requestId, handleFailure) { + const requestData = new AnimalRequestModel() + + if (!requestId) { + requestData.dataLoaded = true + requestData.request.objectid = requestData.request.objectid || uuidv4().toUpperCase() + requestData.request.status = 'Draft' + requestData.cohorts = [new AnimalCohort()] + + return(requestData) + } + + const promises = [new Promise<any>((resolve, reject) => { + Query.selectRows({ + schemaName: "mcc", + queryName: "animalrequests", + columns: [ + "rowid", + "objectId", + "lastname", + "firstname", + "middleinitial", + "earlystageinvestigator", + "institutionname", + "institutioncity", + "institutionstate", + "institutioncountry", + "institutiontype", + "officiallastname", + "officialfirstname", + "officialemail", + "fundingsource", + "experimentalrationale", + "methodsproposed", + "collaborations", + "isbreedinganimals", + "breedingpurpose", + "existingmarmosetcolony", + "existingnhpfacilities", + "animalwelfare", + "certify", + "vetlastname", + "vetfirstname", + "vetemail", + "iacucapproval", + "iacucprotocol", + "grantnumber", + "applicationduedate", + "status" + ], + filterArray: [ + Filter.create('objectId', requestId) + ], + success: function (resp) { + resolve(resp.rows[0]) + }, + failure: handleFailure + }) + }), + new Promise<any>((resolve, reject) => { + Query.selectRows({ + schemaName: "mcc", + queryName: "coinvestigators", + columns: [ + "rowid", + "requestId", + "lastname", + "firstname", + "middleinitial", + "institutionname", + ], + filterArray: [ + Filter.create('requestId', requestId) + ], + success: function (resp) { + if (resp.rows.length) { + // NOTE: this property is purely for client-side UI and not persisted in the DB, so create a value + resp.rows.map(c => c.uuid = uuidv4().toUpperCase()) + } + + resolve(resp.rows) + }, + failure: handleFailure + }) + }), + new Promise<any>((resolve, reject) => { + Query.selectRows({ + schemaName: "mcc", + queryName: "requestcohorts", + columns: [ + "rowid", + "requestId", + "numberofanimals", + "sex", + "othercharacteristics", + ], + filterArray: [ + Filter.create('requestId', requestId) + ], + success: function (resp) { + // NOTE: abort so that we preserve the default value of one empty row + if (!resp.rows.length) { + requestData.cohorts = [new AnimalCohort()] + } else { + requestData.cohorts = resp.rows + + // NOTE: this property is purely for client-side UI and not persisted in the DB, so create a value + requestData.cohorts.map(c => c.uuid = uuidv4().toUpperCase()) + } + + resolve(requestData.cohorts) + }, + failure: handleFailure + }) + })] + + return await Promise.all(promises).then(values => { + requestData.request = values[0] + requestData.coinvestigators = values[1] + requestData.cohorts = values[2] + requestData.dataLoaded = true + + return(requestData) + }) +} diff --git a/mcc/src/client/entryPoints.js b/mcc/src/client/entryPoints.js index 9a628fda2..eedf6e4b8 100644 --- a/mcc/src/client/entryPoints.js +++ b/mcc/src/client/entryPoints.js @@ -15,5 +15,11 @@ module.exports = { title: 'Animal Requests', permission: 'read', path: './src/client/AnimalRequest' + },{ + name: 'requestReview', + title: 'Animal Request Review', + permission: 'read', + template: 'home', + path: './src/client/RequestReview' }] }; diff --git a/mcc/src/client/labkeyOverrides.css b/mcc/src/client/labkeyOverrides.css new file mode 100644 index 000000000..75c029ff8 --- /dev/null +++ b/mcc/src/client/labkeyOverrides.css @@ -0,0 +1,3 @@ +html { + font-size: 16px !important; +} diff --git a/mcc/src/client/AnimalRequest/tailwind.config.js b/mcc/src/client/tailwind.config.js similarity index 100% rename from mcc/src/client/AnimalRequest/tailwind.config.js rename to mcc/src/client/tailwind.config.js diff --git a/mcc/src/client/AnimalRequest/tailwind.css b/mcc/src/client/tailwind.css similarity index 100% rename from mcc/src/client/AnimalRequest/tailwind.css rename to mcc/src/client/tailwind.css diff --git a/mcc/src/org/labkey/mcc/MccController.java b/mcc/src/org/labkey/mcc/MccController.java index 06259a7f1..b04bf782d 100644 --- a/mcc/src/org/labkey/mcc/MccController.java +++ b/mcc/src/org/labkey/mcc/MccController.java @@ -24,6 +24,7 @@ import org.labkey.api.action.ConfirmAction; import org.labkey.api.action.MutatingApiAction; import org.labkey.api.action.SpringActionController; +import org.labkey.api.data.CompareType; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; import org.labkey.api.data.CoreSchema; @@ -42,13 +43,16 @@ import org.labkey.api.security.Group; import org.labkey.api.security.GroupManager; import org.labkey.api.security.IgnoresTermsOfUse; +import org.labkey.api.security.MutableSecurityPolicy; import org.labkey.api.security.RequiresNoPermission; import org.labkey.api.security.RequiresPermission; import org.labkey.api.security.SecurityManager; +import org.labkey.api.security.SecurityPolicyManager; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; import org.labkey.api.security.ValidEmail; import org.labkey.api.security.permissions.AdminPermission; +import org.labkey.api.security.roles.RoleManager; import org.labkey.api.settings.AppProps; import org.labkey.api.settings.LookAndFeelProperties; import org.labkey.api.util.ConfigurationException; @@ -60,6 +64,11 @@ import org.labkey.api.util.URLHelper; import org.labkey.api.view.HtmlView; import org.labkey.mcc.etl.ZimsImportTask; +import org.labkey.mcc.security.MccDataAdminRole; +import org.labkey.mcc.security.MccFinalReviewerRole; +import org.labkey.mcc.security.MccRabReviewerRole; +import org.labkey.mcc.security.MccRequestAdminPermission; +import org.labkey.mcc.security.MccRequesterRole; import org.labkey.security.xml.GroupEnumType; import org.springframework.validation.BindException; import org.springframework.validation.Errors; @@ -69,11 +78,13 @@ import javax.mail.Message; import javax.mail.internet.InternetAddress; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; public class MccController extends SpringActionController { @@ -156,17 +167,11 @@ public Object execute(RequestUserForm form, BindException errors) throws Excepti Table.insert(UserManager.getGuestUser(), ti, row); - Set<User> users = MccManager.get().getNotificationUsers(); - if (users != null && !users.isEmpty()) + Set<Address> emails = MccManager.get().getNotificationUserEmails(); + if (emails != null && !emails.isEmpty()) { try { - Set<Address> emails = new HashSet<>(); - for (User u : users) - { - emails.add(new InternetAddress(u.getEmail())); - } - MailHelper.MultipartMessage mail = MailHelper.createMultipartMessage(); Container c = MccManager.get().getMCCContainer(); if (c == null) @@ -480,17 +485,11 @@ public void validateForm(RequestHelpForm form, Errors errors) @Override public Object execute(RequestHelpForm form, BindException errors) throws Exception { - Set<User> users = MccManager.get().getNotificationUsers(); - if (users != null && !users.isEmpty()) + Set<Address> emails = MccManager.get().getNotificationUserEmails(); + if (emails != null && !emails.isEmpty()) { try { - Set<Address> emails = new HashSet<>(); - for (User u : users) - { - emails.add(new InternetAddress(u.getEmail())); - } - MailHelper.MultipartMessage mail = MailHelper.createMultipartMessage(); mail.setEncodedHtmlContent("A support request was submitted from MCC by: " + form.getEmail() + "<br><br>Message:<br>" + form.getComment()); mail.setFrom(form.getEmail()); @@ -540,6 +539,108 @@ public void setComment(String comment) } } + @RequiresPermission(AdminPermission.class) + public static class ConfigureMccAction extends ConfirmAction<Object> + { + @Override + public ModelAndView getConfirmView(Object o, BindException errors) throws Exception + { + setTitle("Configure MCC"); + + StringBuilder sb = new StringBuilder(); + sb.append("This will ensure various settings required by MCC are configured on this server. Do you want to continue?"); + + return new HtmlView(HtmlString.unsafe(sb.toString())); + } + + @Override + public boolean handlePost(Object o, BindException errors) throws Exception + { + for (String gn : Arrays.asList(MccManager.REQUEST_GROUP_NAME, MccManager.ANIMAL_GROUP_NAME, MccManager.REQUEST_REVIEW_GROUP_NAME, MccManager.FINAL_REVIEW_GROUP_NAME, MccManager.ADMIN_GROUP_NAME)) + { + Group g1 = GroupManager.getGroup(ContainerManager.getRoot(), gn, GroupEnumType.SITE); + if (g1 == null) + { + SecurityManager.createGroup(ContainerManager.getRoot(), gn); + } + } + + // Ensure groups have target roles: + Container requestContainer = MccManager.get().getMCCRequestContainer(); + if (requestContainer != null) + { + Group requestGroup = GroupManager.getGroup(ContainerManager.getRoot(), MccManager.REQUEST_GROUP_NAME, GroupEnumType.SITE); + if (!requestContainer.getPolicy().getAssignedRoles(requestGroup).contains(RoleManager.getRole(MccRequesterRole.class))) + { + MutableSecurityPolicy policy = new MutableSecurityPolicy(requestContainer.getPolicy()); + policy.addRoleAssignment(requestGroup, RoleManager.getRole(MccRequesterRole.class)); + SecurityPolicyManager.savePolicy(policy); + } + + Group reviewGroup = GroupManager.getGroup(ContainerManager.getRoot(), MccManager.REQUEST_REVIEW_GROUP_NAME, GroupEnumType.SITE); + if (!requestContainer.getPolicy().getAssignedRoles(reviewGroup).contains(RoleManager.getRole(MccRabReviewerRole.class))) + { + MutableSecurityPolicy policy = new MutableSecurityPolicy(requestContainer.getPolicy()); + policy.addRoleAssignment(reviewGroup, RoleManager.getRole(MccRabReviewerRole.class)); + SecurityPolicyManager.savePolicy(policy); + } + + Group finalGroup = GroupManager.getGroup(ContainerManager.getRoot(), MccManager.FINAL_REVIEW_GROUP_NAME, GroupEnumType.SITE); + if (!requestContainer.getPolicy().getAssignedRoles(finalGroup).contains(RoleManager.getRole(MccFinalReviewerRole.class))) + { + MutableSecurityPolicy policy = new MutableSecurityPolicy(requestContainer.getPolicy()); + policy.addRoleAssignment(finalGroup, RoleManager.getRole(MccFinalReviewerRole.class)); + SecurityPolicyManager.savePolicy(policy); + } + + Group adminGroup = GroupManager.getGroup(ContainerManager.getRoot(), MccManager.ADMIN_GROUP_NAME, GroupEnumType.SITE); + if (!requestContainer.getPolicy().getAssignedRoles(adminGroup).contains(RoleManager.getRole(MccDataAdminRole.class))) + { + MutableSecurityPolicy policy = new MutableSecurityPolicy(requestContainer.getPolicy()); + policy.addRoleAssignment(adminGroup, RoleManager.getRole(MccDataAdminRole.class)); + SecurityPolicyManager.savePolicy(policy); + } + } + + Container dataContainer = MccManager.get().getMCCContainer(); + if (dataContainer != null) + { + Group adminGroup = GroupManager.getGroup(ContainerManager.getRoot(), MccManager.ADMIN_GROUP_NAME, GroupEnumType.SITE); + if (!dataContainer.getPolicy().getAssignedRoles(adminGroup).contains(RoleManager.getRole(MccDataAdminRole.class))) + { + MutableSecurityPolicy policy = new MutableSecurityPolicy(dataContainer.getPolicy()); + policy.addRoleAssignment(adminGroup, RoleManager.getRole(MccDataAdminRole.class)); + SecurityPolicyManager.savePolicy(policy); + } + } + + return true; + } + + @Override + public void validateCommand(Object o, Errors errors) + { + Container mccContainer = MccManager.get().getMCCContainer(); + if (mccContainer == null) + { + errors.reject(ERROR_MSG, "The MCC data container property has not been set"); + } + + Container requestContainer = MccManager.get().getMCCRequestContainer(); + if (requestContainer == null) + { + errors.reject(ERROR_MSG, "The MCC request container property has not been set"); + } + } + + @NotNull + @Override + public URLHelper getSuccessURL(Object o) + { + return getContainer().getStartURL(getUser()); + } + } + @RequiresPermission(AdminPermission.class) public class ResetZimsRuntimeAction extends ConfirmAction<Object> { @@ -611,4 +712,77 @@ public URLHelper getSuccessURL(Object o) return PageFlowUtil.urlProvider(PipelineUrls.class).urlBegin(getContainer()); } } + + @RequiresPermission(MccRequestAdminPermission.class) + public class NotifyReviewersAction extends MutatingApiAction<NotifyReviewersForm> + { + @Override + public Object execute(NotifyReviewersForm form, BindException errors) throws Exception + { + if (form.getRowIds() == null || form.getRowIds().length == 0) + { + errors.reject(ERROR_MSG, "No rowIds provided"); + return null; + } + + List<Integer> rowIds = Arrays.stream(form.getRowIds()).collect(Collectors.toList()); + List<Integer> userIds = new TableSelector(MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_REQUEST_REVIEWS), PageFlowUtil.set("reviewerId"), new SimpleFilter(FieldKey.fromString("rowid"), rowIds, CompareType.IN), null).getArrayList(Integer.class); + if (userIds.size() != form.getRowIds().length) + { + errors.reject(ERROR_MSG, "Not all users in this request were found"); + return null; + } + + Set<Address> emails = new HashSet<>(); + for (int userId : userIds) + { + User u = UserManager.getUser(userId); + if (u == null) + { + _log.error("Unknown user: " + userId); + errors.reject(ERROR_MSG, "Unknown user: " + userId); + return null; + } + + ValidEmail validEmail = new ValidEmail(u.getEmail()); + emails.add(validEmail.getAddress()); + } + + try + { + MailHelper.MultipartMessage mail = MailHelper.createMultipartMessage(); + mail.setFrom("mcc-do-not-reply@ohsu.edu"); + mail.setSubject("MCC Animal Request Reviews"); + + Container rc = MccManager.get().getMCCRequestContainer(); + DetailsURL url = DetailsURL.fromString("/mcc/rabRequestReview.view", rc); + mail.setEncodedHtmlContent("You have been assigned one or more MCC Animal Requests to review. <a href=\"" + AppProps.getInstance().getBaseServerUrl() + url.getActionURL() + "\">Please click here to view and complete these assignments</a>"); + mail.addRecipients(Message.RecipientType.BCC, emails.toArray(new Address[0])); + mail.addRecipients(Message.RecipientType.TO, "mcc-do-not-reply@ohsu.edu"); + + MailHelper.send(mail, getUser(), getContainer()); + } + catch (Exception e) + { + _log.error("Unable to send MCC email", e); + } + + return new ApiSimpleResponse("success", true); + } + } + + public static class NotifyReviewersForm + { + Integer[] rowIds; + + public Integer[] getRowIds() + { + return rowIds; + } + + public void setRowIds(Integer[] rowIds) + { + this.rowIds = rowIds; + } + } } diff --git a/mcc/src/org/labkey/mcc/MccMaintenanceTask.java b/mcc/src/org/labkey/mcc/MccMaintenanceTask.java new file mode 100644 index 000000000..336e4f7eb --- /dev/null +++ b/mcc/src/org/labkey/mcc/MccMaintenanceTask.java @@ -0,0 +1,5 @@ +package org.labkey.mcc; + +public class MccMaintenanceTask +{ +} diff --git a/mcc/src/org/labkey/mcc/MccManager.java b/mcc/src/org/labkey/mcc/MccManager.java index 25689d5e6..bb93b0f9a 100644 --- a/mcc/src/org/labkey/mcc/MccManager.java +++ b/mcc/src/org/labkey/mcc/MccManager.java @@ -21,13 +21,21 @@ import org.apache.logging.log4j.Logger; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; +import org.labkey.api.ldk.notification.NotificationService; import org.labkey.api.module.Module; import org.labkey.api.module.ModuleLoader; import org.labkey.api.module.ModuleProperty; +import org.labkey.api.security.SecurityManager; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; +import org.labkey.api.security.UserPrincipal; import org.labkey.api.security.ValidEmail; +import org.labkey.api.security.permissions.Permission; +import org.labkey.mcc.security.MccFinalReviewPermission; +import org.labkey.mcc.security.MccRequestAdminPermission; +import org.labkey.mcc.security.MccRequestorPermission; +import javax.mail.Address; import java.io.File; import java.util.HashSet; import java.util.Set; @@ -36,6 +44,65 @@ public class MccManager { private static final Logger _log = LogManager.getLogger(MccManager.class); + public enum RequestStatus + { + Draft(1, "Draft", MccRequestorPermission.class), + Submitted(2, "Submitted", MccRequestorPermission.class), + FormCheck(3, "Internal Review", MccRequestAdminPermission.class), + RabReview(4, "RAB Review", MccRequestAdminPermission.class), + PendingDecision(5, "Pending Decision", MccFinalReviewPermission.class), + Approved(6, "Approved", MccRequestAdminPermission.class), + Rejected(7, "Rejected", MccRequestAdminPermission.class), + Processing(8, "Processing", MccRequestAdminPermission.class), + Fulfilled(8, "Fulfilled", MccRequestAdminPermission.class); + + int sortOrder; + String label; + Class<? extends Permission> editPermission; + + RequestStatus(int sortOrder, String label, Class<? extends Permission> editPermission) + { + this.sortOrder = sortOrder; + this.label = label; + this.editPermission = editPermission; + } + + public boolean canEdit(User u, Container c) + { + return c.hasPermission(u, this.editPermission); + } + + public String getLabel() + { + return label; + } + + public static RequestStatus resolveStatus(String val) + { + if (val == null) + { + return null; + } + + try + { + return valueOf(val); + } + catch (IllegalArgumentException e) + { + for (RequestStatus s : RequestStatus.values()) + { + if (s.label.equals(val)) + { + return s; + } + } + + return valueOf(val.substring(0, 1).toUpperCase() + val.substring(1).toLowerCase()); + } + } + } + public static final String ContainerPropName = "MCCContainer"; public static final String NotifyPropName = "MCCContactUsers"; public static final String MCCRequestNotificationUsers = "MCCRequestNotificationUsers"; @@ -45,6 +112,9 @@ public class MccManager public static final String MCC_GROUP_NAME = "MCC Users"; public static final String ANIMAL_GROUP_NAME = "MCC Animal Data Access"; public static final String REQUEST_GROUP_NAME = "MCC Animal Requestors"; + public static final String REQUEST_REVIEW_GROUP_NAME = "MCC RAB Members"; + public static final String FINAL_REVIEW_GROUP_NAME = "MCC Final Reviewers"; + public static final String ADMIN_GROUP_NAME = "MCC Admins"; private static final MccManager _instance = new MccManager(); @@ -69,6 +139,11 @@ public Container getMCCRequestContainer() return ContainerManager.getForPath(path); } + public String getMccAdminEmail() + { + return "mcc@ohsu.edu"; + } + public Container getMCCContainer() { Module m = ModuleLoader.getInstance().getModule(MccModule.NAME); @@ -80,6 +155,18 @@ public Container getMCCContainer() return ContainerManager.getForPath(path); } + public boolean isRequestAdmin(User u) + { + Container c = getMCCRequestContainer(); + if (c == null) + { + _log.error("MccManager.isRequestAdmin called, but MCCRequestContainer has not been set"); + return false; + } + + return c.hasPermission(u, MccRequestAdminPermission.class); + } + public File getZimsImportFolder(Container c) { Module m = ModuleLoader.getInstance().getModule(MccModule.NAME); @@ -93,17 +180,17 @@ public File getZimsImportFolder(Container c) return new File(val); } - public Set<User> getNotificationUsers() + public Set<Address> getNotificationUserEmails() { - return getUsersForProp(MccManager.NotifyPropName); + return getUserEmailsForProp(MccManager.NotifyPropName); } - public Set<User> getRequestNotificationUsers() + public Set<Address> getRequestNotificationUserEmails() { - return getUsersForProp(MccManager.MCCRequestNotificationUsers); + return getUserEmailsForProp(MccManager.MCCRequestNotificationUsers); } - private Set<User> getUsersForProp(String propName) + private Set<Address> getUserEmailsForProp(String propName) { Module m = ModuleLoader.getInstance().getModule(MccModule.NAME); ModuleProperty mp = m.getModuleProperties().get(propName); @@ -112,30 +199,38 @@ private Set<User> getUsersForProp(String propName) if (userNames == null) return null; - Set<User> ret = new HashSet<>(); - for (String username : userNames.split(",")) + Set<Address> ret = new HashSet<>(); + for (String principalName : userNames.split(",")) { - User u = UserManager.getUserByDisplayName(username); - if (u == null) + User u = UserManager.getUserByDisplayName(principalName); + if (u != null) { try { - u = UserManager.getUser(new ValidEmail(username)); + ret.add(new ValidEmail(u.getEmail()).getAddress()); } catch (ValidEmail.InvalidEmailException e) { - //ignore + _log.error("Invalid MCC email: " + principalName, e); } } - - if (u == null) + else { - _log.error("Unknown user registered for MCC notifications: " + username, new Exception()); - } + UserPrincipal up = SecurityManager.getPrincipal(principalName, getMCCContainer(), true); + if (up == null) + { + _log.error("Unknown user/group registered for MCC notifications: [" + principalName + "]", new Exception()); + continue; + } - if (u != null) - { - ret.add(u); + try + { + ret.addAll(NotificationService.get().getEmailsForPrincipal(up)); + } + catch (ValidEmail.InvalidEmailException e) + { + _log.error("Invalid MCC email: " + principalName, e); + } } } diff --git a/mcc/src/org/labkey/mcc/MccModule.java b/mcc/src/org/labkey/mcc/MccModule.java index 979dcba5c..74756b054 100644 --- a/mcc/src/org/labkey/mcc/MccModule.java +++ b/mcc/src/org/labkey/mcc/MccModule.java @@ -19,8 +19,10 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.json.JSONObject; +import org.labkey.api.data.Container; import org.labkey.api.ehr.EHRService; import org.labkey.api.ldk.ExtendedSimpleModule; +import org.labkey.api.ldk.LDKService; import org.labkey.api.module.Module; import org.labkey.api.module.ModuleContext; import org.labkey.api.query.DefaultSchema; @@ -29,7 +31,12 @@ import org.labkey.api.view.WebPartFactory; import org.labkey.api.writer.ContainerUser; import org.labkey.mcc.query.MccEhrCustomizer; +import org.labkey.mcc.query.ReviewerNotifyButton; import org.labkey.mcc.security.MccDataAdminRole; +import org.labkey.mcc.security.MccFinalReviewPermission; +import org.labkey.mcc.security.MccFinalReviewerRole; +import org.labkey.mcc.security.MccRabReviewPermission; +import org.labkey.mcc.security.MccRabReviewerRole; import org.labkey.mcc.security.MccRequestAdminPermission; import org.labkey.mcc.security.MccRequesterRole; @@ -50,7 +57,7 @@ public String getName() @Override public @Nullable Double getSchemaVersion() { - return 20.008; + return 20.011; } @Override @@ -73,6 +80,8 @@ protected void init() RoleManager.registerRole(new MccRequesterRole()); RoleManager.registerRole(new MccDataAdminRole()); + RoleManager.registerRole(new MccRabReviewerRole()); + RoleManager.registerRole(new MccFinalReviewerRole()); } @NotNull @@ -80,7 +89,11 @@ protected void init() public JSONObject getPageContextJson(ContainerUser context) { JSONObject ret = super.getPageContextJson(context); - ret.put("hasRequestAdminPermission", context.getContainer().hasPermission(context.getUser(), MccRequestAdminPermission.class)); + + Container requestContainer = MccManager.get().getMCCRequestContainer(); + ret.put("hasRequestAdminPermission", requestContainer != null && requestContainer.hasPermission(context.getUser(), MccRequestAdminPermission.class)); + ret.put("hasRabPermission", requestContainer != null && requestContainer.hasPermission(context.getUser(), MccRabReviewPermission.class)); + ret.put("hasFinalDecisionPermission", requestContainer != null && requestContainer.hasPermission(context.getUser(), MccFinalReviewPermission.class)); return ret; } @@ -89,6 +102,7 @@ public JSONObject getPageContextJson(ContainerUser context) protected void doStartupAfterSpringConfig(ModuleContext moduleContext) { registerEHRResources(); + LDKService.get().registerQueryButton(new ReviewerNotifyButton(), MccSchema.NAME, MccSchema.TABLE_REQUEST_REVIEWS); } @Override diff --git a/mcc/src/org/labkey/mcc/MccSchema.java b/mcc/src/org/labkey/mcc/MccSchema.java index f1ab31378..1745b67bb 100644 --- a/mcc/src/org/labkey/mcc/MccSchema.java +++ b/mcc/src/org/labkey/mcc/MccSchema.java @@ -28,6 +28,9 @@ public class MccSchema public static final String TABLE_USER_REQUESTS = "userRequests"; public static final String TABLE_ETL_TRANSLATIONS = "etltranslations"; public static final String TABLE_ANIMAL_MAPPING = "animalMapping"; + public static final String TABLE_ANIMAL_REQUESTS = "animalRequests"; + public static final String TABLE_REQUEST_REVIEWS = "requestReviews"; + public static final String TABLE_REQUEST_SCORE = "requestScores"; public static MccSchema getInstance() { diff --git a/mcc/src/org/labkey/mcc/MccUserSchema.java b/mcc/src/org/labkey/mcc/MccUserSchema.java index cfcd60fc1..449adccad 100644 --- a/mcc/src/org/labkey/mcc/MccUserSchema.java +++ b/mcc/src/org/labkey/mcc/MccUserSchema.java @@ -4,10 +4,24 @@ import org.jetbrains.annotations.Nullable; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerFilter; +import org.labkey.api.data.DataColumn; import org.labkey.api.data.DbSchema; +import org.labkey.api.data.JdbcType; +import org.labkey.api.data.SQLFragment; import org.labkey.api.data.TableInfo; +import org.labkey.api.ldk.table.CustomPermissionsTable; +import org.labkey.api.query.ExprColumn; +import org.labkey.api.query.FieldKey; import org.labkey.api.query.SimpleUserSchema; import org.labkey.api.security.User; +import org.labkey.api.security.permissions.DeletePermission; +import org.labkey.api.security.permissions.InsertPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.permissions.UpdatePermission; +import org.labkey.mcc.security.MccRequestAdminPermission; +import org.labkey.mcc.security.MccRequestorPermission; + +import java.util.Arrays; public class MccUserSchema extends SimpleUserSchema { @@ -20,6 +34,70 @@ public MccUserSchema(User user, Container container, DbSchema dbschema) @Nullable protected TableInfo createWrappedTable(String name, @NotNull TableInfo schemaTable, ContainerFilter cf) { + if (MccSchema.TABLE_ANIMAL_REQUESTS.equalsIgnoreCase(name)) + { + CustomPermissionsTable<?> ret = new CustomPermissionsTable<>(this, schemaTable, cf); + ret.addPermissionMapping(InsertPermission.class, MccRequestorPermission.class); + ret.addPermissionMapping(UpdatePermission.class, MccRequestorPermission.class); + ret.addPermissionMapping(DeletePermission.class, MccRequestAdminPermission.class); + + return ret.init(); + } + else if (MccSchema.TABLE_REQUEST_REVIEWS.equalsIgnoreCase(name) || MccSchema.TABLE_REQUEST_SCORE.equalsIgnoreCase(name)) + { + CustomPermissionsTable<?> ret = new CustomPermissionsTable<>(this, schemaTable, cf); + ret.addPermissionMapping(ReadPermission.class, MccRequestAdminPermission.class); + ret.addPermissionMapping(InsertPermission.class, MccRequestAdminPermission.class); + ret.addPermissionMapping(UpdatePermission.class, MccRequestAdminPermission.class); + ret.addPermissionMapping(DeletePermission.class, MccRequestAdminPermission.class); + + ret = ret.init(); + + if (MccSchema.TABLE_REQUEST_SCORE.equalsIgnoreCase(name)) + { + return addScoreColumns(ret); + } + + return ret; + } + return super.createWrappedTable(name, schemaTable, cf); } + + private CustomPermissionsTable<?> addScoreColumns(CustomPermissionsTable<?> ti) + { + if (ti.getColumn("rabReviewStatus") == null) + { + SQLFragment sql = new SQLFragment("(SELECT CONCAT(COALESCE(CAST(sum(CASE WHEN r.review IS NULL THEN 0 ELSE 1 END) as varchar), '0'), ' of ', cast(count(*) as varchar), ' completed') as expr FROM mcc.requestReviews r WHERE r.requestId = " + ExprColumn.STR_TABLE_ALIAS + ".requestId)"); + ExprColumn newCol = new ExprColumn(ti, "rabReviewStatus", sql, JdbcType.VARCHAR, ti.getColumn("requestId")); + newCol.setSortFieldKeys(Arrays.asList(FieldKey.fromString("pendingRabReviews"))); + + newCol.setLabel("RAB Review Status"); + newCol.setDisplayColumnFactory(colInfo -> { + return new DataColumn(colInfo) + { + @Override + public boolean isFilterable() + { + return false; + } + + @Override + public boolean isSortable() + { + return false; + } + }; + }); + + ti.addColumn(newCol); + + SQLFragment sql2 = new SQLFragment("(SELECT COALESCE(sum(CASE WHEN r.review IS NULL THEN 1 ELSE 0 END), -1) as expr FROM mcc.requestReviews r WHERE r.requestId = " + ExprColumn.STR_TABLE_ALIAS + ".requestId)"); + ExprColumn newCol2 = new ExprColumn(ti, "pendingRabReviews", sql2, JdbcType.INTEGER, ti.getColumn("requestId")); + newCol2.setLabel("Pending RAB Reviews"); + ti.addColumn(newCol2); + } + + return ti; + } } diff --git a/mcc/src/org/labkey/mcc/etl/PopulateIdsStep.java b/mcc/src/org/labkey/mcc/etl/PopulateIdsStep.java index 75c222b82..8ea37d2b9 100644 --- a/mcc/src/org/labkey/mcc/etl/PopulateIdsStep.java +++ b/mcc/src/org/labkey/mcc/etl/PopulateIdsStep.java @@ -50,42 +50,53 @@ public RecordedActionSet run(@NotNull PipelineJob job) throws PipelineJobExcepti throw new PipelineJobException("Unable to find table: aggregatedDemographics"); } - TableSelector ts = new TableSelector(sourceTi, PageFlowUtil.set("originalId", "container"), new SimpleFilter(FieldKey.fromString("Id"), null, CompareType.ISBLANK), null); + populateForField(job, sourceTi, "Id", "originalId"); + populateForField(job, sourceTi, "dam", "originalDam"); + populateForField(job, sourceTi, "sire", "originalSire"); + + return new RecordedActionSet(); + } + + private void populateForField(PipelineJob job, TableInfo sourceTi, String fieldName, String originalIdField) + { + final Map<Container, List<Map<String, Object>>> toAdd = new HashMap<>(); + + SimpleFilter filter = new SimpleFilter(FieldKey.fromString(fieldName), null, CompareType.ISBLANK); + filter.addCondition(FieldKey.fromString(originalIdField), null, CompareType.NONBLANK); + + TableSelector ts = new TableSelector(sourceTi, PageFlowUtil.set(originalIdField, "container"), filter, null); if (ts.exists()) { - final Map<Container, List<Map<String, Object>>> toAdd = new HashMap<>(); ts.forEachResults(rs -> { Container c = ContainerManager.getForId(rs.getString(FieldKey.fromString("container"))); List<Map<String, Object>> rows = toAdd.containsKey(c) ? toAdd.get(c) : new ArrayList<>(); CaseInsensitiveHashMap<Object> row = new CaseInsensitiveHashMap<>(); - row.put("subjectname", rs.getString(FieldKey.fromString("originalId"))); - row.put("externalAlias", null); + row.put("subjectname", rs.getString(FieldKey.fromString(originalIdField))); + row.put("externalAlias", null); //NOTE: the trigger script will auto-assign a value, but we need to include this property on the input JSON rows.add(row); toAdd.put(c, rows); }); + } - try + try + { + for (Container c : toAdd.keySet()) { - for (Container c : toAdd.keySet()) + job.getLogger().info("Total IDs to alias for field " + fieldName + " in container: " + c.getPath() + ": " + toAdd.get(c).size()); + TableInfo ti = QueryService.get().getUserSchema(_containerUser.getUser(), c, MccSchema.NAME).getTable(MccSchema.TABLE_ANIMAL_MAPPING); + BatchValidationException bve = new BatchValidationException(); + ti.getUpdateService().insertRows(_containerUser.getUser(), c, toAdd.get(c), bve, null, null); + if (bve.hasErrors()) { - job.getLogger().info("Total IDs to alias for " + c.getPath() + ": " + toAdd.get(c).size()); - TableInfo ti = QueryService.get().getUserSchema(_containerUser.getUser(), c, MccSchema.NAME).getTable(MccSchema.TABLE_ANIMAL_MAPPING); - BatchValidationException bve = new BatchValidationException(); - ti.getUpdateService().insertRows(_containerUser.getUser(), c, toAdd.get(c), bve, null, null); - if (bve.hasErrors()) - { - throw bve; - } + throw bve; } } - catch (BatchValidationException | DuplicateKeyException | QueryUpdateServiceException | SQLException e) - { - job.getLogger().error("Error populating IDs", e); - } } - - return new RecordedActionSet(); + catch (BatchValidationException | DuplicateKeyException | QueryUpdateServiceException | SQLException e) + { + job.getLogger().error("Error populating IDs", e); + } } @Override diff --git a/mcc/src/org/labkey/mcc/query/AbstractMccDisplayColumn.java b/mcc/src/org/labkey/mcc/query/AbstractMccDisplayColumn.java new file mode 100644 index 000000000..44065cf7c --- /dev/null +++ b/mcc/src/org/labkey/mcc/query/AbstractMccDisplayColumn.java @@ -0,0 +1,43 @@ +package org.labkey.mcc.query; + +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.DataColumn; +import org.labkey.api.query.FieldKey; + +public abstract class AbstractMccDisplayColumn extends DataColumn +{ + public AbstractMccDisplayColumn(ColumnInfo colInfo) + { + super(colInfo); + } + + protected FieldKey getBoundKey(String... colNames) + { + FieldKey ret = null; + for (String colName : colNames) + { + if (ret == null) + { + ret = new FieldKey(getBoundColumn().getFieldKey().getParent(), colName); + } + else + { + ret = ret.append(colName); + } + } + + return ret; + } + + @Override + public boolean isFilterable() + { + return false; + } + + @Override + public boolean isSortable() + { + return false; + } +} diff --git a/mcc/src/org/labkey/mcc/query/AnimalRequestActionsDisplayColumnFactory.java b/mcc/src/org/labkey/mcc/query/AnimalRequestActionsDisplayColumnFactory.java new file mode 100644 index 000000000..7b85c29ca --- /dev/null +++ b/mcc/src/org/labkey/mcc/query/AnimalRequestActionsDisplayColumnFactory.java @@ -0,0 +1,45 @@ +package org.labkey.mcc.query; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.DisplayColumn; +import org.labkey.api.data.DisplayColumnFactory; +import org.labkey.api.data.RenderContext; +import org.labkey.api.query.FieldKey; +import org.labkey.api.security.User; +import org.labkey.api.security.UserManager; +import org.labkey.mcc.MccManager; + +import java.io.IOException; +import java.io.Writer; +import java.util.Set; + +public class AnimalRequestActionsDisplayColumnFactory implements DisplayColumnFactory +{ + private static final Logger _log = LogManager.getLogger(AnimalRequestActionsDisplayColumnFactory.class); + + @Override + public DisplayColumn createRenderer(ColumnInfo colInfo) + { + return new AbstractMccDisplayColumn(colInfo) + { + @Override + public void renderGridCellContents(RenderContext ctx, Writer out) throws IOException + { + int rowId = ctx.get(getBoundKey("rowid"), Integer.class); + out.write("<a class=\"labkey-text-link\" href=\"mailto:" + MccManager.get().getMccAdminEmail() + "?subject=MCC Request #" + rowId + "\">Contact MCC</a>"); + } + + @Override + public void addQueryFieldKeys(Set<FieldKey> keys) + { + super.addQueryFieldKeys(keys); + + keys.add(getBoundKey("rowid")); + keys.add(getBoundKey("createdby")); + keys.add(getBoundKey("status")); + } + }; + } +} diff --git a/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java b/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java index 9463e3fb5..b3b3f9467 100644 --- a/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java +++ b/mcc/src/org/labkey/mcc/query/MccEhrCustomizer.java @@ -30,9 +30,19 @@ public void customize(TableInfo table) { customizeAnimalTable((AbstractTableInfo)table); } + else if (matches(table, "study", "demographics")) + { + customizeDemographics((AbstractTableInfo)table); + } } } + private void customizeDemographics(AbstractTableInfo ti) + { + addMccAlias(ti, "dam", "damMccAlias", "Dam MCC Alias"); + addMccAlias(ti, "sire", "sireMccAlias", "Sire MCC Alias"); + } + private void customizeAnimalTable(AbstractTableInfo ti) { for (String colName : new String[]{"MostRecentArrival", "numRoommates", "MostRecentDeparture", "curLocation", "lastHousing", "weightChange", "CageClass", "MhcStatus"}) @@ -44,11 +54,20 @@ private void customizeAnimalTable(AbstractTableInfo ti) } } - String mccId = "mccAlias"; - if (ti.getColumn(mccId) == null) + addMccAlias(ti, "Id", "mccAlias", "MCC Alias"); + } + + private void addMccAlias(AbstractTableInfo ti, String sourceCol, String name, String label) + { + if (ti.getColumn(sourceCol) == null) + { + return; + } + + if (ti.getColumn(name) == null) { - WrappedColumn ci = new WrappedColumn(ti.getColumn("Id"), mccId); - ci.setFieldKey(FieldKey.fromParts(mccId)); + WrappedColumn ci = new WrappedColumn(ti.getColumn(sourceCol), name); + ci.setFieldKey(FieldKey.fromParts(name)); final UserSchema us = getUserSchema(ti, MccSchema.NAME); LookupForeignKey fk = new LookupForeignKey("subjectname") { @@ -58,11 +77,10 @@ public TableInfo getLookupTableInfo() return us.getTable(MccSchema.TABLE_ANIMAL_MAPPING); } }; - fk.addJoin(FieldKey.fromString("Id"), "subjectname", false); - + fk.addJoin(FieldKey.fromString(sourceCol), "subjectname", false); ci.setFk(fk); ci.setUserEditable(false); - ci.setLabel("MCC Alias"); + ci.setLabel(label); ti.addColumn(ci); } } diff --git a/mcc/src/org/labkey/mcc/query/MccRequest.java b/mcc/src/org/labkey/mcc/query/MccRequest.java new file mode 100644 index 000000000..c89f69fdb --- /dev/null +++ b/mcc/src/org/labkey/mcc/query/MccRequest.java @@ -0,0 +1,440 @@ +package org.labkey.mcc.query; + +import org.labkey.api.data.SimpleFilter; +import org.labkey.api.data.TableSelector; +import org.labkey.api.query.FieldKey; +import org.labkey.mcc.MccSchema; + +import java.util.Date; + +public class MccRequest +{ + private int _rowId; + private String _lastname; + private String _firstname; + private String _middleinitial; + private Boolean _isprincipalinvestigator; + + + private String _institutionname; + private String _institutioncity; + private String _institutionstate; + private String _institutioncountry; + private String _institutiontype; + private String _officiallastname; + private String _officialfirstname; + private String _officialemail; + private String _fundingsource; + private String _grantnumber; + + private Date _applicationduedate; + private String _experimentalrationale; + private String _methodsproposed; + private String _collaborations; + private Boolean _isbreedinganimals; + private String _breedingpurpose; + private Boolean _existingmarmosetcolony; + private Boolean _existingnhpfacilities; + private String _animalwelfare; + private Boolean _certify; + private String _vetlastname; + private String _vetfirstname; + private String _vetemail; + private String _iacucapproval; + private String _iacucprotocol; + private String _status; + + private String _objectId; + private String _container; + private Date _created; + private int _createdby; + private Date _modified; + private int _modifiedby; + + public MccRequest() + { + + } + + public int getRowId() + { + return _rowId; + } + + public void setRowId(int rowId) + { + _rowId = rowId; + } + + public String getLastname() + { + return _lastname; + } + + public void setLastname(String lastname) + { + _lastname = lastname; + } + + public String getFirstname() + { + return _firstname; + } + + public void setFirstname(String firstname) + { + _firstname = firstname; + } + + public String getMiddleinitial() + { + return _middleinitial; + } + + public void setMiddleinitial(String middleinitial) + { + _middleinitial = middleinitial; + } + + public Boolean getIsprincipalinvestigator() + { + return _isprincipalinvestigator; + } + + public void setIsprincipalinvestigator(Boolean isprincipalinvestigator) + { + _isprincipalinvestigator = isprincipalinvestigator; + } + + public String getInstitutionname() + { + return _institutionname; + } + + public void setInstitutionname(String institutionname) + { + _institutionname = institutionname; + } + + public String getInstitutioncity() + { + return _institutioncity; + } + + public void setInstitutioncity(String institutioncity) + { + _institutioncity = institutioncity; + } + + public String getInstitutionstate() + { + return _institutionstate; + } + + public void setInstitutionstate(String institutionstate) + { + _institutionstate = institutionstate; + } + + public String getInstitutioncountry() + { + return _institutioncountry; + } + + public void setInstitutioncountry(String institutioncountry) + { + _institutioncountry = institutioncountry; + } + + public String getInstitutiontype() + { + return _institutiontype; + } + + public void setInstitutiontype(String institutiontype) + { + _institutiontype = institutiontype; + } + + public String getOfficiallastname() + { + return _officiallastname; + } + + public void setOfficiallastname(String officiallastname) + { + _officiallastname = officiallastname; + } + + public String getOfficialfirstname() + { + return _officialfirstname; + } + + public void setOfficialfirstname(String officialfirstname) + { + _officialfirstname = officialfirstname; + } + + public String getOfficialemail() + { + return _officialemail; + } + + public void setOfficialemail(String officialemail) + { + _officialemail = officialemail; + } + + public String getFundingsource() + { + return _fundingsource; + } + + public void setFundingsource(String fundingsource) + { + _fundingsource = fundingsource; + } + + public String getGrantnumber() + { + return _grantnumber; + } + + public void setGrantnumber(String grantnumber) + { + _grantnumber = grantnumber; + } + + public Date getApplicationduedate() + { + return _applicationduedate; + } + + public void setApplicationduedate(Date applicationduedate) + { + _applicationduedate = applicationduedate; + } + + public String getExperimentalrationale() + { + return _experimentalrationale; + } + + public void setExperimentalrationale(String experimentalrationale) + { + _experimentalrationale = experimentalrationale; + } + + public String getMethodsproposed() + { + return _methodsproposed; + } + + public void setMethodsproposed(String methodsproposed) + { + _methodsproposed = methodsproposed; + } + + public String getCollaborations() + { + return _collaborations; + } + + public void setCollaborations(String collaborations) + { + _collaborations = collaborations; + } + + public Boolean getIsbreedinganimals() + { + return _isbreedinganimals; + } + + public void setIsbreedinganimals(Boolean isbreedinganimals) + { + _isbreedinganimals = isbreedinganimals; + } + + public String getBreedingpurpose() + { + return _breedingpurpose; + } + + public void setBreedingpurpose(String breedingpurpose) + { + _breedingpurpose = breedingpurpose; + } + + public Boolean getExistingmarmosetcolony() + { + return _existingmarmosetcolony; + } + + public void setExistingmarmosetcolony(Boolean existingmarmosetcolony) + { + _existingmarmosetcolony = existingmarmosetcolony; + } + + public Boolean getExistingnhpfacilities() + { + return _existingnhpfacilities; + } + + public void setExistingnhpfacilities(Boolean existingnhpfacilities) + { + _existingnhpfacilities = existingnhpfacilities; + } + + public String getAnimalwelfare() + { + return _animalwelfare; + } + + public void setAnimalwelfare(String animalwelfare) + { + _animalwelfare = animalwelfare; + } + + public Boolean getCertify() + { + return _certify; + } + + public void setCertify(Boolean certify) + { + _certify = certify; + } + + public String getVetlastname() + { + return _vetlastname; + } + + public void setVetlastname(String vetlastname) + { + _vetlastname = vetlastname; + } + + public String getVetfirstname() + { + return _vetfirstname; + } + + public void setVetfirstname(String vetfirstname) + { + _vetfirstname = vetfirstname; + } + + public String getVetemail() + { + return _vetemail; + } + + public void setVetemail(String vetemail) + { + _vetemail = vetemail; + } + + public String getIacucapproval() + { + return _iacucapproval; + } + + public void setIacucapproval(String iacucapproval) + { + _iacucapproval = iacucapproval; + } + + public String getIacucprotocol() + { + return _iacucprotocol; + } + + public void setIacucprotocol(String iacucprotocol) + { + _iacucprotocol = iacucprotocol; + } + + public String getStatus() + { + return _status; + } + + public void setStatus(String status) + { + _status = status; + } + + public String getObjectId() + { + return _objectId; + } + + public void setObjectId(String objectId) + { + _objectId = objectId; + } + + public String getContainer() + { + return _container; + } + + public void setContainer(String container) + { + _container = container; + } + + public Date getCreated() + { + return _created; + } + + public void setCreated(Date created) + { + _created = created; + } + + public int getCreatedby() + { + return _createdby; + } + + public void setCreatedby(int createdby) + { + _createdby = createdby; + } + + public Date getModified() + { + return _modified; + } + + public void setModified(Date modified) + { + _modified = modified; + } + + public int getModifiedby() + { + return _modifiedby; + } + + public void setModifiedby(int modifiedby) + { + _modifiedby = modifiedby; + } + + public static MccRequest getForId(String objectId) + { + return new TableSelector(MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_ANIMAL_REQUESTS)).getObject(objectId, MccRequest.class); + } + + public static MccRequest getForRowId(int rowId) + { + SimpleFilter filter = new SimpleFilter(FieldKey.fromString("rowid"), rowId); + + return new TableSelector(MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_ANIMAL_REQUESTS), filter, null).getObject(MccRequest.class); + } +} diff --git a/mcc/src/org/labkey/mcc/query/RequestReviewActionsDisplayColumnFactory.java b/mcc/src/org/labkey/mcc/query/RequestReviewActionsDisplayColumnFactory.java new file mode 100644 index 000000000..2b6c45a6f --- /dev/null +++ b/mcc/src/org/labkey/mcc/query/RequestReviewActionsDisplayColumnFactory.java @@ -0,0 +1,63 @@ +package org.labkey.mcc.query; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.Container; +import org.labkey.api.data.DataColumn; +import org.labkey.api.data.DisplayColumn; +import org.labkey.api.data.DisplayColumnFactory; +import org.labkey.api.data.RenderContext; +import org.labkey.api.query.DetailsURL; +import org.labkey.api.query.FieldKey; +import org.labkey.api.security.User; +import org.labkey.api.security.UserManager; +import org.labkey.mcc.MccManager; + +import java.io.IOException; +import java.io.Writer; +import java.util.Set; + +public class RequestReviewActionsDisplayColumnFactory implements DisplayColumnFactory +{ + private static final Logger _log = LogManager.getLogger(RequestReviewActionsDisplayColumnFactory.class); + + @Override + public DisplayColumn createRenderer(ColumnInfo colInfo) + { + return new AbstractMccDisplayColumn(colInfo) + { + @Override + public void renderGridCellContents(RenderContext ctx, Writer out) throws IOException + { + int userId = ctx.get(getBoundKey("reviewerId"), Integer.class); + User u = UserManager.getUser(userId); + if (u == null) + { + _log.error("Unknown user: " + userId + " for MCC review record " + userId, new Exception()); + return; + } + + if (!ctx.getViewContext().getUser().equals(u)) { + return; + } + + String requestId = ctx.get(getBoundKey("requestId"), String.class); + Container requestContainer = MccManager.get().getMCCRequestContainer(); + DetailsURL url = DetailsURL.fromString("/mcc/requestReview.view?requestId=" + requestId + "&mode=rabReview", requestContainer); + out.write("<a class=\"labkey-text-link\" href=\"" + url.getActionURL().addReturnURL(ctx.getViewContext().getActionURL()) + "\">Enter Review</a>"); + } + + @Override + public void addQueryFieldKeys(Set<FieldKey> keys) + { + super.addQueryFieldKeys(keys); + + keys.add(getBoundKey("container")); + keys.add(getBoundKey("requestid")); + keys.add(getBoundKey("rowid")); + keys.add(getBoundKey("reviewerId")); + } + }; + } +} diff --git a/mcc/src/org/labkey/mcc/query/RequestScoreActionsDisplayColumnFactory.java b/mcc/src/org/labkey/mcc/query/RequestScoreActionsDisplayColumnFactory.java new file mode 100644 index 000000000..5e9688bb3 --- /dev/null +++ b/mcc/src/org/labkey/mcc/query/RequestScoreActionsDisplayColumnFactory.java @@ -0,0 +1,121 @@ +package org.labkey.mcc.query; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.NotNull; +import org.labkey.api.data.ColumnInfo; +import org.labkey.api.data.Container; +import org.labkey.api.data.DataColumn; +import org.labkey.api.data.DisplayColumn; +import org.labkey.api.data.DisplayColumnFactory; +import org.labkey.api.data.RenderContext; +import org.labkey.api.query.DetailsURL; +import org.labkey.api.query.FieldKey; +import org.labkey.api.security.User; +import org.labkey.api.security.UserManager; +import org.labkey.api.view.template.ClientDependency; +import org.labkey.mcc.MccManager; +import org.labkey.mcc.security.MccFinalReviewPermission; +import org.labkey.mcc.security.MccRequestAdminPermission; + +import java.io.IOException; +import java.io.Writer; +import java.util.Set; + +public class RequestScoreActionsDisplayColumnFactory implements DisplayColumnFactory +{ + private static final Logger _log = LogManager.getLogger(RequestScoreActionsDisplayColumnFactory.class); + + @Override + public DisplayColumn createRenderer(ColumnInfo colInfo) + { + return new AbstractMccDisplayColumn(colInfo) + { + @Override + public void renderGridCellContents(RenderContext ctx, Writer out) throws IOException + { + int requestRowId = ctx.get(getBoundKey("requestId", "rowid"), Integer.class); + if (MccManager.get().isRequestAdmin(ctx.getViewContext().getUser())) + { + int userId = ctx.get(getBoundKey("requestId", "createdby"), Integer.class); + User u = UserManager.getUser(userId); + if (u == null) + { + _log.error("Unknown user: " + userId + " for MCC request " + requestRowId, new Exception()); + return; + } + + out.write("<a class=\"labkey-text-link\" href=\"mailto:" + u.getEmail() + "?subject=MCC Request #" + requestRowId + "\">Contact Investigator</a>"); + } + + String status = ctx.get(getBoundKey("requestId", "status"), String.class); + if (status == null) + { + _log.error("MCC Request lacks status: " + requestRowId, new Exception()); + } + else + { + try + { + String requestId = ctx.get(getBoundKey("requestId"), String.class); + + MccManager.RequestStatus st = MccManager.RequestStatus.resolveStatus(status); + Container requestContainer = MccManager.get().getMCCRequestContainer(); + if (requestContainer == null) + { + _log.error("RequestScoreActionsDisplayColumnFactory was called, but MCCRequestContainer is not set", new Exception()); + return; + } + + if (st == MccManager.RequestStatus.Submitted) + { + if (requestContainer.hasPermission(ctx.getViewContext().getUser(), MccRequestAdminPermission.class)) + { + DetailsURL url = DetailsURL.fromString("/mcc/requestReview.view?requestId=" + requestId + "&mode=primaryReview", requestContainer); + out.write("<br><a class=\"labkey-text-link\" href=\"" + url.getActionURL().addReturnURL(ctx.getViewContext().getActionURL()) + "\">Enter MCC Internal Review</a>"); + } + } + else if (st == MccManager.RequestStatus.FormCheck) + { + if (requestContainer.hasPermission(ctx.getViewContext().getUser(), MccRequestAdminPermission.class)) + { + out.write("<br><a class=\"labkey-text-link\" href=\"javascript:void(0)\">Submit For RAB Review</a>"); + } + } + else if (st == MccManager.RequestStatus.PendingDecision || + (st == MccManager.RequestStatus.RabReview && ctx.get(FieldKey.fromString("pendingRabReviews"), Integer.class) == 0) + ) + { + if (requestContainer.hasPermission(ctx.getViewContext().getUser(), MccFinalReviewPermission.class)) + { + DetailsURL url = DetailsURL.fromString("/mcc/requestReview.view?requestId=" + requestId + "&mode=finalReview", requestContainer); + out.write("<br><a class=\"labkey-text-link\" href=\"" + url.getActionURL().addReturnURL(ctx.getViewContext().getActionURL()) + "\">Enter Final Review</a>"); + } + } + else if (st == MccManager.RequestStatus.Approved) + { + out.write("<br><a class=\"labkey-text-link\" href=\"javascript:alert('This is not enabled yet')\">Update Animal Availability</a>"); + } + } + catch (IllegalArgumentException e) + { + _log.error("Unknown MCC Request status: " + requestRowId, new Exception()); + } + } + } + + @Override + public void addQueryFieldKeys(Set<FieldKey> keys) + { + super.addQueryFieldKeys(keys); + + keys.add(getBoundKey("rowid")); + keys.add(getBoundKey("requestId", "createdby")); + keys.add(getBoundKey("requestId")); + keys.add(getBoundKey("pendingRabReviews")); + keys.add(getBoundKey("requestId", "status")); + keys.add(getBoundKey("requestId" , "rowid")); + } + }; + } +} diff --git a/mcc/src/org/labkey/mcc/query/ReviewerNotifyButton.java b/mcc/src/org/labkey/mcc/query/ReviewerNotifyButton.java new file mode 100644 index 000000000..7d114ba32 --- /dev/null +++ b/mcc/src/org/labkey/mcc/query/ReviewerNotifyButton.java @@ -0,0 +1,18 @@ +package org.labkey.mcc.query; + +import org.labkey.api.ldk.table.SimpleButtonConfigFactory; +import org.labkey.api.module.ModuleLoader; +import org.labkey.api.view.template.ClientDependency; +import org.labkey.mcc.MccModule; +import org.labkey.mcc.security.MccRequestAdminPermission; + +import java.util.Arrays; + +public class ReviewerNotifyButton extends SimpleButtonConfigFactory +{ + public ReviewerNotifyButton() + { + super(ModuleLoader.getInstance().getModule(MccModule.class), "Notify Reviewers", "MCC.window.ReviewerNotifyWindow.buttonHandler(dataRegionName);", Arrays.asList(ClientDependency.supplierFromPath("mcc/window/ReviewerNotifyWindow.js"))); + setPermission(MccRequestAdminPermission.class); + } +} diff --git a/mcc/src/org/labkey/mcc/query/TriggerHelper.java b/mcc/src/org/labkey/mcc/query/TriggerHelper.java index 947e73f51..a40fb3d11 100644 --- a/mcc/src/org/labkey/mcc/query/TriggerHelper.java +++ b/mcc/src/org/labkey/mcc/query/TriggerHelper.java @@ -3,6 +3,8 @@ import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +import org.jetbrains.annotations.Nullable; +import org.labkey.api.collections.CaseInsensitiveHashMap; import org.labkey.api.data.Container; import org.labkey.api.data.ContainerManager; import org.labkey.api.data.DbSchema; @@ -10,23 +12,38 @@ import org.labkey.api.data.DbSequence; import org.labkey.api.data.DbSequenceManager; import org.labkey.api.data.SimpleFilter; +import org.labkey.api.data.Table; import org.labkey.api.data.TableInfo; import org.labkey.api.data.TableSelector; +import org.labkey.api.query.BatchValidationException; import org.labkey.api.query.DetailsURL; import org.labkey.api.query.FieldKey; +import org.labkey.api.query.InvalidKeyException; +import org.labkey.api.query.QueryService; +import org.labkey.api.query.QueryUpdateServiceException; +import org.labkey.api.query.UserSchema; import org.labkey.api.security.User; import org.labkey.api.security.UserManager; +import org.labkey.api.security.permissions.DeletePermission; import org.labkey.api.settings.AppProps; -import org.labkey.api.util.ExceptionUtil; import org.labkey.api.util.MailHelper; +import org.labkey.api.util.PageFlowUtil; +import org.labkey.api.view.UnauthorizedException; import org.labkey.mcc.MccManager; import org.labkey.mcc.MccSchema; import javax.mail.Address; import javax.mail.Message; -import javax.mail.internet.InternetAddress; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; import java.util.HashSet; +import java.util.List; +import java.util.Map; import java.util.Set; +import java.util.stream.Collectors; /** * Created by bimber @@ -71,22 +88,85 @@ public boolean isAliasInUse(String alias) return new TableSelector(_animalMapping, new SimpleFilter(FieldKey.fromString("externalAlias"), alias), null).exists(); } - public void sendNotification(int rowid) { - Set<User> users = MccManager.get().getRequestNotificationUsers(); - if (users == null || users.isEmpty()) + public void ensureReviewRecordsCreated(String objectId, String status, @Nullable String previousStatus, int score) + { + if (objectId == null) { - _log.error("An MCC request was finalized but there are no notification users"); + _log.error("No objectId provided, cannot update animalRequest record"); return; } try { - Set<Address> emails = new HashSet<>(); - for (User u : users) + MccManager.RequestStatus st = MccManager.RequestStatus.resolveStatus(status); + if (st == MccManager.RequestStatus.Draft) { - emails.add(new InternetAddress(u.getEmail())); + return; + } + + // NOTE: regular users (opposed to those with MccRequestAdminPermission) cannot read this table. Therefore do these operations using the schema layer, not QUS + TableInfo scoreTable = MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_REQUEST_SCORE); + TableSelector ts = new TableSelector(scoreTable, PageFlowUtil.set("rowid", "preliminaryScore"), new SimpleFilter(FieldKey.fromString("requestid"), objectId), null); + if (!ts.exists()) + { + Map<String, Object> toInsert = new CaseInsensitiveHashMap<>(); + toInsert.put("requestId", objectId); + toInsert.put("preliminaryScore", score); + + toInsert.put("container", _container); + toInsert.put("created", new Date()); + toInsert.put("createdby", _user.getUserId()); + toInsert.put("modified", new Date()); + toInsert.put("modifiedby", _user.getUserId()); + + Table.insert(_user, scoreTable, toInsert); } + else + { + // Ensure score is accurate in the case the underlying data changed: + List<Map<String, Object>> records = new ArrayList<>(ts.getMapCollection()); + if (records.size() != 1) + { + _log.error("More than one requestScore record found for requestId: " + objectId); + } + + Map<String, Object> row = records.get(0); + if (score != (Integer)row.get("preliminaryScore")) + { + row.put("preliminaryScore", score); + row.put("modified", new Date()); + row.put("modifiedby", _user.getUserId()); + Table.update(_user, scoreTable, row, row.get("rowid")); + } + } + + // This indicates the form was submitted immediately (i.e. not a draft), or it was in draft state and has advanced. + MccManager.RequestStatus st2 = previousStatus == null ? null : MccManager.RequestStatus.resolveStatus(previousStatus); + if (st2 == null || st2 == MccManager.RequestStatus.Draft) + { + sendInitialNotification(); + } + } + catch (IllegalArgumentException e) + { + _log.error("Unknown MCC status: " + status); + } + catch (Exception e) + { + _log.error("Error in ensureReviewRecordsCreated", e); + } + } + private void sendInitialNotification() { + Set<Address> emails = MccManager.get().getRequestNotificationUserEmails(); + if (emails == null || emails.isEmpty()) + { + _log.error("An MCC request was finalized but there are no notification users"); + return; + } + + try + { MailHelper.MultipartMessage mail = MailHelper.createMultipartMessage(); mail.setFrom("mcc-do-not-reply@ohsu.edu"); mail.setSubject("MCC Animal Request"); @@ -103,4 +183,63 @@ public void sendNotification(int rowid) { _log.error("Unable to send MCC email", e); } } + + public void cascadeDelete(String schemaName, String queryName, String keyField, Object keyValue) throws SQLException + { + UserSchema schema = QueryService.get().getUserSchema(_user, _container, schemaName); + if (schema == null) + throw new RuntimeException("Unknown schema: " + schemaName); + + TableInfo table = schema.getTable(queryName); + if (table == null) + throw new RuntimeException("Unknown table: " + schemaName + "." + queryName); + + if (!_container.hasPermission(_user, DeletePermission.class)) + throw new UnauthorizedException("User does not have permission to delete from the table: " + table.getPublicName()); + + try + { + List<Map<String, Object>> toDelete = new TableSelector(table, PageFlowUtil.set("rowid"), new SimpleFilter(FieldKey.fromString(keyField), keyValue), null).stream(Integer.class).map(x -> new CaseInsensitiveHashMap<Object>(Collections.singletonMap("rowId", x))).collect(Collectors.toList()); + table.getUpdateService().deleteRows(_user, _container, toDelete, null, null); + } + catch (QueryUpdateServiceException | InvalidKeyException | BatchValidationException e) + { + _log.error("Unable to delete from: " + queryName, e); + } + } + + public boolean hasPermission(String status) + { + try + { + return MccManager.RequestStatus.resolveStatus(status).canEdit(_user, _container); + } + catch (IllegalArgumentException e) + { + _log.error("Unknown MCC status: " + status); + return false; + } + } + + public String resolveObjectId(int rowid) + { + return new TableSelector(MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_ANIMAL_REQUESTS), PageFlowUtil.set("objectid"), new SimpleFilter(FieldKey.fromString("rowid"), rowid), null).getObject(String.class); + } + + public void possiblySetRabComplete(String requestId) + { + TableInfo ti = MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_REQUEST_REVIEWS); + Set<String> reviews = new HashSet<>(new TableSelector(ti, PageFlowUtil.set("review"), new SimpleFilter(FieldKey.fromString("requestId"), requestId), null).getArrayList(String.class)); + if (!reviews.isEmpty() && !reviews.contains(null)) { + TableInfo requestTable = MccSchema.getInstance().getSchema().getTable(MccSchema.TABLE_ANIMAL_REQUESTS); + int rowId = new TableSelector(requestTable, PageFlowUtil.set("rowid"), new SimpleFilter(FieldKey.fromString("objectid"), requestId), null).getObject(Integer.class); + Map<String, Object> map = new HashMap<>(); + map.put("rowid", rowId); + map.put("status", MccManager.RequestStatus.PendingDecision.getLabel()); + map.put("modifiedby", _user.getUserId()); + map.put("modified", new Date()); + + Table.update(_user, requestTable, map, rowId); + } + } } diff --git a/mcc/src/org/labkey/mcc/query/UserRequestCustomizer.java b/mcc/src/org/labkey/mcc/query/UserRequestCustomizer.java index 187288b28..dadcf886c 100644 --- a/mcc/src/org/labkey/mcc/query/UserRequestCustomizer.java +++ b/mcc/src/org/labkey/mcc/query/UserRequestCustomizer.java @@ -38,7 +38,6 @@ public void addUserCol(AbstractTableInfo ti) ")) THEN " + ti.getSqlDialect().getBooleanTRUE() + " ELSE " + ti.getSqlDialect().getBooleanFALSE() + " END)"), JdbcType.BOOLEAN, ti.getColumn("userId")); col.setLabel("Has MCC Access?"); col.setReadOnly(true); - col.setIsUnselectable(true); col.setUserEditable(false); ti.addColumn(col); } diff --git a/mcc/src/org/labkey/mcc/security/MccDataPermission.java b/mcc/src/org/labkey/mcc/security/MccDataAdminPermission.java similarity index 68% rename from mcc/src/org/labkey/mcc/security/MccDataPermission.java rename to mcc/src/org/labkey/mcc/security/MccDataAdminPermission.java index caa833ba4..69e421aed 100644 --- a/mcc/src/org/labkey/mcc/security/MccDataPermission.java +++ b/mcc/src/org/labkey/mcc/security/MccDataAdminPermission.java @@ -2,9 +2,9 @@ import org.labkey.api.security.permissions.AbstractPermission; -public class MccDataPermission extends AbstractPermission +public class MccDataAdminPermission extends AbstractPermission { - public MccDataPermission() + public MccDataAdminPermission() { super("MccDataAdmin", "This permission allows the user to administer animal data in the MCC"); } diff --git a/mcc/src/org/labkey/mcc/security/MccDataAdminRole.java b/mcc/src/org/labkey/mcc/security/MccDataAdminRole.java index 8d992ca22..c3f68a4e3 100644 --- a/mcc/src/org/labkey/mcc/security/MccDataAdminRole.java +++ b/mcc/src/org/labkey/mcc/security/MccDataAdminRole.java @@ -1,14 +1,16 @@ package org.labkey.mcc.security; import org.jetbrains.annotations.NotNull; +import org.labkey.api.security.permissions.InsertPermission; import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.permissions.UpdatePermission; import org.labkey.api.security.roles.AbstractRole; public class MccDataAdminRole extends AbstractRole { public MccDataAdminRole() { - super("MccDataAdmin", "These users can administer data and animal requests", ReadPermission.class, MccRequestorPermission.class, MccDataPermission.class, MccRequestAdminPermission.class); + super("MccDataAdmin", "These users can administer data and animal requests", ReadPermission.class, InsertPermission.class, UpdatePermission.class, MccRequestorPermission.class, MccDataAdminPermission.class, MccRequestAdminPermission.class); } @Override diff --git a/mcc/src/org/labkey/mcc/security/MccFinalReviewPermission.java b/mcc/src/org/labkey/mcc/security/MccFinalReviewPermission.java new file mode 100644 index 000000000..52f5f7243 --- /dev/null +++ b/mcc/src/org/labkey/mcc/security/MccFinalReviewPermission.java @@ -0,0 +1,11 @@ +package org.labkey.mcc.security; + +import org.labkey.api.security.permissions.AbstractPermission; + +public class MccFinalReviewPermission extends AbstractPermission +{ + public MccFinalReviewPermission() + { + super("MccFinalReview", "This permission is required to enter the final decision on animal requests in the MCC"); + } +} diff --git a/mcc/src/org/labkey/mcc/security/MccFinalReviewerRole.java b/mcc/src/org/labkey/mcc/security/MccFinalReviewerRole.java new file mode 100644 index 000000000..99048ea92 --- /dev/null +++ b/mcc/src/org/labkey/mcc/security/MccFinalReviewerRole.java @@ -0,0 +1,21 @@ +package org.labkey.mcc.security; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.security.permissions.InsertPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.permissions.UpdatePermission; +import org.labkey.api.security.roles.AbstractRole; + +public class MccFinalReviewerRole extends AbstractRole +{ + public MccFinalReviewerRole() + { + super("MccFinalReviewer", "These users can enter the final reviews for MCC requests", ReadPermission.class, InsertPermission.class, UpdatePermission.class, MccRequestorPermission.class, MccRabReviewPermission.class, MccFinalReviewPermission.class); + } + + @Override + public @NotNull String getDisplayName() + { + return "MCC Final Reviewer"; + } +} diff --git a/mcc/src/org/labkey/mcc/security/MccRabReviewPermission.java b/mcc/src/org/labkey/mcc/security/MccRabReviewPermission.java new file mode 100644 index 000000000..ae97e9e31 --- /dev/null +++ b/mcc/src/org/labkey/mcc/security/MccRabReviewPermission.java @@ -0,0 +1,11 @@ +package org.labkey.mcc.security; + +import org.labkey.api.security.permissions.AbstractPermission; + +public class MccRabReviewPermission extends AbstractPermission +{ + public MccRabReviewPermission() + { + super("MccRabReview", "This permission allows the user to perform tasked related to RAB review in the MCC"); + } +} diff --git a/mcc/src/org/labkey/mcc/security/MccRabReviewerRole.java b/mcc/src/org/labkey/mcc/security/MccRabReviewerRole.java new file mode 100644 index 000000000..0e3a22ad4 --- /dev/null +++ b/mcc/src/org/labkey/mcc/security/MccRabReviewerRole.java @@ -0,0 +1,21 @@ +package org.labkey.mcc.security; + +import org.jetbrains.annotations.NotNull; +import org.labkey.api.security.permissions.InsertPermission; +import org.labkey.api.security.permissions.ReadPermission; +import org.labkey.api.security.permissions.UpdatePermission; +import org.labkey.api.security.roles.AbstractRole; + +public class MccRabReviewerRole extends AbstractRole +{ + public MccRabReviewerRole() + { + super("MccRabReviewer", "These users can enter RAB reviews", ReadPermission.class, InsertPermission.class, UpdatePermission.class, MccRequestorPermission.class, MccRabReviewPermission.class); + } + + @Override + public @NotNull String getDisplayName() + { + return "MCC RAB Reviewer"; + } +} diff --git a/mcc/src/org/labkey/mcc/security/MccRequestAdminPermission.java b/mcc/src/org/labkey/mcc/security/MccRequestAdminPermission.java index 559d02c31..fa2ce3c84 100644 --- a/mcc/src/org/labkey/mcc/security/MccRequestAdminPermission.java +++ b/mcc/src/org/labkey/mcc/security/MccRequestAdminPermission.java @@ -1,10 +1,7 @@ package org.labkey.mcc.security; -import org.jetbrains.annotations.NotNull; import org.labkey.api.security.permissions.AbstractPermission; -import java.util.Collection; - public class MccRequestAdminPermission extends AbstractPermission { public MccRequestAdminPermission() diff --git a/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java b/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java index 807252057..fc83863eb 100644 --- a/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java +++ b/mcc/test/src/org/labkey/test/tests/mcc/MccTest.java @@ -16,35 +16,34 @@ package org.labkey.test.tests.mcc; -import org.apache.commons.io.FileUtils; import org.jetbrains.annotations.Nullable; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; +import org.labkey.remoteapi.query.Filter; import org.labkey.remoteapi.query.SelectRowsCommand; import org.labkey.remoteapi.query.SelectRowsResponse; import org.labkey.remoteapi.query.Sort; import org.labkey.test.BaseWebDriverTest; import org.labkey.test.Locator; -import org.labkey.test.Locators; import org.labkey.test.ModulePropertyValue; -import org.labkey.test.TestFileUtils; import org.labkey.test.TestTimeoutException; import org.labkey.test.WebTestHelper; import org.labkey.test.categories.External; import org.labkey.test.categories.LabModule; +import org.labkey.test.util.ApiPermissionsHelper; import org.labkey.test.util.DataRegionTable; -import org.openqa.selenium.Keys; +import org.labkey.test.util.PermissionsHelper; -import java.io.File; -import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; @Category({External.class, LabModule.class}) public class MccTest extends BaseWebDriverTest @@ -56,108 +55,157 @@ public void testMccModule() throws Exception doRequestFormTest(); doRequestFormTestWithFailure(); + + testInvalidId(); } private static class FormElement { String inputType = "input"; - String databaseFieldName = null; - boolean isCheckBox = false; + String databaseValue = null; final String inputName; - final CharSequence sendKeysValue; + final Object fieldValue; + final String databaseFieldName; - public FormElement(String inputName, CharSequence sendKeysValue) + public FormElement(String inputName, String databaseFieldName, Object fieldValue) { this.inputName = inputName; - this.sendKeysValue = sendKeysValue; + this.fieldValue = fieldValue; + this.databaseFieldName = databaseFieldName; } - public FormElement withDatabaseField(String databaseFieldName) + public String getDatabaseFieldName() { - this.databaseFieldName = databaseFieldName; + return databaseFieldName; + } + + public FormElement checkBox() + { + if (!(fieldValue instanceof Boolean)) + { + throw new IllegalStateException("Checkbox must have a boolean input fieldValue"); + } + this.inputType = "checkbox"; return this; } - public FormElement isCheckBox() + public FormElement select(String databaseValue) { - this.isCheckBox = true; + this.databaseValue = databaseValue; + this.inputType = "select"; + return this; } - public FormElement withInput(String inputType) + public FormElement radio() { - this.inputType = inputType; + if (!(fieldValue instanceof Boolean)) + { + throw new IllegalStateException("Radio must have a boolean input fieldValue"); + } + + this.inputType = "radio"; + return this; + } + public Object getDatabaseValue() + { + return databaseValue == null ? fieldValue : databaseValue; + } + + public FormElement inputType(String inputType) + { + this.inputType = inputType; return this; } - public String getFieldName() + public String getInputName() { + if ("radio".equals(inputType)) + { + return inputName + ((boolean)fieldValue ? "-yes" : "-no"); + } + return inputName; } - public String getInputType() + public Locator getLocator() { - return inputType; + return Locator.tagWithId("radio".equals(inputType) || "checkbox".equals(inputType) ? "input" : inputType, getInputName()); } public void waitFor(BaseWebDriverTest test) { - Locator loc = Locator.tagWithId(getInputType(), getFieldName()); - test.waitForElement(loc); + test.waitForElement(getLocator()); } public void setFieldValue(BaseWebDriverTest test) { - Locator loc = Locator.tagWithId(getInputType(), getFieldName()); waitFor(test); - if (this.sendKeysValue == null) + if ("checkbox".equals(inputType) || "radio".equals(inputType)) + { + test.waitAndClick(getLocator()); + } + else if ("select".equals(inputType)) { - test.waitAndClick(loc); + test.selectOptionByText(getLocator(), String.valueOf(fieldValue)); } else { - loc.findElement(test.getDriver()).sendKeys(this.sendKeysValue); + test.setFormElement(getLocator(), String.valueOf(fieldValue)); + } + } + + public String getExpectedInputFieldValue() + { + if (fieldValue instanceof Boolean) + { + boolean val = (boolean)fieldValue; + if ("checkbox".equals(inputType)) + { + return val ? "on" : null; + } + else if ("radio".equals(inputType)) + { + return val ? "yes" : "no"; + } } + return String.valueOf(databaseValue == null ? fieldValue : databaseValue); } } // Field name / field value: final FormElement[] FORM_DATA = new FormElement[]{ - new FormElement("investigator-last-name", "last name"), - new FormElement("investigator-first-name", "first name"), - new FormElement("investigator-middle-initial", "m"), - new FormElement("is-principal-investigator-yes", null).isCheckBox(), - new FormElement("institution-name", "institution name"), - new FormElement("institution-city", "institution city"), - new FormElement("institution-state", "institution state"), - new FormElement("institution-country", "institution country"), - new FormElement("official-last-name", "official last name"), - new FormElement("official-first-name", "official first name"), - new FormElement("official-email", "official@email.com"), - new FormElement("funding-source", Keys.ARROW_DOWN).withInput("select"), - new FormElement("funding-grant-number", "grant number"), - new FormElement("experiment-rationale", "rationale").withInput("textarea"), - - - new FormElement("animal-cohorts-0-numberofanimals", "1"), - new FormElement("animal-cohorts-0-sex", Keys.ARROW_DOWN).withInput("select"), - new FormElement("animal-cohorts-0-othercharacteristics", "characteristics").withInput("textarea"), - new FormElement("methods-proposed", "methods").withInput("textarea"), - new FormElement("collaborations", "collaborations").withInput("textarea"), - new FormElement("animal-breeding-is-planning-to-breed-animals-no", null).isCheckBox(), - new FormElement("research-area", Keys.ARROW_DOWN).withInput("select"), - new FormElement("existing-marmoset-colony", Keys.ARROW_DOWN).withInput("select"), - new FormElement("existing-nhp-facilities", Keys.ARROW_DOWN).withInput("select"), - new FormElement("animal-welfare", "welfare").withInput("textarea"), - new FormElement("certify", null).isCheckBox(), - new FormElement("vet-last-name", "vet last name"), - new FormElement("vet-first-name", "vet first name"), - new FormElement("vet-email", "vet@email.com"), - new FormElement("iacuc-approval", Keys.ARROW_DOWN).withInput("select") + new FormElement("investigator-last-name", "lastName", "last name"), + new FormElement("investigator-first-name", "firstName", "first name"), + new FormElement("investigator-middle-initial", "middleinitial", "m"), + new FormElement("is-early-stage-investigator", "earlystageinvestigator", true).radio(), + new FormElement("institution-name", "institutionname", "institution name"), + new FormElement("institution-city", "institutioncity", "institution city"), + new FormElement("institution-state", "institutionstate", "institution state"), + new FormElement("institution-type", "institutiontype", "Minority serving").select("minorityServing"), + new FormElement("institution-country", "institutioncountry", "institution country"), + new FormElement("official-last-name", "officiallastname", "official last name"), + new FormElement("official-first-name", "officialfirstname", "official first name"), + new FormElement("official-email", "officialemail", "official@email.com"), + //TODO: multi-select + new FormElement("funding-source", "fundingsource", "NIH-supported research").select("nih"), + new FormElement("funding-grant-number", "grantnumber", "grant number"), + new FormElement("experiment-rationale", "experimentalrationale", "rationale").inputType("textarea"), + new FormElement("methods-proposed", "methodsproposed", "methods").inputType("textarea"), + new FormElement("collaborations", "collaborations", "collaborations").inputType("textarea"), + new FormElement("animal-breeding-is-planning-to-breed-animals", "isbreedinganimals", false).radio(), + new FormElement("existing-marmoset-colony", "existingmarmosetcolony", "Existing marmoset colony").select("existing"), + new FormElement("existing-nhp-facilities", "existingnhpfacilities", "Existing NHP facilities").select("existing"), + new FormElement("animal-welfare", "animalwelfare", "welfare").inputType("textarea"), + new FormElement("certify", "certify", true).checkBox(), + new FormElement("vet-last-name", "vetlastname", "vet last name"), + new FormElement("vet-first-name", "vetfirstname", "vet first name"), + new FormElement("vet-email", "vetemail", "vet@email.com"), + new FormElement("iacuc-approval", "iacucapproval", "Provisional").select("provisional") }; private Locator getButton(String text) @@ -173,30 +221,276 @@ private void goToAnimalRequests() waitForElement(Locator.tagWithText("a", "Submit New Animal Request")); } + private void waitForSaveToComplete() + { + waitForElementToDisappear(Locator.tagWithText("h2", "Saving").withClass("text-xl")); + } + private void doRequestFormTest() throws Exception { goToAnimalRequests(); waitAndClickAndWait(Locator.tagWithText("a", "Submit New Animal Request")); - waitForElement(getButton("Submit")); + waitForElement(getButton("Save")); - setFormValues(null); + setAllFormValues(); + + addCohort(0); + + addCoinvestigator(0, true); + addCoinvestigator(1, true); + + int expectedRequests = getRequestRows().size(); + + waitAndClick(getButton("Save")); + waitForSaveToComplete(); - waitAndClickAndWait(getButton("Save")); + List<Map<String, Object>> requestRows = getRequestRows(); + String requestId = (String)requestRows.get(0).get("objectid"); + Assert.assertEquals(expectedRequests + 1, requestRows.size()); + + Assert.assertEquals(2, getCoinvestigatorRecords(requestId).size()); + Assert.assertEquals(1, getCohortRecords(requestId).size()); + + // This is to ensure we update the record we have, rather than create a new one + waitAndClick(getButton("Save")); + waitForSaveToComplete(); + Assert.assertEquals(expectedRequests + 1, getRequestRows().size()); + Assert.assertEquals(2, getCoinvestigatorRecords(requestId).size()); + Assert.assertEquals(1, getCohortRecords(requestId).size()); // Verify record created: Map<String, Object> request = getLastModifiedRequestRow(); for (FormElement f : FORM_DATA) { - //TODO: check data + Assert.assertEquals(request.get(f.databaseFieldName), f.getDatabaseValue()); } + + assertCohortValues((String)request.get("objectid"), 1); + assertCoinvestigatorValues((String)request.get("objectid"), 2); + + // Remove Co-I, save: + Locator removeBtn = Locator.tagWithText("p", "Co-Investigator 2").parent("div").followingSibling("div").index(0).child("input"); + waitForElement(removeBtn); + click(removeBtn); + waitForElementToDisappear(removeBtn); + + waitAndClick(getButton("Save")); + waitForSaveToComplete(); + Assert.assertEquals(1, getCoinvestigatorRecords(requestId).size()); + Assert.assertEquals(1, getCohortRecords(requestId).size()); + + // Test IACUC toggle + selectOptionByText(getFormElementByName("iacucapproval").getLocator(), "Approved"); + waitForElement(Locator.tagWithId("input", "iacuc-protocol")); + setFormElement(Locator.tagWithId("input", "iacuc-protocol"), "IACUC 123456"); + waitAndClick(getButton("Save")); + waitForSaveToComplete(); + + Assert.assertEquals(getLastModifiedRequestRow().get("iacucprotocol"), "IACUC 123456"); + waitAndClickAndWait(getButton("Submit")); + + DataRegionTable dr = new DataRegionTable.DataRegionFinder(getDriver()).waitFor(); + Assert.assertEquals("Submitted", dr.getDataAsText(0, "status")); + + beginAt("/mcc/" + getProjectName() + "/mccRequestAdmin.view"); + + // Ensure groups set up correctly: + String dataRegionName = getDataRegionName("webpartRAB"); + dr = new DataRegionTable.DataRegionFinder(getDriver()).withName(dataRegionName).waitFor(); + Assert.assertEquals(dr.getDataRowCount(), 1); + + waitAndClickAndWait(Locator.tagWithText("a", "Enter MCC Internal Review")); + + waitAndClick(getButton("Return to Investigator")); + waitForElement(Locator.tagWithText("h2", "Return To Investigator").notHidden()); + waitAndClickAndWait(getButton("Submit")); + + dr = new DataRegionTable.DataRegionFinder(getDriver()).withName(getDataRegionName("webpartPending")).waitFor(); + dr.clickRowDetails(0); + + // Reset status to Submitted: + waitAndClickAndWait(Locator.tagWithText("span", "Edit Request")); + waitAndClickAndWait(getButton("Submit")); + + beginAt("/mcc/" + getProjectName() + "/mccRequestAdmin.view"); + dataRegionName = getDataRegionName("webpartPending"); + new DataRegionTable.DataRegionFinder(getDriver()).withName(dataRegionName).waitFor(); + waitAndClickAndWait(Locator.tagWithText("a", "Enter MCC Internal Review")); + + waitAndClick(Locator.tagWithText("span", "Assign to RAB Reviewers")); + waitForElement(Locator.tagWithText("h2", "Assign for RAB Review").notHidden()); + waitForElement(Locator.tagWithText("p", getCurrentUserName())); + waitAndClickAndWait(Locator.tagWithText("span", "Submit")); + + goBack(); + + // Repeat to ensure the assignment is picked up + waitAndClick(Locator.tagWithText("span", "Assign to RAB Reviewers")); + waitForElement(Locator.tagWithText("h2", "Assign for RAB Review").notHidden()); + waitForElement(Locator.tagWithText("p", getCurrentUserName() + " (already assigned)")); + waitAndClickAndWait(Locator.tagWithText("span", "Submit")); + + beginAt("/mcc/" + getProjectName() + "/rabRequestReview.view"); + waitAndClickAndWait(Locator.tagWithText("a", "Enter Review")); + waitForElement(Locator.tagWithText("td", "cohort-othercharacteristics")); + + waitAndClick(Locator.tagWithText("span", "Submit Review")); + waitForElement(Locator.tagWithClass("div", "Mui-error")); + + waitAndClick(Locator.tagWithText("div", "Not Decided")); + waitAndClick(Locator.tagWithText("li", "I recommend this proposal")); + waitAndClickAndWait(Locator.tagWithText("span", "Submit Review")); + dr = new DataRegionTable.DataRegionFinder(getDriver()).waitFor(); + Assert.assertEquals(dr.getDataRowCount(), 0); + + + beginAt("/mcc/" + getProjectName() + "/mccRequestAdmin.view"); + + // NOTE: since the last review was entered, this should update the status of the request + Assert.assertEquals("Pending Decision", getLastModifiedRequestRow().get("status")); + + dataRegionName = getDataRegionName("webpartPending"); + new DataRegionTable.DataRegionFinder(getDriver()).withName(dataRegionName).waitFor(); + waitAndClickAndWait(Locator.tagWithText("a", "Enter Final Review")); + waitAndClick(Locator.tagWithText("span", "Approve Request")); + + dataRegionName = getDataRegionName("webpartPending"); + dr = new DataRegionTable.DataRegionFinder(getDriver()).withName(dataRegionName).waitFor(); + Assert.assertEquals(dr.getDataRowCount(), 1); } - private Map<String, Object> getLastModifiedRequestRow() throws Exception + private String getDataRegionName(String divName) + { + Locator.XPathLocator l = Locator.tagWithAttributeContaining("div", "id", divName); + waitForElement(l); + l = l.append(Locator.tag("form")); + waitForElement(l); + + return getAttribute(l, "lk-region-form"); + } + + private FormElement[] getCoinvestigatorFields(int idx) + { + return new FormElement[]{ + new FormElement("coinvestigators-" + idx + "-lastName", "lastname", "coinvestigators-lastName"), + new FormElement("coinvestigators-" + idx + "-firstName", "firstname", "coinvestigators-firstName"), + new FormElement("coinvestigators-" + idx + "-middleInitial", "middleInitial", "mi"), + new FormElement("coinvestigators-" + idx + "-institution", "institutionname", "coinvestigators-institution") + }; + } + + private FormElement[] getCohortFields(int idx) + { + return new FormElement[]{ + new FormElement("animal-cohorts-" + idx + "-numberofanimals", "numberofanimals", 12), + new FormElement("animal-cohorts-" + idx + "-sex", "sex", "Male").select("male"), + new FormElement("animal-cohorts-" + idx + "-othercharacteristics", "othercharacteristics", "cohort-othercharacteristics").inputType("textarea") + }; + } + + private void addCoinvestigator(int idx, boolean clickBtn) + { + if (clickBtn) + { + waitAndClick(Locator.tagWithAttribute("input", "value", "Add Co-investigator")); + } + + FormElement[] fields = getCoinvestigatorFields(idx); + for (FormElement f : fields) + { + f.setFieldValue(this); + } + } + + private void addCohort(int idx) + { + if (idx > 0) + { + waitAndClick(Locator.tagWithText("button", "Add Cohort")); + } + + FormElement[] cohort = getCohortFields(idx); + for (FormElement f : cohort) + { + f.setFieldValue(this); + } + } + + private void assertCoinvestigatorValues(String requestId, int expectedRecords) throws Exception + { + List<Map<String, Object>> rows = getCoinvestigatorRecords(requestId); + Assert.assertEquals(rows.size(), expectedRecords); + + for (int i=0;i<rows.size();i++) + { + Map<String, Object> row = rows.get(i); + FormElement[] cohort = getCoinvestigatorFields(i); + for (FormElement f : cohort) + { + Assert.assertEquals(f.getDatabaseValue(), row.get(f.getDatabaseFieldName())); + } + } + } + + private void assertCohortValues(String requestId, int expectedRecords) throws Exception + { + List<Map<String, Object>> cohortRows = getCohortRecords(requestId); + Assert.assertEquals(cohortRows.size(), expectedRecords); + + for (int i=0;i<cohortRows.size();i++) + { + Map<String, Object> row = cohortRows.get(i); + FormElement[] cohort = getCohortFields(i); + for (FormElement f : cohort) + { + Assert.assertEquals(f.getDatabaseValue(), row.get(f.getDatabaseFieldName())); + } + } + } + + private List<Map<String, Object>> getRequestRows() throws Exception { SelectRowsCommand sr = new SelectRowsCommand("mcc", "animalrequests"); sr.addSort(new Sort("modified", Sort.Direction.DESCENDING)); + List<String> cols = new ArrayList<>(Arrays.stream(FORM_DATA).map(FormElement::getDatabaseFieldName).collect(Collectors.toList())); + cols.add("objectid"); + cols.add("status"); + cols.add("iacucprotocol"); + sr.setColumns(cols); + + SelectRowsResponse srr = sr.execute(createDefaultConnection(), getProjectName()); + return srr.getRows(); + } + + private Map<String, Object> getLastModifiedRequestRow() throws Exception + { + List<Map<String, Object>> rr = getRequestRows(); + + return rr.isEmpty() ? null : rr.get(0); + } + + private List<Map<String, Object>> getCohortRecords(String requestId) throws Exception + { + SelectRowsCommand sr = new SelectRowsCommand("mcc", "requestcohorts"); + sr.addSort(new Sort("rowid", Sort.Direction.ASCENDING)); + sr.setColumns(Arrays.stream(getCohortFields(0)).map(FormElement::getDatabaseFieldName).collect(Collectors.toList())); + sr.addFilter(new Filter("requestid", requestId)); + SelectRowsResponse srr = sr.execute(createDefaultConnection(), getProjectName()); - return srr.getRows().get(0); + + return srr.getRows(); + } + + private List<Map<String, Object>> getCoinvestigatorRecords(String requestId) throws Exception + { + SelectRowsCommand sr = new SelectRowsCommand("mcc", "coinvestigators"); + sr.addSort(new Sort("rowid", Sort.Direction.ASCENDING)); + sr.setColumns(Arrays.stream(getCoinvestigatorFields(0)).map(FormElement::getDatabaseFieldName).collect(Collectors.toList())); + sr.addFilter(new Filter("requestid", requestId)); + + SelectRowsResponse srr = sr.execute(createDefaultConnection(), getProjectName()); + + return srr.getRows(); } private void doRequestFormTestWithFailure() throws Exception @@ -207,7 +501,8 @@ private void doRequestFormTestWithFailure() throws Exception waitForElement(getButton("Submit")); // This omits a required field - setFormValues(Arrays.asList("investigator-last-name")); + setFormValues(Arrays.asList("lastName")); + addCohort(0); waitAndClick(getButton("Submit")); waitForElement(Locator.tagWithText("li", "Last Name: Please fill out this field.")); @@ -216,10 +511,8 @@ private void doRequestFormTestWithFailure() throws Exception waitAndClick(Locator.tagWithAttribute("input", "value", "Add Co-investigator")); waitForElement(Locator.tagWithText("li", "Institution: Please fill out this field.")); - // To full exercise saving, add a cohort and co-investigator - new FormElement("coinvestigators-0-lastName", "coinvestigators-lastName").setFieldValue(this); - new FormElement("coinvestigators-0-firstName", "coinvestigators-firstName").setFieldValue(this); - new FormElement("coinvestigators-0-institution", "coinvestigators-institution").setFieldValue(this); + addCoinvestigator(0, false); //the button was clicked above + waitAndClick(getButton("Save")); waitForElementToDisappear(Locator.tagWithText("li", "Institution: Please fill out this field.")); // Add another, which makes it invalid again @@ -244,29 +537,48 @@ private void doRequestFormTestWithFailure() throws Exception waitAndClick(removeBtn); // Even though last name is missing, it should still be savable: - waitAndClickAndWait(getButton("Save")); + waitAndClick(getButton("Save")); + waitForSaveToComplete(); + + doAndWaitForPageToLoad(() -> { + waitAndClick(getButton("Cancel")); + assertAlert("You are about to leave this page."); + }); // Now reopen this form: DataRegionTable dr = new DataRegionTable.DataRegionFinder(getDriver()).waitFor(); dr.clickEditRow(0); - getFormElementByName("investigator-last-name").waitFor(this); + getFormElementByName("lastName").waitFor(this); // TODO: make sure the field values are remembered // including cohort and co-investigator + for (FormElement f : FORM_DATA) + { + if ("lastName".equals(f.getDatabaseFieldName())) + { + continue; + } + + Assert.assertEquals(getFormElement(f.getLocator()), f.getExpectedInputFieldValue()); + } // Now fill in the missing field: - getFormElementByName("investigator-last-name").setFieldValue(this); + getFormElementByName("lastName").setFieldValue(this); waitAndClickAndWait(getButton("Submit")); dr = new DataRegionTable.DataRegionFinder(getDriver()).waitFor(); - Assert.assertEquals("submitted", dr.getDataAsText(0, "status")); + Assert.assertEquals("Submitted", dr.getDataAsText(0, "status")); dr.clickEditRow(0); - getFormElementByName("investigator-last-name").waitFor(this); - waitForElement(getButton("Approve Request")); + getFormElementByName("lastName").waitFor(this); + + waitForElement(getButton("Update Request")); + assertElementNotPresent(getButton("Submit")); impersonateRoles("Editor", "MCC Requestor"); + + assertElementNotPresent(getButton("Save")); assertElementNotPresent(getButton("Submit")); assertElementNotPresent(getButton("Approve Request")); } @@ -275,7 +587,7 @@ private FormElement getFormElementByName(String name) { for (FormElement e : FORM_DATA) { - if (name.equals(e.getFieldName())) + if (name.equals(e.databaseFieldName)) { return e; } @@ -284,11 +596,16 @@ private FormElement getFormElementByName(String name) throw new IllegalArgumentException("Unknown field: " + name); } + private void setAllFormValues() + { + setFormValues(null); + } + private void setFormValues(@Nullable Collection<String> fieldsToSkip) { for (FormElement el : FORM_DATA) { - if (fieldsToSkip != null && fieldsToSkip.contains(el.getFieldName())) + if (fieldsToSkip != null && fieldsToSkip.contains(el.databaseFieldName)) { continue; } @@ -325,13 +642,29 @@ private void doSetup() throws Exception new ModulePropertyValue("MCC", "/", "MCCContactUsers", getCurrentUserName()), new ModulePropertyValue("MCC", "/", "MCCRequestNotificationUsers", getCurrentUserName()) )); + + beginAt("/mcc/" + getProjectName() + "/configureMcc.view"); + clickButton("OK"); + + ApiPermissionsHelper helper = new ApiPermissionsHelper(this); + if (!helper.isUserInGroup(getCurrentUser(), "MCC RAB Members", "/", PermissionsHelper.PrincipalType.USER)) + { + helper.addUserToSiteGroup(getCurrentUser(), "MCC RAB Members"); + } + else + { + log("Member already in group. This is not expected for fresh installations or TeamCity"); + } } - private String getModulePath() + private void testInvalidId() { - return "server/modules/BimberLabKeyModules/mcc"; + beginAt("/mcc/" + getProjectName() + "/animalRequest.view?requestId=foo"); + + assertElementPresent(Locator.tagWithText("div", "There is no request with id: foo")); } + private void importStudy() { beginAt(WebTestHelper.getBaseURL() + "/mcc/" + getProjectName() + "/importStudy.view"); diff --git a/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java b/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java index 4c2d9dc9f..b35cc6211 100644 --- a/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java +++ b/primeseq/src/org/labkey/primeseq/pipeline/ClusterMaintenanceTask.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.SystemUtils; import org.apache.commons.lang3.time.DateUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; @@ -18,12 +19,14 @@ import org.labkey.api.data.TableSelector; import org.labkey.api.pipeline.PipeRoot; import org.labkey.api.pipeline.PipelineJob; +import org.labkey.api.pipeline.PipelineJobException; import org.labkey.api.pipeline.PipelineJobService; import org.labkey.api.pipeline.PipelineService; import org.labkey.api.pipeline.PipelineValidationException; import org.labkey.api.pipeline.RemoteExecutionEngine; import org.labkey.api.query.FieldKey; import org.labkey.api.security.UserManager; +import org.labkey.api.sequenceanalysis.run.SimpleScriptWrapper; import org.labkey.api.util.FileUtil; import org.labkey.api.util.Job; import org.labkey.api.util.JobRunner; @@ -37,6 +40,7 @@ import java.nio.file.DirectoryStream; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashSet; @@ -152,9 +156,6 @@ public void run(Logger log) log.info("total active pipeline jobs: " + _jobGuids.size()); //hacky, but this is only planned to be used by us - inspectFolder(log, new File("/home/exacloud/lustre1/prime-seq/workDir/")); - inspectFolder(log, new File("/home/exacloud/lustre1/prime-seq/cachedData/")); - inspectFolder(log, new File("/home/exacloud/gscratch/prime-seq/workDir/")); inspectFolder(log, new File("/home/exacloud/gscratch/prime-seq/cachedData/")); } @@ -163,11 +164,18 @@ private void deleteDirectory(File child, Logger log) { try { - FileUtils.deleteDirectory(child); + if (SystemUtils.IS_OS_WINDOWS) + { + FileUtils.deleteDirectory(child); + } + else + { + new SimpleScriptWrapper(log).execute(Arrays.asList("rm", "-Rf", child.getPath())); + } } - catch (IOException e) + catch (IOException | PipelineJobException e) { - log.error(e); + log.error("Unable to delete folder: " + child.getPath(), e); } } diff --git a/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java b/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java index aa64e57cc..cf70378cf 100644 --- a/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java +++ b/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJCellHashingHandler.java @@ -224,6 +224,23 @@ private void processVloupeFile(JobContext ctx, File perCellTsv, Readset rs, Reco throw new PipelineJobException("Missing cell to HTO file"); } + double maxHashingPctDiscordant = -1; + if (ctx.getParams().get(CellHashingService.MAX_HASHING_PCT_DISCORDANT) != null && !StringUtils.isEmpty(ctx.getParams().get(CellHashingService.MAX_HASHING_PCT_DISCORDANT).toString())) + { + maxHashingPctDiscordant = ConvertHelper.convert(ctx.getParams().get(CellHashingService.MAX_HASHING_PCT_DISCORDANT), Double.class); + } + + double maxHashingPctFail = -1; + if (ctx.getParams().get(CellHashingService.MAX_HASHING_PCT_FAIL) != null && !StringUtils.isEmpty(ctx.getParams().get(CellHashingService.MAX_HASHING_PCT_FAIL).toString())) + { + maxHashingPctFail = ConvertHelper.convert(ctx.getParams().get(CellHashingService.MAX_HASHING_PCT_FAIL), Double.class); + } + + if (maxHashingPctDiscordant > -1 || maxHashingPctFail > -1) + { + validateHashingRates(ctx, cellToHto, maxHashingPctFail, maxHashingPctDiscordant); + } + action.addOutput(cellToHto, CellRangerVDJUtils.TCR_HASHING_CALLS, false); ctx.getFileManager().addStepOutputs(action, output); } @@ -337,4 +354,65 @@ private File createCellbarcodeWhitelist(JobContext ctx, File perCellTsv, boolean return cellBarcodeWhitelist; } } + + private void validateHashingRates(JobContext ctx, File cellbarcodeToHtoFile, double maxHashingPctFail, double maxHashingPctDiscordant) throws PipelineJobException + { + try (CSVReader reader = new CSVReader(Readers.getReader(cellbarcodeToHtoFile), '\t')) + { + String[] line; + int discordant = 0; + int negative = 0; + int totalLines = 0; + + int consensusIdx = -1; + while ((line = reader.readNext()) != null) + { + if (line.length < 3) + { + throw new PipelineJobException("Line too short"); + } + + //header + if ("cellbarcode".equalsIgnoreCase(line[0])) + { + consensusIdx = Arrays.asList(line).indexOf("consensuscall"); + continue; + } + + if (consensusIdx == -1) + { + throw new PipelineJobException("consensuscall column not found"); + } + + String hto = line[consensusIdx]; + totalLines++; + if ("Discordant".equals(hto)) + { + discordant++; + } + else if ("Negative".equals(hto)) + { + negative++; + } + } + + double fractionDiscordantHashing = (double)discordant / (double)totalLines; + if (maxHashingPctDiscordant != -1 && fractionDiscordantHashing > maxHashingPctDiscordant) + { + CellHashingService.get().copyHtmlLocally(ctx); + throw new PipelineJobException("Discordant hashing rate was : " + fractionDiscordantHashing + ", which is above threshold of: " + maxHashingPctDiscordant + ". Total cells: " + totalLines); + } + + double fractionFailedHashing = (double)(discordant + negative) / (double)totalLines; + if (maxHashingPctFail != -1 && fractionFailedHashing > maxHashingPctFail) + { + CellHashingService.get().copyHtmlLocally(ctx); + throw new PipelineJobException("Fraction failing cell hashing was : " + fractionFailedHashing + ", which is above threshold of: " + maxHashingPctFail + ". Total cells: " + totalLines); + } + } + catch (IOException e) + { + throw new PipelineJobException(e); + } + } } \ No newline at end of file diff --git a/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJUtils.java b/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJUtils.java index 8434781dd..431fdd624 100644 --- a/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJUtils.java +++ b/tcrdb/src/org/labkey/tcrdb/pipeline/CellRangerVDJUtils.java @@ -196,6 +196,7 @@ public void importAssayData(PipelineJob job, AnalysisModel model, File vLoupeFil int doublet = 0; int discordant = 0; int negative = 0; + int lowCounts = 0; int consensusIdx = -1; while ((line = reader.readNext()) != null) @@ -235,6 +236,11 @@ else if ("Negative".equals(hto)) negative++; continue; } + else if ("Low Counts".equals(hto)) + { + lowCounts++; + continue; + } CDNA_Library cDNA = htoNameToCDNAMap.get(hto); if (cDNA == null) @@ -249,6 +255,7 @@ else if ("Negative".equals(hto)) _log.info("total doublets: " + doublet); _log.info("total discordant: " + discordant); _log.info("total negatives: " + negative); + _log.info("total low counts: " + lowCounts); } catch (IOException e) {