From 6fd697a171e645af12e8bf5d32810dc1f39e0bf5 Mon Sep 17 00:00:00 2001 From: Erik Kleinsteuber Date: Fri, 12 Dec 2025 11:25:13 +0100 Subject: [PATCH 01/37] pushed missing files in smm #2201 --- .../BExIS.Modules.SMM.UI.csproj | 276 ++++++++++++++++++ .../src/routes/+page.svelte | 5 +- .../src/routes/groups/+page.svelte | 10 - .../src/routes/species/+page.svelte | 33 +++ .../src/routes/species/services.ts | 15 + .../src/routes/species/types.ts | 4 + .../src/routes/users/+page.svelte | 9 - .../BExIS.Modules.SMM.UI.csproj | 26 +- .../Controllers/SpeciesController.cs | 40 +++ .../Models/SpeciesModel.cs | 13 + .../Properties/AssemblyInfo.cs | 2 +- .../BExIS.Modules.SMM.UI/SMM.Settings.json | 2 +- .../Views/Species/Index.cshtml | 17 ++ .../Areas/SMM/BExIS.Modules.SMM.UI/web.config | 6 +- Console/Workspace | 2 +- 15 files changed, 430 insertions(+), 30 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/BExIS.Modules.SMM.UI.csproj delete mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/groups/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/types.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/users/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Views/Species/Index.cshtml diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/BExIS.Modules.SMM.UI.csproj b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/BExIS.Modules.SMM.UI.csproj new file mode 100644 index 0000000000..f8d00ee09d --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/BExIS.Modules.SMM.UI.csproj @@ -0,0 +1,276 @@ + + + + + Debug + AnyCPU + + + 2.0 + {37402CAB-EB81-4D08-8791-8653949C0FEB} + {349c5851-65df-11da-9384-00065b846f21};{fae04ec0-301f-11d3-bf4b-00c04f79efbc} + Library + Properties + BExIS.Modules.Smm.UI + BExIS.Modules.Smm.UI + v4.8 + true + + + + + + + + + + + + true + full + false + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + true + bin\ + TRACE + prompt + 4 + + + + ..\..\..\..\packages\Microsoft.AspNet.Identity.Core.2.2.4\lib\net45\Microsoft.AspNet.Identity.Core.dll + + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebHelpers.3.2.8\lib\net45\Microsoft.Web.Helpers.dll + + + ..\..\..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + + ..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + + + + + + + ..\..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll + + + ..\..\..\..\..\packages\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll + + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.Helpers.dll + + + ..\..\..\..\packages\Microsoft.AspNet.WebApi.Core.5.2.3\lib\net45\System.Web.Http.dll + + + ..\..\..\..\..\packages\Microsoft.AspNet.Mvc.5.2.8\lib\net45\System.Web.Mvc.dll + + + ..\..\..\..\..\packages\Microsoft.AspNet.Razor.3.2.9\lib\net45\System.Web.Razor.dll + + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.dll + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.Deployment.dll + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebPages.3.2.9\lib\net45\System.Web.WebPages.Razor.dll + + + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebPages.Data.3.2.9\lib\net45\WebMatrix.Data.dll + + + ..\..\..\..\..\packages\Microsoft.AspNet.WebPages.WebData.3.2.9\lib\net45\WebMatrix.WebData.dll + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Web.config + + + Web.config + + + Web.config + + + + +<<<<<<< Updated upstream + + +======= +>>>>>>> Stashed changes + + + + + {c230693b-d780-438b-b26c-82257642dd5c} + BExIS.Security.Entities + + + {681c8bc4-55f0-4f43-a685-90e246a88cb1} + BExIS.Security.Services + + + {7D7FBF8E-37D7-4A4C-B40E-3F267E9B9760} + BExIS.App.Bootstrap + + + {b4e7b1bf-01b4-40af-8d19-b8f362167261} + BExIS.Dlm.Entities + + + {c4ca0a99-0af3-4372-a9b7-b9073599bd8b} + BExIS.Dlm.Services + + + {c8a05313-b960-406e-92ec-c1e5b3f47fcd} + BExIS.IO.Transform.Validation + + + {DE0AD99C-C559-422F-8132-CC4D7C46FF83} + BExIS.UI + + + {0815d220-3625-4e23-bbbc-8152345637fe} + Vaiona.Entities + + + {e8b37581-1cac-463d-903b-b4bee8b2b0e3} + Vaiona.Logging + + + {640bf81d-354a-4bf0-85fc-f0ad587cf8a2} + Vaiona.Persistence.Api + + + {63fcacaa-9534-4fdd-a082-78dcc06baf28} + Vaiona.Utils + + + {705f8751-e58a-453e-a7fd-0c310fd3cae8} + Vaiona.Web.Mvc.Modularity + + + {5f5d22e8-8c05-49cd-854e-8fe8eff1aa6c} + Vaiona.Web.Mvc + + + {782B71C1-707F-4AB1-80E9-90D2880635B4} + BExIS.Utils + + + {252F7872-A69C-43A6-84B4-4D2ABDBDD9AB} + BExIS.Xml.Helpers + + + + + + + + 10.0 + $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion) + + + bin\ + TRACE + true + pdbonly + AnyCPU + prompt + + + + + + + + + + + + True + True + 16528 + / + http://localhost:16528/ + False + False + + + False + + + + + + mkdir "$(SolutionDir)Console\Workspace\Modules\SMM" +C:\Windows\System32\xcopy "$(ProjectDir)Smm.Settings.json" "$(SolutionDir)Console\Workspace\Modules\SMM" /C /Y /I /D + + + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte index bc202b1c6d..6470380592 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte @@ -12,10 +12,9 @@ ); - + diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/groups/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/groups/+page.svelte deleted file mode 100644 index 5b6a2b5321..0000000000 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/groups/+page.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - - - \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte new file mode 100644 index 0000000000..26b1e210e8 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte @@ -0,0 +1,33 @@ + + + {#await loadData()} +
+ +
+ {:then result} + {data.count} + {data.name} + + {:catch error} + + {/await} + + +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts new file mode 100644 index 0000000000..09677a6d36 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts @@ -0,0 +1,15 @@ +// Implementations for all the calls for the pokemon endpoints. +//import Api from "./Api"; +import { Api } from '@bexis2/bexis2-core-ui'; + +/****************/ +/* Create*/ +/****************/ +export const load = async () => { + try { + const response = await Api.get('/smm/species/load'); + return response.data; + } catch (error) { + console.error(error); + } +}; diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/types.ts new file mode 100644 index 0000000000..b1c6051842 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/types.ts @@ -0,0 +1,4 @@ +export interface SpeciesModel { + count: number; + name: string; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/users/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/users/+page.svelte deleted file mode 100644 index a5003d03ff..0000000000 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/users/+page.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - - \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj index 557cef96fd..5f4e887628 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj @@ -105,11 +105,16 @@ +<<<<<<< Updated upstream +======= + +>>>>>>> Stashed changes + - + @@ -138,13 +143,18 @@ - - + + +<<<<<<< Updated upstream +======= + + +>>>>>>> Stashed changes Web.config @@ -158,7 +168,7 @@ - + @@ -169,6 +179,10 @@ {681c8bc4-55f0-4f43-a685-90e246a88cb1} BExIS.Security.Services + + {7D7FBF8E-37D7-4A4C-B40E-3F267E9B9760} + BExIS.App.Bootstrap + {b4e7b1bf-01b4-40af-8d19-b8f362167261} BExIS.Dlm.Entities @@ -181,6 +195,10 @@ {c8a05313-b960-406e-92ec-c1e5b3f47fcd} BExIS.IO.Transform.Validation + + {DE0AD99C-C559-422F-8132-CC4D7C46FF83} + BExIS.UI + {0815d220-3625-4e23-bbbc-8152345637fe} Vaiona.Entities diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs new file mode 100644 index 0000000000..ccb169261f --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs @@ -0,0 +1,40 @@ +using BExIS.App.Bootstrap.Attributes; +using BExIS.Modules.Smm.UI.Models; +using BExIS.UI.Helpers; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; + +namespace BExIS.Modules.Smm.UI.Controllers +{ + public class SpeciesController : Controller + { + // GET: Species + + public ActionResult Index() + { + string module = "SMM"; + + ViewData["app"] = SvelteHelper.GetApp(module); + ViewData["start"] = SvelteHelper.GetStart(module); + + return View(); + } + + [JsonNetFilter] + public JsonResult Load() + { + SpeciesModel model = new SpeciesModel(); + model.Count = 2021; + model.Name = "David"; + + + return Json(model, JsonRequestBehavior.AllowGet); + } + + + + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs new file mode 100644 index 0000000000..44642fc525 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class SpeciesModel + { + public int Count { get; set; } + public string Name { get; set; } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Properties/AssemblyInfo.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Properties/AssemblyInfo.cs index 1eecfffc92..861e822098 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Properties/AssemblyInfo.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Properties/AssemblyInfo.cs @@ -19,7 +19,7 @@ [assembly: ComVisible(false)] // The following GUID is for the ID of the typelib if this project is exposed to COM -[assembly: Guid("dec22f9c-47be-4146-94be-1c9aa969afc3")] +[assembly: Guid("dec22f9c-47be-4146-94be-1c9aa969afc4")] // Version information for an assembly consists of the following four values: // diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/SMM.Settings.json b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/SMM.Settings.json index a53aaea853..9d0625d437 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/SMM.Settings.json +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/SMM.Settings.json @@ -32,6 +32,6 @@ "value": "Owner" } ], - "id": "smm", + "id": "Smm", "name": "species mapping" } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Views/Species/Index.cshtml b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Views/Species/Index.cshtml new file mode 100644 index 0000000000..72ca073204 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Views/Species/Index.cshtml @@ -0,0 +1,17 @@ +@{ + ViewBag.Title = "Edit"; + Layout = "~/Themes/Default/Layouts/_svelteLayout.cshtml"; + + @*long id = 0; + long version = 0; + + if (ViewData["id"] != null) { id = Convert.ToInt64(ViewData["id"]); } + + if (ViewData["version"] != null) { version = Convert.ToInt64(ViewData["version"]); } + + *@ + } +
+ + @Html.Partial("_sveltePage") +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config index 5b65f6e794..625adfe585 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config @@ -68,7 +68,11 @@ - + + + + + diff --git a/Console/Workspace b/Console/Workspace index 20ac6d2a6b..4dc26a8121 160000 --- a/Console/Workspace +++ b/Console/Workspace @@ -1 +1 @@ -Subproject commit 20ac6d2a6b3d9067c380ff4e6e297066e9a7c921 +Subproject commit 4dc26a81215d36d1836397b46e3d128ec49a7dfa From c0b091c6e917027aaf25d2c7373170fa951ddfd5 Mon Sep 17 00:00:00 2001 From: sventhiel Date: Fri, 12 Dec 2025 11:35:27 +0100 Subject: [PATCH 02/37] #2201 update project file --- .../SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj index 5f4e887628..ac65ae4660 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj @@ -105,11 +105,8 @@
-<<<<<<< Updated upstream -======= ->>>>>>> Stashed changes @@ -148,13 +145,9 @@ -<<<<<<< Updated upstream - - -======= + ->>>>>>> Stashed changes Web.config From c2308c76321b842a5dbadb9622d983f22f6de288 Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 2 Apr 2026 11:42:32 +0200 Subject: [PATCH 03/37] initial push for smm functionalities #980 --- BExIS++.sln | 4 +- .../BExIS.Dlm.Entities.csproj | 1 + .../SpeciesMatching/SpeciesMatchingResult.cs | 51 + .../BExIS.Dlm.Orm.NH/BExIS.Dlm.Orm.NH.csproj | 1 + .../SpeciesMatchingResult.hbm.xml | 45 + .../BExIS.Dlm.Services.csproj | 1 + .../SpeciesMatchingResultManager.cs | 143 + .../BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj | 1 + .../SpeciesMatchingResultManagerTest.cs | 71 + .../package-lock.json | 8 +- .../BExIS.Modules.SMM.UI.Svelte/package.json | 2 +- .../src/routes/+page.svelte | 6 +- .../src/routes/species/+page.svelte | 239 +- .../src/routes/species/services.ts | 1 + .../svelte.config.js | 6 +- .../BExIS.Modules.SMM.UI.csproj | 37 +- .../Controllers/SpeciesController.cs | 764 ++++- .../Models/SpeciesModel.cs | 13 - .../SMM/BExIS.Modules.SMM.UI/packages.config | 5 + .../Areas/SMM/BExIS.Modules.SMM.UI/web.config | 6 +- .../src/lib/stores/persist.ts | 20 + .../src/lib/stores/selectionStore.ts | 11 + .../src/lib/types/types.ts | 60 + .../src/routes/datasets_overview/+page.svelte | 104 + .../ResultTableOptions.svelte | 43 + .../src/routes/datasets_overview/data.ts | 19 + .../src/routes/datasets_overview/services.ts | 10 + .../src/routes/datasets_overview/types.ts | 0 .../src/routes/headermapping/+page.svelte | 171 ++ .../src/routes/headermapping/services.ts | 31 + .../src/routes/headermapping/types.ts | 80 + .../src/routes/matchingresult/+page.svelte | 120 + .../AcceptedTableOptions.svelte | 30 + .../matchingresult/ResultTableOptions.svelte | 40 + .../src/routes/matchingresult/data.ts | 18 + .../src/routes/matchingresult/services.ts | 12 + .../src/routes/matchingresult/types.ts | 0 .../src/routes/progress_overview/+page.svelte | 162 ++ .../progress_overview/TableOptions.svelte | 31 + .../src/routes/progress_overview/data.ts | 9 + .../src/routes/progress_overview/services.ts | 43 + .../src/routes/progress_overview/types.ts | 11 + .../species/AcceptedTableOptions.svelte | 30 + .../src/routes/species/EditResult.svelte | 12 + .../routes/species/ResultTableOptions.svelte | 40 + .../src/routes/species/data.ts | 2448 +++++++++++++++++ .../src/routes/tailor_view/+page.svelte | 136 + .../src/routes/tailor_view/EditResult.svelte | 43 + .../tailor_view/ResultTableOptions.svelte | 40 + .../src/routes/tailor_view/data.ts | 324 +++ .../routes/tailor_view/dataCleaningUtils.ts | 618 +++++ .../src/routes/tailor_view/services.ts | 10 + .../src/routes/tailor_view/types.ts | 0 .../Helpers/MatchingResultHelper.cs | 294 ++ .../Helpers/ProgressHelper.cs | 239 ++ .../Models/AcceptMatchesRequestModel.cs | 18 + .../Models/CLBMatchingResultFile.cs | 34 + .../Models/HeaderMappingsModel.cs | 53 + .../Models/MappingProgressModel.cs | 84 + .../BExIS.Web.Shell/BExIS.Web.Shell.csproj | 2 +- 60 files changed, 6800 insertions(+), 55 deletions(-) create mode 100644 Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs create mode 100644 Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml create mode 100644 Components/DLM/BExIS.Dlm.Services/SpeciesMatching/SpeciesMatchingResultManager.cs create mode 100644 Components/DLM/BExIS.Dlm.Tests/Services/SpeciesMatching/SpeciesMatchingResultManagerTest.cs delete mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/persist.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/selectionStore.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/data.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/services.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/services.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/AcceptedTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/ResultTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/data.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/services.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/TableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/data.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/AcceptedTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/EditResult.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/ResultTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/data.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/dataCleaningUtils.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/services.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingResultHelper.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/ProgressHelper.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/AcceptMatchesRequestModel.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/CLBMatchingResultFile.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/HeaderMappingsModel.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MappingProgressModel.cs diff --git a/BExIS++.sln b/BExIS++.sln index fe37c0864e..1da4bb7532 100644 --- a/BExIS++.sln +++ b/BExIS++.sln @@ -1,6 +1,6 @@ Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 17 -VisualStudioVersion = 17.9.34723.18 +# Visual Studio Version 18 +VisualStudioVersion = 18.2.11415.280 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Console", "Console", "{A24A6801-2ECC-4F47-8284-8C93277D3030}" EndProject diff --git a/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj b/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj index 2f6192e4bd..ce01752b8d 100644 --- a/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj +++ b/Components/DLM/BExIS.Dlm.Entities/BExIS.Dlm.Entities.csproj @@ -124,6 +124,7 @@ + diff --git a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs new file mode 100644 index 0000000000..4177f7a2a0 --- /dev/null +++ b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs @@ -0,0 +1,51 @@ +using BExIS.Dlm.Entities.Data; +using BExIS.Security.Entities.Subjects; +using System; +using Vaiona.Entities.Common; + +namespace BExIS.Dlm.Entities.SpeciesMatching +{ + public class SpeciesMatchingResult : BaseEntity + { + + // original unchanged name submitted for matching + public virtual string OriginalName { get; set; } + + // cleaned name after preprocessing (e.g. trimming, removing special characters, etc.) + public virtual string CleanedName { get; set; } + + // edited name after manual corrections (if any) + public virtual string EditedName { get; set; } + + // matched name from the external source + public virtual string MatchedName { get; set; } + + // taxonomic status of the matched name (e.g. accepted, synonym, etc.) + public virtual string Status { get; set; } + + // type of the match (e.g. exact, fuzzy, etc.) + public virtual string MatchType { get; set; } + + // timestamp of the match + public virtual DateTime TimestampMatch { get; set; } + + // source of the match (e.g. Catalogue of Life, GBIF, etc.) + public virtual string MatchSource { get; set; } + + // version of the source used for matching + public virtual string MatchSourceVersion { get; set; } + + // indicates whether the match has been confirmed by the user + public virtual bool ConfirmedByUser { get; set; } + + // reference to the dataset where the original name was taken from + public virtual Dataset Dataset { get; set; } + + // reference to the specific version of the dataset + // TODO: get this to work (maybe as a normal field instead of many-to-one relation) + //public virtual DatasetVersion DatasetVersion { get; set; } + + // reference to the user who owns this matching result + public virtual User Creator { get; set; } + } +} \ No newline at end of file diff --git a/Components/DLM/BExIS.Dlm.Orm.NH/BExIS.Dlm.Orm.NH.csproj b/Components/DLM/BExIS.Dlm.Orm.NH/BExIS.Dlm.Orm.NH.csproj index dc82b66e33..642b8d5b8e 100644 --- a/Components/DLM/BExIS.Dlm.Orm.NH/BExIS.Dlm.Orm.NH.csproj +++ b/Components/DLM/BExIS.Dlm.Orm.NH/BExIS.Dlm.Orm.NH.csproj @@ -239,6 +239,7 @@ Designer
+ PreserveNewest Designer diff --git a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml new file mode 100644 index 0000000000..15b6726899 --- /dev/null +++ b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj b/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj index f0aedfb538..026162b6dd 100644 --- a/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj +++ b/Components/DLM/BExIS.Dlm.Services/BExIS.Dlm.Services.csproj @@ -166,6 +166,7 @@ + diff --git a/Components/DLM/BExIS.Dlm.Services/SpeciesMatching/SpeciesMatchingResultManager.cs b/Components/DLM/BExIS.Dlm.Services/SpeciesMatching/SpeciesMatchingResultManager.cs new file mode 100644 index 0000000000..266e609bad --- /dev/null +++ b/Components/DLM/BExIS.Dlm.Services/SpeciesMatching/SpeciesMatchingResultManager.cs @@ -0,0 +1,143 @@ +using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Entities.SpeciesMatching; +using System; +using System.Collections.Generic; +using System.Diagnostics.Contracts; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Vaiona.Persistence.Api; + +namespace BExIS.Dlm.Services.SpeciesMatching +{ + public class SpeciesMatchingResultManager : IDisposable + { + + private IUnitOfWork guow = null; + + public SpeciesMatchingResultManager() + { + guow = this.GetIsolatedUnitOfWork(); + this.Repo = guow.GetReadOnlyRepository(); + } + + private bool isDisposed = false; + + ~SpeciesMatchingResultManager() + { + Dispose(true); + } + + public void Dispose() + { + Dispose(true); + } + + protected virtual void Dispose(bool disposing) + { + if (!isDisposed) + { + if (disposing) + { + if (guow != null) + guow.Dispose(); + isDisposed = true; + } + } + } + + public IReadOnlyRepository Repo { get; private set; } + + public SpeciesMatchingResult Create(SpeciesMatchingResult matchingResult) + { + if (matchingResult == null) throw new ArgumentNullException("Species matching result must not be null."); + if (matchingResult.Creator == null) throw new ArgumentNullException("Creator type must not be null."); + if (matchingResult.Dataset == null) throw new ArgumentNullException("Dataset must not be null."); + if (matchingResult.OriginalName == null) throw new ArgumentNullException("Dataset must not be null."); + + using (IUnitOfWork uow = this.GetUnitOfWork()) + { + try + { + IRepository repo = uow.GetRepository(); + repo.Put(matchingResult); + uow.Commit(); + + return (matchingResult); + } + catch (Exception ex) + { + throw new Exception("SpeciesMatchingResult creation failed.", ex); + } + } + } + + public SpeciesMatchingResult Update(SpeciesMatchingResult matchingResult) + { + if (matchingResult == null) throw new ArgumentNullException("Species matching result must not be null."); + + Contract.Ensures(Contract.Result() != null && Contract.Result().Id >= 0); + + using (IUnitOfWork uow = this.GetUnitOfWork()) + { + try + { + IRepository repo = uow.GetRepository(); + repo.Merge(matchingResult); + var merged = repo.Get(matchingResult.Id); + repo.Put(merged); + uow.Commit(); + + return (merged); + } + catch (Exception ex) + { + throw new Exception("SpeciesMatchingResult creation failed.", ex); + } + } + } + public bool Delete(long id) + { + if (id == 0) throw new ArgumentException("Species matching result must not be null."); + + Contract.Ensures(Contract.Result() != null && Contract.Result().Id >= 0); + + using (IUnitOfWork uow = this.GetUnitOfWork()) + { + IRepository repo = uow.GetRepository(); + + var e = repo.Get(id); + + if (e != null) + { + repo.Delete(e); + uow.Commit(); + + return true; + } + else + { + throw new ArgumentException(string.Format("the species matching result with the id {0} does not exist", id)); + } + } + } + + public bool Delete(SpeciesMatchingResult matchingResult) + { + if (matchingResult == null) throw new ArgumentNullException("Entity template must not be null."); + + Contract.Ensures(Contract.Result() != null && Contract.Result().Id >= 0); + + using (IUnitOfWork uow = this.GetUnitOfWork()) + { + IRepository repo = uow.GetRepository(); + + repo.Delete(matchingResult); + uow.Commit(); + + return true; + } + } + + } +} diff --git a/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj b/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj index 204b99e14c..1298fe1228 100644 --- a/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj +++ b/Components/DLM/BExIS.Dlm.Tests/BExIS.Dlm.Tests.csproj @@ -227,6 +227,7 @@ +
diff --git a/Components/DLM/BExIS.Dlm.Tests/Services/SpeciesMatching/SpeciesMatchingResultManagerTest.cs b/Components/DLM/BExIS.Dlm.Tests/Services/SpeciesMatching/SpeciesMatchingResultManagerTest.cs new file mode 100644 index 0000000000..e7da9feb0d --- /dev/null +++ b/Components/DLM/BExIS.Dlm.Tests/Services/SpeciesMatching/SpeciesMatchingResultManagerTest.cs @@ -0,0 +1,71 @@ +using BExIS.App.Testing; +using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Entities.SpeciesMatching; +using BExIS.Dlm.Services.Data; +using BExIS.Dlm.Services.MetadataStructure; +using BExIS.Dlm.Services.SpeciesMatching; +using BExIS.Security.Services.Objects; +using BExIS.Security.Services.Subjects; +using BExIS.Utils.Config; +using NUnit.Framework; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BExIS.Dlm.Tests.Services.SpeciesMatching +{ + internal class SpeciesMatchingResultManagerTest + { + private TestSetupHelper helper = null; + + [OneTimeSetUp] + public void OneTimeSetUp() + { + helper = new TestSetupHelper(WebApiConfig.Register, false); + } + + [OneTimeTearDown] + public void OneTimeTearDown() + { + } + + [Test()] + public void Create_Valid_EntityTemplate() + { + using (var speciesMatchingResultManager = new SpeciesMatchingResultManager()) + using (var userManager = new UserManager()) + using (var datasetManager = new DatasetManager()) + { + //Arrange + SpeciesMatchingResult matchingResult = new SpeciesMatchingResult(); + + var user = userManager.Users.FirstOrDefault(); + var dataset = datasetManager.DatasetRepo.Get().FirstOrDefault(); + + matchingResult.OriginalName = "Sunflower"; + matchingResult.CleanedName = ""; + matchingResult.EditedName = ""; + matchingResult.MatchedName = ""; + matchingResult.Status = ""; + matchingResult.MatchType = ""; + matchingResult.TimestampMatch = DateTime.Now; + matchingResult.MatchSource = ""; + matchingResult.MatchSourceVersion = ""; + matchingResult.ConfirmedByUser = false; + matchingResult.Dataset = dataset; + matchingResult.Creator = user; + + //Act + var created = speciesMatchingResultManager.Create(matchingResult); + var fromdb = speciesMatchingResultManager.Repo.Get().LastOrDefault(); + + //Assert + Assert.IsNotNull(created); + Assert.IsNotNull(fromdb); + Assert.That(created.Id.Equals(fromdb.Id)); + } + } + } +} diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package-lock.json index 5550fb4147..3ed69d646a 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "^0.4.9", + "@bexis2/bexis2-core-ui": "0.4.63", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.9", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.9.tgz", - "integrity": "sha512-7f0Xb0cEzu6/CmoKOTuemJzAnSenqet7SkhU3YgX1qBUzPLAJzvPEWhTkEnuWi2tzKygdZRMyRsL6ugKHhUksQ==", + "version": "0.4.63", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.63.tgz", + "integrity": "sha512-tLqUzCsCslNSA+YoMd6+FRA6SXY2SOet9RVdQbe6khVXEc33lvFwu3ZrNfNBT3Ku5ca1dtngzA4dhSNeCAg99A==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package.json index 1e6792cac2..aa6258dd21 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "^0.4.9", + "@bexis2/bexis2-core-ui": "0.4.63", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte index 6470380592..a5d5481483 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/+page.svelte @@ -14,7 +14,11 @@ diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte index 26b1e210e8..fea9fc907b 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/+page.svelte @@ -2,32 +2,241 @@ import { ErrorMessage, Page, pageContentLayoutType, positionType, Spinner } from "@bexis2/bexis2-core-ui"; import { load } from "./services"; import type { SpeciesModel } from "./types"; + import { Table } from '@bexis2/bexis2-core-ui'; + import type { TableConfig } from '@bexis2/bexis2-core-ui'; + import { Modal, getModalStore } from '@skeletonlabs/skeleton'; + + import { resultStore, acceptedStore } from './data'; + import type { ResultRow } from './data'; + import Dropzone from "svelte-file-dropzone" + import { MultiSelect } from "@bexis2/bexis2-core-ui"; + import ResultTableOptions from "./ResultTableOptions.svelte"; + import AcceptedTableOptions from "./AcceptedTableOptions.svelte"; + import EditResult from "./EditResult.svelte"; + + // let files: FileList; + const ONE_MB: number = 1000000; + const modalStore = getModalStore() + let files: any[] = []; + let fileData: string[][] = []; + let headerData: string[] = []; - let data:SpeciesModel; - async function loadData(){ + function processRawCSV(data: string): string[][] { + const output: string[][] = []; + const rows = data.split("\n"); + if (!rows.length) return output; - data = await load(); + headerData = rows[0].split(","); + + for (let i = 0; i < rows.length; i++) { + const cells = rows[i].split(","); + output.push(cells); + } + + return output; } + function handleFilesSelect(e: CustomEvent) { + files = e.detail.acceptedFiles; + for (let i = 0; i < files.length; i++) { + const reader = new FileReader(); + reader.onload = () => { + const binaryStr = reader.result; + if (typeof binaryStr === "string") { + fileData = processRawCSV(binaryStr); + } else if (binaryStr == null) { + console.error("reader result returned null, could not handle selected file"); + } else { + console.error("reader result returned ArrayBuffer, could not handle selected file"); + } + }; + + // this seems to be the normal way.. + reader.readAsText(files[i]); + } + } + + + function synthLotsOfData() { + var synthRows: ResultRow[] = []; + for (let i = 0; i < 10000; i++) { + synthRows.push({ + inputID: i, + status: "accepted", + }) + } + + resultStore.update(items => [...items, ...synthRows]); + } + + function synthTestData() { + var synthRows: ResultRow[] = []; + for (let i = 0; i < 100; i++) { + synthRows.push({ + inputID: i, + inputName: `inputName_${i}`, + matchType: "exact", + scientificName: `exactName_${i}` + }) + } + + for (let i = 100; i < 200; i++) { + synthRows.push({ + inputID: i, + inputName: `inputName_${i}`, + matchType: "variant", + scientificName: `variantName_${i}` + }) + } + + for (let i = 200; i < 300; i++) { + synthRows.push({ + inputID: i, + inputName: `inputName_${i}`, + matchType: "none", + scientificName: "" + }) + } + + resultStore.update(items => [...items, ...synthRows]); + } + + function acceptAllByMatchType(match_type: string) { + let itemsAccepted: ResultRow[] = []; + resultStore.update(currentItems => { + const remaining: ResultRow[] = []; + for (const item of currentItems) { + if (item.matchType === match_type) { + itemsAccepted.push(item); + } else { + remaining.push(item); + } + } + + return remaining; + }); + + if (itemsAccepted.length > 0) { + acceptedStore.update(currentItems => [...currentItems, ...itemsAccepted]); + } + } + + const resultTableActions = (action: CustomEvent<{ row: ResultRow; type: string }>) => { + const { type, row } = action.detail; + switch (type) { + case 'ACCEPT': + resultStore.update(items => items.filter(i => i.inputID !== row.inputID)); + acceptedStore.update(items => [...items, row]); + break; + case 'READ': + break; + case 'UPDATE': + modalStore.trigger({ + type: 'component', + title: `Edit Result name ${row.inputName}`, + component: { + ref: EditResult, + props: { row: row } + } + }); + break; + + default: + break; + } + }; + + const acceptedTableActions = (action: CustomEvent<{ row: ResultRow; type: string }>) => { + const { type, row } = action.detail; + switch (type) { + case 'REMOVE': + acceptedStore.update(items => items.filter(i => i.inputID !== row.inputID)); + resultStore.update(items => [...items, row]); + break; + + default: + break; + } + }; + + const resultConfig: TableConfig = { + id: 'resultRows', + data: resultStore, + resizable: "columns", + height: 700, + fitToScreen: false, + defaultPageSize: 50, + pageSizes: [20, 50, 100], + showColumnsMenu: true, + columns: { + inputID: { + header: 'inputID', + } + }, + optionsComponent: ResultTableOptions + }; + + const acceptedConfig: TableConfig = { + id: 'acceptedRows', + data: acceptedStore, + resizable: "columns", + height: 700, + fitToScreen: false, + defaultPageSize: 50, + pageSizes: [20, 50, 100], + showColumnsMenu: true, + columns: { + inputID: { + header: 'inputID', + } + }, + optionsComponent: AcceptedTableOptions + }; + - {#await loadData()} -
- -
- {:then result} - {data.count} - {data.name} - - {:catch error} - - {/await} - + + {#each files as item} +

{item.name}

+ {/each} + + + + + + +

Result

+
+ + + + +
+ +

Accepted

+
+
+ +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts index 09677a6d36..587dc16ea8 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/src/routes/species/services.ts @@ -13,3 +13,4 @@ export const load = async () => { console.error(error); } }; + diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/svelte.config.js b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/svelte.config.js index d43ccb685e..d27b7b2bd7 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/svelte.config.js +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI.Svelte/svelte.config.js @@ -10,8 +10,8 @@ const config = { preprocess: vitePreprocess(), kit: { adapter: adapter({ - pages: '../BExIS.Modules.Sam.UI/Scripts/svelte', // ../BExIS.Modules.Dcm.UI/Scripts/svelte - assets: '../BExIS.Modules.Sam.UI/Scripts/svelte', // ../BExIS.Modules.Dcm.UI/Scripts/svelte + pages: '../BExIS.Modules.Smm.UI/Scripts/svelte', // ../BExIS.Modules.Dcm.UI/Scripts/svelte + assets: '../BExIS.Modules.Smm.UI/Scripts/svelte', // ../BExIS.Modules.Dcm.UI/Scripts/svelte fallback: null, precompress: true, preprocess: true, @@ -19,7 +19,7 @@ const config = { }), paths: { relative: true, - base: process.env.NODE_ENV === 'production' ? '/sam' : '' // add module id here, + base: process.env.NODE_ENV === 'production' ? '/smm' : '' // add module id here, }, alias: { diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj index ac65ae4660..d5ea4539bb 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj @@ -49,6 +49,15 @@ ..\..\..\..\packages\Microsoft.AspNet.Identity.Core.2.2.4\lib\net45\Microsoft.AspNet.Identity.Core.dll + + ..\..\..\..\..\packages\Microsoft.IdentityModel.JsonWebTokens.5.7.0\lib\net461\Microsoft.IdentityModel.JsonWebTokens.dll + + + ..\..\..\..\..\packages\Microsoft.IdentityModel.Logging.5.7.0\lib\net461\Microsoft.IdentityModel.Logging.dll + + + ..\..\..\..\..\packages\Microsoft.IdentityModel.Tokens.5.7.0\lib\net461\Microsoft.IdentityModel.Tokens.dll + ..\..\..\..\..\packages\Microsoft.AspNet.WebHelpers.3.2.8\lib\net45\Microsoft.Web.Helpers.dll @@ -56,11 +65,16 @@ ..\..\..\..\..\packages\Microsoft.Web.Infrastructure.2.0.0\lib\net40\Microsoft.Web.Infrastructure.dll - ..\..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + ..\..\..\..\..\packages\Newtonsoft.Json.13.0.1\lib\net45\Newtonsoft.Json.dll + + + + ..\..\..\..\..\packages\System.IdentityModel.Tokens.Jwt.5.7.0\lib\net461\System.IdentityModel.Tokens.Jwt.dll + ..\..\..\..\packages\Microsoft.AspNet.WebApi.Client.5.2.3\lib\net45\System.Net.Http.Formatting.dll @@ -107,9 +121,14 @@ + + - + + + + @@ -160,8 +179,6 @@ - - @@ -184,6 +201,10 @@ {c4ca0a99-0af3-4372-a9b7-b9073599bd8b} BExIS.Dlm.Services + + {455EC826-9A92-40FF-BD3B-388C288955CE} + BExIS.IO.Transform.Output + {c8a05313-b960-406e-92ec-c1e5b3f47fcd} BExIS.IO.Transform.Validation @@ -192,6 +213,10 @@ {DE0AD99C-C559-422F-8132-CC4D7C46FF83} BExIS.UI + + {6EAD7D02-02F7-42FF-85E4-90BB892D3846} + BExIS.Utils.Config + {0815d220-3625-4e23-bbbc-8152345637fe} Vaiona.Entities @@ -224,6 +249,10 @@ {252F7872-A69C-43A6-84B4-4D2ABDBDD9AB} BExIS.Xml.Helpers + + {9BFFFD11-03C6-47DF-9CC9-F458A9A49377} + BExIS.Modules.Dim.UI + diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs index ccb169261f..57eb4c4c4d 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs @@ -1,11 +1,41 @@ using BExIS.App.Bootstrap.Attributes; +using BExIS.App.Bootstrap.Helpers; +using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Entities.DataStructure; +using BExIS.Dlm.Entities.SpeciesMatching; +using BExIS.Dlm.Services.Data; +using BExIS.Dlm.Services.SpeciesMatching; +using BExIS.IO.Transform.Output; +using BExIS.Modules.Dim.UI.Models.Api; +using BExIS.Modules.Smm.UI.Helpers; using BExIS.Modules.Smm.UI.Models; +using BExIS.Security.Entities.Authorization; +using BExIS.Security.Entities.Subjects; +using BExIS.Security.Services.Authorization; +using BExIS.Security.Services.Objects; +using BExIS.Security.Services.Subjects; using BExIS.UI.Helpers; +using BExIS.UI.Models; +using BExIS.Utils.Config; +using Microsoft.IdentityModel.Tokens; +using Newtonsoft.Json; using System; using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.IdentityModel.Tokens.Jwt; +using System.IO; using System.Linq; -using System.Web; +using System.Net; +using System.Net.Http; +using System.Net.Http.Headers; +using System.Security.Claims; +using System.Text; +using System.Threading.Tasks; using System.Web.Mvc; +using Vaiona.Persistence.Api; +using Vaiona.Utils.Cfg; + namespace BExIS.Modules.Smm.UI.Controllers { @@ -23,18 +53,740 @@ public ActionResult Index() return View(); } + private static readonly HttpClient _httpClient = new HttpClient(); + + [JsonNetFilter] + [HttpGet] + public JsonResult GetMyDatasetsJson() + { + var result = new List(); + const string entityname = "Dataset"; + const RightType rightType = RightType.Write; + + var user = ResolveRouteUser(out ActionResult userError); + if (user == null) + { + return JsonWithStatus(new { success = false, message = "User could not be resolved from route." }, HttpStatusCode.Unauthorized, JsonRequestBehavior.AllowGet); + } + + string username = user.Name; + // TODO: - CHANGE - JUST FOR TESTING + if (string.IsNullOrWhiteSpace(username)) username = "erik"; + + using (var datasetManager = new DatasetManager()) + using (var entityPermissionManager = new EntityPermissionManager()) + using (var entityManager = new EntityManager()) + using (var speciesMatchingResultManager = new SpeciesMatchingResultManager()) + { + // Find entity (defensive) + var entity = entityManager.FindByName(entityname); + if (entity == null) + { + return JsonWithStatus(new { error = $"Entity '{entityname}' not found." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); + } + + // collect dataset ids the current user has the requested right for + List datasetIds = entityPermissionManager.GetKeys(username, entityname, typeof(Dataset), rightType).Result ?? new List(); + + // load latest versions for those dataset ids + List versions = datasetManager.GetDatasetLatestVersions(datasetIds, includeCheckouts: true); + + var smrmRepo = speciesMatchingResultManager.GetBulkUnitOfWork().GetReadOnlyRepository(); + + foreach (var dsv in versions) + { + bool isTabular = dsv.Dataset.DataStructure?.Self is StructuredDataStructure; + bool metadataComplete = false; + if (dsv.StateInfo != null) + { + metadataComplete = string.Equals(dsv.StateInfo.State, DatasetStateInfo.Valid.ToString(), StringComparison.OrdinalIgnoreCase); + } + + bool hasSpeciesMatches = smrmRepo.Query().Any(r => r.Dataset.Id == dsv.Dataset.Id); + bool hasHeaderMappings = ProgressHelper.HasHeaderMappings(dsv.Dataset.Id); + + result.Add(new + { + Id = dsv.Dataset.Id, + Title = dsv.Title ?? string.Empty, + Abstract = dsv.Description ?? string.Empty, + IsTabular = isTabular, + MetadataComplete = metadataComplete, + HasMatchingProgress = hasSpeciesMatches || hasHeaderMappings, + DataStructureId = dsv.Dataset.DataStructure?.Id + }); + } + } + + return Json(result, JsonRequestBehavior.AllowGet); + } + + [JsonNetFilter] + [HttpPost] + public JsonResult SubmitHeaderMappings(HeaderMappingsModel data) + { + // basic model binding validation: ensure payload present and DatasetId provided (>0) + if (data == null) + { + return JsonWithStatus(new { success = false, message = "Request body missing or invalid." }, HttpStatusCode.BadRequest); + } + + if (!ModelState.IsValid) + { + // var errors = ModelState.Values.SelectMany(v => v.Errors).Select(e => e.ErrorMessage).Where(m => !string.IsNullOrWhiteSpace(m)).ToList(); + // if (!errors.Any()) errors.Add("Invalid request payload."); + return JsonWithStatus(new { success = false, message = "Validation failed." }, HttpStatusCode.BadRequest); + } + + long datasetId = data.DatasetId; + + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized); + } + + var success = ProgressHelper.CreateHeaderMappingsFile(data, datasetId, out string errorMessage); + + if (success) + { + return Json(new { success = true, id = datasetId }); + } else + { + return JsonWithStatus(new + { + success = false, + message = errorMessage + }, HttpStatusCode.BadRequest); + } + } + + [JsonNetFilter] + [HttpPost] + // Calls Datastatistic API with the given dataset id and variable id, creates a SpeciesMatchingResult for each unique name and saves to database. + public async Task Tailor(long datasetId) + { + /* + This method is supposed to be called after the user has set up the header mappings and wants to start the matching process. + It should then call the DataStatistic API with the given dataset id and variable id and create a SpeciesMatchingResult for each + individual name. The API call needs to be authenticated with a JWT token, which we can generate here with a custom method. + */ + + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized); + } + + // load header mappings for this dataset + var headerMappings = ProgressHelper.LoadHeaderMappings(datasetId); + if (headerMappings == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Header mappings not found for this dataset." }, HttpStatusCode.Conflict); + } + + // find variable id for scientific name field + long? targetVariableId = headerMappings.GetVariableIdForScientificName(); + if (targetVariableId == null) { + return JsonWithStatus(new { success = false, id = datasetId, message = "No variable mapped for scientific name found in header mappings." }, HttpStatusCode.Conflict); + } + + // check mapping progress + if (ProgressHelper.HasMappingProgress(datasetId)) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Mapping progress file already exists for this dataset. Please complete or reset existing mapping progress before starting a new tailoring process." }, HttpStatusCode.Conflict); + } + + // generate token for local api call + string jwtToken = GenerateCustomJwtToken(); + if (jwtToken == null) + { + Debug.WriteLine("JWT token generation failed."); + return JsonWithStatus(new { success = false, id = datasetId, message = "Could not call internal API. Please try again later." }, HttpStatusCode.Conflict); + } + + var result = await TailorDataset(datasetId, targetVariableId.Value, jwtToken); + var list_result = JsonConvert.DeserializeObject>(result.Content); + ApiDataStatisticModel json_result = list_result.FirstOrDefault(); + + if (!result.IsSuccess) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Api call failed " + result.Content }, HttpStatusCode.BadRequest); + } + + using (var speciesMatchingResultManager = new SpeciesMatchingResultManager()) + using (var uow = speciesMatchingResultManager.GetBulkUnitOfWork()) + using (var datasetManager = new DatasetManager()) + { + try + { + // check if rows present in API result + if (json_result.uniqueValues == null || json_result.uniqueValues.Rows.Count <= 0) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "DataStatisticApi returned no meaningful result." }, HttpStatusCode.Conflict); + } + + // check if expected column "var" is present in the API result + if (!json_result.uniqueValues.Columns.Contains("var")) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Column variable 'var' was missing on the Api result." }, HttpStatusCode.Conflict); + } + + var repo = uow.GetRepository(); + var dataset = datasetManager.DatasetRepo.Get(datasetId); + var placeHolderTimeStamp = DateTime.Now; + + // double check if there are already species matching results for this dataset + bool hasSpeciesMatches = repo.Query().Any(r => r.Dataset.Id == datasetId); + if (hasSpeciesMatches) { + return JsonWithStatus(new { success = false, id = datasetId, message = "Species matching results already exist for this dataset. Please complete or reset existing mapping progress before starting a new tailoring process." }, HttpStatusCode.BadRequest); + } + + int rowCount = 0; + + // create one row in SpeciesMatchingResult per unique row from DataStatistic Api + foreach (DataRow row in json_result.uniqueValues.Rows) + { + if (row["var"] == DBNull.Value) continue; + string varValue = row["var"].ToString(); + + // create row + var matchingResult = new SpeciesMatchingResult + { + OriginalName = varValue, + CleanedName = "", + EditedName = "", + MatchedName = "", + Status = "", + MatchType = "", + TimestampMatch = placeHolderTimeStamp, + MatchSource = "", + MatchSourceVersion = "", + ConfirmedByUser = false, + Dataset = dataset, + Creator = user + }; + + repo.Put(matchingResult); + rowCount++; + } + + // TODO: check success (but in general should be built in a way that it never fails) + ProgressHelper.CreateMappingProgressFile(datasetId, rowCount); + + // batch commit + uow.Commit(); + } + catch (Exception ex) + { + // ignore on failure to avoid partial commits and inconsistent state; the user can then try again after fixing the underlying issue + uow.Ignore(); + Debug.WriteLine("Custom exception catch in Tailor."); + return JsonWithStatus(new { success = false, id = datasetId, message = "An error occured while processing the Api result: " + ex.Message }, HttpStatusCode.InternalServerError); + } + } + + return Json(new { success = true, id = datasetId, message = json_result }); + } + + [JsonNetFilter] + [HttpGet] + // Get ALL SpeciesMatchingResults for a given dataset. + // Used to display the overall state of the matching results in the frontend, and to allow users to filter and edit. + public JsonResult ViewTailored(long datasetId) + { + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized, JsonRequestBehavior.AllowGet); + } + + var result = MatchingResultHelper.GetAll(datasetId); + + if (result == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No matching results found for this dataset." }, HttpStatusCode.NotFound, JsonRequestBehavior.AllowGet); + } else + { + return Json(new + { + succes = true, + id = datasetId, + message = result + }, JsonRequestBehavior.AllowGet + ); + } + } + + [JsonNetFilter] + [HttpGet] + public JsonResult ViewProgress(long datasetId) + { + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized, JsonRequestBehavior.AllowGet); + } + + try + { + // header mappings + bool hasHeaderMappings = ProgressHelper.HasHeaderMappings(datasetId); + var headerMappings = hasHeaderMappings ? ProgressHelper.LoadHeaderMappings(datasetId) : null; + + // tailored check: any SpeciesMatchingResult entries for this dataset? + bool isTailored = false; + using (var smrm = new SpeciesMatchingResultManager()) + { + var repo = smrm.GetBulkUnitOfWork().GetReadOnlyRepository(); + isTailored = repo.Query().Any(r => r.Dataset.Id == datasetId); + } + + // mapping progress + bool hasMappingProgress = ProgressHelper.HasMappingProgress(datasetId); + var mappingProgress = hasMappingProgress ? ProgressHelper.LoadMappingProgress(datasetId) : null; + + return Json(new + { + success = true, + hasHeaderMappings = hasHeaderMappings, + headerMappings = headerMappings, + isTailored = isTailored, + hasMappingProgress = hasMappingProgress, + mappingProgress = mappingProgress + }, JsonRequestBehavior.AllowGet); + } + catch (Exception ex) + { + Debug.WriteLine("Error while building progress view: " + ex); + return JsonWithStatus(new { success = false, id = datasetId, message = "Error while retrieving progress information." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); + } + + } + + [JsonNetFilter] + [HttpPost] + public JsonResult GenNewMatchInputFile(long datasetId) + { + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized); + } + + var mappingProgress = ProgressHelper.LoadMappingProgress(datasetId); + if (mappingProgress == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No mapping progress found." }, HttpStatusCode.Unauthorized); + } + + if (!mappingProgress.AreAllStepsDone()) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Not all mapping steps are completed yet. Please complete existing steps before generating a new matching input file." }, HttpStatusCode.Conflict); + } + + var newStepId = mappingProgress.GetNewId(); + var datastructureId = GetDatastructureIdFromDatasetId(datasetId); + if (datastructureId == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Dataset or datastructure not found." }, HttpStatusCode.NotFound); + } + + var (FilePath, RowCount) = MatchingResultHelper.GenerateUnmatchedCsv(datasetId, datastructureId.Value, newStepId); + string filepath = FilePath; + int rows = RowCount; + if (filepath == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Could not generate MatchingInput file." }, HttpStatusCode.Conflict); + } + + // this is double generated, but simpler + var filename = ProgressHelper.GenMatchingFileName(false, datasetId, newStepId); + + mappingProgress.AddStep(newStepId, rows, filename); + ProgressHelper.SaveMappingProgress(mappingProgress); + + return Json(new { success = true, id = datasetId, message = "Matching input file generated." }); + } + [JsonNetFilter] - public JsonResult Load() + [HttpPost] + public async Task MatchNextFile(long datasetId) { - SpeciesModel model = new SpeciesModel(); - model.Count = 2021; - model.Name = "David"; + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized); + } + var mappingProgress = ProgressHelper.LoadMappingProgress(datasetId); + if (mappingProgress == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No mapping progress found." }, HttpStatusCode.Unauthorized); + } - return Json(model, JsonRequestBehavior.AllowGet); + string nextFileName = mappingProgress.GetNextPendingInputFileName(); + if (string.IsNullOrWhiteSpace(nextFileName)) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No pending matching input file found." }, HttpStatusCode.Conflict); + } + + // TODO: - pfad logik vereinfachen + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + + if (!Directory.Exists(directory)) + { + Debug.WriteLine("SaveMappingProgress: dataset directory does not exist: " + directory); + return JsonWithStatus(new { success = false, id = datasetId, message = "No matching input file found on disk." }, HttpStatusCode.Conflict); + } + + string filepath = Path.Combine(directory, nextFileName); + + var api_result = await SendToChecklistBank(datasetId, filepath, mappingProgress); + + if (api_result == null) { + return JsonWithStatus(new { success = false, id = datasetId, message = "Error while calling ChecklistBank API." }, HttpStatusCode.Conflict); + } else + { + return api_result; + } } + [JsonNetFilter] + [HttpGet] + public JsonResult ViewMatchingResult(long datasetId, int stepId) + { + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized, JsonRequestBehavior.AllowGet); + } + + var matchingProgress = ProgressHelper.LoadMappingProgress(datasetId); + if (matchingProgress == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No matching progress found under the given datasetId." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); + } + + if (!matchingProgress.IsIdValidAndMatched(stepId)) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No valid matching job found in the matching progress data for the given stepId." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); + } + + var filepath = ProgressHelper.GetMatchedFilepath(datasetId, stepId); + + if (filepath == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "No result file found." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); + } + + var matchingResults = MatchingResultHelper.ReadClbMatchingResultFile(filepath); + return Json(new { success = true, data = matchingResults }, JsonRequestBehavior.AllowGet); + } + + [JsonNetFilter] + [HttpPost] + public JsonResult AcceptMatches(AcceptMatchesRequestModel request) + { + if (request == null) return JsonWithStatus(new { success = false, message = "Request body missing or invalid." }, HttpStatusCode.BadRequest); + + if (!ModelState.IsValid) return JsonWithStatus(new { success = false, message = "Validation failed." }, HttpStatusCode.BadRequest); + + return Json(new { success = true, id = request.DatasetId }); + } + + public async Task<(bool IsSuccess, string Content)> TailorDataset(long datasetId, long variableId, string jwtToken) + { + // TODO: + // - add variableId, change route, test again + string url = "http://localhost:44345/api/DataStatistic/" + datasetId.ToString() + "/" + variableId.ToString(); + + using (var request = new HttpRequestMessage(HttpMethod.Get, url)) + { + request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", jwtToken); + + using (HttpResponseMessage response = await _httpClient.SendAsync(request)) + { + if (response.IsSuccessStatusCode) + { + string apiResponseContent = await response.Content.ReadAsStringAsync(); + + // since response codes are ambiguous, we need to check with this workaround + if (apiResponseContent.StartsWith("[")) + { + // SUCCESS + return (true, apiResponseContent); + } + else + { + // API SOFT FAILURE + return (false, apiResponseContent); + } + + } + else + { + // API HARD FAILURE + Debug.WriteLine("Error: " + response.StatusCode.ToString()); + return (false, "Response status code was not ok." + response.StatusCode.ToString()); + } + } + } + } + + public async Task SendToChecklistBank(long datasetId, string filepath, MappingProgressModel mappingProgress) + { + if (string.IsNullOrWhiteSpace(filepath) || !System.IO.File.Exists(filepath)) + { + return Json(new { success = false, id = datasetId, message = "Export file not generated." }); + } + + byte[] fileBytes = System.IO.File.ReadAllBytes(filepath); + + using (var content = new ByteArrayContent(fileBytes)) + { + //content.Headers.ContentType = new MediaTypeHeaderValue("text/tab-separated-values"); + content.Headers.ContentType = new MediaTypeHeaderValue("text/csv"); + + // TODO: replace with secure configuration + var username = ""; + var password = ""; + var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); + _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue); + + // Test for now : query parameter format=csv + var url = "https://api.checklistbank.org/dataset/3LR/match/nameusage/job?format=csv"; + try + { + HttpResponseMessage response = await _httpClient.PostAsync(url, content); + string responseString = await response.Content.ReadAsStringAsync(); + + // try to parse the response string as JSON. If parsing fails treat the whole call as a failure + // because we cannot interpret the API response reliably. + object responseJson; + try + { + responseJson = JsonConvert.DeserializeObject(responseString); + } + catch (Exception ex) + { + Debug.WriteLine("Failed to deserialize ChecklistBank response as JSON: " + ex.Message); + // Return a failure result when the response cannot be parsed as JSON. + return Json(new { success = false, id = datasetId, status = response.StatusCode, message = "Failed to parse API response as JSON.", response = responseString }); + } + + if (response.IsSuccessStatusCode) + { + return Json(new { success = true, id = datasetId, status = response.StatusCode, response = responseJson }); + } + else + { + return Json(new { success = false, id = datasetId, status = response.StatusCode, response = responseJson }); + } + } + catch (Exception ex) + { + return Json(new { success = false, id = datasetId, message = ex.Message }); + } + finally + { + _httpClient.DefaultRequestHeaders.Authorization = null; + } + } + } + + // Returns the datastructure id for the given dataset id, or null if not found or on error + private long? GetDatastructureIdFromDatasetId(long datasetId) + { + try + { + using (var datasetManager = new DatasetManager()) + { + var datastructureId = datasetManager.DatasetRepo.Query() + .Where(d => d.Id == datasetId) + .Select(d => d.DataStructure != null ? (long?)d.DataStructure.Id : null) + .FirstOrDefault(); + return datastructureId; + + + } + } + catch (Exception ex) + { + Debug.WriteLine("Error getting datastructure id: " + ex); + return null; + } + } + + // Returns a custom JWT token for authenticating internal API calls + private string GenerateCustomJwtToken() + { + try + { + var jwtConfiguration = GeneralSettings.JwtConfiguration; + + using (var userManager = new UserManager()) + { + // var user = BExISAuthorizeHelper.GetUserFromAuthorizationAsync(HttpContext).Result; + var user = ResolveRouteUser(out ActionResult userError); + + Debug.WriteLine(user.DisplayName, " ", user.Email, " ", user.Id); + + if (user != null) + { + + var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfiguration.IssuerSigningKey)); + var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256); + + + //Create a List of Claims, Keep claims name short + var permClaims = new List + { + new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()), + new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()), + new Claim(ClaimTypes.Name, user.UserName) + }; + + + //Create Security Token object by giving required parameters + var token = new JwtSecurityToken(jwtConfiguration.ValidIssuer, + jwtConfiguration.ValidAudience, + permClaims, + notBefore: DateTime.Now, + expires: jwtConfiguration.ValidLifetime > 0 ? DateTime.Now.AddHours(jwtConfiguration.ValidLifetime) : DateTime.MaxValue, + signingCredentials: credentials); + + var jwtToken = new JwtSecurityTokenHandler().WriteToken(token); + return jwtToken; + } + else + { + return null; + } + } + } + catch (Exception ex) + { + return null; + } + } + + // Resolves user from route and checks write rights for the given datasetId. Returns the user if successful, otherwise null + private User ResolveUserAndRights(long datasetId, out ActionResult errorResult) + { + errorResult = null; + var user = ResolveRouteUser(out ActionResult userError); + if (user == null) + { + errorResult = Json(new { success = false, id = datasetId, message = "User could not be resolved from route." }); + return null; + } + if (!EnsureUserHasWriteRights(user.UserName, datasetId, out ActionResult rightsError)) + { + errorResult = Json(new { success = false, id = datasetId, message = "User has no write rights for this dataset." }); + return null; + } + return user; + } + + // Resolves and returns user from the current HttpContext, or null if not possible + private User ResolveRouteUser(out ActionResult errorResult) + { + errorResult = null; + try + { + using (var userManager = new UserManager()) + { + // try token-based resolution first + var user = BExISAuthorizeHelper.GetUserFromAuthorizationAsync(HttpContext).Result; + if (user != null) + { + Debug.WriteLine("User resolved from token: " + user.Name); + return user; + } + + // fallback: try to find a user named 'erik' + var fallback = userManager.Users.FirstOrDefault(u => u.Name == "erik"); + if (fallback != null) + { + Debug.WriteLine("User 'erik' found and used as fallback."); + return fallback; + } + + // final fallback: any available user (default) + var any = userManager.Users.FirstOrDefault(); + if (any != null) + { + Debug.WriteLine("No specific user found; using any available user: " + any.Name); + return any; + } + + Debug.WriteLine("Resolving Route User failed."); + errorResult = Json(new { success = false, message = "User not found in route data." }); + return null; + } + } + catch (Exception ex) + { + Debug.WriteLine("Error resolving user: " + ex.ToString()); + errorResult = Json(new { success = false, message = "Error while resolving user." }); + return null; + } + } + + // Returns TRUE IF the given username has Write rights on the specified datasetId, ELSE FALSE + private bool EnsureUserHasWriteRights(string username, long datasetId, out ActionResult errorResult) + { + errorResult = null; + + if (string.IsNullOrWhiteSpace(username)) + { + errorResult = Json(new { success = false, id = datasetId, message = "Username is missing." }); + return false; + } + + var entityPermissionManager = new EntityPermissionManager(); + try + { + bool hasRights = entityPermissionManager.HasEffectiveRightsAsync(username, typeof(Dataset), datasetId, RightType.Read).Result; + if (!hasRights) + { + errorResult = Json(new { success = false, id = datasetId, message = "User has no rights to read the given dataset." }); + return false; + } + + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Error while checking permissions: " + ex.ToString()); + errorResult = Json(new { success = false, id = datasetId, message = "Error while checking permissions." }); + return false; + } + finally + { + entityPermissionManager.Dispose(); + } + } + + // Helper overloads to return a JsonResult and set a custom HTTP status code in a consistent way. + // Use the no-behavior overload for POST (will use DenyGet), and the overload with behavior for GET responses. + // GET usage (one-liner): return JsonWithStatus(new { success = false, id = datasetId, message = "..." }, HttpStatusCode.BadRequest, JsonRequestBehavior.AllowGet); + // POST usage (one-liner): return JsonWithStatus(new { success = false, id = datasetId, message = "..." }, HttpStatusCode.BadRequest); + private JsonResult JsonWithStatus(object data, HttpStatusCode statusCode, JsonRequestBehavior behavior) + { + Response.StatusCode = (int)statusCode; + Response.TrySkipIisCustomErrors = true; // ensure IIS does not override the response body + return Json(data, behavior); + } + + private JsonResult JsonWithStatus(object data, HttpStatusCode statusCode) + { + Response.StatusCode = (int)statusCode; + Response.TrySkipIisCustomErrors = true; // ensure IIS does not override the response body + return Json(data, JsonRequestBehavior.DenyGet); + } } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs deleted file mode 100644 index 44642fc525..0000000000 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Models/SpeciesModel.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Web; - -namespace BExIS.Modules.Smm.UI.Models -{ - public class SpeciesModel - { - public int Count { get; set; } - public string Name { get; set; } - } -} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/packages.config b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/packages.config index 24f5593d89..05d77fe48b 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/packages.config +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/packages.config @@ -7,7 +7,12 @@ + + + + + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config index 625adfe585..5b65f6e794 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config @@ -68,11 +68,7 @@ - - - - - + diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/persist.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/persist.ts new file mode 100644 index 0000000000..fcad26565a --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/persist.ts @@ -0,0 +1,20 @@ +import { writable } from 'svelte/store'; + +export function persisted(key, initialValue) { + // 1. Check if we have a saved value in localStorage + const saved = typeof window !== 'undefined' ? localStorage.getItem(key) : null; + + // 2. Use saved value if it exists, otherwise use initialValue + const data = saved ? JSON.parse(saved) : initialValue; + + const store = writable(data); + + // 3. Listen for changes and save them to localStorage + if (typeof window !== 'undefined') { + store.subscribe(value => { + localStorage.setItem(key, JSON.stringify(value)); + }); + } + + return store; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/selectionStore.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/selectionStore.ts new file mode 100644 index 0000000000..7693db6e05 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/stores/selectionStore.ts @@ -0,0 +1,11 @@ +import { persisted } from "./persist"; + +/** + * Currently selected dataset and datastructure to progress the mapping process on. + * -1 means selected none. + */ +export const mappingSelection = persisted('mappingSelection', { + datasetId: -1, + datastructureId: -1 +}); + diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts new file mode 100644 index 0000000000..4d88ea43e0 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts @@ -0,0 +1,60 @@ +// global types + +export interface MappingEntry { + variableId: number, + variableName: string, + headerMapping: string +} + +export interface HeaderMappings { + datastructureId: number, + datasetId: number, + mappings: MappingEntry[], +} + +export interface StepEntry { + id: number, + numRows: number, + inputFileName: string, + resultFileName: string, + jobKey: string, + downloadLink: string, + done: boolean +} + +export interface MappingProgress { + datasetId: number, + numRowsGlobal: number, + steps: StepEntry[], +} + +// this is a helper for typing response content correctly +// success false indicates that either the response failed or the whole request failed +export type ServiceResult = + | { success: true, data: T } + | { success: false, error: string }; + +export interface CLBMatchingResult { + original_ID: string, + original_scientificName: string, + original_rank: string, + original_kingdom: string, + original_authorship: string, + matchType: string, + matchIssues: string, + iD: string, + rank: string, + scientificName: string, + authorship: string, + status: string, + acceptedID: string, + acceptedScientificName: string, + acceptedAuthorship: string, + kingdom: string, + phylum: string, + class: string, + order: string, + family: string, + genus: string, + classification: string, +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte new file mode 100644 index 0000000000..9e757f14a2 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte @@ -0,0 +1,104 @@ + + + +

Datasets Overview

+ +

This page gives an overview of all your datasets and their respective mapping progress. Currently only tabular datasets with complete metadata are shown!

+

If there is an Eye icon at the end of the row, the dataset mapping has already been started. Click it to get an overview and continue the process as you wish.

+

If there is a Plus icon, no mapping has been started. Click it to start a fresh mapping process on this dataset.

+ +

Dataset ID: {$mappingSelection.datasetId}

+

Structure ID: {$mappingSelection.datastructureId}

+ +
+
+ + +
+ + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte new file mode 100644 index 0000000000..5ade95c1f9 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte @@ -0,0 +1,43 @@ + + +
+ {#if row.hasMatchingProgress} + + {:else} + + {/if} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/data.ts new file mode 100644 index 0000000000..72c94263ef --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/data.ts @@ -0,0 +1,19 @@ +import { writable } from 'svelte/store'; + +export type BasicDatasetInfo = { + id: number, + dataStructureId: number, + title: string, + abstract: string, + isTabular: boolean, + metadataComplete: boolean, + hasMatchingProgress: boolean +} + + +let datasetRows: BasicDatasetInfo[] = [ + +] + + +export let datasetsStore = writable(datasetRows); \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/services.ts new file mode 100644 index 0000000000..64d6e80346 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/services.ts @@ -0,0 +1,10 @@ +import { Api } from '@bexis2/bexis2-core-ui'; + +export const loadBasicDatasetInfo = async () => { + try { + const response = await Api.get('/smm/species/GetMyDatasetsJson'); + return response.data; + } catch (error) { + console.error(error); + } +}; diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/types.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/+page.svelte new file mode 100644 index 0000000000..1aa45c240c --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/+page.svelte @@ -0,0 +1,171 @@ + + + + +

Select header mapping

+ +

+ You are working on Dataset: {$mappingSelection.datasetId}. Below this text, the corresponding Datastructure: {$mappingSelection.datastructureId} is shown. Each row corresponds to a column in the original dataset, + and an option to select a mapping for it. Some mappings might already be pre-assigned based on your datasets metadata. Please try to select as many matching mappings as possible, but at the very least select a scientificName mapping. + For columns that have no clear associated mapping, just select IGNORE. If there are no conflicts, you should be able to submit the mappings with the button below. +

+ +

+ This information is used to cut off unnecessary data and help matching APIs understand your data better. Your original data will NOT be changed at any step and will remain fully functional. +

+ +{#if dataStructure} + {#each dataStructure.variables as variable, i} +
+
{variable.name}
+
+
+
+ +
+
+ {/each} + + +{/if} + +
+ +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/services.ts new file mode 100644 index 0000000000..fe01dca01a --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/services.ts @@ -0,0 +1,31 @@ +import { Api } from '@bexis2/bexis2-core-ui'; +import type { HeaderMappings } from '$lib/types/types'; + + +/** + * Submits selected column mappings to backend for storage. (used in later stages) + * @param data HeaderMappings data including a MappingEntry[] with the selected mappings. + * @returns response data + */ +export const submitHeaderMappings = async (data: HeaderMappings) => { + try { + const response = await Api.post('/smm/species/SubmitHeaderMappings', data); + return response.data; + } catch (error) { + console.error(error); + } +} + +/** + * Loads datastructure information for display. + * @param datastructureId .. datastructure id loaded from store + * @returns DataStructureEditModel + */ +export const loadDataStructure = async (datastructureId: number) => { + try { + const response = await Api.get(`/rpm/DataStructure/get?id=${datastructureId}`); + return response.data; + } catch (error) { + console.error(error); + } +} diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/types.ts new file mode 100644 index 0000000000..b156dde82e --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/headermapping/types.ts @@ -0,0 +1,80 @@ +export interface Variable { + id: number, + name: string, + unit: string, + dataType: string, + isKeys: boolean +} + +export interface ListItem { + id: number, + text: string, + group: string, + description: string +} + +export interface UnitItem { + id: number, + text: string, + group: string, + data_types: string[] +} + +export interface VariableTemplateItem { + id: number, + text: string, + group: string, + description: string, + data_type: string, + unit: string, + data_types: string[], + units: string[], + meanings: string[], + constraints: string[] +} + +export interface Link { + label: string, + link: string, + prefix: string, + releation: string +} + +export interface Meaning { + group: string, + id: number, + constraints: string[], + links: Link[], + text: string, +} + +export interface VariableInstanceModel { + is_key: boolean, + is_optional: boolean, + display_pattern: ListItem, + possible_units: UnitItem[], + name: string, + id: number, + meanings: Meaning[], + possible_templates: VariableTemplateItem[], + possible_display_patterns: ListItem[] +} + +export interface MissingValueModel { + display_name: string, + description: string +} + +export interface DataStructureEditModel { + id: number, + title: string, + description: string, + preview: string[], + variables: VariableInstanceModel[], + missing_values: MissingValueModel[] +} + +export interface MultiSelectSourceDetailed { + value: string, + label: string +} diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/+page.svelte new file mode 100644 index 0000000000..44842aa8a3 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/+page.svelte @@ -0,0 +1,120 @@ + + + + {#await load()} + + {:then data} +

Result

+
+
+ + +
+ +

Accepted

+
+
+ + +
+ +
+ +
+ {/await} + +
+ \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/AcceptedTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/AcceptedTableOptions.svelte new file mode 100644 index 0000000000..a603bcece6 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/AcceptedTableOptions.svelte @@ -0,0 +1,30 @@ + + +
+ {#each buttons as button} + + {/each} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/ResultTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/ResultTableOptions.svelte new file mode 100644 index 0000000000..2a807fb7a7 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/ResultTableOptions.svelte @@ -0,0 +1,40 @@ + + +
+ {#each buttons as button} + + {/each} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/data.ts new file mode 100644 index 0000000000..23e718eaed --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/data.ts @@ -0,0 +1,18 @@ +import { writable } from 'svelte/store'; +import type { CLBMatchingResult } from '$lib/types/types'; + + + +let acceptedRows: CLBMatchingResult[] = [ + +] + +export let acceptedStore = writable(acceptedRows) + + + +let resultRows: CLBMatchingResult[] = [ + +] + +export let resultStore = writable(resultRows) \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/services.ts new file mode 100644 index 0000000000..b9ad4b0d9e --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/services.ts @@ -0,0 +1,12 @@ +import { Api } from '@bexis2/bexis2-core-ui'; +import type { ServiceResult } from '$lib/types/types'; + +export const loadMatchingResult = async (datasetId: number, stepId: number): Promise> => { + try { + const response = await Api.get(`/smm/species/ViewMatchingResult?datasetId=${datasetId}&stepId=${stepId}`); + + return { success: true, data: response.data }; + } catch (error: any) { + return { success: false, error: error.data?.message }; + } +}; \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/matchingresult/types.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte new file mode 100644 index 0000000000..8d04cde5a4 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte @@ -0,0 +1,162 @@ + + + +

Progress Overview

+ +

This page shows your current mapping progress for the selected Dataset with ID: {$mappingSelection.datasetId}

+ + {#if tailorError} + + {tailorErrorMessage} + + {/if} + + {#await loadProgress()} + + {:then data} + {#if !data.hasHeaderMappings} +

This dataset does not seem to be initialized. Please go back to the Datasets Overview and start from scratch.

+ {:else} +

The dataset has {data.headerMappings.mappings.length} mapped columns.

+ + {#if !data.isTailored} + {#if tailorLoading} + + {/if} +
+ +
+ {:else} + {#if !data.hasMappingProgress} +

No mapping progress data available. Something went wrong.

+ {:else} + {#if true || data.mappingProgress.steps.length == 0} +

For this dataset, no matching request have been done to external APIs. Feel free to check/edit the current state or begin matching.

+
+ + +
+ {:else} +

Your matching jobs

+ +
+
+ + + {/if} + {/if} + {/if} + {/if} + {:catch error} + + {error.message} + + {/await} + + +
+ + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/TableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/TableOptions.svelte new file mode 100644 index 0000000000..2ddbd16c41 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/TableOptions.svelte @@ -0,0 +1,31 @@ + + +
+ {#if row.done} + + {:else} + + {/if} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/data.ts new file mode 100644 index 0000000000..c319e1ac38 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/data.ts @@ -0,0 +1,9 @@ +import { writable } from 'svelte/store'; +import { get } from 'svelte/store'; +import type { StepEntry } from '$lib/types/types'; + +let matchingJobRows: StepEntry[] = [ + +] + +export let matchingJobStore = writable(matchingJobRows); \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts new file mode 100644 index 0000000000..c01bdd8403 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts @@ -0,0 +1,43 @@ +import { Api } from '@bexis2/bexis2-core-ui'; +import type { ServiceResult } from '$lib/types/types'; + +export const loadDatasetProgress = async (datasetId: number): Promise> => { + try { + const response = await Api.get(`/smm/species/ViewProgress?datasetId=${datasetId}`); + + return { success: true, data: response.data }; + } catch (error: any) { + return { success: false, error: error.data?.message }; + } +}; + +export const tailorDataset = async (datasetId: number): Promise> => { + try { + const response = await Api.post('/smm/species/tailor', { datasetId }); + + return { success: true, data: response.data }; + } catch (error: any) { + console.log(error); + return { success: false, error: error.data?.message }; + } +} + +export const genNewMatchFile = async (datasetId: number): Promise> => { + try { + const response = await Api.post('/smm/species/GenNewMatchInputFile', { datasetId }); + + return { success: true, data: response.data }; + } catch (error: any) { + return { success: false, error: error.data?.message }; + } +} + +export const matchNextFile = async (datasetId: number): Promise> => { + try { + const response = await Api.post('/smm/species/MatchNextFile', { datasetId }); + + return { success: true, data: response.data }; + } catch (error: any) { + return { success: false, error: error.data?.message }; + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts new file mode 100644 index 0000000000..a68bf98083 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts @@ -0,0 +1,11 @@ +import type { HeaderMappings, MappingProgress } from "$lib/types/types" + +export interface ProgressOverview { + success: boolean, + hasHeaderMappings: boolean, + hasMappingProgress: boolean, + isTailored: boolean, + headerMappings: HeaderMappings, + mappingProgress: MappingProgress +} + diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/AcceptedTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/AcceptedTableOptions.svelte new file mode 100644 index 0000000000..a603bcece6 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/AcceptedTableOptions.svelte @@ -0,0 +1,30 @@ + + +
+ {#each buttons as button} + + {/each} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/EditResult.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/EditResult.svelte new file mode 100644 index 0000000000..0e21582b38 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/EditResult.svelte @@ -0,0 +1,12 @@ + + +
+ + +
+ + +
+
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/ResultTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/ResultTableOptions.svelte new file mode 100644 index 0000000000..2a807fb7a7 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/ResultTableOptions.svelte @@ -0,0 +1,40 @@ + + +
+ {#each buttons as button} + + {/each} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts new file mode 100644 index 0000000000..103b11bffc --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts @@ -0,0 +1,2448 @@ +import { writable } from 'svelte/store'; + +export type ResultRow = { + inputID: string, + inputRank?: string, + inputName: string, + matchType: string, + ID: string, + rank: string, + label?: string, + scientificName: string, + authorship: string, + status: string, + acceptedName?: string, + classification?: string, + issues?: string, +} + +let acceptedRows: ResultRow[] = [ + +] + +export let acceptedStore = writable(acceptedRows) + +let emptyTestRows: ResultRow[] = [ + +] + +let resultRows: ResultRow[] = +[ + { + "inputID": "tp", + "inputRank": "", + "inputName": "", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "UNPARSABLE_NAME" + }, + { + "inputID": 1, + "inputRank": "", + "inputName": "Dupoa labradorica", + "matchType": "variant", + "ID": "f_Yu7cBp0esx2hUuQmLAr1", + "rank": "species", + "label": "× Dupoa labradorica (Steud.) J.Cay. & Darbysh.", + "scientificName": "× Dupoa labradorica", + "authorship": "(Steud.) J.Cay. & Darbysh.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:× Dupoa J.Cay. & Darbysh.|FAMILY:Poaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 2, + "inputRank": "", + "inputName": "Hedyosmum mexicanum", + "matchType": "variant", + "ID": "pEpl3JT6UK7P5tKH1KQp-0", + "rank": "species", + "label": "Hedyosmum mexicanum Cordem. ex Baill.", + "scientificName": "Hedyosmum mexicanum", + "authorship": "Cordem. ex Baill.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Hedyosmum Sw.|FAMILY:Chloranthaceae R. Br. ex Sims|ORDER:Chloranthales Mart.|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 3, + "inputRank": "", + "inputName": "Metrosideros polymorpha Gaudich.", + "matchType": "exact", + "ID": "F53jY6wV-sN79_VlpPtqY1", + "rank": "species", + "label": "Metrosideros polymorpha Gaudich.", + "scientificName": "Metrosideros polymorpha", + "authorship": "Gaudich.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Metrosideros Banks ex Gaertn.|SUBFAMILY:Myrtoideae Sweet|FAMILY:Myrtaceae Juss.|ORDER:Myrtales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 4, + "inputRank": "", + "inputName": "Terminalia sericea", + "matchType": "variant", + "ID": "RDkO9iPvGs8ABKcoPPA_R1", + "rank": "species", + "label": "Terminalia sericea Burch. ex DC.", + "scientificName": "Terminalia sericea", + "authorship": "Burch. ex DC.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Terminalia L.|SUBFAMILY:Combretoideae Beilschm.|FAMILY:Combretaceae R. Br.|ORDER:Myrtales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 5, + "inputRank": "", + "inputName": "??Artocarpus obtusus", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 6, + "inputRank": "", + "inputName": "??Dryobalanops aromatica", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 7, + "inputRank": "", + "inputName": "??Ficus sp.", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 8, + "inputRank": "", + "inputName": "??Horsfieldia palidicaura", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 9, + "inputRank": "", + "inputName": "??Madhuca carassipes", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 10, + "inputRank": "", + "inputName": "??Parishia sericea", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 11, + "inputRank": "", + "inputName": "??Shorea fallax", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": "", + "inputRank": "", + "inputName": "", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "NOT_INTERPRETED;UNPARSABLE_NAME" + }, + { + "inputID": 13, + "inputRank": "", + "inputName": "#Acacia?iteaphylla?F.Muell. ex Benth.", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 14, + "inputRank": "", + "inputName": "#Acacia?saligna?(Labill.) H.L.Wendl.", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 15, + "inputRank": "", + "inputName": "(Asteraceae2 sp.", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 16, + "inputRank": "", + "inputName": "(fabaceae)", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 17, + "inputRank": "", + "inputName": "(hippocrateaceae) atenumembra", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 18, + "inputRank": "", + "inputName": "(lauraceae) chiquita", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 19, + "inputRank": "", + "inputName": "(lauraceae) impresofalso", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 20, + "inputRank": "", + "inputName": "(lauraceae) pubescente", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 21, + "inputRank": "", + "inputName": "(malpighiaceae) bulondu", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 22, + "inputRank": "", + "inputName": "(myrtaceae) cortezapeq", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 23, + "inputRank": "", + "inputName": "(myrtaceae) smedcheilo", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 24, + "inputRank": "", + "inputName": "(picramniaceae) sp.nov.", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 25, + "inputRank": "", + "inputName": "(u_angio11492 sp", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 26, + "inputRank": "", + "inputName": "(u_angio5 sp", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 27, + "inputRank": "", + "inputName": "(u_Araceae sp11579", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 28, + "inputRank": "", + "inputName": "(u_Aster14327 sp", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 29, + "inputRank": "", + "inputName": "(u_Crasulaceae sp14326", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 30, + "inputRank": "", + "inputName": "(u_Herb2874 sp", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 31, + "inputRank": "", + "inputName": "(u_liana sp6402", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 32, + "inputRank": "", + "inputName": "(u_Malphig sp6395", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 33, + "inputRank": "", + "inputName": "(u_nanophyte sp6378", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 34, + "inputRank": "", + "inputName": "(u_Orchid3599 sp", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 35, + "inputRank": "", + "inputName": "(u_Poaceae sp1", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 36, + "inputRank": "", + "inputName": "(u_Poaceae sp2049", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 37, + "inputRank": "", + "inputName": "(u_Polypodiaceae sp6388", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 38, + "inputRank": "", + "inputName": "(u_Solana11399 sp", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 39, + "inputRank": "", + "inputName": "(u_Vitaceae sp14439", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 40, + "inputRank": "", + "inputName": "?Betulaceae sp.", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "INDETERMINED" + }, + { + "inputID": 41, + "inputRank": "", + "inputName": "?Pachygone ovata", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "PARTIALLY_PARSABLE_NAME" + }, + { + "inputID": 42, + "inputRank": "", + "inputName": "10 Tree species", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 43, + "inputRank": "", + "inputName": 1398, + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 44, + "inputRank": "", + "inputName": "5 Tall Catinga species", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 45, + "inputRank": "", + "inputName": "8 Mixed forest species", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 46, + "inputRank": "", + "inputName": "9 Tree species", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 47, + "inputRank": "", + "inputName": "Aa argyrolepis", + "matchType": "variant", + "ID": "HzruoTd7anNk90aF3DPf7", + "rank": "species", + "label": "Aa argyrolepis Rchb.f.", + "scientificName": "Aa argyrolepis", + "authorship": "Rchb.f.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 48, + "inputRank": "", + "inputName": "Aa denticulata", + "matchType": "variant", + "ID": "bzgvV2pJfO7r6WK4E4JAL0", + "rank": "species", + "label": "Aa denticulata Schltr.", + "scientificName": "Aa denticulata", + "authorship": "Schltr.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 49, + "inputRank": "", + "inputName": "Aa leucantha", + "matchType": "variant", + "ID": "GEzuA4SJNfuo78sxEfT631", + "rank": "species", + "label": "Aa leucantha (Rchb.f.) Schltr.", + "scientificName": "Aa leucantha", + "authorship": "(Rchb.f.) Schltr.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 50, + "inputRank": "", + "inputName": "Aa matthewsii", + "matchType": "variant", + "ID": "ehMUwBLNrANNDdhC1D7up2", + "rank": "species", + "label": "Aa matthewsii (Rchb.f.) Schltr.", + "scientificName": "Aa matthewsii", + "authorship": "(Rchb.f.) Schltr.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 51, + "inputRank": "", + "inputName": "Aa rosei", + "matchType": "variant", + "ID": "F5RifrVAXB9V5lOLd4bjd2", + "rank": "species", + "label": "Aa rosei Ames", + "scientificName": "Aa rosei", + "authorship": "Ames", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 52, + "inputRank": "", + "inputName": "Aa trilobulata", + "matchType": "variant", + "ID": "22ixDY1ArS9U0WmqzLBCA0", + "rank": "species", + "label": "Aa trilobulata Schltr.", + "scientificName": "Aa trilobulata", + "authorship": "Schltr.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 53, + "inputRank": "", + "inputName": "A-Agroelymus bowdenii", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 54, + "inputRank": "", + "inputName": "A-Argyrautia degeneri", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 55, + "inputRank": "", + "inputName": "Abama americana", + "matchType": "variant", + "ID": "B4INu1ljBsOhD_fMqns7-2", + "rank": "species", + "label": "Abama americana (Ker Gawl.) Morong", + "scientificName": "Abama americana", + "authorship": "(Ker Gawl.) Morong", + "status": "synonym", + "acceptedName": "Narthecium americanum Ker Gawl.", + "classification": "SPECIES:Narthecium americanum Ker Gawl.|GENUS:Narthecium Huds.|FAMILY:Nartheciaceae|ORDER:Dioscoreales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 56, + "inputRank": "", + "inputName": "Abarema adenophora", + "matchType": "variant", + "ID": "-ScsbDkWmvfN7C1Jwe3Py", + "rank": "species", + "label": "Abarema adenophora (Ducke) Barneby & J.W.Grimes", + "scientificName": "Abarema adenophora", + "authorship": "(Ducke) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba adenophora (Ducke) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba adenophora (Ducke) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 57, + "inputRank": "", + "inputName": "Abarema auriculata", + "matchType": "variant", + "ID": "j_pJUPXRWEQB8pOsMMCFh1", + "rank": "species", + "label": "Abarema auriculata (Benth.) Barneby & J.W.Grimes", + "scientificName": "Abarema auriculata", + "authorship": "(Benth.) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba auriculata (Benth.) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba auriculata (Benth.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 58, + "inputRank": "", + "inputName": "Abarema brachystachya", + "matchType": "variant", + "ID": "56wFod7HQVutBCgLusMJY", + "rank": "species", + "label": "Abarema brachystachya (DC.) Barneby & J.W.Grimes", + "scientificName": "Abarema brachystachya", + "authorship": "(DC.) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba brachystachya (DC.) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba brachystachya (DC.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 59, + "inputRank": "", + "inputName": "Abarema cochleata", + "matchType": "variant", + "ID": "DEU19AMASCQHDWipCGjDf0", + "rank": "species", + "label": "Abarema cochleata (Willd.) Barneby & J.W.Grimes", + "scientificName": "Abarema cochleata", + "authorship": "(Willd.) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba cochleata (Willd.) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba cochleata (Willd.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 60, + "inputRank": "", + "inputName": "Abarema curvicarpa", + "matchType": "variant", + "ID": "F_LVKha0vGtI5_2ZvXS4_0", + "rank": "species", + "label": "Abarema curvicarpa (H.S.Irwin) Barneby & J.W.Grimes", + "scientificName": "Abarema curvicarpa", + "authorship": "(H.S.Irwin) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba curvicarpa (H.S.Irwin) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba curvicarpa (H.S.Irwin) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 61, + "inputRank": "", + "inputName": "Abarema gallorum", + "matchType": "variant", + "ID": "HNlawyopeHQZ6_VdYz1FQ2", + "rank": "species", + "label": "Abarema gallorum Barneby & J.W.Grimes", + "scientificName": "Abarema gallorum", + "authorship": "Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba gallorum (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba gallorum (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 62, + "inputRank": "", + "inputName": "Abarema jupunba", + "matchType": "variant", + "ID": "h4jGkCtKNaf07dRMspslJ", + "rank": "species", + "label": "Abarema jupunba (Willd.) Britton & Killip", + "scientificName": "Abarema jupunba", + "authorship": "(Willd.) Britton & Killip", + "status": "synonym", + "acceptedName": "Jupunba trapezifolia var. micradenia (Benth.) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "VARIETY:Jupunba trapezifolia var. micradenia (Benth.) M.V.B.Soares, M.P.Morim & Iganci|SPECIES:Jupunba trapezifolia (Vahl) Moldenke|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 63, + "inputRank": "", + "inputName": "Abarema laeta", + "matchType": "variant", + "ID": "BUQSvsYFyh7T18v3Y_OpU0", + "rank": "species", + "label": "Abarema laeta (Benth.) Barneby & J.W.Grimes", + "scientificName": "Abarema laeta", + "authorship": "(Benth.) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba laeta (Benth.) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba laeta (Benth.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 64, + "inputRank": "", + "inputName": "Abarema leucophylla", + "matchType": "variant", + "ID": "zPm1np9pYb8oAKjanKg0h", + "rank": "species", + "label": "Abarema leucophylla (Spruce ex Benth.) Barneby & J.W.Grimes", + "scientificName": "Abarema leucophylla", + "authorship": "(Spruce ex Benth.) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba leucophylla (Spruce ex Benth.) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba leucophylla (Spruce ex Benth.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 65, + "inputRank": "", + "inputName": "Abarema macradenia", + "matchType": "variant", + "ID": "qTmopQw_cnteCpSYGTXw40", + "rank": "species", + "label": "Abarema macradenia (Pittier) Barneby & J.W.Grimes", + "scientificName": "Abarema macradenia", + "authorship": "(Pittier) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba macradenia (Pittier) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba macradenia (Pittier) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 66, + "inputRank": "", + "inputName": "Abarema maestrensis", + "matchType": "variant", + "ID": "SP3WeGqLEA92AlBsqGA-g", + "rank": "species", + "label": "Abarema maestrensis (Urb.) Bässler", + "scientificName": "Abarema maestrensis", + "authorship": "(Urb.) Bässler", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abarema Pittier|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 67, + "inputRank": "", + "inputName": "Abarema nipensis", + "matchType": "variant", + "ID": "7EKkhAW5sbtc-OQ6Z00PT0", + "rank": "species", + "label": "Abarema nipensis (Britton) Barneby & J.W.Grimes", + "scientificName": "Abarema nipensis", + "authorship": "(Britton) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba nipensis (Britton) Britton & Rose", + "classification": "SPECIES:Jupunba nipensis (Britton) Britton & Rose|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 68, + "inputRank": "", + "inputName": "Abarema oxyphyllidia", + "matchType": "variant", + "ID": "wWTSsVwmR0AP0_11w-vDz0", + "rank": "species", + "label": "Abarema oxyphyllidia Barneby & J.W.Grimes", + "scientificName": "Abarema oxyphyllidia", + "authorship": "Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba oxyphyllidia (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba oxyphyllidia (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 69, + "inputRank": "", + "inputName": "Abarema villifera", + "matchType": "variant", + "ID": "bdDLMxPIub7u8K9cLUytN0", + "rank": "species", + "label": "Abarema villifera (Ducke) Barneby & J.W.Grimes", + "scientificName": "Abarema villifera", + "authorship": "(Ducke) Barneby & J.W.Grimes", + "status": "synonym", + "acceptedName": "Jupunba villifera (Ducke) M.V.B.Soares, M.P.Morim & Iganci", + "classification": "SPECIES:Jupunba villifera (Ducke) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 70, + "inputRank": "", + "inputName": "Abatia americana", + "matchType": "variant", + "ID": "Hgsps3snnYQb9hepgL4yq1", + "rank": "species", + "label": "Abatia americana (Gardner) Eichler", + "scientificName": "Abatia americana", + "authorship": "(Gardner) Eichler", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abatia Ruiz & Pav.|FAMILY:Salicaceae Mirb.|ORDER:Malpighiales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 71, + "inputRank": "", + "inputName": "Abatia glabra", + "matchType": "variant", + "ID": "uDG3lo3mOHdUCpOk5v2U1", + "rank": "species", + "label": "Abatia glabra Sleumer", + "scientificName": "Abatia glabra", + "authorship": "Sleumer", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abatia Ruiz & Pav.|FAMILY:Salicaceae Mirb.|ORDER:Malpighiales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 72, + "inputRank": "", + "inputName": "Abatia rugosa", + "matchType": "variant", + "ID": "8_UtE2oZA0v7C4APQch8B1", + "rank": "species", + "label": "Abatia rugosa Ruiz & Pav.", + "scientificName": "Abatia rugosa", + "authorship": "Ruiz & Pav.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abatia Ruiz & Pav.|FAMILY:Salicaceae Mirb.|ORDER:Malpighiales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 73, + "inputRank": "", + "inputName": "Abelia", + "matchType": "variant", + "ID": "DIAOdF0VHucc90hs_fkUI0", + "rank": "genus", + "label": "Abelia R. Br.", + "scientificName": "Abelia", + "authorship": "R. Br.", + "status": "accepted", + "acceptedName": "", + "classification": "SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 74, + "inputRank": "", + "inputName": "Abelia chinensis", + "matchType": "variant", + "ID": "K0FvBPBmtpcBCxk1ote9A0", + "rank": "species", + "label": "Abelia chinensis R. Br.", + "scientificName": "Abelia chinensis", + "authorship": "R. Br.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 75, + "inputRank": "", + "inputName": "Abelia engleriana", + "matchType": "variant", + "ID": "r4vqKWgz48cFBpH8k2jmq1", + "rank": "species", + "label": "Abelia engleriana (Graebn.) Rehder", + "scientificName": "Abelia engleriana", + "authorship": "(Graebn.) Rehder", + "status": "synonym", + "acceptedName": "Abelia macrotera var. engleriana (Graebn.) Landrein", + "classification": "VARIETY:Abelia macrotera var. engleriana (Graebn.) Landrein|SPECIES:Abelia macrotera (Graebn. & Buchw.) Rehder|GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 76, + "inputRank": "", + "inputName": "Abelia macrotera (Graebn. Et Buchw.) Rehd.", + "matchType": "variant", + "ID": "SCvL400UMudfDpgDV9EbU0", + "rank": "species", + "label": "Abelia macrotera (Graebn. & Buchw.) Rehder", + "scientificName": "Abelia macrotera", + "authorship": "(Graebn. & Buchw.) Rehder", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 77, + "inputRank": "", + "inputName": "Abelia sp", + "matchType": "variant", + "ID": "DIAOdF0VHucc90hs_fkUI0", + "rank": "genus", + "label": "Abelia R. Br.", + "scientificName": "Abelia", + "authorship": "R. Br.", + "status": "accepted", + "acceptedName": "", + "classification": "SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "INDETERMINED" + }, + { + "inputID": 78, + "inputRank": "", + "inputName": "Abelia uniflora", + "matchType": "variant", + "ID": "4tTnTY3mlF920GHk2pFR-1", + "rank": "species", + "label": "Abelia uniflora R. Br.", + "scientificName": "Abelia uniflora", + "authorship": "R. Br.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 79, + "inputRank": "", + "inputName": "Abelia_xgrandiflora", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 80, + "inputRank": "", + "inputName": "Abelmoschus", + "matchType": "variant", + "ID": "I1im3Xq0jTf24xzW-GDKr2", + "rank": "genus", + "label": "Abelmoschus Medik.", + "scientificName": "Abelmoschus", + "authorship": "Medik.", + "status": "accepted", + "acceptedName": "", + "classification": "SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 81, + "inputRank": "", + "inputName": "Abelmoschus esculentus", + "matchType": "variant", + "ID": "joaWuR8_2GAe9_JLZgiLH2", + "rank": "species", + "label": "Abelmoschus esculentus (L.) Moench", + "scientificName": "Abelmoschus esculentus", + "authorship": "(L.) Moench", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abelmoschus Medik.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 82, + "inputRank": "", + "inputName": "Abelmoschus ficulneus (L.) Wight & Arn.", + "matchType": "variant", + "ID": "cQRVMr08yX7eACzSq_li_1", + "rank": "species", + "label": "Abelmoschus ficulneus (L.) Wight & Arn. ex Wight", + "scientificName": "Abelmoschus ficulneus", + "authorship": "(L.) Wight & Arn. ex Wight", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abelmoschus Medik.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 83, + "inputRank": "", + "inputName": "Abelmoschus moschatus", + "matchType": "variant", + "ID": "kW_mJEewg-dN98FKWg1lC2", + "rank": "species", + "label": "Abelmoschus moschatus (L.) Medik.", + "scientificName": "Abelmoschus moschatus", + "authorship": "(L.) Medik.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abelmoschus Medik.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 84, + "inputRank": "", + "inputName": "Abelmoshus esculentus (L.) Moench", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 85, + "inputRank": "", + "inputName": "Abies faxoniana", + "matchType": "variant", + "ID": "ZYxIqzF2_kPA7lDlet4Sw2", + "rank": "species", + "label": "Abies faxoniana Rehder & E.H.Wilson", + "scientificName": "Abies faxoniana", + "authorship": "Rehder & E.H.Wilson", + "status": "synonym", + "acceptedName": "Abies fargesii var. faxoniana (Rehder & E.H.Wilson) Tang S.Liu", + "classification": "VARIETY:Abies fargesii var. faxoniana (Rehder & E.H.Wilson) Tang S.Liu|SPECIES:Abies fargesii Franch.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 86, + "inputRank": "", + "inputName": "Abies ?shastensis (Lemmon) Lemmon [magnifica ? procera]", + "matchType": "variant", + "ID": "oJcwu0yVYcvx58sykTyha1", + "rank": "genus", + "label": "Abies Mill.", + "scientificName": "Abies", + "authorship": "Mill.", + "status": "accepted", + "acceptedName": "", + "classification": "FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "PARTIALLY_PARSABLE_NAME" + }, + { + "inputID": 87, + "inputRank": "", + "inputName": "Abies amabilis (Douglas ex Louden) Douglas ex Forbes", + "matchType": "variant", + "ID": "OF3ByWuRequZ28R-PwNya0", + "rank": "species", + "label": "Abies amabilis (Douglas ex Loudon) J.Forbes", + "scientificName": "Abies amabilis", + "authorship": "(Douglas ex Loudon) J.Forbes", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 88, + "inputRank": "", + "inputName": "Abies balsamea (L.) Mill. var. balsamea", + "matchType": "variant", + "ID": "2NOu3wWzmdQI3SwP5se0O0", + "rank": "form", + "label": "Abies balsamea f. balsamea", + "scientificName": "Abies balsamea f. balsamea", + "authorship": "", + "status": "synonym", + "acceptedName": "Abies balsamea (L.) Mill.", + "classification": "SPECIES:Abies balsamea (L.) Mill.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 89, + "inputRank": "", + "inputName": "Abies beshanzuensis", + "matchType": "variant", + "ID": "-GjhCunoKTNJAGjLYAvvE0", + "rank": "species", + "label": "Abies beshanzuensis M.H.Wu", + "scientificName": "Abies beshanzuensis", + "authorship": "M.H.Wu", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 90, + "inputRank": "", + "inputName": "Abies bornmuelleriana", + "matchType": "variant", + "ID": "Tt8WiVVFdGdl8lAbUI5Ic", + "rank": "species", + "label": "Abies bornmuelleriana Mattf.", + "scientificName": "Abies bornmuelleriana", + "authorship": "Mattf.", + "status": "synonym", + "acceptedName": "Abies nordmanniana subsp. equi-trojani (Asch. & Sint. ex Boiss.) Coode & Cullen", + "classification": "SUBSPECIES:Abies nordmanniana subsp. equi-trojani (Asch. & Sint. ex Boiss.) Coode & Cullen|SPECIES:Abies nordmanniana (Steven) Spach|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 91, + "inputRank": "", + "inputName": "Abies cephalonica J. W. Loudon", + "matchType": "variant", + "ID": "-uqeYbsE1Qvk-pcGiAf4G0", + "rank": "species", + "label": "Abies cephalonica Loudon", + "scientificName": "Abies cephalonica", + "authorship": "Loudon", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 92, + "inputRank": "", + "inputName": "Abies chensiensis", + "matchType": "variant", + "ID": "g04zL4-W_mAz3WpxInZ-R2", + "rank": "species", + "label": "Abies chensiensis Tiegh.", + "scientificName": "Abies chensiensis", + "authorship": "Tiegh.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 93, + "inputRank": "", + "inputName": "Abies cilicica (Antoine & Kotschy) Carriere ssp. isaurica Coode & Cullen", + "matchType": "variant", + "ID": "_LbUU7XXarej2OZLEWyC21", + "rank": "subspecies", + "label": "Abies cilicica subsp. isaurica Coode & Cullen", + "scientificName": "Abies cilicica subsp. isaurica", + "authorship": "Coode & Cullen", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abies cilicica (Antoine & Kotschy) Carrière|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 94, + "inputRank": "", + "inputName": "Abies concolor (Gordon & Glend.) Lindl. ex Hildebr.", + "matchType": "variant", + "ID": "yNGZP9I-z2A3CSDwtcQi-0", + "rank": "species", + "label": "Abies concolor (Gordon) Lindl. ex Hildebr.", + "scientificName": "Abies concolor", + "authorship": "(Gordon) Lindl. ex Hildebr.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 95, + "inputRank": "", + "inputName": "Abies concolor ssp. concolor", + "matchType": "variant", + "ID": "Nv6kf5Sr-Afe6CeHm2-LC0", + "rank": "variety", + "label": "Abies concolor var. concolor", + "scientificName": "Abies concolor var. concolor", + "authorship": "", + "status": "synonym", + "acceptedName": "Abies concolor (Gordon) Lindl. ex Hildebr.", + "classification": "SPECIES:Abies concolor (Gordon) Lindl. ex Hildebr.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 96, + "inputRank": "", + "inputName": "Abies delavayi Franch.", + "matchType": "exact", + "ID": "L8Q6ZpzWzddW70ySlPf6n2", + "rank": "species", + "label": "Abies delavayi Franch.", + "scientificName": "Abies delavayi", + "authorship": "Franch.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 97, + "inputRank": "", + "inputName": "Abies ernestii", + "matchType": "variant", + "ID": "qmjZpKXlpssdDC89W2fZX1", + "rank": "species", + "label": "Abies ernestii Rehder", + "scientificName": "Abies ernestii", + "authorship": "Rehder", + "status": "synonym", + "acceptedName": "Abies recurvata var. ernestii (Rehder) Rushforth", + "classification": "VARIETY:Abies recurvata var. ernestii (Rehder) Rushforth|SPECIES:Abies recurvata Mast.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 98, + "inputRank": "", + "inputName": "Abies fabri (Mast.) Craib", + "matchType": "exact", + "ID": "BC0a4W_TTbuv60xh_2IWL0", + "rank": "species", + "label": "Abies fabri (Mast.) Craib", + "scientificName": "Abies fabri", + "authorship": "(Mast.) Craib", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 99, + "inputRank": "", + "inputName": "Abies ferreana", + "matchType": "variant", + "ID": "U6Yw67urVY8O8pTd8e0Ox1", + "rank": "species", + "label": "Abies ferreana Bordères & Gaussen", + "scientificName": "Abies ferreana", + "authorship": "Bordères & Gaussen", + "status": "synonym", + "acceptedName": "Abies forrestii var. ferreana (Bordères & Gaussen) Farjon & Silba", + "classification": "VARIETY:Abies forrestii var. ferreana (Bordères & Gaussen) Farjon & Silba|SPECIES:Abies forrestii Coltm.-Rog.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 100, + "inputRank": "", + "inputName": "Abies flinckii", + "matchType": "variant", + "ID": "RcrbjMDUoFAa94ScIqglG1", + "rank": "species", + "label": "Abies flinckii Rushforth", + "scientificName": "Abies flinckii", + "authorship": "Rushforth", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 101, + "inputRank": "", + "inputName": "Abies fraseri", + "matchType": "variant", + "ID": "m_0u2Lx-z-v50GhESoZk10", + "rank": "species", + "label": "Abies fraseri (Pursh) Poir.", + "scientificName": "Abies fraseri", + "authorship": "(Pursh) Poir.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 102, + "inputRank": "", + "inputName": "Abies grandis", + "matchType": "variant", + "ID": "kp8OG_WDXxPDBKB_PR0UD0", + "rank": "species", + "label": "Abies grandis (Douglas ex D.Don) Lindl.", + "scientificName": "Abies grandis", + "authorship": "(Douglas ex D.Don) Lindl.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 103, + "inputRank": "", + "inputName": "Abies guatemalensis", + "matchType": "variant", + "ID": "njcsPsDMRkQrEW4MBprq50", + "rank": "species", + "label": "Abies guatemalensis Rehder", + "scientificName": "Abies guatemalensis", + "authorship": "Rehder", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 104, + "inputRank": "", + "inputName": "Abies homolepis", + "matchType": "variant", + "ID": "f8CeNU0xx2Ae5Sp13tcfB2", + "rank": "species", + "label": "Abies homolepis Siebold & Zucc.", + "scientificName": "Abies homolepis", + "authorship": "Siebold & Zucc.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 105, + "inputRank": "", + "inputName": "Abies jaliscana", + "matchType": "variant", + "ID": "UfZnPJ41RQOcD42UufUA70", + "rank": "species", + "label": "Abies jaliscana (Martínez) Mantilla, Shalisko & A.Vázquez", + "scientificName": "Abies jaliscana", + "authorship": "(Martínez) Mantilla, Shalisko & A.Vázquez", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 106, + "inputRank": "", + "inputName": "Abies koreana E.H.Wilson", + "matchType": "exact", + "ID": "pyftbIMhNvQ878jgWcwsI2", + "rank": "species", + "label": "Abies koreana E.H.Wilson", + "scientificName": "Abies koreana", + "authorship": "E.H.Wilson", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 107, + "inputRank": "", + "inputName": "Abies lasiocarpa var. arizonica", + "matchType": "variant", + "ID": "xyVqGYp553AbDx2shAlun2", + "rank": "variety", + "label": "Abies lasiocarpa var. arizonica (Merriam) Lemmon", + "scientificName": "Abies lasiocarpa var. arizonica", + "authorship": "(Merriam) Lemmon", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abies lasiocarpa (Hook.) Nutt.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 108, + "inputRank": "", + "inputName": "Abies magnifica A. Murray", + "matchType": "variant", + "ID": "WkMAPkQs1sAj6xL2_fzbj2", + "rank": "species", + "label": "Abies magnifica A.Murray bis", + "scientificName": "Abies magnifica", + "authorship": "A.Murray bis", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 109, + "inputRank": "", + "inputName": "Abies magnifica A.Murray var. shastensis Lemmon", + "matchType": "variant", + "ID": "Let5Vm5GKVvIC8lxVrxrE", + "rank": "variety", + "label": "Abies magnifica var. shastensis Lemmon", + "scientificName": "Abies magnifica var. shastensis", + "authorship": "Lemmon", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abies magnifica A.Murray bis|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 110, + "inputRank": "", + "inputName": "Abies marocana", + "matchType": "variant", + "ID": "9mYR7vFU1K9Q5lFqYt70F0", + "rank": "species", + "label": "Abies marocana Trab.", + "scientificName": "Abies marocana", + "authorship": "Trab.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 111, + "inputRank": "", + "inputName": "Abies nephrolepis (Trautv.) Maxim", + "matchType": "variant", + "ID": "enOHXselt97780TytM5Cv2", + "rank": "species", + "label": "Abies nephrolepis (Trautv. ex Maxim.) Maxim.", + "scientificName": "Abies nephrolepis", + "authorship": "(Trautv. ex Maxim.) Maxim.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 112, + "inputRank": "", + "inputName": "Abies nordmanniana (Steven) Spach subsp. nordmanniana", + "matchType": "variant", + "ID": "QsRvNnkQnFd55KaVoIw_Z1", + "rank": "subspecies", + "label": "Abies nordmanniana subsp. nordmanniana", + "scientificName": "Abies nordmanniana subsp. nordmanniana", + "authorship": "", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abies nordmanniana (Steven) Spach|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 113, + "inputRank": "", + "inputName": "Abies numidica", + "matchType": "variant", + "ID": "oDRpyaZCENOs14CZ4Wfrl1", + "rank": "species", + "label": "Abies numidica de Lannoy ex Carrière", + "scientificName": "Abies numidica", + "authorship": "de Lannoy ex Carrière", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 114, + "inputRank": "", + "inputName": "Abies phanerolepis", + "matchType": "variant", + "ID": "kMqBLdDvjZeY0WtjPYYAB1", + "rank": "species", + "label": "Abies phanerolepis (Fernald) T.S.Liu", + "scientificName": "Abies phanerolepis", + "authorship": "(Fernald) T.S.Liu", + "status": "synonym", + "acceptedName": "Abies balsamea var. phanerolepis Fernald", + "classification": "VARIETY:Abies balsamea var. phanerolepis Fernald|SPECIES:Abies balsamea (L.) Mill.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 115, + "inputRank": "", + "inputName": "Abies pinsapo Boiss. var. glauca", + "matchType": "variant", + "ID": "eg3kETuVI7sH5OxlnHTTw1", + "rank": "form", + "label": "Abies pinsapo f. glauca (Carrière) Beissn.", + "scientificName": "Abies pinsapo f. glauca", + "authorship": "(Carrière) Beissn.", + "status": "synonym", + "acceptedName": "Abies pinsapo Boiss.", + "classification": "SPECIES:Abies pinsapo Boiss.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 116, + "inputRank": "", + "inputName": "Abies recurvata", + "matchType": "variant", + "ID": "g87NAFKLrpO-9pfZbgvWg1", + "rank": "species", + "label": "Abies recurvata Mast.", + "scientificName": "Abies recurvata", + "authorship": "Mast.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 117, + "inputRank": "", + "inputName": "Abies religiosa (Kunth) Schltdl. & Cham. var. emarginata", + "matchType": "variant", + "ID": "fXYOEmIBYQt83_9Z9LkKa", + "rank": "variety", + "label": "Abies religiosa var. emarginata Loock & Martínez ex Martínez", + "scientificName": "Abies religiosa var. emarginata", + "authorship": "Loock & Martínez ex Martínez", + "status": "synonym", + "acceptedName": "Abies jaliscana (Martínez) Mantilla, Shalisko & A.Vázquez", + "classification": "SPECIES:Abies jaliscana (Martínez) Mantilla, Shalisko & A.Vázquez|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 118, + "inputRank": "", + "inputName": "Abies sachalinensis (F.Schmidt) Mast. var. mayriana Miyabe & Kud?", + "matchType": "variant", + "ID": "_giKXaYvRXQK7tWDcPFlD", + "rank": "variety", + "label": "Abies sachalinensis var. mayriana Miyabe & Kudô", + "scientificName": "Abies sachalinensis var. mayriana", + "authorship": "Miyabe & Kudô", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abies sachalinensis (F.Schmidt) Mast.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "UNUSUAL_NAME_CHARACTERS;DOUBTFUL_NAME;PARTIALLY_PARSABLE_NAME" + }, + { + "inputID": 119, + "inputRank": "", + "inputName": "Abies shastensis", + "matchType": "variant", + "ID": "Ly1NqfaWLnNIAKCLScDR8", + "rank": "species", + "label": "Abies shastensis Lemmon", + "scientificName": "Abies shastensis", + "authorship": "Lemmon", + "status": "synonym", + "acceptedName": "Abies magnifica var. shastensis Lemmon", + "classification": "VARIETY:Abies magnifica var. shastensis Lemmon|SPECIES:Abies magnifica A.Murray bis|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 120, + "inputRank": "", + "inputName": "Abies sp", + "matchType": "variant", + "ID": "oJcwu0yVYcvx58sykTyha1", + "rank": "genus", + "label": "Abies Mill.", + "scientificName": "Abies", + "authorship": "Mill.", + "status": "accepted", + "acceptedName": "", + "classification": "FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "INDETERMINED" + }, + { + "inputID": 121, + "inputRank": "", + "inputName": "Abies spectabilis (D. Don) Spach", + "matchType": "exact", + "ID": "ToHQ5fFUpXAq2_OqLumUq0", + "rank": "species", + "label": "Abies spectabilis (D.Don) Spach", + "scientificName": "Abies spectabilis", + "authorship": "(D.Don) Spach", + "status": "synonym", + "acceptedName": "Abies spectabilis (D.Don) Mirb.", + "classification": "SPECIES:Abies spectabilis (D.Don) Mirb.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 122, + "inputRank": "", + "inputName": "Abies veitchii", + "matchType": "variant", + "ID": "keI9YqXVQSsZ90B2ySIwT1", + "rank": "species", + "label": "Abies veitchii Lindl.", + "scientificName": "Abies veitchii", + "authorship": "Lindl.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 123, + "inputRank": "", + "inputName": "Abies vejarii Mart?nez", + "matchType": "variant", + "ID": "WMLE2QBuP7fp4_6OnR0LF2", + "rank": "species", + "label": "Abies vejarii Martínez", + "scientificName": "Abies vejarii", + "authorship": "Martínez", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "UNUSUAL_NAME_CHARACTERS;DOUBTFUL_NAME;PARTIALLY_PARSABLE_NAME" + }, + { + "inputID": 124, + "inputRank": "", + "inputName": "Abies ziyuanensis", + "matchType": "variant", + "ID": "PjaHyLQMU6A9ExGIRygww2", + "rank": "species", + "label": "Abies ziyuanensis L.K.Fu & S.L.Mo", + "scientificName": "Abies ziyuanensis", + "authorship": "L.K.Fu & S.L.Mo", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 125, + "inputRank": "", + "inputName": "Abies?spectabilis?(D.?Don)?Mirbel", + "matchType": "variant", + "ID": "oJcwu0yVYcvx58sykTyha1", + "rank": "genus", + "label": "Abies Mill.", + "scientificName": "Abies", + "authorship": "Mill.", + "status": "accepted", + "acceptedName": "", + "classification": "FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "UNUSUAL_NAME_CHARACTERS;DOUBTFUL_NAME;PARTIALLY_PARSABLE_NAME" + }, + { + "inputID": 126, + "inputRank": "", + "inputName": "Abies_religiosa_AJU", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 127, + "inputRank": "", + "inputName": "Abildgaardia abortiva (Steud.) Lye", + "matchType": "exact", + "ID": "zSbfadWi0dcmEWKGsHW8e0", + "rank": "species", + "label": "Abildgaardia abortiva (Steud.) Lye", + "scientificName": "Abildgaardia abortiva", + "authorship": "(Steud.) Lye", + "status": "synonym", + "acceptedName": "Bulbostylis abortiva (Steud.) C.B.Clarke", + "classification": "SPECIES:Bulbostylis abortiva (Steud.) C.B.Clarke|GENUS:Bulbostylis Kunth|FAMILY:Cyperaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 128, + "inputRank": "", + "inputName": "Abildgaardia coleotricha", + "matchType": "variant", + "ID": "xyG2XpX7eq9C00Yy9GRf12", + "rank": "species", + "label": "Abildgaardia coleotricha (Hochst. ex A.Rich.) Lye", + "scientificName": "Abildgaardia coleotricha", + "authorship": "(Hochst. ex A.Rich.) Lye", + "status": "synonym", + "acceptedName": "Bulbostylis coleotricha (Hochst. ex A.Rich.) C.B.Clarke", + "classification": "SPECIES:Bulbostylis coleotricha (Hochst. ex A.Rich.) C.B.Clarke|GENUS:Bulbostylis Kunth|FAMILY:Cyperaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 129, + "inputRank": "", + "inputName": "Abildgaardia natalensis", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 130, + "inputRank": "", + "inputName": "Abildgaardia polygama", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 131, + "inputRank": "", + "inputName": "Abiu caramuri", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 132, + "inputRank": "", + "inputName": "ABIURANA", + "matchType": "none", + "ID": "", + "rank": "", + "label": "", + "scientificName": "", + "authorship": "", + "status": "", + "acceptedName": "", + "classification": "", + "issues": "" + }, + { + "inputID": 133, + "inputRank": "", + "inputName": "Abolboda americana", + "matchType": "variant", + "ID": "VvrYN3NRe0968xYIeKZNx2", + "rank": "species", + "label": "Abolboda americana (Aubl.) Lanj.", + "scientificName": "Abolboda americana", + "authorship": "(Aubl.) Lanj.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 134, + "inputRank": "", + "inputName": "Abolboda egleri", + "matchType": "variant", + "ID": "9nZ3AIx2yPugAh8NVQ3R61", + "rank": "species", + "label": "Abolboda egleri L.B.Sm. & Downs", + "scientificName": "Abolboda egleri", + "authorship": "L.B.Sm. & Downs", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 135, + "inputRank": "", + "inputName": "Abolboda linearifolia", + "matchType": "variant", + "ID": "Ob8SRpTDeAA67S235ddqU", + "rank": "species", + "label": "Abolboda linearifolia Maguire", + "scientificName": "Abolboda linearifolia", + "authorship": "Maguire", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 136, + "inputRank": "", + "inputName": "Abolboda poarchon Seub.", + "matchType": "exact", + "ID": "9OPu2_VR9k9F6pp5N-Jbb", + "rank": "species", + "label": "Abolboda poarchon Seub.", + "scientificName": "Abolboda poarchon", + "authorship": "Seub.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 137, + "inputRank": "", + "inputName": "Abortopetalum sandwicense", + "matchType": "variant", + "ID": "FDJwMSbun3766Guys9Pdp", + "rank": "species", + "label": "Abortopetalum sandwicense O. Deg.", + "scientificName": "Abortopetalum sandwicense", + "authorship": "O. Deg.", + "status": "synonym", + "acceptedName": "Abutilon sandwicense (O. Deg.) Christoph.", + "classification": "SPECIES:Abutilon sandwicense (O. Deg.) Christoph.|GENUS:Abutilon Tourn. ex Mill.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 138, + "inputRank": "", + "inputName": "Abrahamia grandidieri", + "matchType": "variant", + "ID": "2m8MPsZBToNl6hX_SW5bE1", + "rank": "species", + "label": "Abrahamia grandidieri (Engl.) Randrian. & Lowry", + "scientificName": "Abrahamia grandidieri", + "authorship": "(Engl.) Randrian. & Lowry", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrahamia Randrian. & Lowry|FAMILY:Anacardiaceae R. Br.|ORDER:Sapindales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 139, + "inputRank": "", + "inputName": "Abrahamia louvelii", + "matchType": "variant", + "ID": "KrgiAF_9X7ez8KuHpodHA2", + "rank": "species", + "label": "Abrahamia louvelii (H. Perrier) Randrian. & Lowry", + "scientificName": "Abrahamia louvelii", + "authorship": "(H. Perrier) Randrian. & Lowry", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrahamia Randrian. & Lowry|FAMILY:Anacardiaceae R. Br.|ORDER:Sapindales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 140, + "inputRank": "", + "inputName": "Abrahamia thouvenotii", + "matchType": "variant", + "ID": "_VyZ4wqBqKeY74n79ac9_2", + "rank": "species", + "label": "Abrahamia thouvenotii (Lecomte) Randrian. & Lowry", + "scientificName": "Abrahamia thouvenotii", + "authorship": "(Lecomte) Randrian. & Lowry", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrahamia Randrian. & Lowry|FAMILY:Anacardiaceae R. Br.|ORDER:Sapindales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 141, + "inputRank": "", + "inputName": "Abrodictyum cupressoides", + "matchType": "variant", + "ID": "2uLocATlEIdJ4dS1ThcDC1", + "rank": "species", + "label": "Abrodictyum cupressoides (Desv.) Ebihara & Dubuisson", + "scientificName": "Abrodictyum cupressoides", + "authorship": "(Desv.) Ebihara & Dubuisson", + "status": "synonym", + "acceptedName": "Trichomanes cupressoides Desv.", + "classification": "SPECIES:Trichomanes cupressoides Desv.|GENUS:Trichomanes L.|SUBFAMILY:Trichomanoideae C.Presl|FAMILY:Hymenophyllaceae Mart.|ORDER:Hymenophyllales A.B.Frank|CLASS:Polypodiopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 142, + "inputRank": "", + "inputName": "Abroma augusta", + "matchType": "variant", + "ID": "lMc-Zdw-gIto-dDmeMCaO0", + "rank": "species", + "label": "Abroma augustum (L.) L. fil.", + "scientificName": "Abroma augustum", + "authorship": "(L.) L. fil.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abroma L.f.|SUBFAMILY:Byttnerioideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 143, + "inputRank": "", + "inputName": "Abronia × minor", + "matchType": "variant", + "ID": "762P_d5oVKfv8_oq7jYph1", + "rank": "species", + "label": "Abronia × minor Standl.", + "scientificName": "Abronia × minor", + "authorship": "Standl.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 144, + "inputRank": "", + "inputName": "Abronia ameliae Lundell", + "matchType": "exact", + "ID": "tykvIegyhesA5O0ncvpL30", + "rank": "species", + "label": "Abronia ameliae Lundell", + "scientificName": "Abronia ameliae", + "authorship": "Lundell", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 145, + "inputRank": "", + "inputName": "Abronia bolackii", + "matchType": "variant", + "ID": "jq-KePU8-hOI6OXJqSDs4", + "rank": "species", + "label": "Abronia bolackii N. D. Atwood, S. L. Welsh & K. D. Heil", + "scientificName": "Abronia bolackii", + "authorship": "N. D. Atwood, S. L. Welsh & K. D. Heil", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 146, + "inputRank": "", + "inputName": "Abronia cycloptera", + "matchType": "variant", + "ID": "IdGsSwfyflt024_au9KOk1", + "rank": "species", + "label": "Abronia cycloptera A. Gray", + "scientificName": "Abronia cycloptera", + "authorship": "A. Gray", + "status": "synonym", + "acceptedName": "Tripterocalyx micranthus (Torr.) Hook.", + "classification": "SPECIES:Tripterocalyx micranthus (Torr.) Hook.|GENUS:Tripterocalyx (Torr.) Hook.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 147, + "inputRank": "", + "inputName": "Abronia fragrans Nutt. ex Hook.", + "matchType": "exact", + "ID": "0GEGBaiJkRc16l720FRyS", + "rank": "species", + "label": "Abronia fragrans Nutt. ex Hook.", + "scientificName": "Abronia fragrans", + "authorship": "Nutt. ex Hook.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 148, + "inputRank": "", + "inputName": "Abronia latifolia", + "matchType": "variant", + "ID": "rX0iWcCIN17138qMk2Wq7", + "rank": "species", + "label": "Abronia latifolia Eschsch.", + "scientificName": "Abronia latifolia", + "authorship": "Eschsch.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 149, + "inputRank": "", + "inputName": "Abronia mellifera", + "matchType": "variant", + "ID": "qJ9pJE_8yXtT5tMzs74Px1", + "rank": "species", + "label": "Abronia mellifera Douglas", + "scientificName": "Abronia mellifera", + "authorship": "Douglas", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 150, + "inputRank": "", + "inputName": "Abronia nana S.Watson", + "matchType": "exact", + "ID": "ASZ6E_LzGosc5py2UQqLL1", + "rank": "species", + "label": "Abronia nana S. Watson", + "scientificName": "Abronia nana", + "authorship": "S. Watson", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 151, + "inputRank": "", + "inputName": "Abronia orbiculata", + "matchType": "variant", + "ID": "vEtredQykwPZ2WKvJxogS2", + "rank": "species", + "label": "Abronia orbiculata Standl.", + "scientificName": "Abronia orbiculata", + "authorship": "Standl.", + "status": "synonym", + "acceptedName": "Abronia turbinata Torr. ex S. Watson", + "classification": "SPECIES:Abronia turbinata Torr. ex S. Watson|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 152, + "inputRank": "", + "inputName": "Abronia pumila", + "matchType": "variant", + "ID": "Yb1TdisQtwdp7G7zgJuBP", + "rank": "species", + "label": "Abronia pumila Rydb.", + "scientificName": "Abronia pumila", + "authorship": "Rydb.", + "status": "synonym", + "acceptedName": "Abronia elliptica A. Nelson", + "classification": "SPECIES:Abronia elliptica A. Nelson|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 153, + "inputRank": "", + "inputName": "Abronia turbinata Torr. ex S. Watson", + "matchType": "exact", + "ID": "dIKAHs7-6DPPE_KkIN5-L", + "rank": "species", + "label": "Abronia turbinata Torr. ex S. Watson", + "scientificName": "Abronia turbinata", + "authorship": "Torr. ex S. Watson", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 154, + "inputRank": "", + "inputName": "Abronia umbellata ssp. breviflora", + "matchType": "variant", + "ID": "SCk01wqXLbup4WVdyTlqO", + "rank": "variety", + "label": "Abronia umbellata var. breviflora (Standl.) L. A. Galloway", + "scientificName": "Abronia umbellata var. breviflora", + "authorship": "(Standl.) L. A. Galloway", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abronia umbellata Lam.|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 155, + "inputRank": "", + "inputName": "Abronia villosa S.Watson", + "matchType": "exact", + "ID": "P0QGPsChR_eu5hOWJ-6D1", + "rank": "species", + "label": "Abronia villosa S. Watson", + "scientificName": "Abronia villosa", + "authorship": "S. Watson", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 156, + "inputRank": "", + "inputName": "Abronia villosa subsp. aurita Orthodox?", + "matchType": "variant", + "ID": "JQwBqywAWi9w3WRaR2WCx0", + "rank": "variety", + "label": "Abronia villosa var. aurita (Abrams) Jeps.", + "scientificName": "Abronia villosa var. aurita", + "authorship": "(Abrams) Jeps.", + "status": "accepted", + "acceptedName": "", + "classification": "SPECIES:Abronia villosa S. Watson|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "QUESTION_MARKS_REMOVED;DOUBTFUL_NAME" + }, + { + "inputID": 157, + "inputRank": "", + "inputName": "Abrophyllum ornans (F.Muell.) Hook.f.", + "matchType": "variant", + "ID": "vrnEX1vIZwt86dygNMuHG", + "rank": "species", + "label": "Abrophyllum ornans (F. Muell.) Benth.", + "scientificName": "Abrophyllum ornans", + "authorship": "(F. Muell.) Benth.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrophyllum Hook.f.|SUBFAMILY:Carpodetoideae J. Lundb.|FAMILY:Rousseaceae DC.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 158, + "inputRank": "", + "inputName": "Abrotanella emarginata (Gaudich.) Cass.", + "matchType": "variant", + "ID": "Goz_DoK_kAQpD8ZuwUcK12", + "rank": "species", + "label": "Abrotanella emarginata (Cass. ex Gaudich.) Cass.", + "scientificName": "Abrotanella emarginata", + "authorship": "(Cass. ex Gaudich.) Cass.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrotanella Cass.|SUBFAMILY:Asteroideae (Cass.) Lindl.|FAMILY:Asteraceae Dumort.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 159, + "inputRank": "", + "inputName": "Abrotanella linearis", + "matchType": "variant", + "ID": "SemiWOk5nocC1xDUOU_lb2", + "rank": "species", + "label": "Abrotanella linearis Berggr.", + "scientificName": "Abrotanella linearis", + "authorship": "Berggr.", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrotanella Cass.|SUBFAMILY:Asteroideae (Cass.) Lindl.|FAMILY:Asteraceae Dumort.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + }, + { + "inputID": 160, + "inputRank": "", + "inputName": "Abrotanella submarginata", + "matchType": "variant", + "ID": "HS_w6YtYms8h5_byMzMpe0", + "rank": "species", + "label": "Abrotanella submarginata A. Gray", + "scientificName": "Abrotanella submarginata", + "authorship": "A. Gray", + "status": "accepted", + "acceptedName": "", + "classification": "GENUS:Abrotanella Cass.|SUBFAMILY:Asteroideae (Cass.) Lindl.|FAMILY:Asteraceae Dumort.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", + "issues": "" + } +] + +export let resultStore = writable(emptyTestRows) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte new file mode 100644 index 0000000000..a56431a8eb --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte @@ -0,0 +1,136 @@ + + + +
+ Select steps for data cleaning (changes applied automatically). Use Global actions to run specific procedures across the whole dataset. +
+
+ Hover the Data cleaning options and Global actions , to get an explanation for what they are doing. +
+
+ Click the pencil icon to edit individual names (if empty, the cleaned name property is used for matching or if empty as well, the original name). +
+
+ When you're done here, be sure to SUBMIT the changes for them to take effect! +
+ + +

Data cleaning config

+
+ {#each Object.entries(cleanConfig) as [key, conf]} +
+ {key} +
+ {/each} +
+ +

Global Actions

+ + +
+
+ + + +
+ +
+ +
+ +
+ +
+ + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte new file mode 100644 index 0000000000..d74d818df5 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte @@ -0,0 +1,43 @@ + + +
+ + +
{row.originalName}
+ +
{row.cleanedName}
+ + +
+ + +
+
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte new file mode 100644 index 0000000000..2a807fb7a7 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte @@ -0,0 +1,40 @@ + + +
+ {#each buttons as button} + + {/each} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/data.ts new file mode 100644 index 0000000000..f238a57f02 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/data.ts @@ -0,0 +1,324 @@ +import { writable } from 'svelte/store'; +import { get } from 'svelte/store'; +import * as CleaningUtils from './dataCleaningUtils'; + +export type TailorResultRow = { + id: number, + originalName: string, + cleanedName: string, + editedName: string, + confirmedByUser: boolean, + matchedName: string, + matchType: string, + status: string, + matchSource: string, + matchSourceVersion: string, + timeStampMatch: string +} + +let originalRows: TailorResultRow[] = [ + +] + +let cleanedRows: TailorResultRow[] = [ + +] + +export let tailorResultStore = writable(originalRows); +export let tailorCleanedStore = writable(cleanedRows); + +export function initializeTableData(data: TailorResultRow[]) { + const processed = data.map(item => ({ + ...item, + cleanedName: cleanName(item.originalName), + editedName: item.editedName || '' + })); + + tailorCleanedStore.set(processed); +} + +export function toggleDataCleaning() { + const currentRows = get(tailorCleanedStore); + + const processed = currentRows.map(item => ({ + ...item, + cleanedName: cleanName(item.originalName), + editedName: item.editedName || '' + })); + + tailorCleanedStore.set(processed); +} + +export const cleanConfig = { + stripSymbols: { + apply: true, + description: "" + }, + removeSymbols: { + apply: true, + description: "" + }, + replaceDiacritics: { + apply: true, + description: "" + }, + replaceNonTrailing: { + apply: true, + description: "" + }, + standardizeHybrids: { + apply: true, + description: "" + }, + deleteAfterEqual: { + apply: true, + description: "" + }, + cleanHybridFormulas: { + apply: true, + description: "" + }, + deleteTripleHybrids: { + apply: true, + description: "" + }, + removeCultivars: { + apply: true, + description: "" + }, + cleanMiddleHyphens: { + apply: true, + description: "" + }, + deleteTaxonomicAbbreviations: { + apply: true, + description: "" + }, + deleteHabitatDescriptors: { + apply: true, + description: "" + }, + deleteGeneralNoise: { + apply: true, + description: "" + }, + deleteLeadingDescriptors: { + apply: true, + description: "" + }, + truncateFromBeginning: { + apply: true, + description: "" + }, + truncateFromMarker: { + apply: true, + description: "" + }, + truncateFromGeographicOrBreeding: { + apply: true, + description: "" + }, + truncateFromUncertainty: { + apply: true, + description: "" + }, + changeVernacularNames: { + apply: true, + description: "" + }, + updateFamilyNames: { + apply: true, + description: "" + }, + deleteUselessMarkers: { + apply: true, + description: "" + }, + correctOcrErrors: { + apply: true, + description: "" + }, + harmonizeAbbreviations: { + apply: true, + description: "" + }, + deletePointAfterKey: { + apply: true, + description: "" + }, + deletePointAfterSpecies: { + apply: true, + description: "" + }, + fixMissingSpaces: { + apply: true, + description: "" + }, + validateFamilySuffix: { + apply: true, + description: "" + }, + informationInParentheses: { + apply: true, + description: "" + }, + correctWritingGenus: { + apply: true, + description: "" + }, + spacesBeforeAndAfterParentheses: { + apply: true, + description: "" + }, + correctionHybrid: { + apply: true, + description: "" + }, + removeAuthors: { + apply: true, + description: "" + }, +} + +export const cleanName = (name: string) => { + if (!name) return ''; + name = CleaningUtils.removeSpecialEscapes(name); + name = CleaningUtils.removeSpecialCharacters(name); + + if (cleanConfig.stripSymbols.apply) { + name = CleaningUtils.stripInsideSymbols(name, '"'); + name = CleaningUtils.stripInsideSymbols(name, "'"); + name = CleaningUtils.stripInsideSymbols(name, "(", ")"); + } + + if (cleanConfig.removeSymbols.apply) { + name = name.replace(/'/g, '').replace(/"/g, '').replace("(", '').replace(")", ''); + } + + if (cleanConfig.replaceDiacritics.apply) { + name = CleaningUtils.replaceDiacritics(name); + } + + name = CleaningUtils.removeNumbers(name); + + if (cleanConfig.replaceNonTrailing.apply) { + name = CleaningUtils.replaceNonTrailingSymbolsWithSpace(name, "_"); + name = CleaningUtils.replaceNonTrailingSymbolsWithSpace(name, "."); + } + + name = CleaningUtils.deleteNumeral(name); + + if (cleanConfig.standardizeHybrids.apply) { + name = CleaningUtils.standardizeHybrids(name); + } + + if (cleanConfig.deleteAfterEqual.apply) { + name = CleaningUtils.deleteAfterEqual(name); + } + + if (cleanConfig.cleanHybridFormulas.apply) { + name = CleaningUtils.cleanHybridFormulas(name); + } + + if (cleanConfig.deleteTripleHybrids.apply) { + name = CleaningUtils.deleteTripleHybrids(name); + } + + if (cleanConfig.removeCultivars.apply) { + name = CleaningUtils.removeCultivars(name); + } + + if (cleanConfig.cleanMiddleHyphens.apply) { + name = CleaningUtils.cleanMiddleHyphens(name); + } + + if (cleanConfig.deleteTaxonomicAbbreviations.apply) { + name = CleaningUtils.deleteTaxonomicAbbreviations(name); + } + + if (cleanConfig.stripSymbols.apply) { + name = CleaningUtils.deleteHabitatDescriptors(name); + } + + if (cleanConfig.deleteGeneralNoise.apply) { + name = CleaningUtils.deleteGeneralNoise(name); + } + + if (cleanConfig.deleteLeadingDescriptors.apply) { + name = CleaningUtils.deleteLeadingDescriptors(name); + } + + if (cleanConfig.truncateFromBeginning.apply) { + name = CleaningUtils.truncateFromBeginning(name); + } + + if (cleanConfig.truncateFromMarker.apply) { + name = CleaningUtils.truncateFromMarker(name); + } + + if (cleanConfig.truncateFromGeographicOrBreeding.apply) { + name = CleaningUtils.truncateFromGeographicOrBreeding(name); + } + + if (cleanConfig.truncateFromUncertainty.apply) { + name = CleaningUtils.truncateFromUncertainty(name); + } + + if (cleanConfig.changeVernacularNames.apply) { + name = CleaningUtils.changeVernacularNames(name); + } + + if (cleanConfig.updateFamilyNames.apply) { + name = CleaningUtils.updateFamilyNames(name); + } + + if (cleanConfig.deleteUselessMarkers.apply) { + name = CleaningUtils.deleteUselessMarkers(name); + } + + if (cleanConfig.correctOcrErrors.apply) { + name = CleaningUtils.correctOcrErrors(name); + } + + if (cleanConfig.harmonizeAbbreviations.apply) { + name = CleaningUtils.harmonizeAbbreviations(name); + } + + if (cleanConfig.deletePointAfterKey.apply) { + name = CleaningUtils.deletePointAfterKey(name); + } + + if (cleanConfig.deletePointAfterSpecies.apply) { + name = CleaningUtils.deletePointAfterSpecies(name); + } + + if (cleanConfig.fixMissingSpaces.apply) { + name = CleaningUtils.fixMissingSpaces(name); + } + + if (cleanConfig.validateFamilySuffix.apply) { + name = CleaningUtils.validateFamilySuffix(name); + } + + if (cleanConfig.informationInParentheses.apply) { + name = CleaningUtils.informationInParentheses(name); + } + + if (cleanConfig.correctWritingGenus.apply) { + name = CleaningUtils.correctWritingGenus(name); + } + + if (cleanConfig.spacesBeforeAndAfterParentheses.apply) { + name = CleaningUtils.spacesBeforeAndAfterParentheses(name); + } + + if (cleanConfig.correctionHybrid.apply) { + name = CleaningUtils.correctionHybrid(name); + } + + if (cleanConfig.removeAuthors.apply) { + name = CleaningUtils.removeAuthors(name); + } + + return name; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/dataCleaningUtils.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/dataCleaningUtils.ts new file mode 100644 index 0000000000..ec20c90161 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/dataCleaningUtils.ts @@ -0,0 +1,618 @@ +export const stripInsideSymbols = (text: string, startSym: string, endSym = startSym) => { + if (!text) return ''; + + // We need to escape symbols like '(' or '[' so Regex doesn't think they are code + const escape = (s: string) => s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + + const s = escape(startSym); + const e = escape(endSym); + + // Dynamically build: /startSymbol\s*(.*?)\s*endSymbol/g + const regex = new RegExp(`${s}\\s*(.*?)\\s*${e}`, 'g'); + + // Replace the whole match with: startSymbol + capturedText + endSymbol + return text.replace(regex, `${startSym}$1${endSym}`); +}; + +export const removeSpecialEscapes = (text: string) => { + if (!text) return ''; + + // remove newline, tab, carriage return + let result = text.replace(/[\n\r\t]/g, ''); + + // remove potentially created double whitespaces + return result.replace(/\s\s+/g, ' ').trim(); +} + +export const removeSpecialCharacters = (text: string) => { + if (!text) return ''; + + const specialChars = /[!?@#\$%&*\^†,¬Ç¡ˆ◊√ó]/g; + let result = text.replace(specialChars, ''); + + result = result.replace(/\.{2,}/g, '.'); + + return result.replace(/\s\s+/g, ' ').trim(); +} + +export const replaceDiacritics = (text: string) => { + if (!text) return ''; + + const diacriticsMap = { + "á": "a", "é": "e", "√™": "e", "í": "i", "ó": "o", "ú": "u", + "Á": "A", "É": "E", "Í": "I", "Ó": "O", "Ú": "U", + "à": "a", "è": "e", "ì": "i", "ò": "o", "ù": "u", + "À": "A", "È": "E", "Ì": "I", "Ò": "O", "Ù": "U", + "ã": "a", "ẽ": "e", "ĩ": "i", "õ": "o", "ũ": "u", + "Ã": "A", "Ẽ": "E", "Ĩ": "I", "Õ": "O", "Ũ": "U", + "Â": "A", "â": "a", "Ê": "E", "ê": "e", "Î": "I", "î": "i", + "Ô": "O", "ô": "o", "Û": "U", "û": "u", + "Æ": "AE", "æ": "ae", "Ç": "S", "ç": "s", "Œ": "oe", + "Ä": "AE", "ä": "ae", "Ö": "OU", "ö": "ou", "Ü": "U", "ü": "u", + "Ÿ": "I", "ÿ": "i" + }; + + // Create a regex that matches any of the keys in our map + // We use [ ... ] for single chars, but since we have multi-char keys like "√™", + // we join them with the OR operator | + const pattern = new RegExp( + Object.keys(diacriticsMap) + .map(key => key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')) // escape keys + .join('|'), + 'g' + ); + + // One single pass over the string! + return text.replace(pattern, (matched) => diacriticsMap[matched]); +}; + +export const removeNumbers = (text: string) => { + if (!text) return ''; + + let result = text.replace(/\d/g, ''); + + return result.replace(/\s\s+/g, ' ').trim(); +} + +export const replaceNonTrailingSymbolsWithSpace = (text: string, separator: string) => { + if (!text) return ''; + + // We escape the separator in case it's a dot + const escaped = separator.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + // Lookaround equivalent in JS: replace separator with space if between word characters + const regex = new RegExp(`(?<=\\w)${escaped}(?=\\w)`, 'g'); + return text.replace(regex, ' ').trim(); +}; + +// Deletes the # symbol +export const deleteNumeral = (text: string) => text.replace(/#/g, ''); + +export const standardizeHybrids = (text: string) => { + if (!text) return ''; + + let result = text; + + // 1. Ensure 'ex' followed by Uppercase has spaces: 'exName' -> ' ex Name' + result = result.replace(/\s*ex(?=[A-Z])/g, ' ex '); + + // 2. Remove leading 'x' or 'X' if followed by Uppercase: 'x Gardenia' -> 'Gardenia' + // ^\s* matches start of string plus any whitespace + result = result.replace(/^\s*x\s*(?=[A-Z])/i, ''); // 'i' flag handles x and X + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deleteAfterEqual = (text: string) => { + if (!text) return ''; + + // Replace '=' and everything after it (.*) with a space + return text.replace(/=.*/, '').trim(); +}; + +export const cleanHybridFormulas = (text: string) => { + if (!text) return ''; + + let result = text; + + // 1. Identify the first word (Genus) + const firstSpaceIndex = result.trim().indexOf(' '); + if (firstSpaceIndex !== -1) { + const genus = result.substring(0, firstSpaceIndex); + const escapedGenus = genus.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + // 2. Remove the genus if it repeats after an ' x ' + // Example: "Quercus alba x Quercus robur" -> "Quercus alba x robur" + // We use a dynamic Regex to find: space + x + space + genus + space + const redundantGenusRegex = new RegExp(` x ${escapedGenus} `, 'g'); + result = result.replace(redundantGenusRegex, ' x '); + } + + // 3. Fix double 'x' markers + result = result.replace(/x\s+x/g, 'x'); + + // 4. Handle 'x Q.' or 'x Q ' (where Q is any genus initial) + // This replaces 'x' followed by an initial and a dot/space with just ' x ' + result = result.replace(/x\s+[A-Z]\b\.?/g, ' x '); + + // 5. Final space cleanup + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deleteTripleHybrids = (text: string) => { + if (!text) return ''; + + // Split the string by the hybrid marker + const parts = text.split(' x '); + + // If there's more than one ' x ' (meaning 3 or more parts) + if (parts.length > 2) { + // Take only the first two parts and join them back + return `${parts[0]} x ${parts[1]}`.trim(); + } + + return text.trim(); +}; + +export const removeCultivars = (text: string) => { + if (!text) return ''; + + let result = text; + + // This regex matches: + // 1. Optional 'cv.' or 'cv' (case insensitive) + // 2. Followed by text in either 'single' or "double" quotes + // 3. Or just the quoted text alone + const cultivarRegex = /\s*(cv\.?)?\s*(['"])(?:(?!\2).)+\2/gi; + + result = result.replace(cultivarRegex, ' '); + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const cleanMiddleHyphens = (text: string) => { + if (!text) return ''; + + let result = text; + + // 1. Collapse spaces around hyphens: 'Word - Word' -> 'Word-Word' + // Matches whitespace before and/or after a hyphen as long as text exists on both sides + result = result.replace(/(?<=\S)\s*-\s*(?=\S)/g, '-'); + + // 2. Truncate at space-dash-space followed by a Capital Letter + // 'Pinus sylvestris - Note' -> 'Pinus sylvestris' + result = result.replace(/\s+-\s+[A-Z].*/, ''); + + // 3. Convert remaining isolated ' - ' to a single space + result = result.replace(/\s+-\s+/g, ' '); + + // 4. Remove trailing hyphen at the end of the string + result = result.replace(/\s*-$/, ''); + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deleteTaxonomicAbbreviations = (text: string) => { + if (!text) return ''; + + const badList = [ + "especie", "taxon", "s(ens)?\\.? ?str\\.", "s(ens)?\\. ?l(at)?\\.", "gen(us)?", "comb", + "agg?r?", "subfo", "subg", "subgen", "subgrp", "aff?", "ef", "cf", "cff", "indet", "indeterminate", + "indeterminad\\w", "inconnue", "ined", "non ?det", "sp\\w?", "sppl?", "spec", "species", "nov(o|a)?", + "sp\\.?nov", "orth", "subspecies" + ]; + + // Join the list into a single (word1|word2|word3) pattern + const joinedPatterns = badList.join('|'); + + // The 'Lasso': Matches start of string, space, hyphen, or dot + // before and after the forbidden words. + const before = '(^|[ \\-\\.\\/])'; + const after = '\\.?([ \\-\\.\\/]|$|\\.)'; + + const regex = new RegExp(`${before}(?:${joinedPatterns})${after}`, 'gi'); + + // Replace with a space to avoid merging words together + let result = text.replace(regex, ' '); + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deleteHabitatDescriptors = (text: string) => { + if (!text) return ''; + + const descriptors = [ + "bunch", "upland", "terrestrial", "rosette", "salt marsh", "spSugden", "including", + "swamp", "bark", "culms?", "terra firme", "chapparral", "catinga", "shortgrass", "steppe", "plateau", + "wetland", "cultivated", "vegetables", "mistletoe", "monocot", "valley", "river", "coastal", "mountain", + "harvest", "residues", "nublados?", "bosques?", "mesophytic", "halophytic", "bamboo", "annual", "perennial", + "secondary", "primary", "rain", "herbaceous", "conifers?", "coniferous", "broadleaf", "broad-leaved", + "canopy", "tall", "low", "mata", "field", "forest", "pseudospecies", "leaf", "leaves", "savanna", + "deciduous", "evergreen", "grassland", "abandoned", "pasture", "meadow", "fine", "broad", "form", + "forbs?", "ferns?", "epiphytes?", "trees?", "lianas?", "palms?", "graminoids?", "grass(es)?", "shrubs?", + "sedges?", "Solling" + ]; + + // Join into a single regex pattern + const joinedDescriptors = descriptors.join('|'); + + // Boundary 'lasso': Handles spaces, start/end of string, and hyphens (-) + const before = '(^|[ \\-])'; + const after = '([ \\-]|$|\\.)'; + + const regex = new RegExp(`${before}(?:${joinedDescriptors})${after}`, 'gi'); + + let result = text.replace(regex, ' '); + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deleteGeneralNoise = (text: string) => { + if (!text) return ''; + + const badList = [ + "herbs?", "red", "white", "blue", "green", "yellow", "black", "name error", + "orthodox( p)?", "hiro", "et al\\.", "none", "null", "small", "dark", "smooth" + ]; + + const joined = badList.join('|'); + // Lasso: Start of string or space | word | space or end of string + const regex = new RegExp(`(^| )(?:${joined})( |$)`, 'gi'); + + // We replace with a space to keep word boundaries clean + let result = text.replace(regex, ' '); + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deleteLeadingDescriptors = (text: string) => { + if (!text) return ''; + + const badList = ["wood", "alpine", "non-\\w{2,}", "pubescent"]; + const joined = badList.join('|'); + + // Anchor to the start of the string (^) + const regex = new RegExp(`^(?:${joined})( |$|-)`, 'i'); + + return text.replace(regex, '').trim(); +}; + +export const truncateFromBeginning = (text: string) => { + if (!text) return ''; + + // Matches 'pau' or 'mata/matas/mata' at the very start + const badList = ["pau", "mat\\w*"]; + const joined = badList.join('|'); + + // ^(?:...) matches start, (?: .*)? matches the rest of the string + const regex = new RegExp(`^(?:${joined})(?: .*|$)`, 'i'); + + return text.replace(regex, '').trim(); +}; + +export const truncateFromMarker = (text: string) => { + if (!text) return ''; + + // se. sect. ind. indet. cv. cv + const badList = ["se(ct)?\\.", "ind(et)?", "cv\\.?"]; + const joined = badList.join('|'); + + // (?:^| ) ensures we match the word at start or after space + // (?: .*|$) captures everything until the end + const regex = new RegExp(`(?:^| )(?:${joined})(?: .*|$)`, 'i'); + + return text.replace(regex, '').trim(); +}; + +export const truncateFromGeographicOrBreeding = (text: string) => { + if (!text) return ''; + + const badList = [ + "caatinga", "boreal", "germany", "north(ern)?", "south(ern)?", "west(ern)?", + "east(ern)?", "subpolar", "ural", "southafrica", "tropical", "temperate", "cultivar", + "genotype", "hybride?", "inbred line", "variety" + ]; + + const joined = badList.join('|'); + // Lasso: Start, space, or hyphen | bad words | everything else + const regex = new RegExp(`(^|[ \\-])(?:${joined})(?: .*|$)`, 'gi'); + + return text.replace(regex, '').trim(); +}; + +export const truncateFromUncertainty = (text: string) => { + if (!text) return ''; + + const badList = [ + "group\\w?", "death", "dwarf", "little", "mid", "average", "other", "mixed", "under", + "all", "dry", "wet", "open", "new", "old", "unk\\.?", "not identified", "unknown", "undetermined", + "undefined", "unidentified", "unclassified" + ]; + + const joined = badList.join('|'); + // Lasso: Start or space | bad words | everything else + const regex = new RegExp(`(^| )(?:${joined})(?: .*|$)`, 'gi'); + + return text.replace(regex, '').trim(); +}; + +export const changeVernacularNames = (text: string) => { + if (!text) return ''; + + // 1. Handle the "Starts with" cases (Genus swaps) + const startsWithMap = { + 'Abiu': 'Pouteria', + 'Lily': 'Lilium', + 'Cotton': 'Gossypium', + 'Strawberry': 'Fragaria', + 'Cashew': 'Anacardium' + }; + + let result = text; + + // Check if the string starts with any of our map keys + for (const [common, scientific] of Object.entries(startsWithMap)) { + const regex = new RegExp(`^${common}( .*|$)`, 'i'); + if (regex.test(result)) { + return result.replace(regex, `${scientific}$1`); + } + } + + // 2. Handle the "Contains" cases (Specific replacements) + // Coffee -> Coffea arabica + result = result.replace(/(^| )coffee( .*|$)/i, '$1Coffea arabica$2'); + + // Orchid -> Orchidaceae + result = result.replace(/(^| )orchid( .*|$)/i, '$1Orchidaceae$2'); + + return result.trim(); +}; + +export const updateFamilyNames = (text: string) => { + if (!text) return ''; + + const familyMap = { + 'Compositae': 'Asteraceae', + 'Cruciferae': 'Brassicaceae', + 'Gramineae': 'Poaceae', + 'Guttiferae': 'Clusiaceae', + 'Labiatae': 'Lamiaceae', + 'Leguminosae': 'Fabaceae', + 'Palmae': 'Arecaceae', + 'Umbelliferae': 'Apiaceae' + }; + + let result = text; + + // We loop through the map and use the ^ anchor to match the start of the string + for (const [oldName, newName] of Object.entries(familyMap)) { + const regex = new RegExp(`^${oldName}`, 'i'); + if (regex.test(result)) { + // Replace only the first occurrence at the start + result = result.replace(regex, newName); + break; // Once we find a match at the start, we can stop + } + } + + return result; +}; + +export const deleteUselessMarkers = (text: string) => { + if (!text) return ''; + + let result = text; + + // 1. Remove trailing hybrid marker: 'Quercus x' -> 'Quercus' + result = result.replace(/\s[xX]$/, ''); + + // 2. Standardize 'A-' notation + result = result.replace(/^A-/, ' '); // At start + result = result.replace(/\sA-/g, ' x '); // In middle + + // 3. Remove leading lowercase words (Invalid for Genus) + result = result.replace(/^[a-z]+\s+/, ' '); + + // 4. Remove 3-letter uppercase codes, but PROTECT 'POA' + // (?!POA\s) is a negative lookahead + result = result.replace(/^(?!POA\s)[A-Z]{3}\s/, ''); + + // 5. Remove 'NA' markers + result = result.replace(/\sNA(\s|$)/g, ' '); + + // 6. The d'Urville correction + // Matches 'd', up to 2 chars, 'd', up to 2 chars, 'Urv' and everything after + result = result.replace(/d.{0,2}d.{0,2}Urv.*/, "d'Urv"); + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const correctOcrErrors = (text: string) => { + if (!text) return ''; + // Replaces I with l ONLY if surrounded by lowercase letters + return text.replace(/(?<=[a-z])I(?=[a-z])/g, 'l'); +}; + +export const harmonizeAbbreviations = (text: string) => { + if (!text) return ''; + + let result = text; + + // 1. Standardize subspecies variations to ' subsp. ' + // Matches s., ssp, sspp, susbp, etc. + result = result.replace(/(?:\.|\s)?s(ub)?sp(\.)?(?:\s|$|\.)/gi, ' subsp. '); + result = result.replace(/\s(susbp|subs)(\.|\s)/gi, ' subsp. '); + result = result.replace(/(\.)?subspecies(\.)?/gi, ' subsp. '); + result = result.replace(/\s+s\.\s+/g, ' subsp. '); + + // 2. Standardize form variations to ' f. ' + result = result.replace(/fo?(rma)?\.?(\s|$)/gi, ' f. '); + + // 3. Standardize variety to ' var. ' + result = result.replace(/\s+var(\.|\s)/gi, ' var. '); + + // 4. Clean up "stacked" or redundant abbreviations + result = result.replace(/f\.\s+subsp\./g, 'subsp.'); + result = result.replace(/f\.\s+var\./g, 'var.'); + + // 5. Remove abbreviations if they start the string + result = result.replace(/^ ?(subsp|var|f)(\.)?\s+.*/i, ' '); + + // 6. Remove "trailing" abbreviations with no content after them + result = result.replace(/\s(subsp|var|f)\.?\s*$/i, ''); + + return result.replace(/\s\s+/g, ' ').trim(); +}; + +export const deletePointAfterKey = (text: string) => { + if (!text) return ''; + + // Regex breakdown: + // ^([A-Z][a-z\-\s]*[a-z]) -> Group 1: The Genus (Starts with Caps) + // \s+(subsp|var|f) -> Group 2: The Rank + // \. -> The dot we want to remove + const regex = /^([A-Z][a-z\-\s]*[a-z])\s+(subsp|var|f)\./; + + // We replace the whole match with Group 1 + space + Group 2 (no dot) + return text.replace(regex, '$1 $2').trim(); +}; + +export const deletePointAfterSpecies = (text: string) => { + if (!text) return ''; + + // Regex breakdown: + // ^([A-Z][a-z\-\s]*[a-z]) -> Group 1: Genus + // \s+ -> Space + // ([a-z][a-z\-]*[a-z]) -> Group 2: species epithet + // \. -> The dot we want to remove + const regex = /^([A-Z][a-z\-\s]*[a-z])\s+([a-z][a-z\-]*[a-z])\./; + + return text.replace(regex, '$1 $2').trim(); +}; + +export const fixMissingSpaces = (text: string) => { + if (!text) return ''; + + let result = text; + + // 1. Remove space before hyphen or period: 'Canis -' -> 'Canis-' + result = result.replace(/\s-/g, '-'); + result = result.replace(/\s\./g, '.'); + + // 2. Ensure a space follows a period, UNLESS it's a closing bracket + // Example: 'C.lupus' -> 'C. lupus' | '(sp.)' -> '(sp.)' (stays same) + result = result.replace(/\.(?!\))/g, '. '); + + // 3. Special case for period-hyphen: '. -' -> '.-' + result = result.replace(/\.\s-/g, '.-'); + + // 4. Final Spacing Cleanup + // Replace multiple spaces with one, then trim edges + return result.replace(/\s+/g, ' ').trim(); +}; + +export const validateFamilySuffix = (text: string) => { + if (!text) return ''; + + // Condition 2: Does it contain a word ending in 'aceae'? + const familyMatch = text.match(/[A-Za-z]+aceae/); + if (!familyMatch) return text; + + const foundWord = familyMatch[0]; + + // Condition 3: Is it preceded by a Genus/Species pattern? + // This regex looks for: Capitalized Genus + word + (optional rank) + our 'aceae' word + const speciesContextRegex = new RegExp(`[A-Z][a-z\\-]+(?:\\s+[a-z\\-]+)+(?:\\s+[a-z]+\\.)?\\s+${foundWord}`); + + const isSpeciesEpithet = speciesContextRegex.test(text); + + if (!isSpeciesEpithet) { + // It's a TRUE family name. Capitalize the first letter. + const capitalized = foundWord.charAt(0).toUpperCase() + foundWord.slice(1); + return text.replace(foundWord, capitalized).trim(); + } else { + // It's a FALSE family (a species name). Change suffix to 'cea'. + // We handle the three specific cases from the Python code + let corrected = text; + corrected = corrected.replace(/ceae$/g, 'cea'); + corrected = corrected.replace(/ceae\s/g, 'cea '); + corrected = corrected.replace(/ceae\)/g, 'cea)'); + return corrected.trim(); + } +}; + +export const informationInParentheses = (text: string) => { + if (!text) return ""; + + // 1. Remove (lowercase-words-with-hyphens) + // Equivalent to: r'\([a-z]([a-z]|-){1,}[a-z]\)' + const lowercaseInfo = /\([a-z]([a-z]|-)+[a-z]\)/g; + text = text.replace(lowercaseInfo, ''); + + // 2. Remove empty or whitespace-only parentheses: ( ) + // Equivalent to: r'\(\s*\)' + const emptyParens = /\(\s*\)/g; + text = text.replace(emptyParens, ''); + + return text.replace(/\s+/g, ' ').trim(); +} + +export const correctWritingGenus = (text: string) => { + if (!text) return ""; + + const pattern = /^([A-Z]{2,}((\s(x|X))?\s+|\W|$))+/; + const match = text.match(pattern); + + if (match) { + const matchedText = match[0]; + const transformed = matchedText.charAt(0) + matchedText.slice(1).toLowerCase(); + text = transformed + text.slice(matchedText.length); + } + + return text.replace(/\s+/g, ' ').trim(); +}; + +export const spacesBeforeAndAfterParentheses = (text: string) => { + if (!text) return ""; + + text = text.replace(/\( /g, '('); + text = text.replace(/ \)/g, ')'); + + return text.replace(/\s+/g, ' ').trim(); +}; + +export const correctionHybrid = (text: string) => { + if (!text) return ""; + + if (/^x\s/.test(text)) { + // Note: hybrid_1 is unused in the original Python snippet's return, + // but the regex replacement is performed here. + text = text.replace(/^x\s/, ''); + } + + return text.replace(/\s+/g, ' ').trim(); +}; + +export const removeAuthors = (text: string) => { + if (!text) return ""; + + const array = text.split(" "); + const length = array.length; + + // Find the index of the first item starting with '(' + let indexOpen = -1; + for (let i = 0; i < array.length; i++) { + if (array[i].startsWith('(')) { + indexOpen = i; + break; + } + } + + if (indexOpen > 0) { + const a = array.slice(0, indexOpen); + return a.join(' ').replace(/\s+/g, ' ').trim(); + } + + if (length > 2) { + const a = array.slice(0, length - 1); + return a.join(' ').replace(/\s+/g, ' ').trim(); + } else { + return text; + } +}; \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/services.ts new file mode 100644 index 0000000000..35bdc3d2f1 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/services.ts @@ -0,0 +1,10 @@ +import { Api } from '@bexis2/bexis2-core-ui'; + +export const loadResult = async (datasetId: number) => { + try { + const response = await Api.get(`http://localhost:44345/smm/species/ViewTailored?datasetId=${datasetId}`); + return response.data; + } catch (error) { + console.error(error); + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/types.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingResultHelper.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingResultHelper.cs new file mode 100644 index 0000000000..4a0cbfe44d --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingResultHelper.cs @@ -0,0 +1,294 @@ +using BExIS.Dlm.Entities.SpeciesMatching; +using BExIS.Dlm.Services.SpeciesMatching; +using BExIS.IO.Transform.Output; +using BExIS.Modules.Smm.UI.Models; +using System; +using System.Collections.Generic; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Text; +using System.Web; +using System.Web.Http.Results; +using System.Web.Mvc; +using Vaiona.Persistence.Api; + +namespace BExIS.Modules.Smm.UI.Helpers +{ + // This helper class is used for reading and parsing the matching result files. Currently only ChecklistBank (CLB) but later also other APIs. + public class MatchingResultHelper + { + // returns all SpeciesMatchingResult entries for a given datasetId, or null if an error occurs + public static List GetAll(long datasetId) + { + try + { + using (var smrm = new SpeciesMatchingResultManager()) + { + var smrmRepo = smrm.GetBulkUnitOfWork().GetReadOnlyRepository(); + List result = smrmRepo.Query().Where(r => r.Dataset.Id == datasetId).ToList(); + + return result; + } + } + catch (Exception ex) + { + return null; + } + } + + // Generate a CSV file containing all confirmed SpeciesMatchingResults for a given datasetId. Returns the file path and the number of rows written, or (null, 0) if an error occurs. + public static (string FilePath, int RowCount) GenerateUnmatchedCsv(long datasetId, long dataStructureId, int stepId) + { + DataTable dt = new DataTable("SpeciesUnmatched"); + dt.Columns.Add("ID", typeof(long)); + dt.Columns.Add("scientificName", typeof(string)); + dt.Columns.Add("rank", typeof(string)); + dt.Columns.Add("kingdom", typeof(string)); + dt.Columns.Add("authorship", typeof(string)); + + int writtenCount = 0; + + using (var smrm = new SpeciesMatchingResultManager()) + { + var smrmRepo = smrm.GetBulkUnitOfWork().GetReadOnlyRepository(); + List result = smrmRepo.Query().Where(r => r.Dataset.Id == datasetId && r.ConfirmedByUser == false).ToList(); + + // TODO: - write all columns correctly + foreach (var item in result) + { + if (item.EditedName != null && item.EditedName != "") + { + dt.Rows.Add(item.Id, item.EditedName, "species", "", ""); + writtenCount++; + } + else if (item.CleanedName != null && item.CleanedName != "") + { + dt.Rows.Add(item.Id, item.CleanedName, "species", "", ""); + writtenCount++; + } + else if (item.OriginalName != null && item.OriginalName != "") + { + dt.Rows.Add(item.Id, item.OriginalName, "species", "", ""); + writtenCount++; + } + else + { + continue; + } + } + } + + var outputManager = new OutputDataManager(); + string ns = datasetId.ToString(); + string title = ProgressHelper.GenMatchingFileName(false, datasetId, stepId, false); + + string filepath = outputManager.GenerateAsciiFile(ns, dt, title, "text/csv", dataStructureId); + + if (!System.IO.File.Exists(filepath)) return (null, 0); + return (filepath, writtenCount); + } + + // Read a ChecklistBank matching CSV file and map rows to CLBMatchingResultFile objects + public static List ReadClbMatchingResultFile(string filepath) + { + var result = new List(); + + try + { + if (string.IsNullOrWhiteSpace(filepath) || !System.IO.File.Exists(filepath)) return result; + + using (var sr = new StreamReader(filepath, Encoding.UTF8)) + { + string headerLine = sr.ReadLine(); + if (headerLine == null) return result; + + // parse header columns + var headers = ParseCsvLine(headerLine).Select(h => h?.Trim()).ToList(); + // map header name (case-insensitive) to index + var headerIndex = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < headers.Count; i++) + { + if (!string.IsNullOrEmpty(headers[i]) && !headerIndex.ContainsKey(headers[i])) + { + headerIndex[headers[i]] = i; + } + } + + string line; + while ((line = sr.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) continue; + var fields = ParseCsvLine(line); + + string GetField(string name) + { + if (!headerIndex.TryGetValue(name, out int idx)) return string.Empty; + if (idx < 0 || idx >= fields.Count) return string.Empty; + var v = fields[idx]; + return string.IsNullOrEmpty(v) ? string.Empty : v; + } + + var entry = new CLBMatchingResultFile + { + Original_ID = GetField("Original_ID"), + Original_scientificName = GetField("Original_scientificName"), + Original_rank = GetField("Original_rank"), + Original_kingdom = GetField("Original_kingdom"), + Original_authorship = GetField("Original_authorship"), + MatchType = GetField("MatchType"), + MatchIssues = GetField("MatchIssues"), + ID = GetField("ID"), + Rank = GetField("Rank"), + ScientificName = GetField("ScientificName"), + Authorship = GetField("Authorship"), + Status = GetField("Status"), + AcceptedID = GetField("AcceptedID"), + AcceptedScientificName = GetField("AcceptedScientificName"), + AcceptedAuthorship = GetField("AcceptedAuthorship"), + Kingdom = GetField("Kingdom"), + Phylum = GetField("Phylum"), + Class = GetField("Class"), + Order = GetField("Order"), + Family = GetField("Family"), + Genus = GetField("Genus"), + Classification = GetField("Classification") + }; + + result.Add(entry); + } + } + + return result; + } + catch (Exception ex) + { + return result; + } + } + + public static bool AcceptClbMatches(long datasetId, int stepId, HashSet acceptedIds) + { + var filepath = ProgressHelper.GetMatchedFilepath(datasetId, stepId); + if (filepath == null) return false; + + try + { + using (var sr = new StreamReader(filepath, Encoding.UTF8)) + { + string headerLine = sr.ReadLine(); + if (headerLine == null) return false; + + // parse header columns + var headers = ParseCsvLine(headerLine).Select(h => h?.Trim()).ToList(); + // map header name (case-insensitive) to index + var headerIndex = new Dictionary(StringComparer.OrdinalIgnoreCase); + for (int i = 0; i < headers.Count; i++) + { + if (!string.IsNullOrEmpty(headers[i]) && !headerIndex.ContainsKey(headers[i])) + { + headerIndex[headers[i]] = i; + } + } + + string line; + while ((line = sr.ReadLine()) != null) + { + if (string.IsNullOrWhiteSpace(line)) continue; + var fields = ParseCsvLine(line); + + string GetField(string name) + { + if (!headerIndex.TryGetValue(name, out int idx)) return string.Empty; + if (idx < 0 || idx >= fields.Count) return string.Empty; + var v = fields[idx]; + return string.IsNullOrEmpty(v) ? string.Empty : v; + } + + var original_id = GetField("Original_ID"); + if (acceptedIds.Contains(long.Parse(original_id))) + { + // query for the SpeciesMatchingResult with this Original_ID and mark it as confirmed + + } + + var entry = new CLBMatchingResultFile + { + Original_ID = GetField("Original_ID"), + Original_scientificName = GetField("Original_scientificName"), + Original_rank = GetField("Original_rank"), + Original_kingdom = GetField("Original_kingdom"), + Original_authorship = GetField("Original_authorship"), + MatchType = GetField("MatchType"), + MatchIssues = GetField("MatchIssues"), + ID = GetField("ID"), + Rank = GetField("Rank"), + ScientificName = GetField("ScientificName"), + Authorship = GetField("Authorship"), + Status = GetField("Status"), + AcceptedID = GetField("AcceptedID"), + AcceptedScientificName = GetField("AcceptedScientificName"), + AcceptedAuthorship = GetField("AcceptedAuthorship"), + Kingdom = GetField("Kingdom"), + Phylum = GetField("Phylum"), + Class = GetField("Class"), + Order = GetField("Order"), + Family = GetField("Family"), + Genus = GetField("Genus"), + Classification = GetField("Classification") + }; + + + } + } + + return true; + } + catch (Exception ex) + { + return false; + } + } + + // Simple CSV line parser that handles quoted fields and commas inside quotes. + public static List ParseCsvLine(string line) + { + var fields = new List(); + if (line == null) return fields; + + var sb = new StringBuilder(); + bool inQuotes = false; + for (int i = 0; i < line.Length; i++) + { + char c = line[i]; + if (c == '"') + { + if (inQuotes && i + 1 < line.Length && line[i + 1] == '"') + { + // escaped quote + sb.Append('"'); + i++; // skip next + } + else + { + inQuotes = !inQuotes; + } + } + else if (c == ',' && !inQuotes) + { + fields.Add(sb.ToString()); + sb.Clear(); + } + else + { + sb.Append(c); + } + } + + fields.Add(sb.ToString()); + return fields; + } + + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/ProgressHelper.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/ProgressHelper.cs new file mode 100644 index 0000000000..7e43f5383c --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/ProgressHelper.cs @@ -0,0 +1,239 @@ +using BExIS.Modules.Smm.UI.Models; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Linq; +using System.Net; +using System.Text; +using System.Web; +using Vaiona.Utils.Cfg; + +namespace BExIS.Modules.Smm.UI.Helpers +{ + public class ProgressHelper + { + const string HM_FILENAME = "header_mappings.json"; + const string MP_FILENAME = "mapping_progress.json"; + const string MATCHED_PREFIX = "species_matched"; + const string UNMATCHED_PREFIX = "species_unmatched"; + + public static MappingProgressModel LoadMappingProgress(long datasetId) + { + try + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + string filepath = Path.Combine(directory, MP_FILENAME); + + if (!System.IO.File.Exists(filepath)) + { + Debug.WriteLine($"Mapping Progress file not found: {filepath}"); + return null; + } + + string content = System.IO.File.ReadAllText(filepath); + if (string.IsNullOrWhiteSpace(content)) + { + Debug.WriteLine($"Mapping progress file empty: {filepath}"); + return null; + } + + var model = JsonConvert.DeserializeObject(content); + return model; + } + catch (Exception ex) + { + Debug.WriteLine("Failed to load mapping progress: " + ex); + return null; + } + } + + + // Loads the header mappings JSON file for the given dataset id. + // Returns the deserialized HeaderMappingsModel or null when the file + // does not exist, is empty or cannot be parsed. + public static HeaderMappingsModel LoadHeaderMappings(long datasetId) + { + try + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + string filepath = Path.Combine(directory, HM_FILENAME); + + if (!System.IO.File.Exists(filepath)) + { + Debug.WriteLine($"Header mappings file not found: {filepath}"); + return null; + } + + string content = System.IO.File.ReadAllText(filepath); + if (string.IsNullOrWhiteSpace(content)) + { + Debug.WriteLine($"Header mappings file empty: {filepath}"); + return null; + } + + var model = JsonConvert.DeserializeObject(content); + return model; + } + catch (Exception ex) + { + Debug.WriteLine("Failed to load header mappings: " + ex); + return null; + } + } + + + // Creates a mapping_progress.json file for the given dataset with an empty Steps list. + // Returns true when the file was created successfully, false on error. + public static bool CreateMappingProgressFile(long datasetId, int numRowsGlobal) + { + try + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + + // TODO: auto generate if missing? + if (!Directory.Exists(directory)) + { + Debug.WriteLine("CreateMappingProgressFile: dataset directory does not exist: " + directory); + return false; + } + + string filepath = Path.Combine(directory, MP_FILENAME); + + var model = new MappingProgressModel + { + DatasetId = datasetId, + NumRowsGlobal = numRowsGlobal, + Steps = new List() + }; + + string json = JsonConvert.SerializeObject(model, Formatting.Indented); + System.IO.File.WriteAllText(filepath, json); + + Debug.WriteLine("Created mapping progress file: " + filepath); + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Failed to create mapping progress file: " + ex); + return false; + } + } + + public static bool CreateHeaderMappingsFile(HeaderMappingsModel data, long datasetId, out string errorMessage) + { + foreach (var entry in data.Mappings) + { + if (!MappingValidator.IsValid(entry.HeaderMapping)) + { + errorMessage = "The selected HeaderMapping " + entry.HeaderMapping + " does not exist."; + return false; + } + } + + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + string filepath = Path.Combine(directory, HM_FILENAME); + + if (!Directory.Exists(directory)) + { + errorMessage = "The dataset folder with id " + datasetId + " does not exist."; + return false; + } + else + { + System.IO.File.WriteAllText(filepath, JsonConvert.SerializeObject(data)); + errorMessage = null; + return true; + } + } + + // Persist the provided MappingProgressModel to the dataset's mapping_progress.json file. + // This method will overwrite the file regardless of whether it already exists. + // Returns true on success, false on failure. + public static bool SaveMappingProgress(MappingProgressModel model) + { + if (model == null) + { + Debug.WriteLine("SaveMappingProgress: model is null."); + return false; + } + + long datasetId = model.DatasetId; + if (datasetId <= 0) + { + Debug.WriteLine($"SaveMappingProgress: invalid dataset id: {datasetId}"); + return false; + } + + try + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + + if (!Directory.Exists(directory)) + { + Debug.WriteLine("SaveMappingProgress: dataset directory does not exist: " + directory); + return false; + } + + string filepath = Path.Combine(directory, MP_FILENAME); + + string json = JsonConvert.SerializeObject(model, Formatting.Indented); + + // Overwrite the file (or create it if missing) + System.IO.File.WriteAllText(filepath, json, Encoding.UTF8); + + Debug.WriteLine("Saved mapping progress file: " + filepath); + return true; + } + catch (Exception ex) + { + Debug.WriteLine("Failed to save mapping progress: " + ex); + return false; + } + } + + public static string GenMatchingFileName(bool matched, long datasetId, int suffixId, bool withFileEnding = true) + { + string prefix = matched ? MATCHED_PREFIX : UNMATCHED_PREFIX; + if (withFileEnding) + { + return $"{prefix}_{datasetId}_{suffixId}.csv"; + } + else + { + return $"{prefix}_{datasetId}_{suffixId}"; + } + } + + public static string GetMatchedFilepath(long datasetId, int stepId) + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + string filename = GenMatchingFileName(true, datasetId, stepId); + string filepath = Path.Combine(directory, filename); + if (System.IO.File.Exists(filepath)) + { + return filepath; + } + else + { + return null; + } + + } + + public static bool HasMappingProgress(long datasetId) + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + string filepath = Path.Combine(directory, MP_FILENAME); + return System.IO.File.Exists(filepath); + } + + public static bool HasHeaderMappings(long datasetId) + { + string directory = Path.Combine(AppConfiguration.DataPath, "Datasets", datasetId.ToString()); + string filepath = Path.Combine(directory, HM_FILENAME); + return System.IO.File.Exists(filepath); + } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/AcceptMatchesRequestModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/AcceptMatchesRequestModel.cs new file mode 100644 index 0000000000..6889250b75 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/AcceptMatchesRequestModel.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class AcceptMatchesRequestModel + { + [Range(1, long.MaxValue, ErrorMessage = "DatasetId must be provided and greater than 0.")] + public long DatasetId { get; set; } + + [Required(ErrorMessage = "At least one MatchId must be provided.")] + [MinLength(1, ErrorMessage = "At least one MatchId must be provided.")] + public List MatchIds { get; set; } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/CLBMatchingResultFile.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/CLBMatchingResultFile.cs new file mode 100644 index 0000000000..3652127139 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/CLBMatchingResultFile.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class CLBMatchingResultFile + { + public string Original_ID { get; set; } + public string Original_scientificName { get; set; } + public string Original_rank { get; set; } + public string Original_kingdom { get; set; } + public string Original_authorship { get; set; } + public string MatchType { get; set; } + public string MatchIssues { get; set; } + public string ID { get; set; } + public string Rank { get; set; } + public string ScientificName { get; set; } + public string Authorship { get; set; } + public string Status { get; set; } + public string AcceptedID { get; set; } + public string AcceptedScientificName { get; set; } + public string AcceptedAuthorship { get; set; } + public string Kingdom { get; set; } + public string Phylum { get; set; } + public string Class { get; set; } + public string Order { get; set; } + public string Family { get; set; } + public string Genus { get; set; } + public string Classification { get; set; } + + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/HeaderMappingsModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/HeaderMappingsModel.cs new file mode 100644 index 0000000000..2b85fdce18 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/HeaderMappingsModel.cs @@ -0,0 +1,53 @@ +using Newtonsoft.Json; +using System.ComponentModel.DataAnnotations; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class HeaderMappingsModel + { + public List Mappings { get; set; } = new List(); + + public long DatastructureId { get; set; } + + [Range(1, long.MaxValue, ErrorMessage = "DatasetId must be provided and greater than 0.")] + public long DatasetId { get; set; } + + // Returns the VariableId of the mapping entry whose HeaderMapping equals + // "scientificName". If no such entry exists the method returns null. + public long? GetVariableIdForScientificName() + { + var entry = Mappings?.FirstOrDefault(m => string.Equals(m.HeaderMapping, "scientificName", StringComparison.OrdinalIgnoreCase)); + return entry?.VariableId; + } + } + + public class MappingEntry + { + public long VariableId { get; set; } + + public string VariableName { get; set; } + + public string HeaderMapping { get; set; } + } + + public static class MappingValidator + { + private static readonly HashSet ValidOptions = new HashSet + { + "scientificName", + "authorship", + "rank", + "kingdom", + "IGNORE" + }; + + public static bool IsValid(string value) + { + return ValidOptions.Contains(value); + } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MappingProgressModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MappingProgressModel.cs new file mode 100644 index 0000000000..939cd505e6 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MappingProgressModel.cs @@ -0,0 +1,84 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class MappingProgressModel + { + + public List Steps { get; set; } = new List(); + + public int NumRowsGlobal { get; set; } + + public long DatasetId { get; set; } + + public int GetNewId() + { + return Steps.Count; + } + + public void AddStep(int id, int numRows, string inputFileName) + { + var entry = new StepEntry + { + Id = id, + NumRows = numRows, + InputFileName = inputFileName ?? string.Empty, + ResultFileName = string.Empty, + DownloadLink = string.Empty, + JobKey = string.Empty, + Done = false + }; + + Steps.Add(entry); + } + + public bool AreAllStepsDone() + { + // Return true when there are no unfinished steps (i.e. no step with Done == false) + return Steps == null || Steps.All(s => s.Done); + } + + public string GetNextPendingInputFileName() + { + if (Steps == null || Steps.Count == 0) return null; + + var entry = Steps.FirstOrDefault(s => s.Done == false + && string.IsNullOrEmpty(s.DownloadLink) + && string.IsNullOrEmpty(s.JobKey)); + + return entry?.InputFileName; + } + + public bool IsIdValidAndMatched(int stepId) + { + // Return false when there are no steps + if (Steps == null || Steps.Count == 0) return false; + + var entry = Steps.FirstOrDefault(s => s.Id == stepId); + + // Valid and matched when the step exists and has a non-empty ResultFileName + return entry != null && !string.IsNullOrEmpty(entry.ResultFileName); + } + } + + + public class StepEntry + { + public int Id { get; set; } + + public int NumRows { get; set; } + + public string InputFileName { get; set; } + + public string ResultFileName { get; set; } + + public string DownloadLink { get; set; } + + public string JobKey { get; set; } + + public bool Done { get; set; } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/BExIS.Web.Shell.csproj b/Console/BExIS.Web.Shell/BExIS.Web.Shell.csproj index 86a0d9076c..7e9bdcc025 100644 --- a/Console/BExIS.Web.Shell/BExIS.Web.Shell.csproj +++ b/Console/BExIS.Web.Shell/BExIS.Web.Shell.csproj @@ -1114,7 +1114,7 @@ - + From 760e63adf89dce5a045b6d78b75585a933914c5b Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 15 Apr 2026 13:30:19 +0200 Subject: [PATCH 04/37] Removed hardcoded test data --- .../src/routes/species/data.ts | 2419 ----------------- 1 file changed, 2419 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts index 103b11bffc..442dc8cbe1 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/species/data.ts @@ -26,2423 +26,4 @@ let emptyTestRows: ResultRow[] = [ ] -let resultRows: ResultRow[] = -[ - { - "inputID": "tp", - "inputRank": "", - "inputName": "", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "UNPARSABLE_NAME" - }, - { - "inputID": 1, - "inputRank": "", - "inputName": "Dupoa labradorica", - "matchType": "variant", - "ID": "f_Yu7cBp0esx2hUuQmLAr1", - "rank": "species", - "label": "× Dupoa labradorica (Steud.) J.Cay. & Darbysh.", - "scientificName": "× Dupoa labradorica", - "authorship": "(Steud.) J.Cay. & Darbysh.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:× Dupoa J.Cay. & Darbysh.|FAMILY:Poaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 2, - "inputRank": "", - "inputName": "Hedyosmum mexicanum", - "matchType": "variant", - "ID": "pEpl3JT6UK7P5tKH1KQp-0", - "rank": "species", - "label": "Hedyosmum mexicanum Cordem. ex Baill.", - "scientificName": "Hedyosmum mexicanum", - "authorship": "Cordem. ex Baill.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Hedyosmum Sw.|FAMILY:Chloranthaceae R. Br. ex Sims|ORDER:Chloranthales Mart.|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 3, - "inputRank": "", - "inputName": "Metrosideros polymorpha Gaudich.", - "matchType": "exact", - "ID": "F53jY6wV-sN79_VlpPtqY1", - "rank": "species", - "label": "Metrosideros polymorpha Gaudich.", - "scientificName": "Metrosideros polymorpha", - "authorship": "Gaudich.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Metrosideros Banks ex Gaertn.|SUBFAMILY:Myrtoideae Sweet|FAMILY:Myrtaceae Juss.|ORDER:Myrtales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 4, - "inputRank": "", - "inputName": "Terminalia sericea", - "matchType": "variant", - "ID": "RDkO9iPvGs8ABKcoPPA_R1", - "rank": "species", - "label": "Terminalia sericea Burch. ex DC.", - "scientificName": "Terminalia sericea", - "authorship": "Burch. ex DC.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Terminalia L.|SUBFAMILY:Combretoideae Beilschm.|FAMILY:Combretaceae R. Br.|ORDER:Myrtales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 5, - "inputRank": "", - "inputName": "??Artocarpus obtusus", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 6, - "inputRank": "", - "inputName": "??Dryobalanops aromatica", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 7, - "inputRank": "", - "inputName": "??Ficus sp.", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 8, - "inputRank": "", - "inputName": "??Horsfieldia palidicaura", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 9, - "inputRank": "", - "inputName": "??Madhuca carassipes", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 10, - "inputRank": "", - "inputName": "??Parishia sericea", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 11, - "inputRank": "", - "inputName": "??Shorea fallax", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": "", - "inputRank": "", - "inputName": "", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "NOT_INTERPRETED;UNPARSABLE_NAME" - }, - { - "inputID": 13, - "inputRank": "", - "inputName": "#Acacia?iteaphylla?F.Muell. ex Benth.", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 14, - "inputRank": "", - "inputName": "#Acacia?saligna?(Labill.) H.L.Wendl.", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 15, - "inputRank": "", - "inputName": "(Asteraceae2 sp.", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 16, - "inputRank": "", - "inputName": "(fabaceae)", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 17, - "inputRank": "", - "inputName": "(hippocrateaceae) atenumembra", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 18, - "inputRank": "", - "inputName": "(lauraceae) chiquita", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 19, - "inputRank": "", - "inputName": "(lauraceae) impresofalso", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 20, - "inputRank": "", - "inputName": "(lauraceae) pubescente", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 21, - "inputRank": "", - "inputName": "(malpighiaceae) bulondu", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 22, - "inputRank": "", - "inputName": "(myrtaceae) cortezapeq", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 23, - "inputRank": "", - "inputName": "(myrtaceae) smedcheilo", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 24, - "inputRank": "", - "inputName": "(picramniaceae) sp.nov.", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 25, - "inputRank": "", - "inputName": "(u_angio11492 sp", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 26, - "inputRank": "", - "inputName": "(u_angio5 sp", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 27, - "inputRank": "", - "inputName": "(u_Araceae sp11579", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 28, - "inputRank": "", - "inputName": "(u_Aster14327 sp", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 29, - "inputRank": "", - "inputName": "(u_Crasulaceae sp14326", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 30, - "inputRank": "", - "inputName": "(u_Herb2874 sp", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 31, - "inputRank": "", - "inputName": "(u_liana sp6402", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 32, - "inputRank": "", - "inputName": "(u_Malphig sp6395", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 33, - "inputRank": "", - "inputName": "(u_nanophyte sp6378", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 34, - "inputRank": "", - "inputName": "(u_Orchid3599 sp", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 35, - "inputRank": "", - "inputName": "(u_Poaceae sp1", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 36, - "inputRank": "", - "inputName": "(u_Poaceae sp2049", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 37, - "inputRank": "", - "inputName": "(u_Polypodiaceae sp6388", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 38, - "inputRank": "", - "inputName": "(u_Solana11399 sp", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 39, - "inputRank": "", - "inputName": "(u_Vitaceae sp14439", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 40, - "inputRank": "", - "inputName": "?Betulaceae sp.", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "INDETERMINED" - }, - { - "inputID": 41, - "inputRank": "", - "inputName": "?Pachygone ovata", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "PARTIALLY_PARSABLE_NAME" - }, - { - "inputID": 42, - "inputRank": "", - "inputName": "10 Tree species", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 43, - "inputRank": "", - "inputName": 1398, - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 44, - "inputRank": "", - "inputName": "5 Tall Catinga species", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 45, - "inputRank": "", - "inputName": "8 Mixed forest species", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 46, - "inputRank": "", - "inputName": "9 Tree species", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 47, - "inputRank": "", - "inputName": "Aa argyrolepis", - "matchType": "variant", - "ID": "HzruoTd7anNk90aF3DPf7", - "rank": "species", - "label": "Aa argyrolepis Rchb.f.", - "scientificName": "Aa argyrolepis", - "authorship": "Rchb.f.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 48, - "inputRank": "", - "inputName": "Aa denticulata", - "matchType": "variant", - "ID": "bzgvV2pJfO7r6WK4E4JAL0", - "rank": "species", - "label": "Aa denticulata Schltr.", - "scientificName": "Aa denticulata", - "authorship": "Schltr.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 49, - "inputRank": "", - "inputName": "Aa leucantha", - "matchType": "variant", - "ID": "GEzuA4SJNfuo78sxEfT631", - "rank": "species", - "label": "Aa leucantha (Rchb.f.) Schltr.", - "scientificName": "Aa leucantha", - "authorship": "(Rchb.f.) Schltr.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 50, - "inputRank": "", - "inputName": "Aa matthewsii", - "matchType": "variant", - "ID": "ehMUwBLNrANNDdhC1D7up2", - "rank": "species", - "label": "Aa matthewsii (Rchb.f.) Schltr.", - "scientificName": "Aa matthewsii", - "authorship": "(Rchb.f.) Schltr.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 51, - "inputRank": "", - "inputName": "Aa rosei", - "matchType": "variant", - "ID": "F5RifrVAXB9V5lOLd4bjd2", - "rank": "species", - "label": "Aa rosei Ames", - "scientificName": "Aa rosei", - "authorship": "Ames", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 52, - "inputRank": "", - "inputName": "Aa trilobulata", - "matchType": "variant", - "ID": "22ixDY1ArS9U0WmqzLBCA0", - "rank": "species", - "label": "Aa trilobulata Schltr.", - "scientificName": "Aa trilobulata", - "authorship": "Schltr.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Aa Rchb.f.|FAMILY:Orchidaceae|ORDER:Asparagales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 53, - "inputRank": "", - "inputName": "A-Agroelymus bowdenii", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 54, - "inputRank": "", - "inputName": "A-Argyrautia degeneri", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 55, - "inputRank": "", - "inputName": "Abama americana", - "matchType": "variant", - "ID": "B4INu1ljBsOhD_fMqns7-2", - "rank": "species", - "label": "Abama americana (Ker Gawl.) Morong", - "scientificName": "Abama americana", - "authorship": "(Ker Gawl.) Morong", - "status": "synonym", - "acceptedName": "Narthecium americanum Ker Gawl.", - "classification": "SPECIES:Narthecium americanum Ker Gawl.|GENUS:Narthecium Huds.|FAMILY:Nartheciaceae|ORDER:Dioscoreales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 56, - "inputRank": "", - "inputName": "Abarema adenophora", - "matchType": "variant", - "ID": "-ScsbDkWmvfN7C1Jwe3Py", - "rank": "species", - "label": "Abarema adenophora (Ducke) Barneby & J.W.Grimes", - "scientificName": "Abarema adenophora", - "authorship": "(Ducke) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba adenophora (Ducke) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba adenophora (Ducke) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 57, - "inputRank": "", - "inputName": "Abarema auriculata", - "matchType": "variant", - "ID": "j_pJUPXRWEQB8pOsMMCFh1", - "rank": "species", - "label": "Abarema auriculata (Benth.) Barneby & J.W.Grimes", - "scientificName": "Abarema auriculata", - "authorship": "(Benth.) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba auriculata (Benth.) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba auriculata (Benth.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 58, - "inputRank": "", - "inputName": "Abarema brachystachya", - "matchType": "variant", - "ID": "56wFod7HQVutBCgLusMJY", - "rank": "species", - "label": "Abarema brachystachya (DC.) Barneby & J.W.Grimes", - "scientificName": "Abarema brachystachya", - "authorship": "(DC.) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba brachystachya (DC.) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba brachystachya (DC.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 59, - "inputRank": "", - "inputName": "Abarema cochleata", - "matchType": "variant", - "ID": "DEU19AMASCQHDWipCGjDf0", - "rank": "species", - "label": "Abarema cochleata (Willd.) Barneby & J.W.Grimes", - "scientificName": "Abarema cochleata", - "authorship": "(Willd.) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba cochleata (Willd.) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba cochleata (Willd.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 60, - "inputRank": "", - "inputName": "Abarema curvicarpa", - "matchType": "variant", - "ID": "F_LVKha0vGtI5_2ZvXS4_0", - "rank": "species", - "label": "Abarema curvicarpa (H.S.Irwin) Barneby & J.W.Grimes", - "scientificName": "Abarema curvicarpa", - "authorship": "(H.S.Irwin) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba curvicarpa (H.S.Irwin) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba curvicarpa (H.S.Irwin) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 61, - "inputRank": "", - "inputName": "Abarema gallorum", - "matchType": "variant", - "ID": "HNlawyopeHQZ6_VdYz1FQ2", - "rank": "species", - "label": "Abarema gallorum Barneby & J.W.Grimes", - "scientificName": "Abarema gallorum", - "authorship": "Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba gallorum (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba gallorum (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 62, - "inputRank": "", - "inputName": "Abarema jupunba", - "matchType": "variant", - "ID": "h4jGkCtKNaf07dRMspslJ", - "rank": "species", - "label": "Abarema jupunba (Willd.) Britton & Killip", - "scientificName": "Abarema jupunba", - "authorship": "(Willd.) Britton & Killip", - "status": "synonym", - "acceptedName": "Jupunba trapezifolia var. micradenia (Benth.) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "VARIETY:Jupunba trapezifolia var. micradenia (Benth.) M.V.B.Soares, M.P.Morim & Iganci|SPECIES:Jupunba trapezifolia (Vahl) Moldenke|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 63, - "inputRank": "", - "inputName": "Abarema laeta", - "matchType": "variant", - "ID": "BUQSvsYFyh7T18v3Y_OpU0", - "rank": "species", - "label": "Abarema laeta (Benth.) Barneby & J.W.Grimes", - "scientificName": "Abarema laeta", - "authorship": "(Benth.) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba laeta (Benth.) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba laeta (Benth.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 64, - "inputRank": "", - "inputName": "Abarema leucophylla", - "matchType": "variant", - "ID": "zPm1np9pYb8oAKjanKg0h", - "rank": "species", - "label": "Abarema leucophylla (Spruce ex Benth.) Barneby & J.W.Grimes", - "scientificName": "Abarema leucophylla", - "authorship": "(Spruce ex Benth.) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba leucophylla (Spruce ex Benth.) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba leucophylla (Spruce ex Benth.) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 65, - "inputRank": "", - "inputName": "Abarema macradenia", - "matchType": "variant", - "ID": "qTmopQw_cnteCpSYGTXw40", - "rank": "species", - "label": "Abarema macradenia (Pittier) Barneby & J.W.Grimes", - "scientificName": "Abarema macradenia", - "authorship": "(Pittier) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba macradenia (Pittier) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba macradenia (Pittier) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 66, - "inputRank": "", - "inputName": "Abarema maestrensis", - "matchType": "variant", - "ID": "SP3WeGqLEA92AlBsqGA-g", - "rank": "species", - "label": "Abarema maestrensis (Urb.) Bässler", - "scientificName": "Abarema maestrensis", - "authorship": "(Urb.) Bässler", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abarema Pittier|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 67, - "inputRank": "", - "inputName": "Abarema nipensis", - "matchType": "variant", - "ID": "7EKkhAW5sbtc-OQ6Z00PT0", - "rank": "species", - "label": "Abarema nipensis (Britton) Barneby & J.W.Grimes", - "scientificName": "Abarema nipensis", - "authorship": "(Britton) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba nipensis (Britton) Britton & Rose", - "classification": "SPECIES:Jupunba nipensis (Britton) Britton & Rose|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 68, - "inputRank": "", - "inputName": "Abarema oxyphyllidia", - "matchType": "variant", - "ID": "wWTSsVwmR0AP0_11w-vDz0", - "rank": "species", - "label": "Abarema oxyphyllidia Barneby & J.W.Grimes", - "scientificName": "Abarema oxyphyllidia", - "authorship": "Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba oxyphyllidia (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba oxyphyllidia (Barneby & J.W.Grimes) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 69, - "inputRank": "", - "inputName": "Abarema villifera", - "matchType": "variant", - "ID": "bdDLMxPIub7u8K9cLUytN0", - "rank": "species", - "label": "Abarema villifera (Ducke) Barneby & J.W.Grimes", - "scientificName": "Abarema villifera", - "authorship": "(Ducke) Barneby & J.W.Grimes", - "status": "synonym", - "acceptedName": "Jupunba villifera (Ducke) M.V.B.Soares, M.P.Morim & Iganci", - "classification": "SPECIES:Jupunba villifera (Ducke) M.V.B.Soares, M.P.Morim & Iganci|GENUS:Jupunba Britton & Rose|FAMILY:Fabaceae|ORDER:Fabales Bromhead|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 70, - "inputRank": "", - "inputName": "Abatia americana", - "matchType": "variant", - "ID": "Hgsps3snnYQb9hepgL4yq1", - "rank": "species", - "label": "Abatia americana (Gardner) Eichler", - "scientificName": "Abatia americana", - "authorship": "(Gardner) Eichler", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abatia Ruiz & Pav.|FAMILY:Salicaceae Mirb.|ORDER:Malpighiales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 71, - "inputRank": "", - "inputName": "Abatia glabra", - "matchType": "variant", - "ID": "uDG3lo3mOHdUCpOk5v2U1", - "rank": "species", - "label": "Abatia glabra Sleumer", - "scientificName": "Abatia glabra", - "authorship": "Sleumer", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abatia Ruiz & Pav.|FAMILY:Salicaceae Mirb.|ORDER:Malpighiales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 72, - "inputRank": "", - "inputName": "Abatia rugosa", - "matchType": "variant", - "ID": "8_UtE2oZA0v7C4APQch8B1", - "rank": "species", - "label": "Abatia rugosa Ruiz & Pav.", - "scientificName": "Abatia rugosa", - "authorship": "Ruiz & Pav.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abatia Ruiz & Pav.|FAMILY:Salicaceae Mirb.|ORDER:Malpighiales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 73, - "inputRank": "", - "inputName": "Abelia", - "matchType": "variant", - "ID": "DIAOdF0VHucc90hs_fkUI0", - "rank": "genus", - "label": "Abelia R. Br.", - "scientificName": "Abelia", - "authorship": "R. Br.", - "status": "accepted", - "acceptedName": "", - "classification": "SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 74, - "inputRank": "", - "inputName": "Abelia chinensis", - "matchType": "variant", - "ID": "K0FvBPBmtpcBCxk1ote9A0", - "rank": "species", - "label": "Abelia chinensis R. Br.", - "scientificName": "Abelia chinensis", - "authorship": "R. Br.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 75, - "inputRank": "", - "inputName": "Abelia engleriana", - "matchType": "variant", - "ID": "r4vqKWgz48cFBpH8k2jmq1", - "rank": "species", - "label": "Abelia engleriana (Graebn.) Rehder", - "scientificName": "Abelia engleriana", - "authorship": "(Graebn.) Rehder", - "status": "synonym", - "acceptedName": "Abelia macrotera var. engleriana (Graebn.) Landrein", - "classification": "VARIETY:Abelia macrotera var. engleriana (Graebn.) Landrein|SPECIES:Abelia macrotera (Graebn. & Buchw.) Rehder|GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 76, - "inputRank": "", - "inputName": "Abelia macrotera (Graebn. Et Buchw.) Rehd.", - "matchType": "variant", - "ID": "SCvL400UMudfDpgDV9EbU0", - "rank": "species", - "label": "Abelia macrotera (Graebn. & Buchw.) Rehder", - "scientificName": "Abelia macrotera", - "authorship": "(Graebn. & Buchw.) Rehder", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 77, - "inputRank": "", - "inputName": "Abelia sp", - "matchType": "variant", - "ID": "DIAOdF0VHucc90hs_fkUI0", - "rank": "genus", - "label": "Abelia R. Br.", - "scientificName": "Abelia", - "authorship": "R. Br.", - "status": "accepted", - "acceptedName": "", - "classification": "SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "INDETERMINED" - }, - { - "inputID": 78, - "inputRank": "", - "inputName": "Abelia uniflora", - "matchType": "variant", - "ID": "4tTnTY3mlF920GHk2pFR-1", - "rank": "species", - "label": "Abelia uniflora R. Br.", - "scientificName": "Abelia uniflora", - "authorship": "R. Br.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abelia R. Br.|SUBFAMILY:Linnaeoideae Raf.|FAMILY:Caprifoliaceae Juss.|ORDER:Dipsacales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 79, - "inputRank": "", - "inputName": "Abelia_xgrandiflora", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 80, - "inputRank": "", - "inputName": "Abelmoschus", - "matchType": "variant", - "ID": "I1im3Xq0jTf24xzW-GDKr2", - "rank": "genus", - "label": "Abelmoschus Medik.", - "scientificName": "Abelmoschus", - "authorship": "Medik.", - "status": "accepted", - "acceptedName": "", - "classification": "SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 81, - "inputRank": "", - "inputName": "Abelmoschus esculentus", - "matchType": "variant", - "ID": "joaWuR8_2GAe9_JLZgiLH2", - "rank": "species", - "label": "Abelmoschus esculentus (L.) Moench", - "scientificName": "Abelmoschus esculentus", - "authorship": "(L.) Moench", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abelmoschus Medik.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 82, - "inputRank": "", - "inputName": "Abelmoschus ficulneus (L.) Wight & Arn.", - "matchType": "variant", - "ID": "cQRVMr08yX7eACzSq_li_1", - "rank": "species", - "label": "Abelmoschus ficulneus (L.) Wight & Arn. ex Wight", - "scientificName": "Abelmoschus ficulneus", - "authorship": "(L.) Wight & Arn. ex Wight", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abelmoschus Medik.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 83, - "inputRank": "", - "inputName": "Abelmoschus moschatus", - "matchType": "variant", - "ID": "kW_mJEewg-dN98FKWg1lC2", - "rank": "species", - "label": "Abelmoschus moschatus (L.) Medik.", - "scientificName": "Abelmoschus moschatus", - "authorship": "(L.) Medik.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abelmoschus Medik.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 84, - "inputRank": "", - "inputName": "Abelmoshus esculentus (L.) Moench", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 85, - "inputRank": "", - "inputName": "Abies faxoniana", - "matchType": "variant", - "ID": "ZYxIqzF2_kPA7lDlet4Sw2", - "rank": "species", - "label": "Abies faxoniana Rehder & E.H.Wilson", - "scientificName": "Abies faxoniana", - "authorship": "Rehder & E.H.Wilson", - "status": "synonym", - "acceptedName": "Abies fargesii var. faxoniana (Rehder & E.H.Wilson) Tang S.Liu", - "classification": "VARIETY:Abies fargesii var. faxoniana (Rehder & E.H.Wilson) Tang S.Liu|SPECIES:Abies fargesii Franch.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 86, - "inputRank": "", - "inputName": "Abies ?shastensis (Lemmon) Lemmon [magnifica ? procera]", - "matchType": "variant", - "ID": "oJcwu0yVYcvx58sykTyha1", - "rank": "genus", - "label": "Abies Mill.", - "scientificName": "Abies", - "authorship": "Mill.", - "status": "accepted", - "acceptedName": "", - "classification": "FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "PARTIALLY_PARSABLE_NAME" - }, - { - "inputID": 87, - "inputRank": "", - "inputName": "Abies amabilis (Douglas ex Louden) Douglas ex Forbes", - "matchType": "variant", - "ID": "OF3ByWuRequZ28R-PwNya0", - "rank": "species", - "label": "Abies amabilis (Douglas ex Loudon) J.Forbes", - "scientificName": "Abies amabilis", - "authorship": "(Douglas ex Loudon) J.Forbes", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 88, - "inputRank": "", - "inputName": "Abies balsamea (L.) Mill. var. balsamea", - "matchType": "variant", - "ID": "2NOu3wWzmdQI3SwP5se0O0", - "rank": "form", - "label": "Abies balsamea f. balsamea", - "scientificName": "Abies balsamea f. balsamea", - "authorship": "", - "status": "synonym", - "acceptedName": "Abies balsamea (L.) Mill.", - "classification": "SPECIES:Abies balsamea (L.) Mill.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 89, - "inputRank": "", - "inputName": "Abies beshanzuensis", - "matchType": "variant", - "ID": "-GjhCunoKTNJAGjLYAvvE0", - "rank": "species", - "label": "Abies beshanzuensis M.H.Wu", - "scientificName": "Abies beshanzuensis", - "authorship": "M.H.Wu", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 90, - "inputRank": "", - "inputName": "Abies bornmuelleriana", - "matchType": "variant", - "ID": "Tt8WiVVFdGdl8lAbUI5Ic", - "rank": "species", - "label": "Abies bornmuelleriana Mattf.", - "scientificName": "Abies bornmuelleriana", - "authorship": "Mattf.", - "status": "synonym", - "acceptedName": "Abies nordmanniana subsp. equi-trojani (Asch. & Sint. ex Boiss.) Coode & Cullen", - "classification": "SUBSPECIES:Abies nordmanniana subsp. equi-trojani (Asch. & Sint. ex Boiss.) Coode & Cullen|SPECIES:Abies nordmanniana (Steven) Spach|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 91, - "inputRank": "", - "inputName": "Abies cephalonica J. W. Loudon", - "matchType": "variant", - "ID": "-uqeYbsE1Qvk-pcGiAf4G0", - "rank": "species", - "label": "Abies cephalonica Loudon", - "scientificName": "Abies cephalonica", - "authorship": "Loudon", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 92, - "inputRank": "", - "inputName": "Abies chensiensis", - "matchType": "variant", - "ID": "g04zL4-W_mAz3WpxInZ-R2", - "rank": "species", - "label": "Abies chensiensis Tiegh.", - "scientificName": "Abies chensiensis", - "authorship": "Tiegh.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 93, - "inputRank": "", - "inputName": "Abies cilicica (Antoine & Kotschy) Carriere ssp. isaurica Coode & Cullen", - "matchType": "variant", - "ID": "_LbUU7XXarej2OZLEWyC21", - "rank": "subspecies", - "label": "Abies cilicica subsp. isaurica Coode & Cullen", - "scientificName": "Abies cilicica subsp. isaurica", - "authorship": "Coode & Cullen", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abies cilicica (Antoine & Kotschy) Carrière|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 94, - "inputRank": "", - "inputName": "Abies concolor (Gordon & Glend.) Lindl. ex Hildebr.", - "matchType": "variant", - "ID": "yNGZP9I-z2A3CSDwtcQi-0", - "rank": "species", - "label": "Abies concolor (Gordon) Lindl. ex Hildebr.", - "scientificName": "Abies concolor", - "authorship": "(Gordon) Lindl. ex Hildebr.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 95, - "inputRank": "", - "inputName": "Abies concolor ssp. concolor", - "matchType": "variant", - "ID": "Nv6kf5Sr-Afe6CeHm2-LC0", - "rank": "variety", - "label": "Abies concolor var. concolor", - "scientificName": "Abies concolor var. concolor", - "authorship": "", - "status": "synonym", - "acceptedName": "Abies concolor (Gordon) Lindl. ex Hildebr.", - "classification": "SPECIES:Abies concolor (Gordon) Lindl. ex Hildebr.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 96, - "inputRank": "", - "inputName": "Abies delavayi Franch.", - "matchType": "exact", - "ID": "L8Q6ZpzWzddW70ySlPf6n2", - "rank": "species", - "label": "Abies delavayi Franch.", - "scientificName": "Abies delavayi", - "authorship": "Franch.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 97, - "inputRank": "", - "inputName": "Abies ernestii", - "matchType": "variant", - "ID": "qmjZpKXlpssdDC89W2fZX1", - "rank": "species", - "label": "Abies ernestii Rehder", - "scientificName": "Abies ernestii", - "authorship": "Rehder", - "status": "synonym", - "acceptedName": "Abies recurvata var. ernestii (Rehder) Rushforth", - "classification": "VARIETY:Abies recurvata var. ernestii (Rehder) Rushforth|SPECIES:Abies recurvata Mast.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 98, - "inputRank": "", - "inputName": "Abies fabri (Mast.) Craib", - "matchType": "exact", - "ID": "BC0a4W_TTbuv60xh_2IWL0", - "rank": "species", - "label": "Abies fabri (Mast.) Craib", - "scientificName": "Abies fabri", - "authorship": "(Mast.) Craib", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 99, - "inputRank": "", - "inputName": "Abies ferreana", - "matchType": "variant", - "ID": "U6Yw67urVY8O8pTd8e0Ox1", - "rank": "species", - "label": "Abies ferreana Bordères & Gaussen", - "scientificName": "Abies ferreana", - "authorship": "Bordères & Gaussen", - "status": "synonym", - "acceptedName": "Abies forrestii var. ferreana (Bordères & Gaussen) Farjon & Silba", - "classification": "VARIETY:Abies forrestii var. ferreana (Bordères & Gaussen) Farjon & Silba|SPECIES:Abies forrestii Coltm.-Rog.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 100, - "inputRank": "", - "inputName": "Abies flinckii", - "matchType": "variant", - "ID": "RcrbjMDUoFAa94ScIqglG1", - "rank": "species", - "label": "Abies flinckii Rushforth", - "scientificName": "Abies flinckii", - "authorship": "Rushforth", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 101, - "inputRank": "", - "inputName": "Abies fraseri", - "matchType": "variant", - "ID": "m_0u2Lx-z-v50GhESoZk10", - "rank": "species", - "label": "Abies fraseri (Pursh) Poir.", - "scientificName": "Abies fraseri", - "authorship": "(Pursh) Poir.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 102, - "inputRank": "", - "inputName": "Abies grandis", - "matchType": "variant", - "ID": "kp8OG_WDXxPDBKB_PR0UD0", - "rank": "species", - "label": "Abies grandis (Douglas ex D.Don) Lindl.", - "scientificName": "Abies grandis", - "authorship": "(Douglas ex D.Don) Lindl.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 103, - "inputRank": "", - "inputName": "Abies guatemalensis", - "matchType": "variant", - "ID": "njcsPsDMRkQrEW4MBprq50", - "rank": "species", - "label": "Abies guatemalensis Rehder", - "scientificName": "Abies guatemalensis", - "authorship": "Rehder", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 104, - "inputRank": "", - "inputName": "Abies homolepis", - "matchType": "variant", - "ID": "f8CeNU0xx2Ae5Sp13tcfB2", - "rank": "species", - "label": "Abies homolepis Siebold & Zucc.", - "scientificName": "Abies homolepis", - "authorship": "Siebold & Zucc.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 105, - "inputRank": "", - "inputName": "Abies jaliscana", - "matchType": "variant", - "ID": "UfZnPJ41RQOcD42UufUA70", - "rank": "species", - "label": "Abies jaliscana (Martínez) Mantilla, Shalisko & A.Vázquez", - "scientificName": "Abies jaliscana", - "authorship": "(Martínez) Mantilla, Shalisko & A.Vázquez", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 106, - "inputRank": "", - "inputName": "Abies koreana E.H.Wilson", - "matchType": "exact", - "ID": "pyftbIMhNvQ878jgWcwsI2", - "rank": "species", - "label": "Abies koreana E.H.Wilson", - "scientificName": "Abies koreana", - "authorship": "E.H.Wilson", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 107, - "inputRank": "", - "inputName": "Abies lasiocarpa var. arizonica", - "matchType": "variant", - "ID": "xyVqGYp553AbDx2shAlun2", - "rank": "variety", - "label": "Abies lasiocarpa var. arizonica (Merriam) Lemmon", - "scientificName": "Abies lasiocarpa var. arizonica", - "authorship": "(Merriam) Lemmon", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abies lasiocarpa (Hook.) Nutt.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 108, - "inputRank": "", - "inputName": "Abies magnifica A. Murray", - "matchType": "variant", - "ID": "WkMAPkQs1sAj6xL2_fzbj2", - "rank": "species", - "label": "Abies magnifica A.Murray bis", - "scientificName": "Abies magnifica", - "authorship": "A.Murray bis", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 109, - "inputRank": "", - "inputName": "Abies magnifica A.Murray var. shastensis Lemmon", - "matchType": "variant", - "ID": "Let5Vm5GKVvIC8lxVrxrE", - "rank": "variety", - "label": "Abies magnifica var. shastensis Lemmon", - "scientificName": "Abies magnifica var. shastensis", - "authorship": "Lemmon", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abies magnifica A.Murray bis|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 110, - "inputRank": "", - "inputName": "Abies marocana", - "matchType": "variant", - "ID": "9mYR7vFU1K9Q5lFqYt70F0", - "rank": "species", - "label": "Abies marocana Trab.", - "scientificName": "Abies marocana", - "authorship": "Trab.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 111, - "inputRank": "", - "inputName": "Abies nephrolepis (Trautv.) Maxim", - "matchType": "variant", - "ID": "enOHXselt97780TytM5Cv2", - "rank": "species", - "label": "Abies nephrolepis (Trautv. ex Maxim.) Maxim.", - "scientificName": "Abies nephrolepis", - "authorship": "(Trautv. ex Maxim.) Maxim.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 112, - "inputRank": "", - "inputName": "Abies nordmanniana (Steven) Spach subsp. nordmanniana", - "matchType": "variant", - "ID": "QsRvNnkQnFd55KaVoIw_Z1", - "rank": "subspecies", - "label": "Abies nordmanniana subsp. nordmanniana", - "scientificName": "Abies nordmanniana subsp. nordmanniana", - "authorship": "", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abies nordmanniana (Steven) Spach|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 113, - "inputRank": "", - "inputName": "Abies numidica", - "matchType": "variant", - "ID": "oDRpyaZCENOs14CZ4Wfrl1", - "rank": "species", - "label": "Abies numidica de Lannoy ex Carrière", - "scientificName": "Abies numidica", - "authorship": "de Lannoy ex Carrière", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 114, - "inputRank": "", - "inputName": "Abies phanerolepis", - "matchType": "variant", - "ID": "kMqBLdDvjZeY0WtjPYYAB1", - "rank": "species", - "label": "Abies phanerolepis (Fernald) T.S.Liu", - "scientificName": "Abies phanerolepis", - "authorship": "(Fernald) T.S.Liu", - "status": "synonym", - "acceptedName": "Abies balsamea var. phanerolepis Fernald", - "classification": "VARIETY:Abies balsamea var. phanerolepis Fernald|SPECIES:Abies balsamea (L.) Mill.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 115, - "inputRank": "", - "inputName": "Abies pinsapo Boiss. var. glauca", - "matchType": "variant", - "ID": "eg3kETuVI7sH5OxlnHTTw1", - "rank": "form", - "label": "Abies pinsapo f. glauca (Carrière) Beissn.", - "scientificName": "Abies pinsapo f. glauca", - "authorship": "(Carrière) Beissn.", - "status": "synonym", - "acceptedName": "Abies pinsapo Boiss.", - "classification": "SPECIES:Abies pinsapo Boiss.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 116, - "inputRank": "", - "inputName": "Abies recurvata", - "matchType": "variant", - "ID": "g87NAFKLrpO-9pfZbgvWg1", - "rank": "species", - "label": "Abies recurvata Mast.", - "scientificName": "Abies recurvata", - "authorship": "Mast.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 117, - "inputRank": "", - "inputName": "Abies religiosa (Kunth) Schltdl. & Cham. var. emarginata", - "matchType": "variant", - "ID": "fXYOEmIBYQt83_9Z9LkKa", - "rank": "variety", - "label": "Abies religiosa var. emarginata Loock & Martínez ex Martínez", - "scientificName": "Abies religiosa var. emarginata", - "authorship": "Loock & Martínez ex Martínez", - "status": "synonym", - "acceptedName": "Abies jaliscana (Martínez) Mantilla, Shalisko & A.Vázquez", - "classification": "SPECIES:Abies jaliscana (Martínez) Mantilla, Shalisko & A.Vázquez|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 118, - "inputRank": "", - "inputName": "Abies sachalinensis (F.Schmidt) Mast. var. mayriana Miyabe & Kud?", - "matchType": "variant", - "ID": "_giKXaYvRXQK7tWDcPFlD", - "rank": "variety", - "label": "Abies sachalinensis var. mayriana Miyabe & Kudô", - "scientificName": "Abies sachalinensis var. mayriana", - "authorship": "Miyabe & Kudô", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abies sachalinensis (F.Schmidt) Mast.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "UNUSUAL_NAME_CHARACTERS;DOUBTFUL_NAME;PARTIALLY_PARSABLE_NAME" - }, - { - "inputID": 119, - "inputRank": "", - "inputName": "Abies shastensis", - "matchType": "variant", - "ID": "Ly1NqfaWLnNIAKCLScDR8", - "rank": "species", - "label": "Abies shastensis Lemmon", - "scientificName": "Abies shastensis", - "authorship": "Lemmon", - "status": "synonym", - "acceptedName": "Abies magnifica var. shastensis Lemmon", - "classification": "VARIETY:Abies magnifica var. shastensis Lemmon|SPECIES:Abies magnifica A.Murray bis|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 120, - "inputRank": "", - "inputName": "Abies sp", - "matchType": "variant", - "ID": "oJcwu0yVYcvx58sykTyha1", - "rank": "genus", - "label": "Abies Mill.", - "scientificName": "Abies", - "authorship": "Mill.", - "status": "accepted", - "acceptedName": "", - "classification": "FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "INDETERMINED" - }, - { - "inputID": 121, - "inputRank": "", - "inputName": "Abies spectabilis (D. Don) Spach", - "matchType": "exact", - "ID": "ToHQ5fFUpXAq2_OqLumUq0", - "rank": "species", - "label": "Abies spectabilis (D.Don) Spach", - "scientificName": "Abies spectabilis", - "authorship": "(D.Don) Spach", - "status": "synonym", - "acceptedName": "Abies spectabilis (D.Don) Mirb.", - "classification": "SPECIES:Abies spectabilis (D.Don) Mirb.|GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 122, - "inputRank": "", - "inputName": "Abies veitchii", - "matchType": "variant", - "ID": "keI9YqXVQSsZ90B2ySIwT1", - "rank": "species", - "label": "Abies veitchii Lindl.", - "scientificName": "Abies veitchii", - "authorship": "Lindl.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 123, - "inputRank": "", - "inputName": "Abies vejarii Mart?nez", - "matchType": "variant", - "ID": "WMLE2QBuP7fp4_6OnR0LF2", - "rank": "species", - "label": "Abies vejarii Martínez", - "scientificName": "Abies vejarii", - "authorship": "Martínez", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "UNUSUAL_NAME_CHARACTERS;DOUBTFUL_NAME;PARTIALLY_PARSABLE_NAME" - }, - { - "inputID": 124, - "inputRank": "", - "inputName": "Abies ziyuanensis", - "matchType": "variant", - "ID": "PjaHyLQMU6A9ExGIRygww2", - "rank": "species", - "label": "Abies ziyuanensis L.K.Fu & S.L.Mo", - "scientificName": "Abies ziyuanensis", - "authorship": "L.K.Fu & S.L.Mo", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abies Mill.|FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 125, - "inputRank": "", - "inputName": "Abies?spectabilis?(D.?Don)?Mirbel", - "matchType": "variant", - "ID": "oJcwu0yVYcvx58sykTyha1", - "rank": "genus", - "label": "Abies Mill.", - "scientificName": "Abies", - "authorship": "Mill.", - "status": "accepted", - "acceptedName": "", - "classification": "FAMILY:Pinaceae Spreng. ex Rudolphi|ORDER:Pinales Gorozh.|SUBCLASS:Pinidae Cronquist, Takht. & W.Zimm.|CLASS:Pinopsida Burnett|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "UNUSUAL_NAME_CHARACTERS;DOUBTFUL_NAME;PARTIALLY_PARSABLE_NAME" - }, - { - "inputID": 126, - "inputRank": "", - "inputName": "Abies_religiosa_AJU", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 127, - "inputRank": "", - "inputName": "Abildgaardia abortiva (Steud.) Lye", - "matchType": "exact", - "ID": "zSbfadWi0dcmEWKGsHW8e0", - "rank": "species", - "label": "Abildgaardia abortiva (Steud.) Lye", - "scientificName": "Abildgaardia abortiva", - "authorship": "(Steud.) Lye", - "status": "synonym", - "acceptedName": "Bulbostylis abortiva (Steud.) C.B.Clarke", - "classification": "SPECIES:Bulbostylis abortiva (Steud.) C.B.Clarke|GENUS:Bulbostylis Kunth|FAMILY:Cyperaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 128, - "inputRank": "", - "inputName": "Abildgaardia coleotricha", - "matchType": "variant", - "ID": "xyG2XpX7eq9C00Yy9GRf12", - "rank": "species", - "label": "Abildgaardia coleotricha (Hochst. ex A.Rich.) Lye", - "scientificName": "Abildgaardia coleotricha", - "authorship": "(Hochst. ex A.Rich.) Lye", - "status": "synonym", - "acceptedName": "Bulbostylis coleotricha (Hochst. ex A.Rich.) C.B.Clarke", - "classification": "SPECIES:Bulbostylis coleotricha (Hochst. ex A.Rich.) C.B.Clarke|GENUS:Bulbostylis Kunth|FAMILY:Cyperaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 129, - "inputRank": "", - "inputName": "Abildgaardia natalensis", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 130, - "inputRank": "", - "inputName": "Abildgaardia polygama", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 131, - "inputRank": "", - "inputName": "Abiu caramuri", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 132, - "inputRank": "", - "inputName": "ABIURANA", - "matchType": "none", - "ID": "", - "rank": "", - "label": "", - "scientificName": "", - "authorship": "", - "status": "", - "acceptedName": "", - "classification": "", - "issues": "" - }, - { - "inputID": 133, - "inputRank": "", - "inputName": "Abolboda americana", - "matchType": "variant", - "ID": "VvrYN3NRe0968xYIeKZNx2", - "rank": "species", - "label": "Abolboda americana (Aubl.) Lanj.", - "scientificName": "Abolboda americana", - "authorship": "(Aubl.) Lanj.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 134, - "inputRank": "", - "inputName": "Abolboda egleri", - "matchType": "variant", - "ID": "9nZ3AIx2yPugAh8NVQ3R61", - "rank": "species", - "label": "Abolboda egleri L.B.Sm. & Downs", - "scientificName": "Abolboda egleri", - "authorship": "L.B.Sm. & Downs", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 135, - "inputRank": "", - "inputName": "Abolboda linearifolia", - "matchType": "variant", - "ID": "Ob8SRpTDeAA67S235ddqU", - "rank": "species", - "label": "Abolboda linearifolia Maguire", - "scientificName": "Abolboda linearifolia", - "authorship": "Maguire", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 136, - "inputRank": "", - "inputName": "Abolboda poarchon Seub.", - "matchType": "exact", - "ID": "9OPu2_VR9k9F6pp5N-Jbb", - "rank": "species", - "label": "Abolboda poarchon Seub.", - "scientificName": "Abolboda poarchon", - "authorship": "Seub.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abolboda Bonpl.|FAMILY:Xyridaceae|ORDER:Poales|CLASS:Liliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 137, - "inputRank": "", - "inputName": "Abortopetalum sandwicense", - "matchType": "variant", - "ID": "FDJwMSbun3766Guys9Pdp", - "rank": "species", - "label": "Abortopetalum sandwicense O. Deg.", - "scientificName": "Abortopetalum sandwicense", - "authorship": "O. Deg.", - "status": "synonym", - "acceptedName": "Abutilon sandwicense (O. Deg.) Christoph.", - "classification": "SPECIES:Abutilon sandwicense (O. Deg.) Christoph.|GENUS:Abutilon Tourn. ex Mill.|SUBFAMILY:Malvoideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 138, - "inputRank": "", - "inputName": "Abrahamia grandidieri", - "matchType": "variant", - "ID": "2m8MPsZBToNl6hX_SW5bE1", - "rank": "species", - "label": "Abrahamia grandidieri (Engl.) Randrian. & Lowry", - "scientificName": "Abrahamia grandidieri", - "authorship": "(Engl.) Randrian. & Lowry", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrahamia Randrian. & Lowry|FAMILY:Anacardiaceae R. Br.|ORDER:Sapindales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 139, - "inputRank": "", - "inputName": "Abrahamia louvelii", - "matchType": "variant", - "ID": "KrgiAF_9X7ez8KuHpodHA2", - "rank": "species", - "label": "Abrahamia louvelii (H. Perrier) Randrian. & Lowry", - "scientificName": "Abrahamia louvelii", - "authorship": "(H. Perrier) Randrian. & Lowry", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrahamia Randrian. & Lowry|FAMILY:Anacardiaceae R. Br.|ORDER:Sapindales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 140, - "inputRank": "", - "inputName": "Abrahamia thouvenotii", - "matchType": "variant", - "ID": "_VyZ4wqBqKeY74n79ac9_2", - "rank": "species", - "label": "Abrahamia thouvenotii (Lecomte) Randrian. & Lowry", - "scientificName": "Abrahamia thouvenotii", - "authorship": "(Lecomte) Randrian. & Lowry", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrahamia Randrian. & Lowry|FAMILY:Anacardiaceae R. Br.|ORDER:Sapindales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 141, - "inputRank": "", - "inputName": "Abrodictyum cupressoides", - "matchType": "variant", - "ID": "2uLocATlEIdJ4dS1ThcDC1", - "rank": "species", - "label": "Abrodictyum cupressoides (Desv.) Ebihara & Dubuisson", - "scientificName": "Abrodictyum cupressoides", - "authorship": "(Desv.) Ebihara & Dubuisson", - "status": "synonym", - "acceptedName": "Trichomanes cupressoides Desv.", - "classification": "SPECIES:Trichomanes cupressoides Desv.|GENUS:Trichomanes L.|SUBFAMILY:Trichomanoideae C.Presl|FAMILY:Hymenophyllaceae Mart.|ORDER:Hymenophyllales A.B.Frank|CLASS:Polypodiopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 142, - "inputRank": "", - "inputName": "Abroma augusta", - "matchType": "variant", - "ID": "lMc-Zdw-gIto-dDmeMCaO0", - "rank": "species", - "label": "Abroma augustum (L.) L. fil.", - "scientificName": "Abroma augustum", - "authorship": "(L.) L. fil.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abroma L.f.|SUBFAMILY:Byttnerioideae Burnett|FAMILY:Malvaceae Juss.|ORDER:Malvales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 143, - "inputRank": "", - "inputName": "Abronia × minor", - "matchType": "variant", - "ID": "762P_d5oVKfv8_oq7jYph1", - "rank": "species", - "label": "Abronia × minor Standl.", - "scientificName": "Abronia × minor", - "authorship": "Standl.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 144, - "inputRank": "", - "inputName": "Abronia ameliae Lundell", - "matchType": "exact", - "ID": "tykvIegyhesA5O0ncvpL30", - "rank": "species", - "label": "Abronia ameliae Lundell", - "scientificName": "Abronia ameliae", - "authorship": "Lundell", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 145, - "inputRank": "", - "inputName": "Abronia bolackii", - "matchType": "variant", - "ID": "jq-KePU8-hOI6OXJqSDs4", - "rank": "species", - "label": "Abronia bolackii N. D. Atwood, S. L. Welsh & K. D. Heil", - "scientificName": "Abronia bolackii", - "authorship": "N. D. Atwood, S. L. Welsh & K. D. Heil", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 146, - "inputRank": "", - "inputName": "Abronia cycloptera", - "matchType": "variant", - "ID": "IdGsSwfyflt024_au9KOk1", - "rank": "species", - "label": "Abronia cycloptera A. Gray", - "scientificName": "Abronia cycloptera", - "authorship": "A. Gray", - "status": "synonym", - "acceptedName": "Tripterocalyx micranthus (Torr.) Hook.", - "classification": "SPECIES:Tripterocalyx micranthus (Torr.) Hook.|GENUS:Tripterocalyx (Torr.) Hook.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 147, - "inputRank": "", - "inputName": "Abronia fragrans Nutt. ex Hook.", - "matchType": "exact", - "ID": "0GEGBaiJkRc16l720FRyS", - "rank": "species", - "label": "Abronia fragrans Nutt. ex Hook.", - "scientificName": "Abronia fragrans", - "authorship": "Nutt. ex Hook.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 148, - "inputRank": "", - "inputName": "Abronia latifolia", - "matchType": "variant", - "ID": "rX0iWcCIN17138qMk2Wq7", - "rank": "species", - "label": "Abronia latifolia Eschsch.", - "scientificName": "Abronia latifolia", - "authorship": "Eschsch.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 149, - "inputRank": "", - "inputName": "Abronia mellifera", - "matchType": "variant", - "ID": "qJ9pJE_8yXtT5tMzs74Px1", - "rank": "species", - "label": "Abronia mellifera Douglas", - "scientificName": "Abronia mellifera", - "authorship": "Douglas", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 150, - "inputRank": "", - "inputName": "Abronia nana S.Watson", - "matchType": "exact", - "ID": "ASZ6E_LzGosc5py2UQqLL1", - "rank": "species", - "label": "Abronia nana S. Watson", - "scientificName": "Abronia nana", - "authorship": "S. Watson", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 151, - "inputRank": "", - "inputName": "Abronia orbiculata", - "matchType": "variant", - "ID": "vEtredQykwPZ2WKvJxogS2", - "rank": "species", - "label": "Abronia orbiculata Standl.", - "scientificName": "Abronia orbiculata", - "authorship": "Standl.", - "status": "synonym", - "acceptedName": "Abronia turbinata Torr. ex S. Watson", - "classification": "SPECIES:Abronia turbinata Torr. ex S. Watson|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 152, - "inputRank": "", - "inputName": "Abronia pumila", - "matchType": "variant", - "ID": "Yb1TdisQtwdp7G7zgJuBP", - "rank": "species", - "label": "Abronia pumila Rydb.", - "scientificName": "Abronia pumila", - "authorship": "Rydb.", - "status": "synonym", - "acceptedName": "Abronia elliptica A. Nelson", - "classification": "SPECIES:Abronia elliptica A. Nelson|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 153, - "inputRank": "", - "inputName": "Abronia turbinata Torr. ex S. Watson", - "matchType": "exact", - "ID": "dIKAHs7-6DPPE_KkIN5-L", - "rank": "species", - "label": "Abronia turbinata Torr. ex S. Watson", - "scientificName": "Abronia turbinata", - "authorship": "Torr. ex S. Watson", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 154, - "inputRank": "", - "inputName": "Abronia umbellata ssp. breviflora", - "matchType": "variant", - "ID": "SCk01wqXLbup4WVdyTlqO", - "rank": "variety", - "label": "Abronia umbellata var. breviflora (Standl.) L. A. Galloway", - "scientificName": "Abronia umbellata var. breviflora", - "authorship": "(Standl.) L. A. Galloway", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abronia umbellata Lam.|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 155, - "inputRank": "", - "inputName": "Abronia villosa S.Watson", - "matchType": "exact", - "ID": "P0QGPsChR_eu5hOWJ-6D1", - "rank": "species", - "label": "Abronia villosa S. Watson", - "scientificName": "Abronia villosa", - "authorship": "S. Watson", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 156, - "inputRank": "", - "inputName": "Abronia villosa subsp. aurita Orthodox?", - "matchType": "variant", - "ID": "JQwBqywAWi9w3WRaR2WCx0", - "rank": "variety", - "label": "Abronia villosa var. aurita (Abrams) Jeps.", - "scientificName": "Abronia villosa var. aurita", - "authorship": "(Abrams) Jeps.", - "status": "accepted", - "acceptedName": "", - "classification": "SPECIES:Abronia villosa S. Watson|GENUS:Abronia Juss.|FAMILY:Nyctaginaceae Juss.|ORDER:Caryophyllales Juss. ex Bercht. & J. Presl|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "QUESTION_MARKS_REMOVED;DOUBTFUL_NAME" - }, - { - "inputID": 157, - "inputRank": "", - "inputName": "Abrophyllum ornans (F.Muell.) Hook.f.", - "matchType": "variant", - "ID": "vrnEX1vIZwt86dygNMuHG", - "rank": "species", - "label": "Abrophyllum ornans (F. Muell.) Benth.", - "scientificName": "Abrophyllum ornans", - "authorship": "(F. Muell.) Benth.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrophyllum Hook.f.|SUBFAMILY:Carpodetoideae J. Lundb.|FAMILY:Rousseaceae DC.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 158, - "inputRank": "", - "inputName": "Abrotanella emarginata (Gaudich.) Cass.", - "matchType": "variant", - "ID": "Goz_DoK_kAQpD8ZuwUcK12", - "rank": "species", - "label": "Abrotanella emarginata (Cass. ex Gaudich.) Cass.", - "scientificName": "Abrotanella emarginata", - "authorship": "(Cass. ex Gaudich.) Cass.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrotanella Cass.|SUBFAMILY:Asteroideae (Cass.) Lindl.|FAMILY:Asteraceae Dumort.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 159, - "inputRank": "", - "inputName": "Abrotanella linearis", - "matchType": "variant", - "ID": "SemiWOk5nocC1xDUOU_lb2", - "rank": "species", - "label": "Abrotanella linearis Berggr.", - "scientificName": "Abrotanella linearis", - "authorship": "Berggr.", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrotanella Cass.|SUBFAMILY:Asteroideae (Cass.) Lindl.|FAMILY:Asteraceae Dumort.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - }, - { - "inputID": 160, - "inputRank": "", - "inputName": "Abrotanella submarginata", - "matchType": "variant", - "ID": "HS_w6YtYms8h5_byMzMpe0", - "rank": "species", - "label": "Abrotanella submarginata A. Gray", - "scientificName": "Abrotanella submarginata", - "authorship": "A. Gray", - "status": "accepted", - "acceptedName": "", - "classification": "GENUS:Abrotanella Cass.|SUBFAMILY:Asteroideae (Cass.) Lindl.|FAMILY:Asteraceae Dumort.|ORDER:Asterales|CLASS:Magnoliopsida|PHYLUM:Tracheophyta|SUBKINGDOM:Pteridobiotina Britton & Brown|KINGDOM:Plantae|DOMAIN:Eukaryota (Chatton, 1925) Whittaker & Margulis, 1978", - "issues": "" - } -] - export let resultStore = writable(emptyTestRows) From d11ae2ab7d34eb31259c2602e090e7fab8fa0505 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 15 Apr 2026 13:32:09 +0200 Subject: [PATCH 05/37] Species Matching included VersionID handling #980 --- .../SpeciesMatching/SpeciesMatchingResult.cs | 17 +- .../SpeciesMatchingResult.hbm.xml | 7 +- .../SpeciesMatchingResultManager.cs | 1 - .../SpeciesMatchingResultManagerTest.cs | 3 +- .../src/routes/species/+page.svelte | 1 - .../src/routes/species/services.ts | 13 - .../BExIS.Modules.SMM.UI.csproj | 5 + .../Controllers/SpeciesController.cs | 244 ++++++++++++++---- .../src/lib/stores/selectionStore.ts | 3 +- .../src/lib/types/types.ts | 7 + .../src/routes/datasets_overview/+page.svelte | 47 +++- .../src/routes/datasets_overview/data.ts | 36 ++- .../src/routes/headermapping/+page.svelte | 19 +- .../src/routes/headermapping/services.ts | 24 +- .../src/routes/matchingresult/+page.svelte | 29 ++- .../src/routes/matchingresult/services.ts | 18 +- .../src/routes/progress_overview/+page.svelte | 20 +- .../src/routes/progress_overview/services.ts | 16 +- .../src/routes/tailor_view/+page.svelte | 2 +- .../src/routes/tailor_view/services.ts | 4 +- .../Helpers/ConversionHelper.cs | 33 +++ .../Helpers/MatchingResultHelper.cs | 100 ++++--- .../Helpers/ProgressHelper.cs | 132 +++++++--- .../Models/AcceptMatchesRequestModel.cs | 9 +- .../Models/HeaderMappingsModel.cs | 13 + .../Models/MappingProgressModel.cs | 2 + 26 files changed, 581 insertions(+), 224 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/ConversionHelper.cs diff --git a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs index 4177f7a2a0..848bdd8c22 100644 --- a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs +++ b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs @@ -8,16 +8,13 @@ namespace BExIS.Dlm.Entities.SpeciesMatching public class SpeciesMatchingResult : BaseEntity { - // original unchanged name submitted for matching + // original unchanged name (used for matching if EditedName is empty, and for display purposes) public virtual string OriginalName { get; set; } - // cleaned name after preprocessing (e.g. trimming, removing special characters, etc.) - public virtual string CleanedName { get; set; } - - // edited name after manual corrections (if any) + // edited name after data cleaning + manual corrections (used for matching) public virtual string EditedName { get; set; } - // matched name from the external source + // matched name from the external source (the result) public virtual string MatchedName { get; set; } // taxonomic status of the matched name (e.g. accepted, synonym, etc.) @@ -41,11 +38,7 @@ public class SpeciesMatchingResult : BaseEntity // reference to the dataset where the original name was taken from public virtual Dataset Dataset { get; set; } - // reference to the specific version of the dataset - // TODO: get this to work (maybe as a normal field instead of many-to-one relation) - //public virtual DatasetVersion DatasetVersion { get; set; } - - // reference to the user who owns this matching result - public virtual User Creator { get; set; } + // VersionId + Dataset make the unique key for the matching result + public virtual long DatasetVersionId { get; set; } } } \ No newline at end of file diff --git a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml index 15b6726899..fda12a6bce 100644 --- a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml +++ b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/SpeciesMatching/SpeciesMatchingResult.hbm.xml @@ -8,8 +8,6 @@ - - @@ -28,12 +26,11 @@ + + - - - + +{/if} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts index e3ee3b4315..89546968fd 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts @@ -1,5 +1,5 @@ import { Api } from '@bexis2/bexis2-core-ui'; -import type { ServiceResult } from '$lib/types/types'; +import type { IApiOptions, ServiceResult } from '$lib/types/types'; export const loadDatasetProgress = async (datasetId: number, versionId: number): Promise> => { try { @@ -32,9 +32,9 @@ export const genNewMatchFile = async (datasetId: number, versionId: number, apiI } } -export const matchNextFile = async (datasetId: number, versionId: number, apiIdentifier: string): Promise> => { +export const matchNextFile = async (datasetId: number, versionId: number, apiOptions: IApiOptions): Promise> => { try { - const response = await Api.post('/smm/species/MatchNextFile', { datasetId, versionId, apiIdentifier }); + const response = await Api.post(`/smm/species/MatchNextFile?datasetId=${datasetId}&versionId=${versionId}`, apiOptions); return { success: true, data: response.data }; } catch (error: any) { diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts index 4f315075f7..ac2247f9d4 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/types.ts @@ -1,4 +1,5 @@ import type { HeaderMappings, MatchingProgress } from "$lib/types/types" +import type { ExternalApiMetadata } from "$lib/types/types" export interface ProgressOverview { success: boolean, @@ -6,6 +7,7 @@ export interface ProgressOverview { hasMatchingProgress: boolean, isTailored: boolean, headerMappings: HeaderMappings, - matchingProgress: MatchingProgress + matchingProgress: MatchingProgress, + externalApiMetadata: ExternalApiMetadata } diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/CLBApi.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/CLBApi.cs index 64b5d4a505..8e21579169 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/CLBApi.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/CLBApi.cs @@ -29,6 +29,8 @@ public class CLBApi : MatchingApiBase public CLBApi(HttpClient http) : base(http) { } public override string Identifier => "CLB"; + + public override Type OptionsType => typeof(ClbOptions); public override string BaseUrl => "https://api.checklistbank.org/dataset/3LR/match/nameusage/job"; @@ -291,7 +293,7 @@ string GetField(string name) } } - public override async Task MatchAsync(long datasetId, long versionId, string filepath, MatchingProgressModel matchingProgress) + public override async Task MatchAsync(long datasetId, long versionId, string filepath, MatchingProgressModel matchingProgress, IApiOptions apiOptions) { if (string.IsNullOrWhiteSpace(filepath) || !System.IO.File.Exists(filepath)) { @@ -310,6 +312,38 @@ public override async Task MatchAsync(long datasetId, long Debug.WriteLine(filepath); byte[] fileBytes = System.IO.File.ReadAllBytes(filepath); + // Debug: inspect apiOptions concrete type and values + try + { + if (apiOptions == null) + { + Debug.WriteLine("apiOptions == null"); + } + else if (apiOptions is ClbOptions clb) + { + Debug.WriteLine($"ClbOptions: SourceKey={clb.SourceKey}, Synonyms={clb.Synonyms}"); + } + else if (apiOptions is GenericOptions gen) + { + Debug.WriteLine("GenericOptions.Raw: " + (gen.Raw != null ? gen.Raw.ToString(Formatting.Indented) : "")); + } + else + { + try + { + Debug.WriteLine("apiOptions: " + JsonConvert.SerializeObject(apiOptions)); + } + catch + { + Debug.WriteLine("apiOptions type: " + apiOptions.GetType().FullName); + } + } + } + catch (Exception ex) + { + Debug.WriteLine("Failed to debug-print apiOptions: " + ex.Message); + } + GBFICrendentials credentials = ModuleManager.GetModuleSettings("DIM").GetValueByKey("gbifapicredentials"); var username = credentials.Username; diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/IApiOptions.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/IApiOptions.cs new file mode 100644 index 0000000000..abfd8aea00 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/IApiOptions.cs @@ -0,0 +1,33 @@ +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.ComponentModel.DataAnnotations; + +namespace BExIS.Modules.Smm.UI.Helpers.MatchingAPIs +{ + public interface IApiOptions { } + + public class ClbOptions : IApiOptions + { + [JsonProperty("sourceKey")] + [Required] + public string SourceKey { get; set; } + + [JsonProperty("synonyms")] + public bool Synonyms { get; set; } + } + + // TODO: - remove (just an example) + public class GbifOptions : IApiOptions + { + [JsonProperty("parameter1")] + public string Parameter1 { get; set; } + + [JsonProperty("parameter2")] + public string Parameter2 { get; set; } + } + + public class GenericOptions : IApiOptions + { + public JObject Raw { get; set; } + } +} diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiBase.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiBase.cs index 445ed6b637..cf60ed28d4 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiBase.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiBase.cs @@ -32,7 +32,7 @@ protected MatchingApiBase(HttpClient http) // Method to perform the matching based on the provided file path // (this actually makes the post request to the API and returns the result as a JsonResult) - public abstract Task MatchAsync(long datasetId, long versionId, string filepath, MatchingProgressModel matchingProgress); + public abstract Task MatchAsync(long datasetId, long versionId, string filepath, MatchingProgressModel matchingProgress, IApiOptions apiOptions); // Method to generate the unmatched input file (source file for matching) // NOTE: different APIs need different file structure and input format @@ -55,5 +55,8 @@ public HashSet GetAcceptableMatchTypes() { return AcceptableMatchTypes; } + + // options type for the API, used for deserialization of options from JSON + public virtual Type OptionsType => null; } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiProvider.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiProvider.cs index be981c9121..7be58b62c5 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiProvider.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Helpers/MatchingAPIs/MatchingApiProvider.cs @@ -2,6 +2,9 @@ using System.Collections.Generic; using System.Linq; using System.Web; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using System.ComponentModel.DataAnnotations; namespace BExIS.Modules.Smm.UI.Helpers.MatchingAPIs { @@ -36,5 +39,53 @@ public MatchingApiBase GetApi(string identifier) } throw new KeyNotFoundException($"No matching API found for identifier: {identifier}"); } + + // Resolves the options for a given API identifier and options payload + public IApiOptions ResolveOptions(string apiIdentifier, JObject options) + { + if (options == null) return null; + if (string.IsNullOrWhiteSpace(apiIdentifier)) + throw new ArgumentException("API identifier cannot be null or empty.", nameof(apiIdentifier)); + + MatchingApiBase api; + try + { + api = GetApi(apiIdentifier); + } + catch (KeyNotFoundException) + { + // unknown api -> keep raw + return new GenericOptions { Raw = options }; + } + + var targetType = api?.OptionsType; + if (targetType != null) + { + try + { + var typed = (IApiOptions)options.ToObject(targetType); + Validate(typed); // keep your existing Validate method + return typed; + } + catch (JsonException ex) + { + throw new ArgumentException("Invalid JSON for options payload.", ex); + } + } + + return new GenericOptions { Raw = options }; + } + + // Validates an options object using data annotations + private void Validate(object obj) + { + if (obj == null) return; + var ctx = new ValidationContext(obj); + var results = new List(); + if (!Validator.TryValidateObject(obj, ctx, results, true)) + { + throw new ValidationException(results.First().ErrorMessage); + } + } } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/ExternalApiMetadata.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/ExternalApiMetadata.cs new file mode 100644 index 0000000000..464164a09f --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/ExternalApiMetadata.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using Newtonsoft.Json; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class ExternalApiMetadata + { + [JsonProperty("clb")] + public ExternalApiSource Clb { get; set; } + } + + public class ExternalApiSource + { + [JsonProperty("sourceKeyInfo")] + public List SourceKeyInfo { get; set; } + } + + public class SourceKeyInfoItem + { + [JsonProperty("sourceKey")] + public string SourceKey { get; set; } + [JsonProperty("title")] + public string Title { get; set; } + + [JsonProperty("alias")] + public string Alias { get; set; } + } +} \ No newline at end of file From 746914f45d5f613686504f77d4a15655f8279439 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 07:36:52 +0200 Subject: [PATCH 28/37] comments + correct StepEntry init #980 --- .../Models/MatchingProgressModel.cs | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs index 6987da7c0c..eaa53e26ce 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs @@ -10,10 +10,13 @@ public class MatchingProgressModel public List Steps { get; set; } = new List(); + // total number of rows in the original data, should be set at the beginning of the matching process public int NumRowsGlobal { get; set; } + // identifier for the dataset being matched, should be set at the beginning of the matching process public long DatasetId { get; set; } + // identifier for the specific version of the dataset being matched, should be set at the beginning of the matching process public long VersionId { get; set; } public int GetNewId() @@ -40,6 +43,8 @@ public void AddStep(int id, int numRows, string inputFileName, string apiIdentif ApiIdentifier = apiIdentifier, DownloadLink = string.Empty, JobKey = string.Empty, + MatchSource = string.Empty, + TimeStamp = DateTime.MinValue, Done = false }; @@ -125,27 +130,39 @@ public bool UpdateStep(StepEntry updatedStep) } } - + // Represents a single step in the matching process + // Each step corresponds to a matching operation, which involves an input file, result file and an API call + // to a file based matching service (e.g. CheckListBank). The step is considered completed when the result file is available and the API call is done. public class StepEntry { + // identifier for this step, should be unique within the context of a MatchingProgressModel public int Id { get; set; } - + + // number of rows in the input file public int NumRows { get; set; } + // name of the input file for this step public string InputFileName { get; set; } + // name of the result file for this step, should be non-empty when the step is completed public string ResultFileName { get; set; } + // identifier for the API call associated with this step, should be non-empty when the step is completed public string ApiIdentifier { get; set; } + // download link for the result file public string DownloadLink { get; set; } + // source of the matching results (e.g. string of dataset sourceKey in CheckListBank) public string MatchSource { get; set; } + // timestamp when the match request is sent public DateTime TimeStamp { get; set; } + // job key for tracking the matching job (if asynchronous) public string JobKey { get; set; } + // indicates whether the matching step is completed (completed when the result file is available and the API call is done) public bool Done { get; set; } } } \ No newline at end of file From 8526bb386728dced505b2b1c0cb64bd7e0968a7a Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 07:47:28 +0200 Subject: [PATCH 29/37] removed unused code #980 --- .../Controllers/SpeciesController.cs | 67 ------------------- 1 file changed, 67 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs index 060f31cf97..756eae97a7 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs @@ -988,73 +988,6 @@ public JsonResult ApplyTailorEdits(long datasetId, long versionId, TailorEdit[] } } - public async Task SendToChecklistBank(long datasetId, string filepath, MatchingProgressModel matchingProgress) - { - if (string.IsNullOrWhiteSpace(filepath) || !System.IO.File.Exists(filepath)) - { - return Json(new { success = false, id = datasetId, message = "Export file not generated." }); - } - - Debug.WriteLine("{====================FILEPATH:====================}"); - Debug.WriteLine(filepath); - byte[] fileBytes = System.IO.File.ReadAllBytes(filepath); - - using (var content = new ByteArrayContent(fileBytes)) - { - //content.Headers.ContentType = new MediaTypeHeaderValue("text/tab-separated-values"); - content.Headers.ContentType = new MediaTypeHeaderValue("text/csv"); - - // TODO: replace with secure configuration - GBFICrendentials credentials = ModuleManager.GetModuleSettings("DIM").GetValueByKey("gbifapicredentials"); - var username = credentials.Username; - var password = credentials.Password; - - var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{username}:{password}")); - _httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", authValue); - - // Test for now : query parameter format=csv - //var url = "https://api.checklistbank.org/dataset/3LR/match/nameusage/job?format=csv"; - var url = "https://api.checklistbank.org/match/nameusage?format=csv&sourceDatasetKey=3"; - try - { - HttpResponseMessage response = await _httpClient.PostAsync(url, content); - string responseString = await response.Content.ReadAsStringAsync(); - - // try to parse the response string as JSON. If parsing fails treat the whole call as a failure - // because we cannot interpret the API response reliably. - object responseJson; - try - { - responseJson = JsonConvert.DeserializeObject(responseString); - } - catch (Exception ex) - { - Debug.WriteLine("Failed to deserialize ChecklistBank response as JSON: " + ex.Message); - Debug.WriteLine("RESPONSE STRING: "); - Debug.WriteLine(responseString); - // Return a failure result when the response cannot be parsed as JSON. - return Json(new { success = false, id = datasetId, status = response.StatusCode, message = "Failed to parse API response as JSON.", response = responseString }); - } - - if (response.IsSuccessStatusCode) - { - return Json(new { success = true, id = datasetId, status = response.StatusCode, response = responseJson }); - } - else - { - return Json(new { success = false, id = datasetId, status = response.StatusCode, response = responseJson }); - } - } - catch (Exception ex) - { - return Json(new { success = false, id = datasetId, message = ex.Message }); - } - finally - { - _httpClient.DefaultRequestHeaders.Authorization = null; - } - } - } // Returns the datastructure id for the given dataset id, or null if not found or on error private long? GetDatastructureIdFromDatasetId(long datasetId) From 74457586a5ce23b4852cbcb49ba0aeed7aaefaef Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 08:06:11 +0200 Subject: [PATCH 30/37] retrieving stepId when generating new match input file #980 --- .../BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs | 2 +- .../src/routes/progress_overview/+page.svelte | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs index 756eae97a7..3c40f6e1e9 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs @@ -677,7 +677,7 @@ public JsonResult GenNewMatchInputFile(long datasetId, long versionId, string ap return JsonWithStatus(new { success = false, id = datasetId, message = "Unexpected error while generating matching input file: " + ex.Message }, HttpStatusCode.InternalServerError); } - return Json(new { success = true, id = datasetId, message = "Matching input file generated." }); + return Json(new { success = true, data = new { id = datasetId, stepId = newStepId }, message = "Matching input file generated." }); } [JsonNetFilter] diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte index 9d97b46af3..2669ac41eb 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte @@ -119,6 +119,13 @@ return; } console.log(responseCreate); + var stepId: number = responseCreate.data.data.stepId; + + if (stepId == undefined || stepId == null || stepId < 0) { + console.error("Variable stepId could not be read from genNewMatchFile response: ", stepId); + return; + } + console.log("Selected Api Options: "); console.log(selectedApiOptions) From c13d6139f818db153a488c703ea2e9b7f5a18784 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 08:15:19 +0200 Subject: [PATCH 31/37] make match file request more explicit #980 --- .../Controllers/SpeciesController.cs | 11 ++++++++--- .../src/routes/progress_overview/+page.svelte | 2 +- .../src/routes/progress_overview/services.ts | 4 ++-- .../Models/MatchingProgressModel.cs | 6 ++++++ 4 files changed, 17 insertions(+), 6 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs index 3c40f6e1e9..3a280c007d 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs @@ -682,7 +682,7 @@ public JsonResult GenNewMatchInputFile(long datasetId, long versionId, string ap [JsonNetFilter] [HttpPost] - public async Task MatchNextFile(long datasetId, long versionId) + public async Task MatchFileByStepId(long datasetId, long versionId, int stepId) { Debug.WriteLine("EXECUTING MatchNextFile"); var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); @@ -697,10 +697,15 @@ public async Task MatchNextFile(long datasetId, long versionId) return JsonWithStatus(new { success = false, id = datasetId, message = "No matching progress found." }, HttpStatusCode.Unauthorized); } - StepEntry step = matchingProgress.GetNextPendingStepEntry(); + StepEntry step = matchingProgress.GetStepById(stepId); if (step == null) { - return JsonWithStatus(new { success = false, id = datasetId, message = "No pending StepEntry found." }, HttpStatusCode.Conflict); + return JsonWithStatus(new { success = false, id = datasetId, message = "Step not found." }, HttpStatusCode.Conflict); + } + + if (!step.IsReadyToMatch()) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Step is not ready to match. Either no input file available or step is already completed." }, HttpStatusCode.Conflict); } string nextFileName = step.InputFileName; diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte index 2669ac41eb..a487e37cd5 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte @@ -130,7 +130,7 @@ console.log("Selected Api Options: "); console.log(selectedApiOptions) - const responseMatch = await matchNextFile($matchingSelection.datasetId, $matchingSelection.versionId, selectedApiOptions); + const responseMatch = await matchNextFile($matchingSelection.datasetId, $matchingSelection.versionId, stepId, selectedApiOptions); if (!responseMatch.success) { console.error("Error generating new Matching input file."); diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts index 89546968fd..795266d9f6 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/services.ts @@ -32,9 +32,9 @@ export const genNewMatchFile = async (datasetId: number, versionId: number, apiI } } -export const matchNextFile = async (datasetId: number, versionId: number, apiOptions: IApiOptions): Promise> => { +export const matchNextFile = async (datasetId: number, versionId: number, stepId: number, apiOptions: IApiOptions): Promise> => { try { - const response = await Api.post(`/smm/species/MatchNextFile?datasetId=${datasetId}&versionId=${versionId}`, apiOptions); + const response = await Api.post(`/smm/species/MatchFileByStepId?datasetId=${datasetId}&versionId=${versionId}&stepId=${stepId}`, apiOptions); return { success: true, data: response.data }; } catch (error: any) { diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs index eaa53e26ce..1da7bfb841 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs @@ -164,5 +164,11 @@ public class StepEntry // indicates whether the matching step is completed (completed when the result file is available and the API call is done) public bool Done { get; set; } + + public bool IsReadyToMatch() + { + // Ready to match when there is a non-empty InputFileName, and is not done yet + return !string.IsNullOrEmpty(InputFileName) && !Done; + } } } \ No newline at end of file From 900434aeb3b1cb1cd00bf97c2dce52626f0a4f62 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 08:20:48 +0200 Subject: [PATCH 32/37] removed unused code #980 --- .../Models/MatchingProgressModel.cs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs index 1da7bfb841..463cb8b9db 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs @@ -57,28 +57,6 @@ public bool AreAllStepsDone() return Steps == null || Steps.All(s => s.Done); } - public string GetNextPendingInputFileName() - { - if (Steps == null || Steps.Count == 0) return null; - - var entry = Steps.FirstOrDefault(s => s.Done == false - && string.IsNullOrEmpty(s.DownloadLink) - && string.IsNullOrEmpty(s.JobKey)); - - return entry?.InputFileName; - } - - public StepEntry GetNextPendingStepEntry() - { - if (Steps == null || Steps.Count == 0) return null; - - var entry = Steps.FirstOrDefault(s => s.Done == false - && string.IsNullOrEmpty(s.DownloadLink) - && string.IsNullOrEmpty(s.JobKey)); - - return entry; - } - public bool IsIdValidAndMatched(int stepId) { // Return false when there are no steps From f6b676a5c3769e710d43e27d62e50c2df48a8d97 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 08:50:59 +0200 Subject: [PATCH 33/37] made matchingProgress and steps more explicit #980 --- .../Controllers/SpeciesController.cs | 11 ++++--- .../src/lib/types/types.ts | 2 +- .../Models/MatchingProgressModel.cs | 29 ++++++++++--------- 3 files changed, 22 insertions(+), 20 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs index 3a280c007d..17ab36e523 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Controllers/SpeciesController.cs @@ -97,7 +97,6 @@ public async Task StartDownloadResultFile(long datasetId, long versi if (stepLocal != null) { stepLocal.ResultFileName = Path.GetFileName(downloadedFilepath); - stepLocal.Done = true; matchingProgressLocal.UpdateStep(stepLocal); ProgressHelper.SaveMatchingProgress(matchingProgressLocal, datasetId, versionId); } @@ -191,7 +190,7 @@ public JsonResult GetMatchingFileStatus(long datasetId, long versionId, int step MarkerStart = markerStart, MatchingProgressExists = matchingProgressExists, StepExists = stepExists, - StepDone = step?.Done ?? false, + StepCompleted = step?.IsCompleted() ?? false, DownloadLinkPresent = !string.IsNullOrWhiteSpace(step?.DownloadLink), JobKeyPresent = !string.IsNullOrWhiteSpace(step?.JobKey) } @@ -641,7 +640,7 @@ public JsonResult GenNewMatchInputFile(long datasetId, long versionId, string ap return JsonWithStatus(new { success = false, id = datasetId, message = "No matching progress found." }, HttpStatusCode.Unauthorized); } - if (!matchingProgress.AreAllStepsDone()) + if (!matchingProgress.AllStepsCompleted()) { return JsonWithStatus(new { success = false, id = datasetId, message = "Not all matching steps are completed yet. Please complete existing steps before generating a new matching input file." }, HttpStatusCode.Conflict); } @@ -796,7 +795,7 @@ public JsonResult ViewMatchingResult(long datasetId, long versionId, int stepId) return JsonWithStatus(new { success = false, id = datasetId, message = "No matching progress found under the given datasetId." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); } - if (!matchingProgress.IsIdValidAndMatched(stepId)) + if (!matchingProgress.IsCompletedById(stepId)) { return JsonWithStatus(new { success = false, id = datasetId, message = "No valid matching job found in the matching progress data for the given stepId." }, HttpStatusCode.Conflict, JsonRequestBehavior.AllowGet); } @@ -810,7 +809,7 @@ public JsonResult ViewMatchingResult(long datasetId, long versionId, int stepId) try { - var apiIdentifier = matchingProgress.GetApiIdentifier(stepId); + var apiIdentifier = matchingProgress.GetApiIdentifierById(stepId); Debug.WriteLine("SEARCHING MATCHING PROGRESS FOR: " + datasetId.ToString() + " " + versionId.ToString()); Debug.WriteLine("API IDENTIFIER: " + apiIdentifier); MatchingApiBase apiBase = matchingApiProvider.GetApi(apiIdentifier); @@ -895,7 +894,7 @@ public JsonResult AcceptMatches(AcceptMatchesRequestModel request) return JsonWithStatus(new { success = false, id = datasetId, message = "No matching progress found under the given datasetId." }, HttpStatusCode.Conflict); } - if (!matchingProgress.IsIdValidAndMatched(stepId)) + if (!matchingProgress.IsCompletedById(stepId)) { return JsonWithStatus(new { success = false, id = datasetId, message = "No valid matching job found in the matching progress data for the given stepId." }, HttpStatusCode.Conflict); } diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts index 8a625e1f88..f498d20925 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/lib/types/types.ts @@ -44,7 +44,7 @@ export interface MatchingFileStatus { markerStart: string, matchingProgressExists: boolean, stepExists: boolean, - stepDone: boolean, + stepCompleted: boolean, downloadLinkPresent: boolean, jobKeyPresent: boolean, } diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs index 463cb8b9db..bbdb768a92 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/MatchingProgressModel.cs @@ -45,30 +45,30 @@ public void AddStep(int id, int numRows, string inputFileName, string apiIdentif JobKey = string.Empty, MatchSource = string.Empty, TimeStamp = DateTime.MinValue, - Done = false }; Steps.Add(entry); } - public bool AreAllStepsDone() + public bool AllStepsCompleted() { // Return true when there are no unfinished steps (i.e. no step with Done == false) - return Steps == null || Steps.All(s => s.Done); + return Steps == null || Steps.All(s => s.IsCompleted()); } - public bool IsIdValidAndMatched(int stepId) + public bool IsCompletedById(int stepId) { // Return false when there are no steps if (Steps == null || Steps.Count == 0) return false; var entry = Steps.FirstOrDefault(s => s.Id == stepId); - // Valid and matched when the step exists and has a non-empty ResultFileName - return entry != null && !string.IsNullOrEmpty(entry.ResultFileName); + if (entry == null) return false; + + return entry.IsCompleted(); } - public string GetApiIdentifier(int stepId) + public string GetApiIdentifierById(int stepId) { // Return null when there are no steps if (Steps == null || Steps.Count == 0) return null; @@ -102,7 +102,6 @@ public bool UpdateStep(StepEntry updatedStep) existing.DownloadLink = updatedStep.DownloadLink; existing.MatchSource = updatedStep.MatchSource; existing.JobKey = updatedStep.JobKey; - existing.Done = updatedStep.Done; return true; } @@ -140,13 +139,17 @@ public class StepEntry // job key for tracking the matching job (if asynchronous) public string JobKey { get; set; } - // indicates whether the matching step is completed (completed when the result file is available and the API call is done) - public bool Done { get; set; } - public bool IsReadyToMatch() { - // Ready to match when there is a non-empty InputFileName, and is not done yet - return !string.IsNullOrEmpty(InputFileName) && !Done; + // input file exists + // matching process has not started for this step + return !string.IsNullOrEmpty(InputFileName) && string.IsNullOrEmpty(JobKey) && string.IsNullOrEmpty(ResultFileName) && string.IsNullOrEmpty(DownloadLink); + } + + public bool IsCompleted() + { + // step is completed when the result file is available and the API call is done + return !string.IsNullOrEmpty(ResultFileName); } } } \ No newline at end of file From 5531e8566ae9894a91930ebc268cba72cea22528 Mon Sep 17 00:00:00 2001 From: Erik Date: Fri, 19 Jun 2026 09:00:23 +0200 Subject: [PATCH 34/37] better dataset overview #980 --- .../src/routes/datasets_overview/+page.svelte | 15 ++++++++++++--- .../datasets_overview/ResultTableOptions.svelte | 2 ++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte index be33fda73d..ea0c0698b2 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/+page.svelte @@ -82,14 +82,23 @@ pageSizes: [20, 50, 100], showColumnsMenu: true, columns: { + id: { + header: "Dataset ID" + }, metadataComplete: { - disableFiltering: true + disableFiltering: true, + exclude: true }, isTabular: { - disableFiltering: true + disableFiltering: true, + exclude: true }, hasMatchingProgress: { - disableFiltering: true + disableFiltering: true, + exclude: true + }, + dataStructureId: { + exclude: true }, versionId: { exclude: true diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte index 5ade95c1f9..ca7d87fa4b 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/datasets_overview/ResultTableOptions.svelte @@ -27,6 +27,7 @@
{#if row.hasMatchingProgress} {:else} + +
+ \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte index a487e37cd5..56ef547b90 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/progress_overview/+page.svelte @@ -96,6 +96,7 @@ }; async function handleTailor() { + // TODO: redirecting variable, to hide original page when finishing tailor tailorLoading = true; const response = await tailorDataset($matchingSelection.datasetId, $matchingSelection.versionId); @@ -148,9 +149,14 @@ note="" contentLayoutType={pageContentLayoutType.center} > -

Progress Overview

-

This page shows your current mapping progress for the selected Dataset with ID: {$matchingSelection.datasetId} VerionNr: {$matchingSelection.versionNr} VersionID: {$matchingSelection.versionId} StepID: {$matchingSelection.stepId}

+
+ + + +
+ +

Progress Overview

{#if tailorError} diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte index cbd85bfae4..5ce2babbdd 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/+page.svelte @@ -1,84 +1,304 @@ +
+ + + +
+
Select steps for data cleaning (changes applied automatically). Use Global actions to run specific procedures across the whole dataset.
@@ -220,6 +560,17 @@ {:then data}

Data cleaning config

+ + +
{#each Object.entries(cleanConfig) as [key, conf]}
@@ -230,6 +581,16 @@

Global Actions

+ +
@@ -245,9 +606,17 @@
+

{showEditsOnly ? 'Edits only (row edits disabled)' : 'Table data'}

-
- + {#if tableInDOM} +
+
+ + + {#if showEditsOnly} +
+ {/if} + {/if} {/await} diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditNameModal.svelte similarity index 75% rename from Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte rename to Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditNameModal.svelte index a982ea515a..e9f3d55233 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditResult.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditNameModal.svelte @@ -1,29 +1,29 @@ + +
+
You are about to RESET ALL edited rows. Are you SURE you want to continue?
+
+ + +
+
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte index c53286944c..a56fd12b75 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/ResultTableOptions.svelte @@ -22,6 +22,7 @@ {#each buttons as button}