From 4eb6c838e3db84ac8ee13c45fc65cd269f60689b Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 10 Sep 2025 07:25:55 +0200 Subject: [PATCH 001/490] #2197 create entity extension with store and seed data --- .../Vaiona.Logging/Vaiona.Logging.csproj | 6 +- .../BExIS.Xml.Helpers.csproj | 1 + .../XML/BExIS.Xml.Helpers/ExtensionStore.cs | 226 ++++++++++++++++++ .../BExIS.Web.Shell.Svelte/package-lock.json | 6 +- .../Helpers/DCMSeedDataGenerator.cs | 47 ++++ .../package-lock.json | 6 +- database update scripts/4.1.0.-4.2.0.sql | 33 +++ 7 files changed, 316 insertions(+), 9 deletions(-) create mode 100644 Components/XML/BExIS.Xml.Helpers/ExtensionStore.cs create mode 100644 database update scripts/4.1.0.-4.2.0.sql diff --git a/Components/Vaiona/Vaiona.Logging/Vaiona.Logging.csproj b/Components/Vaiona/Vaiona.Logging/Vaiona.Logging.csproj index fcc9faa73a..e678b94e5d 100644 --- a/Components/Vaiona/Vaiona.Logging/Vaiona.Logging.csproj +++ b/Components/Vaiona/Vaiona.Logging/Vaiona.Logging.csproj @@ -58,9 +58,6 @@ - - - {0815d220-3625-4e23-bbbc-8152345637fe} @@ -79,6 +76,9 @@ Vaiona.Utils + + + diff --git a/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj b/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj index 149d36bc51..ffc725e8e2 100644 --- a/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj +++ b/Components/XML/BExIS.Xml.Helpers/BExIS.Xml.Helpers.csproj @@ -74,6 +74,7 @@ + diff --git a/Components/XML/BExIS.Xml.Helpers/ExtensionStore.cs b/Components/XML/BExIS.Xml.Helpers/ExtensionStore.cs new file mode 100644 index 0000000000..8bfd13b929 --- /dev/null +++ b/Components/XML/BExIS.Xml.Helpers/ExtensionStore.cs @@ -0,0 +1,226 @@ +using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Services.Data; +using BExIS.Dlm.Services.MetadataStructure; +using BExIS.Security.Services.Objects; +using System; +using System.Collections.Generic; +using System.Linq; +using Vaiona.Persistence.Api; + +namespace BExIS.Xml.Helpers +{ + public class ExtensionStore : IEntityStore + { + private const string _entityName = "Extension"; + + public List GetEntities() + { + return GetEntities(0, 0); + } + + public List GetEntities(int skip, int take) + { + bool withPaging = (take > 0); + + using (var uow = this.GetUnitOfWork()) + using (DatasetManager dm = new DatasetManager()) + using (MetadataStructureManager metadataStructureManager = new MetadataStructureManager()) + { + XmlDatasetHelper xmlDatasetHelper = new XmlDatasetHelper(); + var entities = new List(); + + try + { + List metadataStructureIds = metadataStructureManager.Repo.Query().Select(m => m.Id).ToList(); + + List metadataSturctureIdsForDatasets = new List(); + metadataSturctureIdsForDatasets = metadataStructureIds.Where(m => xmlDatasetHelper.HasEntity(m, _entityName)).ToList(); + + foreach (var msid in metadataSturctureIdsForDatasets) + { + var datasetIds = new List(); + // get all datasets based on metadata data structure id + if (withPaging) + { + datasetIds = dm.DatasetRepo + .Query(d => d.MetadataStructure.Id.Equals(msid)) + .Skip(skip) + .Take(take) + .Select(d => d.Id).ToList(); + } + else + { + datasetIds = dm.DatasetRepo.Query(d => d.MetadataStructure.Id.Equals(msid)).Select(d => d.Id).ToList(); + } + + if (!datasetIds.Any()) continue; + + // create tuples based on dataset id list, and get latest version of each dataset + + List datasetVersions = dm.GetDatasetLatestVersions(datasetIds, false); + foreach (var dsv in datasetVersions) + { + var e = new EntityStoreItem() + { + Id = dsv.Dataset.Id, + Title = dsv.Title, + Version = dm.GetDatasetVersionCount(dsv.Dataset.Id) + }; + + entities.Add(e); + } + } + + return entities.ToList(); + } + catch (Exception ex) + { + throw ex; + } + } + } + + public int CountEntities() + { + using (var uow = this.GetUnitOfWork()) + using (DatasetManager dm = new DatasetManager()) + using (MetadataStructureManager metadataStructureManager = new MetadataStructureManager()) + { + XmlDatasetHelper xmlDatasetHelper = new XmlDatasetHelper(); + var entities = new List(); + int count = 0; + + try + { + List metadataStructureIds = metadataStructureManager.Repo.Query().Select(m => m.Id).ToList(); + + List metadataSturctureIdsForDatasets = new List(); + metadataSturctureIdsForDatasets = metadataStructureIds.Where(m => xmlDatasetHelper.HasEntity(m, _entityName)).ToList(); + + foreach (var msid in metadataSturctureIdsForDatasets) + { + var datasetIds = new List(); + // get all datasets based on metadata data structure id + + datasetIds = dm.DatasetRepo.Query(d => d.MetadataStructure.Id.Equals(msid)).Select(d => d.Id).ToList(); + count += datasetIds.Count; + } + + return count; + } + catch (Exception ex) + { + throw ex; + } + finally + { + dm.Dispose(); + } + } + } + + public string GetTitleById(long id) + { + using (var uow = this.GetUnitOfWork()) + { + var dm = new DatasetManager(); + + try + { + var dsv = dm.GetDatasetLatestVersion(id); + + return dsv.Title; + } + catch + { + return String.Empty; + } + finally + { + dm.Dispose(); + } + } + } + + public int CountVersions(long id) + { + DatasetManager dm = new DatasetManager(); + + try + { + var datasetIds = dm.GetDatasetLatestIds(); + var datasetHelper = new XmlDatasetHelper(); + + int version = dm.GetDataset(id).Versions.Count; + + return version; + } + catch (Exception ex) + { + return 0; + } + finally + { + dm.Dispose(); + } + } + + public List GetVersionsById(long id) + { + DatasetManager dm = new DatasetManager(); + List tmp = new List(); + try + { + var datasetIds = dm.GetDatasetLatestIds(); + var datasetHelper = new XmlDatasetHelper(); + var versions = dm.GetDataset(id).Versions.OrderBy(v => v.Timestamp).ToList(); + + foreach (var v in versions) + { + tmp.Add(new EntityStoreItem() + { + Id = v.Id, + Title = v.Title, + Version = versions.IndexOf(v) + 1, + CommitComment = "(" + v.Timestamp.ToString("dd.MM.yyyy HH:mm") + "): " + v.ChangeDescription + }); + } + + return tmp; + } + catch (Exception ex) + { + return tmp; + } + finally + { + dm.Dispose(); + } + } + + public bool HasVersions() + { + return true; + } + + public bool Exist(long id) + { + DatasetManager dm = new DatasetManager(); + Dataset dataset = null; + + try + { + dataset = dm.GetDataset(id); + return dataset != null ? true : false; + } + catch (Exception ex) + { + return false; + } + finally + { + dm.Dispose(); + } + } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell.Svelte/package-lock.json b/Console/BExIS.Web.Shell.Svelte/package-lock.json index f0b2696886..3823b38fa0 100644 --- a/Console/BExIS.Web.Shell.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell.Svelte/package-lock.json @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.57", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.57.tgz", - "integrity": "sha512-oMrm1H0FujE3t9SAfXHcmlv43Mm9Rm2A/vpXjB2Sx9gG9PVGhpIcfLgLgxFFx7oDeSZV2ZHQ/PRuwN05KYAjPg==", + "version": "0.4.58", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.58.tgz", + "integrity": "sha512-u7g8+e0hEV4Eu4VxsT/Fpv+YVxoUSYV3a01wwE2dg2GbwF7Th5QxHTiN6AisvcVO7N2XIBmkBwE5RjEgXB7ihw==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DCMSeedDataGenerator.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DCMSeedDataGenerator.cs index 4ce6330ec9..478953ee91 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DCMSeedDataGenerator.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DCMSeedDataGenerator.cs @@ -155,6 +155,45 @@ public void GenerateSeedData() entityManager.Update(publication); } + // publication + var extension = entityManager.Entities.Where(e => e.Name.ToUpperInvariant() == "Extension".ToUpperInvariant()).FirstOrDefault(); + + if (extension == null) + { + extension = new Entity(); + extension.Name = "Extension"; + extension.EntityType = typeof(Dataset); + extension.EntityStoreType = typeof(Xml.Helpers.ExtensionStore); + extension.UseMetadata = true; + extension.Securable = true; + + //add to Extra + + XmlDocument xmlDoc = new XmlDocument(); + XmlDatasetHelper xmlDatasetHelper = new XmlDatasetHelper(); + xmlDatasetHelper.AddReferenceToXml(xmlDoc, AttributeNames.name.ToString(), "ddm", AttributeType.parameter.ToString(), "extra/modules/module"); + + extension.Extra = xmlDoc; + + entityManager.Create(extension); + } + else + { + XmlDocument xmlDoc = new XmlDocument(); + + if (extension.Extra != null) + if (extension.Extra is XmlDocument) xmlDoc = extension.Extra as XmlDocument; + else xmlDoc.AppendChild(extension.Extra); + + //update to Extra + XmlDatasetHelper xmlDatasetHelper = new XmlDatasetHelper(); + xmlDatasetHelper.AddReferenceToXml(xmlDoc, AttributeNames.name.ToString(), "ddm", AttributeType.parameter.ToString(), "extra/modules/module"); + + extension.Extra = xmlDoc; + + entityManager.Update(extension); + } + #endregion create entities #region SECURITY @@ -312,6 +351,14 @@ public void GenerateSeedData() ImportSchema("Publication", "BEXIS2-Publication-Schema-draft.xsd", "Metadata", publication.Name, publication.EntityType.FullName, titleXPath, descriptionXpath); } + if (!metadataStructureManager.Repo.Get().Any(m => m.Name.Equals("Extension"))) + { + string titleXPath = "Metadata/Title/TitleType"; + string descriptionXpath = "Metadata/Description/DescriptionType"; + + ImportSchema("Extension", "BEXIS2-Extension.xsd", "Metadata", extension.Name, extension.EntityType.FullName, titleXPath, descriptionXpath); + } + #endregion Add Metadata #region create default entitytemplate diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json index 3e9c2e57e2..fe07841c69 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json @@ -81,9 +81,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.57", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.57.tgz", - "integrity": "sha512-oMrm1H0FujE3t9SAfXHcmlv43Mm9Rm2A/vpXjB2Sx9gG9PVGhpIcfLgLgxFFx7oDeSZV2ZHQ/PRuwN05KYAjPg==", + "version": "0.4.58", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.58.tgz", + "integrity": "sha512-u7g8+e0hEV4Eu4VxsT/Fpv+YVxoUSYV3a01wwE2dg2GbwF7Th5QxHTiN6AisvcVO7N2XIBmkBwE5RjEgXB7ihw==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/database update scripts/4.1.0.-4.2.0.sql b/database update scripts/4.1.0.-4.2.0.sql new file mode 100644 index 0000000000..05994d4892 --- /dev/null +++ b/database update scripts/4.1.0.-4.2.0.sql @@ -0,0 +1,33 @@ +BEGIN TRANSACTION; + +-- entities - extension +INSERT INTO public.entities ( + versionno, + extra, + entitystoretype, + entitytype, + name, + securable, + usemetadata, + parentref + ) +SELECT + 1, + '', + 'BExIS.Xml.Helpers.ExtensionStore, BExIS.Xml.Helpers, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null', + 'BExIS.Dlm.Entities.Data.Dataset, BExIS.Dlm.Entities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null', + 'Extension', + true, + true, + null + +WHERE NOT EXISTS (SELECT * FROM public.entities WHERE name='Extension'); + + + +-- BEXIS2 Version Update +INSERT INTO public.versions( + versionno, extra, module, value, date) + VALUES (1, null, 'Shell', '4.2.0',NOW()); + +commit; From 9ae950228b4b3a88bce6810e76a26fae9e9d9185 Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 10 Sep 2025 07:31:53 +0200 Subject: [PATCH 002/490] #2197 update workspace --- Console/Workspace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/Workspace b/Console/Workspace index 4dc26a8121..4d0998d15f 160000 --- a/Console/Workspace +++ b/Console/Workspace @@ -1 +1 @@ -Subproject commit 4dc26a81215d36d1836397b46e3d128ec49a7dfa +Subproject commit 4d0998d15f9663514c65796616f0e52581a31ccb From 551fe26a74821574add09230237008992d655f32 Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 10 Sep 2025 11:35:15 +0200 Subject: [PATCH 003/490] #2196 add properties to entity reference, refactor all functions , models, config file also refactor xml entityreference config to json --- .../Objects/EntityReference.cs | 11 +- .../Default/Objects/EntityReference.hbm.xml | 2 + .../Objects/EntityReferenceManager.cs | 18 ++- .../UI/BExIS.UI/Models/ReferenceModels.cs | 40 +++++++ .../BExIS.Utils.Data/BExIS.Utils.Data.csproj | 3 + .../Helpers/EntityReferenceHelper.cs | 110 +++++++++--------- .../Utils/BExIS.Utils.Data/packages.config | 1 + .../Hooks/EntityReferenceController.cs | 2 +- .../Legacy/CreateDatasetController.cs | 4 +- .../Views/EntityReference/_create.cshtml | 2 + 10 files changed, 131 insertions(+), 62 deletions(-) diff --git a/Components/AAA/BExIS.Security.Entities/Objects/EntityReference.cs b/Components/AAA/BExIS.Security.Entities/Objects/EntityReference.cs index 501f7b072b..943a813f8b 100644 --- a/Components/AAA/BExIS.Security.Entities/Objects/EntityReference.cs +++ b/Components/AAA/BExIS.Security.Entities/Objects/EntityReference.cs @@ -27,6 +27,8 @@ public class EntityReference : BaseEntity public virtual int TargetVersion { get; set; } public virtual string Context { get; set; } public virtual string ReferenceType { get; set; } + public virtual string LinkType { get; set; } + public virtual string Category { get; set; } public virtual DateTime CreationDate { get; set; } public EntityReference() @@ -37,9 +39,14 @@ public EntityReference() TargetEntityId = 0; Context = ""; ReferenceType = ""; + CreationDate = DateTime.Now; + LinkType = ""; + Category = ""; + SourceVersion = 0; + TargetVersion = 0; } - public EntityReference(long sourceId, long sourceEntityId, int sourceVersion, long targetId, long targetEntityId, int targetVersion, string context, string type, DateTime creationDate) + public EntityReference(long sourceId, long sourceEntityId, int sourceVersion, long targetId, long targetEntityId, int targetVersion, string context, string type, DateTime creationDate, string linkType , string category) { SourceId = sourceId; SourceEntityId = sourceEntityId; @@ -50,6 +57,8 @@ public EntityReference(long sourceId, long sourceEntityId, int sourceVersion, lo Context = context; ReferenceType = type; CreationDate = creationDate; + Category = category; + LinkType = linkType; } } } \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Orm.NH/Mappings/Default/Objects/EntityReference.hbm.xml b/Components/AAA/BExIS.Security.Orm.NH/Mappings/Default/Objects/EntityReference.hbm.xml index c27b6415e8..53a3183835 100644 --- a/Components/AAA/BExIS.Security.Orm.NH/Mappings/Default/Objects/EntityReference.hbm.xml +++ b/Components/AAA/BExIS.Security.Orm.NH/Mappings/Default/Objects/EntityReference.hbm.xml @@ -22,6 +22,8 @@ + + \ No newline at end of file diff --git a/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs b/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs index cda1cad4f5..41c342bb4f 100644 --- a/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs +++ b/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs @@ -42,7 +42,9 @@ public bool Exist(EntityReference entityReference, bool includeVersion = false, r.TargetEntityId.Equals(entityReference.TargetEntityId) && r.TargetVersion.Equals(entityReference.TargetVersion) && r.Context.Equals(entityReference.Context) && - r.ReferenceType.Equals(entityReference.ReferenceType) + r.ReferenceType.Equals(entityReference.ReferenceType) && + r.LinkType.Equals(entityReference.LinkType) && + r.Category.Equals(entityReference.Category) ).Count() == 0) return false; } @@ -55,7 +57,10 @@ public bool Exist(EntityReference entityReference, bool includeVersion = false, r.TargetEntityId.Equals(entityReference.TargetEntityId) && r.TargetVersion.Equals(entityReference.TargetVersion) && r.Context.Equals(entityReference.Context) && - r.ReferenceType.Equals(entityReference.ReferenceType) + r.ReferenceType.Equals(entityReference.ReferenceType) && + r.LinkType.Equals(entityReference.LinkType) && + r.Category.Equals(entityReference.Category) + ).Count() == 0) return false; } @@ -67,7 +72,10 @@ public bool Exist(EntityReference entityReference, bool includeVersion = false, r.TargetId.Equals(entityReference.TargetId) && r.TargetEntityId.Equals(entityReference.TargetEntityId) && r.Context.Equals(entityReference.Context) && - r.ReferenceType.Equals(entityReference.ReferenceType) + r.ReferenceType.Equals(entityReference.ReferenceType) && + r.LinkType.Equals(entityReference.LinkType) && + r.Category.Equals(entityReference.Category) + ).Count() == 0) return false; } @@ -85,9 +93,9 @@ public void Create(EntityReference entityReference) } } - public EntityReference Create(long sourceId, long sourceEntityId, int sourceEntityVersion, long targetId, long targetEntityId, int targetEntityVersion, string context, string type) + public EntityReference Create(long sourceId, long sourceEntityId, int sourceEntityVersion, long targetId, long targetEntityId, int targetEntityVersion, string context, string type, string linkType, string category) { - EntityReference entityReference = new EntityReference(sourceId, sourceEntityId, sourceEntityVersion, targetId, targetEntityId, targetEntityVersion, context, type, DateTime.Now); + EntityReference entityReference = new EntityReference(sourceId, sourceEntityId, sourceEntityVersion, targetId, targetEntityId, targetEntityVersion, context, type, DateTime.Now, linkType, category); using (var uow = this.GetUnitOfWork()) { diff --git a/Components/UI/BExIS.UI/Models/ReferenceModels.cs b/Components/UI/BExIS.UI/Models/ReferenceModels.cs index 607ead2be2..a7ad83fb44 100644 --- a/Components/UI/BExIS.UI/Models/ReferenceModels.cs +++ b/Components/UI/BExIS.UI/Models/ReferenceModels.cs @@ -40,6 +40,8 @@ public class ReferenceModel public string Context { get; set; } public string ReferenceType { get; set; } + public string LinkType { get; set; } + public string Category { get; set; } public ReferenceModel() { @@ -48,6 +50,8 @@ public ReferenceModel() Source = new ReferenceElementModel(); Context = ""; ReferenceType = ""; + LinkType = ""; + Category = ""; } } @@ -100,6 +104,7 @@ public class CreateSimpleReferenceModel [Required] public String ReferenceType { get; set; } + public CreateSimpleReferenceModel() { Context = ""; @@ -113,4 +118,39 @@ public CreateSimpleReferenceModel(long sourceId, long sourceTypeId, int sourceVe Context = ""; } } + + public class ReferenceConfig + { + public List ReferenceTypes { get; set; } + public List EntityWhiteList { get; set; } + + public ReferenceConfig() + { + ReferenceTypes = new List(); + EntityWhiteList = new List(); + } + } + + public class ReferenceConfigElement + { + /* + "description": "has dwc:Event extension", + "referenceType": "HasEvent", + "linkType": "extension", + "category": "extension" + }, + */ + public string ReferenceType { get; set; } + public string Description { get; set; } + public string LinkType { get; set; } + public string Category { get; set; } + + public ReferenceConfigElement() + { + ReferenceType=""; + Description = ""; + LinkType = ""; + Category = ""; + } + } } \ No newline at end of file diff --git a/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj b/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj index b8291b9234..2e61b79db3 100644 --- a/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj +++ b/Components/Utils/BExIS.Utils.Data/BExIS.Utils.Data.csproj @@ -44,6 +44,9 @@ ..\..\..\packages\Microsoft.Web.Infrastructure.1.0.0.0\lib\net40\Microsoft.Web.Infrastructure.dll + + ..\..\..\packages\Newtonsoft.Json.13.0.3\lib\net45\Newtonsoft.Json.dll + diff --git a/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs b/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs index 25ac21be5d..943e2ec55f 100644 --- a/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs +++ b/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs @@ -1,6 +1,7 @@ using BExIS.Security.Entities.Objects; using BExIS.Security.Services.Objects; using BExIS.UI.Models.EntityReference; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -15,9 +16,11 @@ namespace BExIS.Utils.Data.Helpers { public class EntityReferenceHelper { + private ReferenceConfig _config = null; + public EntityReferenceHelper() { - + _config = getReferenceConfig(); } public bool EntityExist(long id, long typeId) @@ -193,21 +196,17 @@ public EntityReference Convert(CreateSimpleReferenceModel model) tmp.ReferenceType = model.ReferenceType; tmp.CreationDate = DateTime.Now; - return tmp; - } + // get additional informations + ReferenceConfigElement config = GetReferenceConfigByType(model.ReferenceType); - //public EntityReference Convert(SimpleReferenceModel model, long sourceId, long sourceTypeId) - //{ - // EntityReference tmp = new EntityReference(); - // tmp.SourceId = sourceId; - // tmp.SourceEntityId = sourceTypeId; - // tmp.TargetId = model.Id; - // tmp.TargetEntityId = model.TypeId; - // tmp.Context = model.Context; - // tmp.ReferenceType = model.ReferenceType; + if (config != null) + { + tmp.LinkType = config.LinkType; + tmp.Category = config.Category; + } - // return tmp; - //} + return tmp; + } public SimpleSourceReferenceModel GetSimpleReferenceModel(long id, long typeId, int version) { @@ -248,6 +247,8 @@ public ReferenceModel Convert(EntityReference entityReference) tmp.Context = entityReference.Context; tmp.ReferenceType = entityReference.ReferenceType; tmp.RefId = entityReference.Id; + tmp.LinkType = entityReference.LinkType; + tmp.Category = entityReference.Category; return tmp; } @@ -346,54 +347,58 @@ public List GetTargetReferences(long id, long typeid, int versio #region Entity Reference Config - /// - /// this function return a list of all reference types. This types are listed in the entity reference config.xml in the workspace - /// - /// - public SelectList GetReferencesTypes() + private ReferenceConfig getReferenceConfig() { - string filepath = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DCM"), "EntityReferenceConfig.xml"); + string filepath = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DCM"), "EntityReferenceConfig.json"); string dir = Path.GetDirectoryName(filepath); if (Directory.Exists(dir) && File.Exists(filepath)) { - XDocument xdoc = XDocument.Load(filepath); + ReferenceConfig referenceConfig = new ReferenceConfig(); + referenceConfig = JsonConvert.DeserializeObject(File.ReadAllText(filepath)); - var types = xdoc.Root.Descendants("referenceType").Select(e => new SelectListItem() - { - Text = String.IsNullOrEmpty(e.Attribute("description").Value) ? e.Value : e.Attribute("description").Value, - Value = e.Value - }).ToList(); - - return new SelectList(types, "Value", "Text"); + return referenceConfig; } else { - throw new FileNotFoundException("File EntityReferenceConfig.xml not found in :" + dir, "EntityReferenceConfig.xml"); + throw new FileNotFoundException("File EntityReferenceConfig.json not found in :" + dir, "EntityReferenceConfig.json"); } } - public SelectList GetReferencesHelpTypes() + private ReferenceConfigElement GetReferenceConfigByType(string type) { - string filepath = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DCM"), "EntityReferenceConfig.xml"); - string dir = Path.GetDirectoryName(filepath); - - if (Directory.Exists(dir) && File.Exists(filepath)) + if (_config != null) { - XDocument xdoc = XDocument.Load(filepath); + return _config.ReferenceTypes.Where(e => e.ReferenceType.Equals(type)).FirstOrDefault(); + } + + return null; + } - var types = xdoc.Root.Descendants("referenceType").Select(e => new SelectListItem() + /// + /// this function return a list of all reference types. This types are listed in the entity reference config.xml in the workspace + /// + /// + public SelectList GetReferencesTypes() + { + + if (_config != null) + { + var types = _config.ReferenceTypes.Select(e => new SelectListItem() { - Text = String.IsNullOrEmpty(e.Attribute("description").Value) ? e.Value : e.Attribute("description").Value, - Value = e.Value, + Text = String.IsNullOrEmpty(e.Description) ? e.ReferenceType : e.Description, + Value = e.ReferenceType }).ToList(); return new SelectList(types, "Value", "Text"); } - else - { - throw new FileNotFoundException("File EntityReferenceConfig.xml not found in :" + dir, "EntityReferenceConfig.xml"); - } + + return new SelectList(new List(), "Value", "Text"); + } + + public SelectList GetReferencesHelpTypes() + { + return GetReferencesTypes(); } #endregion Entity Reference Config @@ -406,21 +411,18 @@ public SelectList GetReferencesHelpTypes() /// public SelectList GetEntityTypesWhitlist() { - string filepath = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DCM"), "EntityReferenceConfig.xml"); - string dir = Path.GetDirectoryName(filepath); - - if (Directory.Exists(dir) && File.Exists(filepath)) + if (_config != null) { - XDocument xdoc = XDocument.Load(filepath); - - var types = xdoc.Root.Descendants("entityType").Select(e => new SelectListItem() { Text = e.Attribute("description").Value.ToString(), Value = e.Value }).ToList(); + var types = _config.EntityWhiteList.Select(e => new SelectListItem() + { + Text = e, + Value = e + }).ToList(); - return new SelectList(types, "Text", "Value"); - } - else - { - throw new FileNotFoundException("File EntityReferenceConfig.xml not found in :" + dir, "EntityReferenceConfig.xml"); + return new SelectList(types, "Value", "Text"); } + + return new SelectList(new List(), "Value", "Text"); } #endregion Entity Config diff --git a/Components/Utils/BExIS.Utils.Data/packages.config b/Components/Utils/BExIS.Utils.Data/packages.config index 6813cae0ec..7ae810c359 100644 --- a/Components/Utils/BExIS.Utils.Data/packages.config +++ b/Components/Utils/BExIS.Utils.Data/packages.config @@ -5,4 +5,5 @@ + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs index c8f083815e..9ed18a2314 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs @@ -170,7 +170,7 @@ public JsonResult GetTargetVersions(long id, long type) /// [HttpPost] - [CustomValidateAntiForgeryToken] + //[CustomValidateAntiForgeryToken] public JsonResult Delete(long id) { if (id == 0) return Json(false); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/CreateDatasetController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/CreateDatasetController.cs index b328f326fa..9a922f0085 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/CreateDatasetController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/CreateDatasetController.cs @@ -800,7 +800,9 @@ private List getAllMetadataReferences(DatasetVersion datasetVer xVersion, xpath, DefaultEntitiyReferenceType.MetadataLink.GetDisplayName(), - DateTime.Now + DateTime.Now, + "", + "" )); } } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/EntityReference/_create.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/EntityReference/_create.cshtml index bdc40e9d93..63c016e350 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/EntityReference/_create.cshtml +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/EntityReference/_create.cshtml @@ -26,6 +26,8 @@ @using (Ajax.BeginForm("Create", "EntityReference", new AjaxOptions { HttpMethod = "POST", UpdateTargetId = "content_createEnityReference", OnSuccess = "createEntityReference_OnSuccess" })) { + @Html.AntiForgeryToken() + @Html.ValidationSummary(true) @Html.HiddenFor(m => m.SourceId); From cbfd6b9e01f5ed9bfa554aa8715a2545e1ee49e7 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 11 Sep 2025 11:06:43 +0200 Subject: [PATCH 004/490] #2206 enhance entity temaple with extnsions list --- .../BExIS.Dlm.Entities/Data/EntityTemplate.cs | 29 +++++++++++++-- .../Default/Data/EntityTemplate.hbm.xml | 8 +++++ .../src/models/EntityTemplate.ts | 2 ++ .../src/routes/entitytemplates/+page.svelte | 6 +++- .../src/routes/entitytemplates/Edit.svelte | 36 +++++++++++++++++++ .../src/services/EntityTemplateCaller.ts | 10 ++++++ .../Controllers/EntityTemplatesController.cs | 16 +++++++++ .../Helpers/EntityTemplateHelper.cs | 6 ++++ .../EntityTemplates/EntityTemplateModels.cs | 10 ++++++ .../Controllers/DataController.cs | 2 -- database update scripts/4.1.0.-4.2.0.sql | 8 +++++ 11 files changed, 127 insertions(+), 6 deletions(-) diff --git a/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs b/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs index 2049032591..da1fdb8658 100644 --- a/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs +++ b/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs @@ -57,9 +57,7 @@ public virtual List MetadataFields public virtual bool MetadataInvalidSaveMode { get; set; } /// - /// should the user be able to save the metadata if not alle mandatory are filled correct - /// if true - also not valid metadat will be stored - /// if false - only valid metadata will be stored + /// should the user be able to select a datastructure /// public virtual bool HasDatastructure { get; set; } @@ -79,6 +77,27 @@ public virtual List DatastructureList JsonDatastructureList = JsonConvert.SerializeObject(value); } } + /// + /// should the user be able to select a extension + /// + public virtual bool HasExtension { get; set; } + + /// + /// List of available Extensions + /// + public virtual string JsonExtensionList { get; set; } + + public virtual List ExtensionList + { + get + { + return JsonConvert.DeserializeObject>(JsonExtensionList); + } + set + { + JsonExtensionList = JsonConvert.SerializeObject(value); + } + } /// /// @@ -169,6 +188,7 @@ public EntityTemplate() PermissionGroups = new PermissionsType(); NotificationGroups = new List(); MetadataInvalidSaveMode = true; + ExtensionList = new List(); JsonAllowedFileTypes = ""; JsonDatastructureList = ""; @@ -176,6 +196,7 @@ public EntityTemplate() JsonMetadataFields = ""; JsonPermissionGroups = ""; JsonNotificationGroups = ""; + JsonExtensionList = ""; } public EntityTemplate(string name, string description, Entity entityType, MetadataStructure.MetadataStructure metadataStructure) @@ -187,6 +208,7 @@ public EntityTemplate(string name, string description, Entity entityType, Metada AllowedFileTypes = new List(); DisabledHooks = new List(); DatastructureList = new List(); + ExtensionList = new List(); MetadataFields = new List(); PermissionGroups = new PermissionsType(); NotificationGroups = new List(); @@ -198,6 +220,7 @@ public EntityTemplate(string name, string description, Entity entityType, Metada JsonMetadataFields = ""; JsonPermissionGroups = ""; JsonNotificationGroups = ""; + JsonExtensionList = ""; } } diff --git a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml index 59d4a5c1cd..88dac5884f 100644 --- a/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml +++ b/Components/DLM/BExIS.Dlm.Orm.NH/Mappings/Default/Data/EntityTemplate.hbm.xml @@ -40,6 +40,14 @@ + + + + + + + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts index 256c132412..8b94438be9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts @@ -10,6 +10,8 @@ export interface EntityTemplateModel { metadataInvalidSaveMode: boolean; hasDatastructure: boolean; datastructureList: number[]; + hasExtension: boolean; + extentionsList: number[]; allowedFileTypes: string[]; disabledHooks: string[]; notificationGroups: number[]; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte index f1b6fa4e05..dd735a5420 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte @@ -20,7 +20,8 @@ getGroups, getHooks, getFileTypes, - getEntityTemplateList + getEntityTemplateList, + getExtensions } from '../../services/EntityTemplateCaller'; // types @@ -35,6 +36,7 @@ let entities = []; let groups = []; let filetypes = []; + let extensions = []; let isOpen = false; let header = ''; @@ -49,6 +51,7 @@ entities = await getEntities(); groups = await getGroups(); filetypes = await getFileTypes(); + extensions = await getExtensions(); entityTemplatesStore.set(await getEntityTemplateList()); } @@ -127,6 +130,7 @@ {entities} {groups} {filetypes} + {extensions} on:save={refresh} on:cancel={() => (isOpen = false)} /> diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte index 388d7cfdbe..3db74d5df8 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte @@ -46,6 +46,7 @@ export let entities = []; export let groups = []; export let filetypes: string[]; + export let extensions: []; const dispatch = createEventDispatcher(); @@ -286,6 +287,41 @@ +
+

Extension

+
+ +
helpStore.show('hasExtension')} + on:focus={() => helpStore.show('hasExtension')} + > + + Allow to use data structures + + + {#if entityTemplate.hasExtension} + + {/if} +
+
+
+
+

Administration

Set permissions per default to the following groups

diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts index 76de6a462a..37552091b9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts @@ -61,6 +61,16 @@ export const getDataStructures = async () => { } }; +export const getExtensions = async () => { + try { + const response = await Api.get('/dcm/entitytemplates/Extensions'); + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + export const getHooks = async () => { try { const response = await Api.get('/dcm/entitytemplates/Hooks'); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs index a2123248fc..a39f6ef8db 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs @@ -188,6 +188,22 @@ public JsonResult DataStructures() return Json(tmp, JsonRequestBehavior.AllowGet); } + [JsonNetFilter] + [HttpGet] + public JsonResult Extensions() + { + List> tmp = new List>(); + using (var entityTemplateManager = new EntityTemplateManager()) + using (var entityManager = new EntityManager()) + { + var extensionEntity = entityManager.EntityRepository.Get().Where(e => e.Name.Equals("Extension")).FirstOrDefault(); + tmp = entityTemplateManager.Repo.Query(t=>t.EntityType.Id.Equals(extensionEntity.Id)) + .Select(e => new KeyValuePair(e.Id, e.Name)).ToList(); + } + + return Json(tmp, JsonRequestBehavior.AllowGet); + } + [JsonNetFilter] [HttpGet] public JsonResult Hooks() diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs index c6813b4117..5ef684eebc 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs @@ -23,6 +23,8 @@ public static EntityTemplate ConvertTo(EntityTemplateModel model) entityTemplate.HasDatastructure = model.HasDatastructure; entityTemplate.DisabledHooks = model.DisabledHooks; entityTemplate.DatastructureList = model.DatastructureList; + entityTemplate.HasExtension = model.HasExtension; + entityTemplate.ExtensionList = model.ExtensionList; entityTemplate.AllowedFileTypes = model.AllowedFileTypes; entityTemplate.PermissionGroups = model.PermissionGroups; entityTemplate.NotificationGroups = model.NotificationGroups; @@ -61,8 +63,10 @@ public static EntityTemplate Merge(EntityTemplateModel model) entityTemplate.Description = model.Description; entityTemplate.MetadataInvalidSaveMode = model.MetadataInvalidSaveMode; entityTemplate.HasDatastructure = model.HasDatastructure; + entityTemplate.HasExtension = model.HasExtension; entityTemplate.DisabledHooks = model.DisabledHooks; entityTemplate.DatastructureList = model.DatastructureList; + entityTemplate.ExtensionList = model.ExtensionList; entityTemplate.AllowedFileTypes = model.AllowedFileTypes; entityTemplate.PermissionGroups = model.PermissionGroups; entityTemplate.NotificationGroups = model.NotificationGroups; @@ -91,8 +95,10 @@ public static EntityTemplateModel ConvertTo(EntityTemplate entityTemplate, bool model.Description = entityTemplate.Description; model.MetadataInvalidSaveMode = entityTemplate.MetadataInvalidSaveMode; model.HasDatastructure = entityTemplate.HasDatastructure; + model.HasExtension = entityTemplate.HasExtension; model.DisabledHooks = entityTemplate.DisabledHooks != null ? entityTemplate.DisabledHooks : new List(); ; model.DatastructureList = entityTemplate.DatastructureList != null ? entityTemplate.DatastructureList : new List(); + model.ExtensionList = entityTemplate.ExtensionList != null ? entityTemplate.ExtensionList : new List(); model.AllowedFileTypes = entityTemplate.AllowedFileTypes != null ? entityTemplate.AllowedFileTypes : new List(); model.PermissionGroups = entityTemplate.PermissionGroups != null ? entityTemplate.PermissionGroups : new PermissionsType(); model.NotificationGroups = entityTemplate.NotificationGroups != null ? entityTemplate.NotificationGroups : new List(); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs index 1db777c199..3dffe7aa9d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs @@ -45,6 +45,11 @@ public class EntityTemplateModel ///
public virtual bool HasDatastructure { get; set; } + /// + /// If this flag is true, the entity will have a extensions + /// + public virtual bool HasExtension { get; set; } + /// /// If this flag is true, user can use this tempate to create a entity /// @@ -55,6 +60,11 @@ public class EntityTemplateModel /// public virtual List DatastructureList { get; set; } + /// + /// List of available extensions + /// + public virtual List ExtensionList { get; set; } + public List AllowedFileTypes { get; set; } /// diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs index a195cc2896..5fd6be6435 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs @@ -2243,8 +2243,6 @@ public Dictionary getLabels(long id, long versionId, double tag, { Dictionary keyValuePairs = new Dictionary(); - - var publications = publicationManager.PublicationRepo.Query(p => p.Dataset.Id == id && p.DatasetVersion.Id == versionId && p.ExternalLink != ""); if (publications != null && publications.Any()) { diff --git a/database update scripts/4.1.0.-4.2.0.sql b/database update scripts/4.1.0.-4.2.0.sql index 05994d4892..f4a9c148f9 100644 --- a/database update scripts/4.1.0.-4.2.0.sql +++ b/database update scripts/4.1.0.-4.2.0.sql @@ -23,6 +23,14 @@ SELECT WHERE NOT EXISTS (SELECT * FROM public.entities WHERE name='Extension'); +-- update entity template +--- add columns +--- update existing entity templates + +-- update entity references +--- add link type, category + + -- BEXIS2 Version Update From 0c83670811255d2f7970887bc246859c839ffde0 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 11 Sep 2025 11:27:35 +0200 Subject: [PATCH 005/490] #2206 fix typing issue in entity template model --- .../BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts index 8b94438be9..35c90ee9ac 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/EntityTemplate.ts @@ -11,7 +11,7 @@ export interface EntityTemplateModel { hasDatastructure: boolean; datastructureList: number[]; hasExtension: boolean; - extentionsList: number[]; + extensionsList: number[]; allowedFileTypes: string[]; disabledHooks: string[]; notificationGroups: number[]; From 90addd8d2cfa9c355880d9508e5f52a34713e2a7 Mon Sep 17 00:00:00 2001 From: david schoene Date: Fri, 12 Sep 2025 09:34:36 +0200 Subject: [PATCH 006/490] #2209 add extension update into edit of a entity --- Components/UI/BExIS.UI/BExIS.UI.csproj | 1 + .../UI/BExIS.UI/Models/ExtensionItem.cs | 18 ++ .../lib/components/ExtensionCreation.svelte | 1 + .../src/routes/edit/+page.svelte | 250 +++--------------- .../src/routes/edit/AdvancedEntity.svelte | 46 ++++ .../src/routes/edit/Entity.svelte | 222 ++++++++++++++++ .../src/routes/edit/services.js | 15 ++ .../src/routes/edit/types.ts | 6 + .../src/routes/entitytemplates/Edit.svelte | 2 +- .../src/services/EntityTemplateCaller.ts | 10 + .../Controllers/EditController.cs | 38 +++ .../Controllers/EntityTemplatesController.cs | 17 ++ 12 files changed, 414 insertions(+), 212 deletions(-) create mode 100644 Components/UI/BExIS.UI/Models/ExtensionItem.cs create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte diff --git a/Components/UI/BExIS.UI/BExIS.UI.csproj b/Components/UI/BExIS.UI/BExIS.UI.csproj index efdf488fdf..80e6e0ac7d 100644 --- a/Components/UI/BExIS.UI/BExIS.UI.csproj +++ b/Components/UI/BExIS.UI/BExIS.UI.csproj @@ -119,6 +119,7 @@ + diff --git a/Components/UI/BExIS.UI/Models/ExtensionItem.cs b/Components/UI/BExIS.UI/Models/ExtensionItem.cs new file mode 100644 index 0000000000..d6e1acd953 --- /dev/null +++ b/Components/UI/BExIS.UI/Models/ExtensionItem.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace BExIS.UI.Models +{ + public class ExtensionItem + { + public long Id { get; set; } + public int Version { get; set; } + public string Title { get; set; } + + public string LinkType { get; set; } + public string ReferenceType { get; set; } + } +} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte new file mode 100644 index 0000000000..c7e9705d78 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte @@ -0,0 +1 @@ +

creat extnsion here

\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte index 9a23532e56..81a7cb32e8 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte @@ -1,236 +1,64 @@ - -
- {#await load()} - - {:then a} - {#if model && model.hooks && datasethooks && addtionalhooks && hookStatusList} - - -
+ {#if entityTemplate} +
+ + {#if entityTemplate.hasExtension} + - - {:else} - - {/if} - {:catch error} - - {/await} - + {:else} + + {/if} + + {/if} + - + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte new file mode 100644 index 0000000000..15a56b92f2 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte @@ -0,0 +1,46 @@ + + + + + entity + + + + {#each extensions as ext (ext.id)} + + {ext.title} + + {/each} + + + + + + + + + {#if tabSet === 0} + + {:else if tabSet === 100} + + {/if} + + {#each extensions as ext (ext.id)} + {#if tabSet === ext.id} + {id},{title} + + {/if} + {/each} + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte new file mode 100644 index 0000000000..9e418456be --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte @@ -0,0 +1,222 @@ + + + {#await load()} + + {:then a} + {#if model && model.hooks && datasethooks && addtionalhooks && hookStatusList} + + + +
+ + + {:else} + + {/if} + {:catch error} + + {/await} + + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js index 898e8b7326..677f10c2ef 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js @@ -32,6 +32,21 @@ export const getHooks = async (id) => { } }; +// get Model for Edit page +export const getExtensions = async (id) => { + console.log('getExtensions', id); + + try { + const response = await Api.get('/dcm/edit/GetExtensions?id=' + id); + console.log(response); + + return response.data; + } catch (error) { + console.error('error', error); + throw error; + } +}; + // get Model for Edit page export const submit = async (id) => { //console.log("edit",id); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/types.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/types.ts index 79cb3d4c4d..c39583c58b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/types.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/types.ts @@ -39,3 +39,9 @@ export enum HookMode { view = 0, edit = 1 } + +export interface ExtensionType{ + id: number; + version: number; + title: string; +}; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte index 3db74d5df8..fae7971fb2 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte @@ -310,7 +310,7 @@ id="datastructures" title="Limit the selection of allowed extensions" source={extensions} - bind:target={entityTemplate.extentionsList} + bind:target={entityTemplate.extensionList} itemId="key" itemLabel="value" complexSource={true} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts index 37552091b9..0fc56da0a0 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts @@ -11,6 +11,16 @@ export const getEntityTemplate = async (id: number) => { } }; +export const getEntityTemplateByObject = async (id: number) => { + try { + const response = await Api.get('/dcm/entitytemplates/GetByObject?id=' + id); + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + export const getEntityTemplateList = async () => { try { const response = await Api.get('/dcm/entitytemplates/Load'); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs index a2e089b1a2..4ebfa78c64 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs @@ -4,10 +4,13 @@ using BExIS.Dlm.Services.Data; using BExIS.Modules.Dcm.UI.Models.Edit; using BExIS.Security.Entities.Authorization; +using BExIS.Security.Services.Objects; using BExIS.UI.Helpers; using BExIS.UI.Hooks; +using BExIS.UI.Models; using System; using System.Collections.Generic; +using System.Linq; using System.Web.Mvc; namespace BExIS.Modules.Dcm.UI.Controllers @@ -121,5 +124,40 @@ public JsonResult Hooks(long id, int version = 0) return Json(Hooks, JsonRequestBehavior.AllowGet); } } + + #region extension + [JsonNetFilter] + public JsonResult GetExtensions(long id) + { + List tmp = new List(); + + using (var datasetManager = new DatasetManager()) + using (var entityReferenceManager = new EntityReferenceManager()) + { + var dataset = datasetManager.GetDataset(id); + var entity = dataset.EntityTemplate.EntityType; + + var entityreferences = entityReferenceManager.ReferenceRepository.Query(e => + e.LinkType.Equals("extension") && + e.SourceId.Equals(id) && + e.SourceEntityId.Equals(entity.Id)).ToList(); + + foreach (var x in entityreferences) + { + string title = datasetManager.GetDatasetVersion(x.TargetId, x.TargetVersion).Title; + tmp.Add(new ExtensionItem() + { + Id = x.TargetId, + Version = x.TargetVersion, + Title = title, + LinkType = x.LinkType, + ReferenceType = x.ReferenceType + }); + } + } + return Json(tmp, JsonRequestBehavior.AllowGet); + } + + #endregion } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs index a39f6ef8db..a357040915 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs @@ -64,6 +64,23 @@ public JsonResult Get(long id) } } + + [JsonNetFilter] + [HttpGet] + public JsonResult GetByObject(long id) + { + if (id == 0) return Json(new EntityTemplateModel(), JsonRequestBehavior.AllowGet); + + using (var datasetManager = new DatasetManager()) + using (var entityTemplateManager = new EntityTemplateManager()) + { + var obj = datasetManager.GetDataset(id); + var entityTemplate = entityTemplateManager.Repo.Get(obj.EntityTemplate.Id); + return Json(EntityTemplateHelper.ConvertTo(entityTemplate), JsonRequestBehavior.AllowGet); + } + } + + [JsonNetFilter] [HttpDelete] public JsonResult Delete(long id) From 3957db54ab2124ee1e7a001bf4f463edfb36e30d Mon Sep 17 00:00:00 2001 From: david schoene Date: Fri, 19 Sep 2025 13:28:00 +0200 Subject: [PATCH 007/490] #2206 refactor extension selection by template #2209 change edit page that extensions are addeable --- .../BExIS.Dlm.Entities/Data/EntityTemplate.cs | 23 +++- .../Helpers/EntityReferenceHelper.cs | 33 ++++- .../components}/EntryContainer.svelte | 0 .../lib/components/ExtensionCreation.svelte | 1 - .../lib/components/ExtensionEntries.svelte | 55 ++++++++ .../src/lib/components/ExtensionEntry.svelte | 52 ++++++++ .../components/entityTemplate}/Form.svelte | 0 .../entityTemplate}/InputEntry.svelte | 0 .../components/entityTemplate}/List.svelte | 2 +- .../entityTemplate}/ListItem.svelte | 0 .../components/entityTemplate}/form.js | 0 .../lib/components/entityTemplate/services.js | 24 ++++ .../src/models/EntityTemplate.ts | 18 ++- .../src/routes/create/+page.svelte | 4 +- .../src/routes/create/services.js | 17 --- .../src/routes/edit/AdvancedEntity.svelte | 4 +- .../src/routes/edit/ExtensionCreation.svelte | 86 +++++++++++++ .../src/routes/edit/services.js | 21 ++++ .../src/routes/entitytemplates/+page.svelte | 16 ++- .../src/routes/entitytemplates/Edit.svelte | 48 +++---- .../src/services/EntityTemplateCaller.ts | 11 ++ .../Controllers/EditController.cs | 118 +++++++++++++++++- .../Controllers/EntityTemplatesController.cs | 13 +- .../Helpers/EntityTemplateHelper.cs | 2 +- .../EntityTemplates/EntityTemplateModels.cs | 2 +- .../Helpers/DimSeedDataGenerator.cs | 38 ++++++ 26 files changed, 525 insertions(+), 63 deletions(-) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/entitytemplates => lib/components}/EntryContainer.svelte (100%) delete mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntries.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntry.svelte rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/create => lib/components/entityTemplate}/Form.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/create => lib/components/entityTemplate}/InputEntry.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/create => lib/components/entityTemplate}/List.svelte (85%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/create => lib/components/entityTemplate}/ListItem.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/create => lib/components/entityTemplate}/form.js (100%) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/services.js create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte diff --git a/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs b/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs index da1fdb8658..bec56ae4fe 100644 --- a/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs +++ b/Components/DLM/BExIS.Dlm.Entities/Data/EntityTemplate.cs @@ -87,11 +87,11 @@ public virtual List DatastructureList ///
public virtual string JsonExtensionList { get; set; } - public virtual List ExtensionList + public virtual List ExtensionList { get { - return JsonConvert.DeserializeObject>(JsonExtensionList); + return JsonConvert.DeserializeObject>(JsonExtensionList); } set { @@ -188,7 +188,7 @@ public EntityTemplate() PermissionGroups = new PermissionsType(); NotificationGroups = new List(); MetadataInvalidSaveMode = true; - ExtensionList = new List(); + ExtensionList = new List(); JsonAllowedFileTypes = ""; JsonDatastructureList = ""; @@ -208,7 +208,7 @@ public EntityTemplate(string name, string description, Entity entityType, Metada AllowedFileTypes = new List(); DisabledHooks = new List(); DatastructureList = new List(); - ExtensionList = new List(); + ExtensionList = new List(); MetadataFields = new List(); PermissionGroups = new PermissionsType(); NotificationGroups = new List(); @@ -239,4 +239,19 @@ public PermissionsType() ViewEdit = new List(); } } + + public class ExtensionType + { + public long TemplateId { get; set; } + public string ReferenceType { get; set; } + public bool Unique { get; set; } + + + public ExtensionType() + { + TemplateId = 0; + ReferenceType = ""; + Unique = true; + } + } } \ No newline at end of file diff --git a/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs b/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs index 943e2ec55f..a6b1ad1aba 100644 --- a/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs +++ b/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs @@ -365,7 +365,7 @@ private ReferenceConfig getReferenceConfig() } } - private ReferenceConfigElement GetReferenceConfigByType(string type) + public ReferenceConfigElement GetReferenceConfigByType(string type) { if (_config != null) { @@ -375,6 +375,7 @@ private ReferenceConfigElement GetReferenceConfigByType(string type) return null; } + /// /// this function return a list of all reference types. This types are listed in the entity reference config.xml in the workspace /// @@ -396,6 +397,36 @@ public SelectList GetReferencesTypes() return new SelectList(new List(), "Value", "Text"); } + public SelectList GetReferencesTypes(string type) + { + + if (_config != null) + { + var types = _config.ReferenceTypes.Where(e => e.LinkType.Equals(type)).Select(e => new SelectListItem() + { + Text = String.IsNullOrEmpty(e.Description) ? e.ReferenceType : e.Description, + Value = e.ReferenceType + }).ToList(); + + return new SelectList(types, "Value", "Text"); + } + + return new SelectList(new List(), "Value", "Text"); + } + + public List> GetReferencesTypesAsKVP(string type) + { + List> tmp = new List>(); + if (_config != null) + { + tmp = _config.ReferenceTypes.Where(e => e.LinkType.Equals(type)).Select(e => + new KeyValuePair(e.ReferenceType, string.IsNullOrEmpty(e.Description) ? e.ReferenceType : e.Description)).ToList(); + + } + + return tmp; + } + public SelectList GetReferencesHelpTypes() { return GetReferencesTypes(); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/EntryContainer.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/EntryContainer.svelte similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/EntryContainer.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/EntryContainer.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte deleted file mode 100644 index c7e9705d78..0000000000 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionCreation.svelte +++ /dev/null @@ -1 +0,0 @@ -

creat extnsion here

\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntries.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntries.svelte new file mode 100644 index 0000000000..040030b681 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntries.svelte @@ -0,0 +1,55 @@ + +{#if selectedExtensions && selectedExtensions.length > 0} +
+ +
+ +
+
Extension Template
+
Reference Type
+
+
+ {#each selectedExtensions as extension, i} +
+
+ +
+
+ +
+
+ {/each} + + +
+{/if} +
+ +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntry.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntry.svelte new file mode 100644 index 0000000000..75fa145270 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/ExtensionEntry.svelte @@ -0,0 +1,52 @@ + + +
+ +
+ + +
+ +
+ + onChangeFn(e)} + /> +
+
+ Unique +
+ + +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/Form.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/Form.svelte similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/Form.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/Form.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/InputEntry.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/InputEntry.svelte similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/InputEntry.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/InputEntry.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/List.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/List.svelte similarity index 85% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/List.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/List.svelte index b5579674d0..ccb7435faa 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/create/List.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/entityTemplate/List.svelte @@ -1,5 +1,5 @@ + + +
+ {#await load()} +
+ +
+ {:then result} +
+ + + {#if selected && isOpen} +
(isOpen = false)} + on:save={(e) => onSaveHandler(e)} + /> + {/if} +
+ {:catch error} + + {/await} +
+ diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js index 677f10c2ef..a048db883d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js @@ -95,3 +95,24 @@ export const removeFile = async (action, id, file) => { throw error; } }; + +export const getExtensionEntityTemplateList = async (id) => { + try { + const response = await Api.get('/dcm/edit/GetExtensionEntityTemplateList?id=' + id); + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + +export const createExtensionLink = async (id, extensionId) => { + try { + const response = await Api.post('/dcm/edit/CreateExtensionLink',{ id, extensionId }); + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte index dd735a5420..7661d3b469 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/+page.svelte @@ -2,7 +2,7 @@ import { fade } from 'svelte/transition'; import { positionType, ErrorMessage } from '@bexis2/bexis2-core-ui'; - import type { linkType } from '@bexis2/bexis2-core-ui'; + import type { keyValuePairType, linkType, listItemType } from '@bexis2/bexis2-core-ui'; // ui components import Fa from 'svelte-fa'; @@ -21,11 +21,14 @@ getHooks, getFileTypes, getEntityTemplateList, - getExtensions + getExtensions, + + getReferenceTypes + } from '../../services/EntityTemplateCaller'; // types - import type { EntityTemplateModel } from '../../models/EntityTemplate'; + import type { EntityTemplateModel, extensionType } from '../../models/EntityTemplate'; // Store import { entityTemplatesStore } from './store'; @@ -36,7 +39,8 @@ let entities = []; let groups = []; let filetypes = []; - let extensions = []; + let extensions:listItemType[] = []; + let referenceTypes:string[] = []; let isOpen = false; let header = ''; @@ -52,6 +56,9 @@ groups = await getGroups(); filetypes = await getFileTypes(); extensions = await getExtensions(); + console.log("🚀 ~ load ~ extensions:", extensions) + referenceTypes = await getReferenceTypes(); + console.log("🚀 ~ load ~ referenceTypes:", referenceTypes) entityTemplatesStore.set(await getEntityTemplateList()); } @@ -131,6 +138,7 @@ {groups} {filetypes} {extensions} + {referenceTypes} on:save={refresh} on:cancel={() => (isOpen = false)} /> diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte index fae7971fb2..0d179607a0 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte @@ -12,7 +12,8 @@ import { Modal, getModalStore } from '@skeletonlabs/skeleton'; const modalStore = getModalStore(); - import EntryContainer from './EntryContainer.svelte'; + import EntryContainer from '../../lib/components/EntryContainer.svelte'; + // validation import suite from './edit'; @@ -25,13 +26,15 @@ } from '../../services/EntityTemplateCaller'; // types - import type { EntityTemplateModel } from '../../models/EntityTemplate'; - import type { listItemType } from '@bexis2/bexis2-core-ui'; + import type { EntityTemplateModel, extensionType } from '../../models/EntityTemplate'; + import type { keyValuePairType, listItemType } from '@bexis2/bexis2-core-ui'; import type { ModalSettings } from '@skeletonlabs/skeleton'; // help import { editHelp } from './help'; import { helpStore } from '@bexis2/bexis2-core-ui'; + import ExtensionEntries from '../../lib/components/ExtensionEntries.svelte'; + //Set list of help items and clear selection helpStore.setHelpItemList(editHelp); @@ -46,7 +49,8 @@ export let entities = []; export let groups = []; export let filetypes: string[]; - export let extensions: []; + export let extensions:listItemType[] = []; + export let referenceTypes:any[] = []; const dispatch = createEventDispatcher(); @@ -287,40 +291,38 @@
-
+

Extension

-
- +
+ +
- Allow to use data structures + Allow to use extensions - +
+
{#if entityTemplate.hasExtension} - + + {/if}
- +
-
+

Administration

Set permissions per default to the following groups

diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts index 0fc56da0a0..c86592435c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/EntityTemplateCaller.ts @@ -81,6 +81,17 @@ export const getExtensions = async () => { } }; +export const getReferenceTypes = async () => { + try { + const response = await Api.get('/dcm/entitytemplates/ReferenceTypes'); + console.log("🚀 ~ getReferenceTypes ~ response:", response.data) + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + export const getHooks = async () => { try { const response = await Api.get('/dcm/entitytemplates/Hooks'); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs index 4ebfa78c64..9a0579e5c0 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs @@ -2,12 +2,17 @@ using BExIS.App.Bootstrap.Helpers; using BExIS.Dlm.Entities.Data; using BExIS.Dlm.Services.Data; +using BExIS.Modules.Dcm.UI.Helpers; using BExIS.Modules.Dcm.UI.Models.Edit; +using BExIS.Modules.Dcm.UI.Models.EntityTemplate; using BExIS.Security.Entities.Authorization; +using BExIS.Security.Entities.Objects; using BExIS.Security.Services.Objects; using BExIS.UI.Helpers; using BExIS.UI.Hooks; using BExIS.UI.Models; +using BExIS.Utils.Data.Helpers; +using DocumentFormat.OpenXml.Drawing.Diagrams; using System; using System.Collections.Generic; using System.Linq; @@ -144,7 +149,12 @@ public JsonResult GetExtensions(long id) foreach (var x in entityreferences) { - string title = datasetManager.GetDatasetVersion(x.TargetId, x.TargetVersion).Title; + string title = ""; + if (x.TargetVersion == 0) // latest + title = datasetManager.GetDatasetLatestVersion(x.TargetId).Title; + else + title = datasetManager.GetDatasetVersion(x.TargetId, x.TargetVersion).Title; + tmp.Add(new ExtensionItem() { Id = x.TargetId, @@ -158,6 +168,108 @@ public JsonResult GetExtensions(long id) return Json(tmp, JsonRequestBehavior.AllowGet); } - #endregion - } + [JsonNetFilter] + [HttpGet] + public JsonResult GetExtensionEntityTemplateList(long id) + { + if(id==0) throw new Exception("id is missing"); + + List entityTemplateModels = new List(); + + using (var datasetManager = new DatasetManager()) + using (var entityTemplateManager = new EntityTemplateManager()) + { + + var dataset = datasetManager.GetDataset(id); + var template = dataset.EntityTemplate; + var extensions = template.ExtensionList.Select(e=>e.TemplateId); + + foreach (var e in entityTemplateManager.Repo.Query(e => e.Activated && extensions.Contains(e.Id)).ToList()) + { + entityTemplateModels.Add(EntityTemplateHelper.ConvertTo(e, false)); + } + + } + + return Json(entityTemplateModels, JsonRequestBehavior.AllowGet); + + } + + [JsonNetFilter] + [HttpPost] + public JsonResult CreateExtensionLink(long id, long extensionId) + { + using (var datasetmanager = new DatasetManager()) + using (var entityReferenceManager = new EntityReferenceManager()) + { + try + { + + if (id == 0) throw new Exception("id is missing"); + if (extensionId == 0) throw new Exception("extensionId is missing"); + + + // get object + var dataset = datasetmanager.GetDataset(id); + var extension = datasetmanager.GetDataset(extensionId); + + // get templates + var datasetTemplate = dataset.EntityTemplate; + var extensionTemplate = extension.EntityTemplate; + + var extensionType = datasetTemplate.ExtensionList.Where(e => e.TemplateId.Equals(extensionTemplate.Id)).FirstOrDefault(); + + // check if extension is allowed + if (datasetTemplate.ExtensionList == null || extensionType == null) + throw new Exception("This extension is not allowed for this subject."); + + // check if extension is unique and allready exists + if (datasetTemplate.ExtensionList.Any(e => e.TemplateId.Equals(extensionTemplate.Id) && e.Unique)) + { + var existingLinks = entityReferenceManager.ReferenceRepository.Query(e => + e.LinkType.Equals("extension") && + e.SourceId.Equals(id) && + e.SourceEntityId.Equals(dataset.EntityTemplate.EntityType.Id) && + e.TargetEntityId.Equals(extension.EntityTemplate.EntityType.Id)).ToList(); + + if (existingLinks.Count > 0) + throw new Exception("This extension is unique and allready exists."); + } + + // create link + EntityReferenceHelper entityReferenceHelper = new EntityReferenceHelper(); + var extensionRef = entityReferenceHelper.GetReferenceConfigByType(extensionType.ReferenceType); + + + + EntityReference entitreference = new EntityReference(); + entitreference.SourceId = id; + entitreference.SourceEntityId = dataset.EntityTemplate.EntityType.Id; + entitreference.SourceVersion = 0; // not used + entitreference.TargetId = extensionId; + entitreference.TargetEntityId = extension.EntityTemplate.EntityType.Id; + entitreference.TargetVersion = 0; + entitreference.LinkType = extensionRef.LinkType; + entitreference.ReferenceType = extensionRef.ReferenceType; + //entitreference.Context = "added"; + entitreference.Category = extensionRef.Category; + + entityReferenceManager.Create(entitreference); + + + + } + catch (Exception ex) + { + datasetmanager.PurgeDataset(extensionId); + + throw new Exception(ex.Message); + } + } + + return Json(true); + } + + #endregion + } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs index a357040915..654da3e5b3 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs @@ -13,6 +13,7 @@ using BExIS.UI.Helpers; using BExIS.UI.Hooks; using BExIS.UI.Models; +using BExIS.Utils.Data.Helpers; using BExIS.Xml.Helpers; using System; using System.Collections.Generic; @@ -209,18 +210,26 @@ public JsonResult DataStructures() [HttpGet] public JsonResult Extensions() { - List> tmp = new List>(); + List tmp = new List(); using (var entityTemplateManager = new EntityTemplateManager()) using (var entityManager = new EntityManager()) { var extensionEntity = entityManager.EntityRepository.Get().Where(e => e.Name.Equals("Extension")).FirstOrDefault(); tmp = entityTemplateManager.Repo.Query(t=>t.EntityType.Id.Equals(extensionEntity.Id)) - .Select(e => new KeyValuePair(e.Id, e.Name)).ToList(); + .Select(e => new ListItem(e.Id, e.Name,"")).ToList(); } return Json(tmp, JsonRequestBehavior.AllowGet); } + [JsonNetFilter] + [HttpGet] + public JsonResult ReferenceTypes() + { + EntityReferenceHelper helper = new EntityReferenceHelper(); + return Json(helper.GetReferencesTypesAsKVP("extension"), JsonRequestBehavior.AllowGet); + } + [JsonNetFilter] [HttpGet] public JsonResult Hooks() diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs index 5ef684eebc..f38cb7c06f 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs @@ -98,7 +98,7 @@ public static EntityTemplateModel ConvertTo(EntityTemplate entityTemplate, bool model.HasExtension = entityTemplate.HasExtension; model.DisabledHooks = entityTemplate.DisabledHooks != null ? entityTemplate.DisabledHooks : new List(); ; model.DatastructureList = entityTemplate.DatastructureList != null ? entityTemplate.DatastructureList : new List(); - model.ExtensionList = entityTemplate.ExtensionList != null ? entityTemplate.ExtensionList : new List(); + model.ExtensionList = entityTemplate.ExtensionList != null ? entityTemplate.ExtensionList : new List(); model.AllowedFileTypes = entityTemplate.AllowedFileTypes != null ? entityTemplate.AllowedFileTypes : new List(); model.PermissionGroups = entityTemplate.PermissionGroups != null ? entityTemplate.PermissionGroups : new PermissionsType(); model.NotificationGroups = entityTemplate.NotificationGroups != null ? entityTemplate.NotificationGroups : new List(); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs index 3dffe7aa9d..d55bcc8fae 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/EntityTemplates/EntityTemplateModels.cs @@ -63,7 +63,7 @@ public class EntityTemplateModel /// /// List of available extensions /// - public virtual List ExtensionList { get; set; } + public virtual List ExtensionList { get; set; } public List AllowedFileTypes { get; set; } diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs index 76795791f8..e1037bbbf3 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs @@ -1729,6 +1729,44 @@ private void createSystemKeyMappings() } #endregion mapping GBIF to System Keys + + #region extension to system keys + + if (metadataStructures.Any(m => m.Name.ToLower().Equals("extension"))) + { + MetadataStructure metadataStructure = + metadataStructures.FirstOrDefault(m => m.Name.ToLower().Equals("extension")); + + XDocument metadataRef = xmlMetadataWriter.CreateMetadataXml(metadataStructure.Id); + + //create root mapping + LinkElement extensionRoot = createLinkELementIfNotExist(mappingManager, metadataStructure.Id, metadataStructure.Name, LinkElementType.MetadataStructure, LinkElementComplexity.None, ""); + + //create system mapping + LinkElement system = createLinkELementIfNotExist(mappingManager, 0, "System", LinkElementType.System, LinkElementComplexity.None, ""); + + #region mapping GBIF to System Keys + + Mapping rootTo = mappingManager.CreateMapping(extensionRoot, system, 0, null, null); + Mapping rootFrom = mappingManager.CreateMapping(system, extensionRoot, 0, null, null); + + if (Exist("title", LinkElementType.MetadataAttributeUsage, uow)) + { + createToKeyMapping("title", LinkElementType.MetadataAttributeUsage, "title", LinkElementType.MetadataAttributeUsage, Key.Title, rootTo, metadataRef, mappingManager); + createFromKeyMapping("title", LinkElementType.MetadataAttributeUsage, "title", LinkElementType.MetadataAttributeUsage, Key.Title, rootFrom, metadataRef, mappingManager); + } + + if (Exist("description", LinkElementType.MetadataAttributeUsage, uow)) + { + createToKeyMapping("description", LinkElementType.MetadataAttributeUsage, "description", LinkElementType.MetadataAttributeUsage, Key.Description, rootTo, metadataRef, mappingManager); + createFromKeyMapping("description", LinkElementType.MetadataAttributeUsage, "description", LinkElementType.MetadataAttributeUsage, Key.Description, rootFrom, metadataRef, mappingManager); + } + + + #endregion mapping GBIF to System Keys + } + + #endregion } } From 258e88bfebc0f54b542a76a761f08b22312968ed Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 9 Oct 2025 09:55:44 +0200 Subject: [PATCH 008/490] #2195 remove dependency from smm Microsoft.Web.Infrastructure --- .../Areas/SMM/BExIS.Modules.SMM.UI/BExIS.Modules.SMM.UI.csproj | 3 --- 1 file changed, 3 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 177152d86d..7bbd8528ba 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 @@ -52,9 +52,6 @@ ..\..\..\..\..\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 From 1289632152861b430cf799d9276cd2bef014ddaa Mon Sep 17 00:00:00 2001 From: david schoene Date: Fri, 10 Oct 2025 07:53:59 +0200 Subject: [PATCH 009/490] #2233 hide options when extension is created as template --- .../src/routes/entitytemplates/Edit.svelte | 29 +++++++++++++++---- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte index 0d179607a0..d785cef632 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte @@ -52,6 +52,9 @@ export let extensions:listItemType[] = []; export let referenceTypes:any[] = []; + let isExtensions = false; + $: isExtensions; + const dispatch = createEventDispatcher(); let entityTemplate: EntityTemplateModel; @@ -59,7 +62,6 @@ $: entityTemplate; $: systemKeys; $: subsetMetadataStructures; - $: loaded = false; let type = []; @@ -78,7 +80,7 @@ console.log('load entity', entityTemplate); console.log('load filetypes', filetypes); updateSystemKeys('metadataStructure'); - + updateIsExtensions(entityTemplate.entityType.text); // if id > 0 then run validation if (id > 0) { res = suite(entityTemplate); @@ -103,7 +105,11 @@ //change event: if input change check also validation only on the field // e.target.id is the id of the input component async function onChangeHandler(e) { - //console.log("input changed", e) + + + console.log("input changed", entityTemplate) + + updateIsExtensions(entityTemplate.entityType.text); // add some delay so the entityTemplate is updated // otherwise the values are old setTimeout(async () => { @@ -163,6 +169,15 @@ modalStore.trigger(modal); } + +function updateIsExtensions(entityTypeText:string){ + if(entityTypeText === "Extension"){ + isExtensions = true; + }else{ + isExtensions = false; + } + } + {#if entityTemplate} @@ -256,6 +271,7 @@
+ {#if !isExtensions}

Data Structure

@@ -324,6 +340,7 @@
+

Administration

Set permissions per default to the following groups

@@ -395,9 +412,11 @@ />
- +{/if }

Dataset Settings

+
+ {#if !isExtensions} - + {/if} Date: Fri, 10 Oct 2025 08:30:47 +0200 Subject: [PATCH 010/490] #2195 hide extention from create view --- Components/DLM/BExIS.Dlm.Entities/Data/Dataset.cs | 11 +++++++++++ .../Controllers/CreateController.cs | 4 +++- .../Controllers/EntityTemplatesController.cs | 2 +- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/Components/DLM/BExIS.Dlm.Entities/Data/Dataset.cs b/Components/DLM/BExIS.Dlm.Entities/Data/Dataset.cs index c40174b707..459201da8a 100644 --- a/Components/DLM/BExIS.Dlm.Entities/Data/Dataset.cs +++ b/Components/DLM/BExIS.Dlm.Entities/Data/Dataset.cs @@ -9,6 +9,17 @@ /// namespace BExIS.Dlm.Entities.Data { + /// + /// This is a list fo currently used entity types in BExIS. It is used to identify the type of the entity in a generic way. + /// + public enum EntityType + { + Dataset = 1, + Publication = 2, + Sample = 3, + Extension = 4, + } + /// /// /// diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs index 5adaff82e1..0ff19580cc 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs @@ -458,7 +458,9 @@ public JsonResult GetEntityTemplateList() List entityTemplateModels = new List(); using (var entityTemplateManager = new EntityTemplateManager()) { - foreach (var e in entityTemplateManager.Repo.Query(e=>e.Activated).ToList()) + // get entity templates without extension + string extensionName = Convert.ToString(EntityType.Extention); + foreach (var e in entityTemplateManager.Repo.Query(e=>e.Activated && !e.EntityType.Name.ToLower().Equals(extensionName.ToLower())).ToList()) { entityTemplateModels.Add(EntityTemplateHelper.ConvertTo(e, false)); } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs index 654da3e5b3..e88a71635d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs @@ -215,7 +215,7 @@ public JsonResult Extensions() using (var entityManager = new EntityManager()) { var extensionEntity = entityManager.EntityRepository.Get().Where(e => e.Name.Equals("Extension")).FirstOrDefault(); - tmp = entityTemplateManager.Repo.Query(t=>t.EntityType.Id.Equals(extensionEntity.Id)) + tmp = entityTemplateManager.Repo.Query(t=>t.EntityType.Id.Equals(extensionEntity.Id) && t.Activated) .Select(e => new ListItem(e.Id, e.Name,"")).ToList(); } From 78d3835d5fc5e8c5e6772061ecbd3713ff8ce813 Mon Sep 17 00:00:00 2001 From: david schoene Date: Fri, 10 Oct 2025 09:26:34 +0200 Subject: [PATCH 011/490] #2200 hide extensions from serach index --- .../BExIS.Modules.Dcm.UI/Controllers/CreateController.cs | 2 +- .../Indexer/BexisIndexer.cs | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs index 0ff19580cc..442fac6106 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs @@ -459,7 +459,7 @@ public JsonResult GetEntityTemplateList() using (var entityTemplateManager = new EntityTemplateManager()) { // get entity templates without extension - string extensionName = Convert.ToString(EntityType.Extention); + string extensionName = Convert.ToString(EntityType.Extension); foreach (var e in entityTemplateManager.Repo.Query(e=>e.Activated && !e.EntityType.Name.ToLower().Equals(extensionName.ToLower())).ToList()) { entityTemplateModels.Add(EntityTemplateHelper.ConvertTo(e, false)); diff --git a/Modules/DDM/BExIS.Ddm.Providers.LuceneProvider/Indexer/BexisIndexer.cs b/Modules/DDM/BExIS.Ddm.Providers.LuceneProvider/Indexer/BexisIndexer.cs index 32e1cf7742..742b0fff59 100644 --- a/Modules/DDM/BExIS.Ddm.Providers.LuceneProvider/Indexer/BexisIndexer.cs +++ b/Modules/DDM/BExIS.Ddm.Providers.LuceneProvider/Indexer/BexisIndexer.cs @@ -408,6 +408,7 @@ private void writeBexisIndex(long id, bool onlyReleasedTags, DatasetManager dm) string doi = ""; string date = ""; string entityTemplate = ""; + string entityName = ""; DatasetVersion version = null; XmlDocument metadata = null; @@ -430,11 +431,15 @@ private void writeBexisIndex(long id, bool onlyReleasedTags, DatasetManager dm) { // doi entityTemplate = version.Dataset.EntityTemplate.Name; + entityName = version.Dataset.EntityTemplate.EntityType.Name; date = version.ModificationInfo?.Timestamp?.ToString("yyyy-MM-dd"); if(date == null) version.CreationInfo?.Timestamp?.ToString("yyyy-MM-dd"); if (date == null) date = ""; } + // stop indexing if entity is an extension + if(entityName.ToLowerInvariant().Equals(Convert.ToString(EntityType.Extension).ToLowerInvariant())) return; + var dataset = new Document(); List facetNodes = facetXmlNodeList; dataset.Add(new Field("doc_id", docId, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); @@ -445,7 +450,7 @@ private void writeBexisIndex(long id, bool onlyReleasedTags, DatasetManager dm) dataset.Add(new Field("gen_isPublic", entityPermissionManager.ExistsAsync(entityTypeId.Value, id).Result ? "TRUE" : "FALSE", Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); XmlDatasetHelper xmlDatasetHelper = new XmlDatasetHelper(); - var entityName = xmlDatasetHelper.GetEntityName(id); + //var entityName = xmlDatasetHelper.GetEntityName(id); dataset.Add(new Field("gen_entity_name", entityName, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); dataset.Add(new Field("gen_doi", doi, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); dataset.Add(new Field("gen_modifieddate", date, Lucene.Net.Documents.Field.Store.YES, Lucene.Net.Documents.Field.Index.NOT_ANALYZED)); From 415268caaf880151724ca7150bc9e0a060066035 Mon Sep 17 00:00:00 2001 From: david schoene Date: Mon, 20 Oct 2025 14:03:23 +0200 Subject: [PATCH 012/490] #2209 change edit page because of hook update issues with extensions --- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 4 +-- .../src/lib/hooks/Data.svelte | 11 +++--- .../src/lib/hooks/DataDescription.svelte | 8 +++-- .../src/lib/hooks/Submit.svelte | 20 ++++++----- .../src/lib/hooks/Validation.svelte | 19 ++++++---- .../src/routes/edit/AdvancedEntity.svelte | 4 +-- .../src/routes/edit/Entity.svelte | 35 +++++++++++++++++-- .../src/routes/edit/ExtensionCreation.svelte | 7 ++-- .../src/routes/edit/services.js | 4 +-- 9 files changed, 75 insertions(+), 37 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index edb4ea0fe1..441ae7694e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -7,8 +7,8 @@ %sveltekit.head% -
-
+
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte index c5d42cd9bd..cb9f1bb751 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte @@ -8,6 +8,7 @@ import { ErrorMessage } from '@bexis2/bexis2-core-ui'; import { latestSubmitDate, latestDataDate } from '../../routes/edit/stores'; + export let id = 0; export let version = 1; export let hook; @@ -16,16 +17,18 @@ const dispatch = createEventDispatcher(); + // latestSubmitDate.subscribe((s) => { + // reload(); + // }); + onMount(async () => { console.log('DATA', hook); load(); - latestSubmitDate.subscribe((s) => { - reload(); - }); }); async function reload() { + console.log('reload data hook'); /*update store*/ latestDataDate.set(Date.now()); @@ -35,7 +38,7 @@ async function load() { model = await getHookStart(hook.start, id, version); - console.log('🚀 ~ load ~ model:', model); + console.log('🚀 ~ load ~ model:',id, model); dispatch('dateChanged', { lastModification: model.lastModification }); } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte index 2759ce8902..8d6201244a 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte @@ -20,9 +20,7 @@ const dispatch = createEventDispatcher(); - onMount(async () => { - load(); - latestFileUploadDate.subscribe((s) => { + latestFileUploadDate.subscribe((s) => { if (s > 0) { reloadByFileUpdate(); } @@ -32,6 +30,10 @@ reload(); } }); + + onMount(async () => { + load(); + }); async function load() { diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte index 232861c285..45570bca95 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte @@ -39,8 +39,7 @@ let isSubmitting: boolean = false; - onMount(async () => { - latestFileUploadDate.subscribe((s) => { + latestFileUploadDate.subscribe((s) => { if (s > 0) { reload(); } @@ -68,22 +67,25 @@ reload(); } }); + + onMount(async () => { + }); async function reload() { - console.log('reload submit', start, id, version); - console.log('latestDataDate', latestDataDate); + //console.log('reload submit', start, id, version); + //console.log('latestDataDate', latestDataDate); canSubmit = false; - console.log(' before hook'); + //console.log(' before hook'); model = await getHookStart(start, id, version); - console.log(' before activateSubmit', canSubmit); + //console.log(' before activateSubmit', canSubmit); canSubmit = activateSubmit(); - console.log(' after activateSubmit', canSubmit); + //console.log(' after activateSubmit', canSubmit); - console.log('reload submit', model); + //console.log('reload submit', model); return model; } @@ -134,7 +136,7 @@ //2. updload data with data structure function activateSubmit() { //check use case 1 - console.log('🚀 ~ activateSubmit ~ model:', model); + //console.log('🚀 ~ activateSubmit ~ model:', model); if (model.hasStructrue == false && model.files.length > 0) { return true; } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Validation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Validation.svelte index 4240ddaa83..30fc28c976 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Validation.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Validation.svelte @@ -29,8 +29,7 @@ let model: ValidationModel | null; $: model; - onMount(async () => { - latestFileUploadDate.subscribe((s) => { + latestFileUploadDate.subscribe((s) => { if (s > 0) { console.log( '🚀 ~ file: Validation.svelte:37 ~ onMount ~ latestFileUploadDate:', @@ -39,6 +38,7 @@ reload('latestFileUploadDate'); } }); + latestDataDescriptionDate.subscribe((s) => { if (s > 0) { console.log( @@ -48,6 +48,7 @@ reload('latestDataDescriptionDate'); } }); + latestFileReaderDate.subscribe((s) => { if (s > 0) { console.log( @@ -57,22 +58,26 @@ reload('latestFileReaderDate'); } }); + latestSubmitDate.subscribe((s) => { if (s > 0) { - console.log( - '🚀 ~ file: Validation.svelte:49 ~ onMount ~ latestSubmitDate:', - $latestSubmitDate - ); + // console.log( + // '🚀 ~ file: Validation.svelte:49 ~ onMount ~ latestSubmitDate:', + // $latestSubmitDate + // ); //reload('latestSubmitDate'); } }); + + onMount(async () => { + }); async function reload(type) { model = null; model = await getHookStart(start, id, version); console.log('validation end', model); - latestValidationDate.set(Date.now()); + //latestValidationDate.set(Date.now()); } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte index 6e5ba9803d..4c622c08d8 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte @@ -24,7 +24,7 @@ {/each} - + + @@ -37,8 +37,8 @@ {/if} {#each extensions as ext (ext.id)} + {#if tabSet === ext.id} - {id},{title} {/if} {/each} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte index 9e418456be..7dc6bb51fa 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Entity.svelte @@ -21,6 +21,7 @@ import type { EditModel, HookModel, ViewModel } from './types'; import Placeholder from './PlaceholderPage.svelte'; + import { onDestroy, onMount } from 'svelte'; export let id: number = 0; @@ -73,7 +74,8 @@ }); latestValidationDate.subscribe((e) => { - updateHookStatus(); + console.log('latestValidationDate in edit entity', id); + updateHookStatus(); }); latestSubmitDate.subscribe((e) => { @@ -81,9 +83,37 @@ }); latestDataDate.subscribe((e) => { + console.log('latestDataDate in edit entity', id); updateHookStatus(); }); + + const unsubscribe = () =>{ + + latestFileUploadDate.set(0); + latestDataDescriptionDate.set(0); + latestFileReaderDate.set(0); + latestValidationDate.set(0); + latestSubmitDate.set(0); + latestDataDate.set(0); + + hooksStatus.set({ ['']: 0 }); + + } + + + + onMount(() => { + + + }); + + + onDestroy(() => { + console.log('DESTROY EDIT ENTITY'); + unsubscribe(); + }); + async function load() { console.log('LOAD EDIT', Date.now); @@ -138,7 +168,7 @@ } await sleep(time); - console.log('test'); + //console.log('test'); } while (wait); } } @@ -200,7 +230,6 @@ - {#await load()} {:then a} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte index 7c1e67dd86..cf00909985 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte @@ -6,7 +6,7 @@ import { Spinner, positionType } from '@bexis2/bexis2-core-ui'; import { createExtensionLink, getExtensionEntityTemplateList } from './services'; - // import { goTo } from '$services/BaseCaller'; + import { goTo } from '$services/BaseCaller'; import type { EntityTemplateModel } from '$models/EntityTemplate'; @@ -46,7 +46,7 @@ const res = await createExtensionLink(id,e.detail); notificationStore.showNotification({ notificationType: notificationType.success, - message: 'This is the success style Notification' + message: 'Extension created and linked successfully' }) goTo('/dcm/edit?id=' + id); @@ -56,9 +56,6 @@ //console.log(links) - function goTo(arg0: string) { - throw new Error('Function not implemented.'); - } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js index a048db883d..1f16f62ece 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js @@ -19,11 +19,11 @@ export const getEdit = async (id) => { // get Model for Edit page export const getHooks = async (id) => { - console.log('getHooks', id); + //console.log('getHooks', id); try { const response = await Api.get('/dcm/edit/hooks?id=' + id); - console.log(response); + //console.log(response); return response.data; } catch (error) { From 70b36d1462e69840c069113f0ae8ee2e5a997937 Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 21 Oct 2025 09:52:51 +0200 Subject: [PATCH 013/490] #2235 add function to delete extensions --- .../Objects/EntityReferenceManager.cs | 12 ++++ .../src/routes/edit/AdvancedEntity.svelte | 58 ++++++++++++++++++- .../src/routes/edit/ExtensionCreation.svelte | 2 +- .../src/routes/edit/services.js | 10 ++++ .../Controllers/EditController.cs | 44 +++++++++++++- 5 files changed, 122 insertions(+), 4 deletions(-) diff --git a/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs b/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs index 41c342bb4f..7677a8aee6 100644 --- a/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs +++ b/Components/AAA/BExIS.Security.Services/Objects/EntityReferenceManager.cs @@ -1,5 +1,6 @@ using BExIS.Security.Entities.Objects; using System; +using System.Collections.Generic; using System.Linq; using Vaiona.Persistence.Api; @@ -118,6 +119,17 @@ public void Delete(long id) } } + public void Delete(IEnumerable ids) + { + using (var uow = this.GetUnitOfWork()) + { + var repo = uow.GetRepository(); + var entityReferences = repo.Query(l=> ids.Contains(l.Id)).Select(l=>l.Id).ToList(); + repo.Delete(entityReferences); + uow.Commit(); + } + } + public void Delete(EntityReference entityReference) { using (var uow = this.GetUnitOfWork()) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte index 4c622c08d8..1a713fa47e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte @@ -1,8 +1,18 @@ @@ -21,6 +68,8 @@ {#each extensions as ext (ext.id)} {ext.title} + + {/each} @@ -39,7 +88,12 @@ {#each extensions as ext (ext.id)} {#if tabSet === ext.id} - +
+ +
+ + + {/if} {/each} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte index cf00909985..cba9cc7ea5 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte @@ -49,7 +49,7 @@ message: 'Extension created and linked successfully' }) - goTo('/dcm/edit?id=' + id); + location.reload(); } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js index 1f16f62ece..7bd04a11d2 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/services.js @@ -116,3 +116,13 @@ export const createExtensionLink = async (id, extensionId) => { } }; +export const deleteExtension = async (extensionId) => { + try { + const response = await Api.post('/dcm/edit/DeleteExtension',{ extensionId }); + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs index 9a0579e5c0..f32f2bb826 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs @@ -16,6 +16,8 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Net; +using System.Net.Http; using System.Web.Mvc; namespace BExIS.Modules.Dcm.UI.Controllers @@ -270,6 +272,46 @@ public JsonResult CreateExtensionLink(long id, long extensionId) return Json(true); } - #endregion + [JsonNetFilter] + [HttpPost] + public JsonResult DeleteExtension(long extensionId) + { + + + using (var datasetmanager = new DatasetManager()) + using (var entityReferenceManager = new EntityReferenceManager()) + { + try + { + if (extensionId == 0) throw new Exception("extensionId is missing"); + + // remove all existing links + + var linkIds = entityReferenceManager.ReferenceRepository.Query(e => + e.TargetId.Equals(extensionId) && + e.LinkType.Equals("extension")).Select(l=>l.Id); + + entityReferenceManager.Delete(linkIds.ToList()); + + + // purge dataset + datasetmanager.PurgeDataset(extensionId); + + + } + catch (Exception ex) + { + + throw new Exception(ex.Message); + } + } + + Response.StatusCode = (int)HttpStatusCode.OK; + + return Json( new { Success = true, Message = "Extension successful deleted" }); + } + + #endregion + } } \ No newline at end of file From 4fa4d0993240406fd2c20507d8a133359ab839d2 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 23 Oct 2025 08:26:29 +0200 Subject: [PATCH 014/490] #2195 fix issue from merging --- .../BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/web.config | 4 ---- 1 file changed, 4 deletions(-) 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 cd8e28c8e8..d0f8c984f6 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 @@ -10,10 +10,6 @@ - - - - From 15fb2133ac122718928cb256bc0daf7d1c64fe54 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 23 Oct 2025 12:44:13 +0200 Subject: [PATCH 015/490] #2195 try fixing pipeline with ssm module changes --- .../BExIS.Modules.SMM.UI.csproj | 1 - .../Areas/SMM/BExIS.Modules.SMM.UI/web.config | 16 ++++++++++++---- 2 files changed, 12 insertions(+), 5 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 7bbd8528ba..06327ef840 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 @@ -125,7 +125,6 @@ - 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 d0f8c984f6..5dd006164c 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 @@ -9,6 +9,10 @@ + + + + @@ -58,10 +62,6 @@ - - - - @@ -70,6 +70,14 @@ + + + + + + + + \ No newline at end of file From 7735cb17e1412a8f33b03ec29cb4b35d0201bb2e Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 23 Oct 2025 13:42:46 +0200 Subject: [PATCH 016/490] #2195 reinstall nuget packages to fix msbuild error in smm --- .../BExIS.Modules.SMM.UI.csproj | 10 +- .../BExIS.Modules.SMM.UI/Scripts/respond.js | 224 ++++++++++++++ .../Scripts/respond.matchmedia.addListener.js | 273 ++++++++++++++++++ .../respond.matchmedia.addListener.min.js | 5 + .../Scripts/respond.min.js | 5 + .../Areas/SMM/BExIS.Modules.SMM.UI/web.config | 6 +- 6 files changed, 516 insertions(+), 7 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.js create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.js create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.min.js create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.min.js 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 06327ef840..469bd76552 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 @@ -52,6 +52,9 @@ ..\..\..\..\..\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 @@ -63,7 +66,7 @@ ..\..\..\..\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\System.Runtime.CompilerServices.Unsafe.6.0.0\lib\net461\System.Runtime.CompilerServices.Unsafe.dll @@ -125,6 +128,10 @@ + + + + @@ -145,7 +152,6 @@ - diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.js b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.js new file mode 100644 index 0000000000..b1298d0756 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.js @@ -0,0 +1,224 @@ +/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ +/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ +(function(w) { + "use strict"; + w.matchMedia = w.matchMedia || function(doc, undefined) { + var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div"); + div.id = "mq-test-1"; + div.style.cssText = "position:absolute;top:-100em"; + fakeBody.style.background = "none"; + fakeBody.appendChild(div); + return function(q) { + div.innerHTML = '­'; + docElem.insertBefore(fakeBody, refNode); + bool = div.offsetWidth === 42; + docElem.removeChild(fakeBody); + return { + matches: bool, + media: q + }; + }; + }(w.document); +})(this); + +/*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs */ +(function(w) { + "use strict"; + var respond = {}; + w.respond = respond; + respond.update = function() {}; + var requestQueue = [], xmlHttp = function() { + var xmlhttpmethod = false; + try { + xmlhttpmethod = new w.XMLHttpRequest(); + } catch (e) { + xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP"); + } + return function() { + return xmlhttpmethod; + }; + }(), ajax = function(url, callback) { + var req = xmlHttp(); + if (!req) { + return; + } + req.open("GET", url, true); + req.onreadystatechange = function() { + if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) { + return; + } + callback(req.responseText); + }; + if (req.readyState === 4) { + return; + } + req.send(null); + }; + respond.ajax = ajax; + respond.queue = requestQueue; + respond.regex = { + media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi, + keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi, + urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, + findStyles: /@media *([^\{]+)\{([\S\s]+?)$/, + only: /(only\s+)?([a-zA-Z]+)\s?/, + minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/, + maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ + }; + respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches; + if (respond.mediaQueriesSupported) { + return; + } + var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() { + var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false; + div.style.cssText = "position:absolute;font-size:1em;width:1em"; + if (!body) { + body = fakeUsed = doc.createElement("body"); + body.style.background = "none"; + } + docElem.style.fontSize = "100%"; + body.style.fontSize = "100%"; + body.appendChild(div); + if (fakeUsed) { + docElem.insertBefore(body, docElem.firstChild); + } + ret = div.offsetWidth; + if (fakeUsed) { + docElem.removeChild(body); + } else { + body.removeChild(div); + } + docElem.style.fontSize = originalHTMLFontSize; + if (originalBodyFontSize) { + body.style.fontSize = originalBodyFontSize; + } + ret = eminpx = parseFloat(ret); + return ret; + }, applyMedia = function(fromResize) { + var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime(); + if (fromResize && lastCall && now - lastCall < resizeThrottle) { + w.clearTimeout(resizeDefer); + resizeDefer = w.setTimeout(applyMedia, resizeThrottle); + return; + } else { + lastCall = now; + } + for (var i in mediastyles) { + if (mediastyles.hasOwnProperty(i)) { + var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em"; + if (!!min) { + min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1); + } + if (!!max) { + max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1); + } + if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) { + if (!styleBlocks[thisstyle.media]) { + styleBlocks[thisstyle.media] = []; + } + styleBlocks[thisstyle.media].push(rules[thisstyle.rules]); + } + } + } + for (var j in appendedEls) { + if (appendedEls.hasOwnProperty(j)) { + if (appendedEls[j] && appendedEls[j].parentNode === head) { + head.removeChild(appendedEls[j]); + } + } + } + appendedEls.length = 0; + for (var k in styleBlocks) { + if (styleBlocks.hasOwnProperty(k)) { + var ss = doc.createElement("style"), css = styleBlocks[k].join("\n"); + ss.type = "text/css"; + ss.media = k; + head.insertBefore(ss, lastLink.nextSibling); + if (ss.styleSheet) { + ss.styleSheet.cssText = css; + } else { + ss.appendChild(doc.createTextNode(css)); + } + appendedEls.push(ss); + } + } + }, translate = function(styles, href, media) { + var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0; + href = href.substring(0, href.lastIndexOf("/")); + var repUrls = function(css) { + return css.replace(respond.regex.urls, "$1" + href + "$2$3"); + }, useMedia = !ql && media; + if (href.length) { + href += "/"; + } + if (useMedia) { + ql = 1; + } + for (var i = 0; i < ql; i++) { + var fullq, thisq, eachq, eql; + if (useMedia) { + fullq = media; + rules.push(repUrls(styles)); + } else { + fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1; + rules.push(RegExp.$2 && repUrls(RegExp.$2)); + } + eachq = fullq.split(","); + eql = eachq.length; + for (var j = 0; j < eql; j++) { + thisq = eachq[j]; + mediastyles.push({ + media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all", + rules: rules.length - 1, + hasquery: thisq.indexOf("(") > -1, + minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""), + maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "") + }); + } + } + applyMedia(); + }, makeRequests = function() { + if (requestQueue.length) { + var thisRequest = requestQueue.shift(); + ajax(thisRequest.href, function(styles) { + translate(styles, thisRequest.href, thisRequest.media); + parsedSheets[thisRequest.href] = true; + w.setTimeout(function() { + makeRequests(); + }, 0); + }); + } + }, ripCSS = function() { + for (var i = 0; i < links.length; i++) { + var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; + if (!!href && isCSS && !parsedSheets[href]) { + if (sheet.styleSheet && sheet.styleSheet.rawCssText) { + translate(sheet.styleSheet.rawCssText, href, media); + parsedSheets[href] = true; + } else { + if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) { + if (href.substring(0, 2) === "//") { + href = w.location.protocol + href; + } + requestQueue.push({ + href: href, + media: media + }); + } + } + } + } + makeRequests(); + }; + ripCSS(); + respond.update = ripCSS; + respond.getEmValue = getEmValue; + function callMedia() { + applyMedia(true); + } + if (w.addEventListener) { + w.addEventListener("resize", callMedia, false); + } else if (w.attachEvent) { + w.attachEvent("onresize", callMedia); + } +})(this); \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.js b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.js new file mode 100644 index 0000000000..31571cda33 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.js @@ -0,0 +1,273 @@ +/*! matchMedia() polyfill - Test a CSS media type/query in JS. Authors & copyright (c) 2012: Scott Jehl, Paul Irish, Nicholas Zakas. Dual MIT/BSD license */ +/*! NOTE: If you're already including a window.matchMedia polyfill via Modernizr or otherwise, you don't need this part */ +(function(w) { + "use strict"; + w.matchMedia = w.matchMedia || function(doc, undefined) { + var bool, docElem = doc.documentElement, refNode = docElem.firstElementChild || docElem.firstChild, fakeBody = doc.createElement("body"), div = doc.createElement("div"); + div.id = "mq-test-1"; + div.style.cssText = "position:absolute;top:-100em"; + fakeBody.style.background = "none"; + fakeBody.appendChild(div); + return function(q) { + div.innerHTML = '­'; + docElem.insertBefore(fakeBody, refNode); + bool = div.offsetWidth === 42; + docElem.removeChild(fakeBody); + return { + matches: bool, + media: q + }; + }; + }(w.document); +})(this); + +/*! matchMedia() polyfill addListener/removeListener extension. Author & copyright (c) 2012: Scott Jehl. Dual MIT/BSD license */ +(function(w) { + "use strict"; + if (w.matchMedia && w.matchMedia("all").addListener) { + return false; + } + var localMatchMedia = w.matchMedia, hasMediaQueries = localMatchMedia("only all").matches, isListening = false, timeoutID = 0, queries = [], handleChange = function(evt) { + w.clearTimeout(timeoutID); + timeoutID = w.setTimeout(function() { + for (var i = 0, il = queries.length; i < il; i++) { + var mql = queries[i].mql, listeners = queries[i].listeners || [], matches = localMatchMedia(mql.media).matches; + if (matches !== mql.matches) { + mql.matches = matches; + for (var j = 0, jl = listeners.length; j < jl; j++) { + listeners[j].call(w, mql); + } + } + } + }, 30); + }; + w.matchMedia = function(media) { + var mql = localMatchMedia(media), listeners = [], index = 0; + mql.addListener = function(listener) { + if (!hasMediaQueries) { + return; + } + if (!isListening) { + isListening = true; + w.addEventListener("resize", handleChange, true); + } + if (index === 0) { + index = queries.push({ + mql: mql, + listeners: listeners + }); + } + listeners.push(listener); + }; + mql.removeListener = function(listener) { + for (var i = 0, il = listeners.length; i < il; i++) { + if (listeners[i] === listener) { + listeners.splice(i, 1); + } + } + }; + return mql; + }; +})(this); + +/*! Respond.js v1.4.0: min/max-width media query polyfill. (c) Scott Jehl. MIT Lic. j.mp/respondjs */ +(function(w) { + "use strict"; + var respond = {}; + w.respond = respond; + respond.update = function() {}; + var requestQueue = [], xmlHttp = function() { + var xmlhttpmethod = false; + try { + xmlhttpmethod = new w.XMLHttpRequest(); + } catch (e) { + xmlhttpmethod = new w.ActiveXObject("Microsoft.XMLHTTP"); + } + return function() { + return xmlhttpmethod; + }; + }(), ajax = function(url, callback) { + var req = xmlHttp(); + if (!req) { + return; + } + req.open("GET", url, true); + req.onreadystatechange = function() { + if (req.readyState !== 4 || req.status !== 200 && req.status !== 304) { + return; + } + callback(req.responseText); + }; + if (req.readyState === 4) { + return; + } + req.send(null); + }; + respond.ajax = ajax; + respond.queue = requestQueue; + respond.regex = { + media: /@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi, + keyframes: /@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi, + urls: /(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g, + findStyles: /@media *([^\{]+)\{([\S\s]+?)$/, + only: /(only\s+)?([a-zA-Z]+)\s?/, + minw: /\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/, + maxw: /\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/ + }; + respond.mediaQueriesSupported = w.matchMedia && w.matchMedia("only all") !== null && w.matchMedia("only all").matches; + if (respond.mediaQueriesSupported) { + return; + } + var doc = w.document, docElem = doc.documentElement, mediastyles = [], rules = [], appendedEls = [], parsedSheets = {}, resizeThrottle = 30, head = doc.getElementsByTagName("head")[0] || docElem, base = doc.getElementsByTagName("base")[0], links = head.getElementsByTagName("link"), lastCall, resizeDefer, eminpx, getEmValue = function() { + var ret, div = doc.createElement("div"), body = doc.body, originalHTMLFontSize = docElem.style.fontSize, originalBodyFontSize = body && body.style.fontSize, fakeUsed = false; + div.style.cssText = "position:absolute;font-size:1em;width:1em"; + if (!body) { + body = fakeUsed = doc.createElement("body"); + body.style.background = "none"; + } + docElem.style.fontSize = "100%"; + body.style.fontSize = "100%"; + body.appendChild(div); + if (fakeUsed) { + docElem.insertBefore(body, docElem.firstChild); + } + ret = div.offsetWidth; + if (fakeUsed) { + docElem.removeChild(body); + } else { + body.removeChild(div); + } + docElem.style.fontSize = originalHTMLFontSize; + if (originalBodyFontSize) { + body.style.fontSize = originalBodyFontSize; + } + ret = eminpx = parseFloat(ret); + return ret; + }, applyMedia = function(fromResize) { + var name = "clientWidth", docElemProp = docElem[name], currWidth = doc.compatMode === "CSS1Compat" && docElemProp || doc.body[name] || docElemProp, styleBlocks = {}, lastLink = links[links.length - 1], now = new Date().getTime(); + if (fromResize && lastCall && now - lastCall < resizeThrottle) { + w.clearTimeout(resizeDefer); + resizeDefer = w.setTimeout(applyMedia, resizeThrottle); + return; + } else { + lastCall = now; + } + for (var i in mediastyles) { + if (mediastyles.hasOwnProperty(i)) { + var thisstyle = mediastyles[i], min = thisstyle.minw, max = thisstyle.maxw, minnull = min === null, maxnull = max === null, em = "em"; + if (!!min) { + min = parseFloat(min) * (min.indexOf(em) > -1 ? eminpx || getEmValue() : 1); + } + if (!!max) { + max = parseFloat(max) * (max.indexOf(em) > -1 ? eminpx || getEmValue() : 1); + } + if (!thisstyle.hasquery || (!minnull || !maxnull) && (minnull || currWidth >= min) && (maxnull || currWidth <= max)) { + if (!styleBlocks[thisstyle.media]) { + styleBlocks[thisstyle.media] = []; + } + styleBlocks[thisstyle.media].push(rules[thisstyle.rules]); + } + } + } + for (var j in appendedEls) { + if (appendedEls.hasOwnProperty(j)) { + if (appendedEls[j] && appendedEls[j].parentNode === head) { + head.removeChild(appendedEls[j]); + } + } + } + appendedEls.length = 0; + for (var k in styleBlocks) { + if (styleBlocks.hasOwnProperty(k)) { + var ss = doc.createElement("style"), css = styleBlocks[k].join("\n"); + ss.type = "text/css"; + ss.media = k; + head.insertBefore(ss, lastLink.nextSibling); + if (ss.styleSheet) { + ss.styleSheet.cssText = css; + } else { + ss.appendChild(doc.createTextNode(css)); + } + appendedEls.push(ss); + } + } + }, translate = function(styles, href, media) { + var qs = styles.replace(respond.regex.keyframes, "").match(respond.regex.media), ql = qs && qs.length || 0; + href = href.substring(0, href.lastIndexOf("/")); + var repUrls = function(css) { + return css.replace(respond.regex.urls, "$1" + href + "$2$3"); + }, useMedia = !ql && media; + if (href.length) { + href += "/"; + } + if (useMedia) { + ql = 1; + } + for (var i = 0; i < ql; i++) { + var fullq, thisq, eachq, eql; + if (useMedia) { + fullq = media; + rules.push(repUrls(styles)); + } else { + fullq = qs[i].match(respond.regex.findStyles) && RegExp.$1; + rules.push(RegExp.$2 && repUrls(RegExp.$2)); + } + eachq = fullq.split(","); + eql = eachq.length; + for (var j = 0; j < eql; j++) { + thisq = eachq[j]; + mediastyles.push({ + media: thisq.split("(")[0].match(respond.regex.only) && RegExp.$2 || "all", + rules: rules.length - 1, + hasquery: thisq.indexOf("(") > -1, + minw: thisq.match(respond.regex.minw) && parseFloat(RegExp.$1) + (RegExp.$2 || ""), + maxw: thisq.match(respond.regex.maxw) && parseFloat(RegExp.$1) + (RegExp.$2 || "") + }); + } + } + applyMedia(); + }, makeRequests = function() { + if (requestQueue.length) { + var thisRequest = requestQueue.shift(); + ajax(thisRequest.href, function(styles) { + translate(styles, thisRequest.href, thisRequest.media); + parsedSheets[thisRequest.href] = true; + w.setTimeout(function() { + makeRequests(); + }, 0); + }); + } + }, ripCSS = function() { + for (var i = 0; i < links.length; i++) { + var sheet = links[i], href = sheet.href, media = sheet.media, isCSS = sheet.rel && sheet.rel.toLowerCase() === "stylesheet"; + if (!!href && isCSS && !parsedSheets[href]) { + if (sheet.styleSheet && sheet.styleSheet.rawCssText) { + translate(sheet.styleSheet.rawCssText, href, media); + parsedSheets[href] = true; + } else { + if (!/^([a-zA-Z:]*\/\/)/.test(href) && !base || href.replace(RegExp.$1, "").split("/")[0] === w.location.host) { + if (href.substring(0, 2) === "//") { + href = w.location.protocol + href; + } + requestQueue.push({ + href: href, + media: media + }); + } + } + } + } + makeRequests(); + }; + ripCSS(); + respond.update = ripCSS; + respond.getEmValue = getEmValue; + function callMedia() { + applyMedia(true); + } + if (w.addEventListener) { + w.addEventListener("resize", callMedia, false); + } else if (w.attachEvent) { + w.attachEvent("onresize", callMedia); + } +})(this); \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.min.js b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.min.js new file mode 100644 index 0000000000..50ac74c9c6 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.SMM.UI/Scripts/respond.matchmedia.addListener.min.js @@ -0,0 +1,5 @@ +/*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl + * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT + * */ + +!function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";if(a.matchMedia&&a.matchMedia("all").addListener)return!1;var b=a.matchMedia,c=b("only all").matches,d=!1,e=0,f=[],g=function(){a.clearTimeout(e),e=a.setTimeout(function(){for(var c=0,d=f.length;d>c;c++){var e=f[c].mql,g=f[c].listeners||[],h=b(e.media).matches;if(h!==e.matches){e.matches=h;for(var i=0,j=g.length;j>i;i++)g[i].call(a,e)}}},30)};a.matchMedia=function(e){var h=b(e),i=[],j=0;return h.addListener=function(b){c&&(d||(d=!0,a.addEventListener("resize",g,!0)),0===j&&(j=f.push({mql:h,listeners:i})),i.push(b))},h.removeListener=function(a){for(var b=0,c=i.length;c>b;b++)i[b]===a&&i.splice(b,1)},h}}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b #mq-test-1 { width: 42px; }',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b - + @@ -70,10 +70,6 @@ - - - - From e0bc8c9cac4a66432dbc68dfd5900e11090cbd1a Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 28 Oct 2025 09:02:34 +0100 Subject: [PATCH 017/490] #2195 changes after merge --- .../Helpers/DimSeedDataGenerator.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs index 720f807582..cd23c79f18 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs @@ -1778,10 +1778,10 @@ private void createSystemKeyMappings() XDocument metadataRef = xmlMetadataWriter.CreateMetadataXml(metadataStructure.Id); //create root mapping - LinkElement extensionRoot = createLinkELementIfNotExist(mappingManager, metadataStructure.Id, metadataStructure.Name, LinkElementType.MetadataStructure, LinkElementComplexity.None, ""); + LinkElement extensionRoot = createLinkELementIfNotExist(mappingManager, metadataAttributeManager, metadataStructure.Id, metadataStructure.Name, LinkElementType.MetadataStructure, LinkElementComplexity.None, ""); //create system mapping - LinkElement system = createLinkELementIfNotExist(mappingManager, 0, "System", LinkElementType.System, LinkElementComplexity.None, ""); + LinkElement system = createLinkELementIfNotExist(mappingManager, metadataAttributeManager, 0, "System", LinkElementType.System, LinkElementComplexity.None, ""); #region mapping GBIF to System Keys @@ -1790,14 +1790,14 @@ private void createSystemKeyMappings() if (Exist("title", LinkElementType.MetadataAttributeUsage, uow)) { - createToKeyMapping("title", LinkElementType.MetadataAttributeUsage, "title", LinkElementType.MetadataAttributeUsage, Key.Title, rootTo, metadataRef, mappingManager); - createFromKeyMapping("title", LinkElementType.MetadataAttributeUsage, "title", LinkElementType.MetadataAttributeUsage, Key.Title, rootFrom, metadataRef, mappingManager); + createToKeyMapping("title", LinkElementType.MetadataAttributeUsage, "title", LinkElementType.MetadataAttributeUsage, Key.Title, rootTo, metadataRef, mappingManager, metadataAttributeManager); + createFromKeyMapping("title", LinkElementType.MetadataAttributeUsage, "title", LinkElementType.MetadataAttributeUsage, Key.Title, rootFrom, metadataRef, mappingManager, metadataAttributeManager); } if (Exist("description", LinkElementType.MetadataAttributeUsage, uow)) { - createToKeyMapping("description", LinkElementType.MetadataAttributeUsage, "description", LinkElementType.MetadataAttributeUsage, Key.Description, rootTo, metadataRef, mappingManager); - createFromKeyMapping("description", LinkElementType.MetadataAttributeUsage, "description", LinkElementType.MetadataAttributeUsage, Key.Description, rootFrom, metadataRef, mappingManager); + createToKeyMapping("description", LinkElementType.MetadataAttributeUsage, "description", LinkElementType.MetadataAttributeUsage, Key.Description, rootTo, metadataRef, mappingManager, metadataAttributeManager); + createFromKeyMapping("description", LinkElementType.MetadataAttributeUsage, "description", LinkElementType.MetadataAttributeUsage, Key.Description, rootFrom, metadataRef, mappingManager, metadataAttributeManager); } From 828066e0c67acc6ae307ea933379bf9d89b1fdc1 Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 11 Nov 2025 14:49:51 +0100 Subject: [PATCH 018/490] #2256 add links, publish and permissions hook to edit view --- .../App_Data/BExIS.Modules.Dim.UI.xml | 8 ++ .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../src/lib/components/DefaultViewHook.svelte | 69 ++++++++++++ .../src/lib/components/Hook.svelte | 101 ++++-------------- .../src/lib/components/View.svelte | 1 + .../components/datadescription/Show.svelte | 1 - .../src/lib/hooks/Link.svelte | 26 +++++ .../src/lib/hooks/Permission.svelte | 26 +++++ .../src/lib/hooks/Publish.svelte | 26 +++++ .../src/routes/edit/Hooks.svelte | 62 ++++++++++- .../Hooks/EntityReferenceController.cs | 3 +- .../DCM/BExIS.Modules.Dcm.UI/Dcm.Manifest.xml | 8 +- .../Views/EntityReference/Show.cshtml | 52 ++++++--- .../BExIS.Modules.Dim.UI.csproj | 3 +- .../Controllers/PublishController.cs | 13 +++ .../Controllers/SubmissionController.cs | 16 ++- .../DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml | 14 ++- .../{PublishHook.cs => PublishEditHook.cs} | 4 +- .../Hooks/PublishViewHook.cs | 40 +++++++ .../Models/ShowPublishDataModel.cs | 4 +- .../Submission/_showPublishDataView.cshtml | 25 ++++- .../BExIS.Modules.Sam.UI.csproj | 3 +- .../Controllers/UserPermissionsController.cs | 18 +++- ...ionsHook.cs => UserPermissionsEditHook.cs} | 4 +- .../Hooks/UserPermissionsViewHook.cs | 45 ++++++++ .../SAM/BExIS.Modules.Sam.UI/Sam.Manifest.xml | 10 +- .../Views/UserPermissions/_Subjects.cshtml | 29 ++++- 27 files changed, 489 insertions(+), 124 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/DefaultViewHook.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Link.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Permission.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Publish.svelte rename Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/{PublishHook.cs => PublishEditHook.cs} (94%) create mode 100644 Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishViewHook.cs rename Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/{UserPermissionsHook.cs => UserPermissionsEditHook.cs} (92%) create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsViewHook.cs diff --git a/Console/BExIS.Web.Shell/App_Data/BExIS.Modules.Dim.UI.xml b/Console/BExIS.Web.Shell/App_Data/BExIS.Modules.Dim.UI.xml index f6f5bf1d5b..dfeb52f484 100644 --- a/Console/BExIS.Web.Shell/App_Data/BExIS.Modules.Dim.UI.xml +++ b/Console/BExIS.Web.Shell/App_Data/BExIS.Modules.Dim.UI.xml @@ -899,6 +899,14 @@ + + + Entrypoint for Publish Hook + + + + + ToDo Refactor submission Commented by Javad due to modularity issues. diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 441ae7694e..dbc22e82db 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -8,7 +8,7 @@
-
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/DefaultViewHook.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/DefaultViewHook.svelte new file mode 100644 index 0000000000..5dc692d47b --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/DefaultViewHook.svelte @@ -0,0 +1,69 @@ + + + + +{#if isEnabled} +
+ +
+ + + +{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/Hook.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/Hook.svelte index 0db7172105..7e76dd54ba 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/Hook.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/Hook.svelte @@ -8,9 +8,17 @@ --> {#if isEnabled}
- {displayName.toUpperCase()} +
-{/if} - + + +{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/View.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/View.svelte index 8c4aa2b360..7db0100a02 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/View.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/View.svelte @@ -16,6 +16,7 @@ onMount(async () => { //load javascript from server const urlscript = host + start + '?id=' + id + '&&version=' + version; + console.log("🚀 ~ urlscript:", urlscript) import(urlscript).then((resp) => { ExtComponent = resp.default; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte index 1154428e07..33703142e8 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte @@ -3,7 +3,6 @@ import Header from './ShowHeader.svelte'; import { Table } from '@bexis2/bexis2-core-ui'; import type { TableConfig } from '@bexis2/bexis2-core-ui'; - import { dataset_dev } from 'svelte/internal'; import { writable } from 'svelte/store'; import NameTableCol from './NameTableCol.svelte'; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Link.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Link.svelte new file mode 100644 index 0000000000..6de4babd56 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Link.svelte @@ -0,0 +1,26 @@ + + +
+
+ +
+
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Permission.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Permission.svelte new file mode 100644 index 0000000000..6de4babd56 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Permission.svelte @@ -0,0 +1,26 @@ + + +
+
+ +
+
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Publish.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Publish.svelte new file mode 100644 index 0000000000..6de4babd56 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Publish.svelte @@ -0,0 +1,26 @@ + + +
+
+ +
+
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte index 82c1e0b819..3717b62635 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte @@ -1,11 +1,12 @@ - - +@section scripts +{ + + + + + + +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/BExIS.Modules.Dim.UI.csproj b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/BExIS.Modules.Dim.UI.csproj index db6df8b470..7514fad4c4 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/BExIS.Modules.Dim.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/BExIS.Modules.Dim.UI.csproj @@ -509,7 +509,8 @@ - + + diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs index 443d296dd7..b6d59a4139 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs @@ -21,6 +21,19 @@ public ActionResult Index() /// [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Read)] public ActionResult Start(long id, int version = 0) + { + // not implemented yet + return RedirectToAction("getPublishDataView", "Submission", new { datasetId = id, versionId = version }); + } + + /// + /// Entrypoint for Publish Hook + /// + /// + /// + /// + [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Read)] + public ActionResult StartView(long id, int version = 0) { return RedirectToAction("getPublishDataPartialView", "Submission", new { datasetId = id, versionId = version }); } diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/SubmissionController.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/SubmissionController.cs index 444e2d4ade..82a115d794 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/SubmissionController.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/SubmissionController.cs @@ -148,6 +148,15 @@ public ActionResult getPublishDataPartialView(long datasetId, long datasetVersio return PartialView("_showPublishDataView", model); } + [BExISEntityAuthorize(typeof(Dataset), "datasetId", RightType.Read)] + public ActionResult getPublishDataView(long datasetId, long datasetVersionId = -1) + { + setViewData(datasetId); + ShowPublishDataModel model = getShowPublishDataModel(datasetId, datasetVersionId); + + return View("_showPublishDataView", model); + } + public async Task LoadRequirementView(long brokerId, long datasetId, int versionNr = 0, double tagNr = 0) { setViewData(datasetId); @@ -435,6 +444,8 @@ private ShowPublishDataModel getShowPublishDataModel(long datasetId, long datase try { Dataset dataset = datasetManager.GetDataset(datasetId); + var latestVersion = datasetManager.GetDatasetLatestVersion(datasetId); + model.Title = latestVersion != null ? latestVersion.Title : "No title available"; List Brokers = GetBrokers(dataset.MetadataStructure.Id, publicationManager); @@ -501,9 +512,9 @@ private ShowPublishDataModel getShowPublishDataModel(long datasetId, long datase Status = pub.Status, DatasetVersionNr = versionNr, Tag = pub.DatasetVersion.Tag != null ? pub.DatasetVersion.Tag.Nr : 0, + }); } - return model; } finally @@ -915,7 +926,8 @@ private void setViewData(long datasetId) ViewData["VersionNrs"] = versionNumbers; ViewData["Tags"] = tags; - + ViewData["Title"] = tags; + } } } diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml index 0e8e43613a..15d85c62a3 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml @@ -61,12 +61,22 @@ + type="BExIS.Modules.Dim.UI.Hooks.PublishViewHook, BExIS.Modules.DIM.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> + + + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishHook.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishEditHook.cs similarity index 94% rename from Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishHook.cs rename to Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishEditHook.cs index 6daa37d4c5..36b46d7c1a 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishHook.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishEditHook.cs @@ -4,9 +4,9 @@ namespace BExIS.Modules.Dim.UI.Hooks { - public class PublishHook : Hook + public class PublishEditHook : Hook { - public PublishHook() + public PublishEditHook() { Start = "/dim/publish/start"; } diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishViewHook.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishViewHook.cs new file mode 100644 index 0000000000..c327a336d1 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Hooks/PublishViewHook.cs @@ -0,0 +1,40 @@ +using BExIS.Dlm.Services.Data; +using BExIS.Security.Entities.Authorization; +using BExIS.UI.Hooks; + +namespace BExIS.Modules.Dim.UI.Hooks +{ + public class PublishViewHook : Hook + { + public PublishViewHook() + { + Start = "/dim/publish/startView"; + } + + public override void Check(long id, string username) + { + // check status + checkStatus(id, username); + } + + private void checkStatus(long id, string username) + { + Status = HookStatus.Open; + + // check if the user has access rights to the entrypoint - set in Start + bool hasAccess = hasUserAccessRights(username); + + // user rights to the dataset + bool hasRights = hasUserEntityRights(id, username, RightType.Write); + + // if one fail then access is denied + if (hasAccess == false || hasRights == false) Status = HookStatus.AccessDenied; + + using (var datasetManager = new DatasetManager()) + { + var dataset = datasetManager.GetDataset(id); + if (dataset.Status != Dlm.Entities.Data.DatasetStatus.CheckedIn) Status = HookStatus.Disabled; + } + } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/ShowPublishDataModel.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/ShowPublishDataModel.cs index 80e1c2ee19..730639ee3e 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/ShowPublishDataModel.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/ShowPublishDataModel.cs @@ -8,6 +8,7 @@ public class ShowPublishDataModel { public List Brokers; public long DatasetId; + public string Title; public bool EditRights; public bool DownloadRights; public bool MetadataIsValid; @@ -22,7 +23,8 @@ public ShowPublishDataModel() EditRights = false; DownloadRights = false; MetadataIsValid = false; - } + Title = "No title available"; + } } public class PublicationModel diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Views/Submission/_showPublishDataView.cshtml b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Views/Submission/_showPublishDataView.cshtml index e53c3bb283..d2ed9a31fa 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Views/Submission/_showPublishDataView.cshtml +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Views/Submission/_showPublishDataView.cshtml @@ -4,6 +4,7 @@ @model BExIS.Modules.Dim.UI.Models.ShowPublishDataModel @{ + ViewBag.Title = "Preparation for "+Model.Title; List datarepolist = Model.Brokers; List versionNrs = new List(); List tags = new List(); @@ -60,7 +61,7 @@ $("#preloader").preloader(14, "Please wait..."); - + jQuery.ajax({ type: "POST", url: "@Url.Action("CheckExportPossibility", "Submission")", @@ -268,9 +269,25 @@ }); }); } + + function backFn() { + + window.location.href = '/dcm/edit/?id=@Model.DatasetId'; + } + + +
+ +
+
+ +
+ +
+
@@ -417,5 +434,11 @@ .t-state-active { line-height: 14pt } + + .publishContentContainer-header { + display: flex; + gap: 3px; + align-items: center; + }
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj index 3901ce12d1..b71ad867f0 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj @@ -147,7 +147,8 @@ - + + diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs index b72bfdaf18..96f9eadf5f 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs @@ -20,7 +20,16 @@ public ActionResult Start(long id, int version = 0) { using (var entityManager = new EntityManager()) { - return RedirectToAction("Subjects", "UserPermissions", new { EntityId = entityManager.FindByName("Dataset").Id, InstanceId = id }); + return RedirectToAction("SubjectsView", "UserPermissions", new { EntityId = entityManager.FindByName("Dataset").Id, InstanceId = id }); + } + } + + [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Grant)] + public ActionResult StartView(long id, int version = 0) + { + using (var entityManager = new EntityManager()) + { + return RedirectToAction("SubjectsPartialView", "UserPermissions", new { EntityId = entityManager.FindByName("Dataset").Id, InstanceId = id }); } } @@ -64,11 +73,16 @@ public async Task RemoveRightFromEntityPermission(long subjectId, long entityId, } } - public ActionResult Subjects(long entityId, long instanceId) + public ActionResult SubjectsPartialView(long entityId, long instanceId) { return PartialView("_Subjects", new EntityInstanceModel() { EntityId = entityId, InstanceId = instanceId }); } + public ActionResult SubjectsView(long entityId, long instanceId) + { + return View("_Subjects", new EntityInstanceModel() { EntityId = entityId, InstanceId = instanceId}); + } + [GridAction] public ActionResult Subjects_Select(long entityId, long instanceId) { diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsHook.cs b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsEditHook.cs similarity index 92% rename from Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsHook.cs rename to Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsEditHook.cs index 4262e27fd1..c44333373f 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsHook.cs +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsEditHook.cs @@ -7,9 +7,9 @@ namespace BExIS.Modules.Sam.UI.Hooks { - public class UserPermissionsHook : Hook + public class UserPermissionsEditHook : Hook { - public UserPermissionsHook() + public UserPermissionsEditHook() { Start = "/sam/UserPermissions/start"; } diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsViewHook.cs b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsViewHook.cs new file mode 100644 index 0000000000..c6fb642543 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Hooks/UserPermissionsViewHook.cs @@ -0,0 +1,45 @@ +using BExIS.Security.Entities.Authorization; +using BExIS.UI.Hooks; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Sam.UI.Hooks +{ + public class UserPermissionsViewHook : Hook + { + public UserPermissionsViewHook() + { + Start = "/sam/UserPermissions/startView"; + } + + public override void Check(long id, string username) + { + // check status + checkStatus(id, username); + + } + + private void checkStatus(long id, string username) + { + // check if the user has access rights to the entrypoint - set in Start + bool hasAccess = hasUserAccessRights(username); + + // user rights to the dataset + bool hasRights = hasUserEntityRights(id, username,RightType.Grant); + + // if one fail then access is denied + if (hasAccess == false || hasRights == false) + { + Status = HookStatus.AccessDenied; + } + else + { + Status = HookStatus.Open; + } + + } + + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Sam.Manifest.xml b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Sam.Manifest.xml index 3891160b8a..9b64b6fd8f 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Sam.Manifest.xml +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Sam.Manifest.xml @@ -107,21 +107,21 @@ + type="BExIS.Modules.Sam.UI.Hooks.UserPermissionsViewHook, BExIS.Modules.SAM.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> - + type="BExIS.Modules.Sam.UI.Hooks.UserPermissionsEditHook, BExIS.Modules.SAM.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" /> \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Views/UserPermissions/_Subjects.cshtml b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Views/UserPermissions/_Subjects.cshtml index 2bf5c9da44..f21c2f1afd 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Views/UserPermissions/_Subjects.cshtml +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Views/UserPermissions/_Subjects.cshtml @@ -3,12 +3,31 @@ @using Telerik.Web.Mvc.UI @model EntityInstanceModel +@{ + ViewBag.Title = "Permissions for "+Model.InstanceId; +} + + + +
+
+ +
+ @*
+

Permissions for

+
*@ +
@(Html.Telerik().Grid() .Name("grid_subjects") @@ -55,4 +74,12 @@ .ClientEvents(events => { events.OnDataBound("grid_subjects_onDataBound"); - })) \ No newline at end of file + })) + + \ No newline at end of file From fb1d2c11012bff838de964f00e94beaeaf9bf9b8 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 13 Nov 2025 09:20:28 +0100 Subject: [PATCH 019/490] #2209 fix issue with extension seed data import schema --- .../src/routes/entitytemplates/Edit.svelte | 15 ++++++++--- .../Helpers/DCMSeedDataGenerator.cs | 6 ++--- .../Views/EntityReference/Show.cshtml | 26 +++++++++++-------- Console/Workspace | 2 +- 4 files changed, 31 insertions(+), 18 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte index d785cef632..e46974f852 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/entitytemplates/Edit.svelte @@ -22,7 +22,10 @@ import { getEntityTemplate, saveEntityTemplate, - getSystemKeys + getSystemKeys, + + getExtensions + } from '../../services/EntityTemplateCaller'; // types @@ -81,6 +84,7 @@ console.log('load filetypes', filetypes); updateSystemKeys('metadataStructure'); updateIsExtensions(entityTemplate.entityType.text); + updateExtensions(); // if id > 0 then run validation if (id > 0) { res = suite(entityTemplate); @@ -149,6 +153,11 @@ } } + async function updateExtensions(){ + extensions = await getExtensions(); + console.log("🚀 ~ updateExtensions ~ extensions:", extensions) + } + function onCancel() { let x = 'create'; if (id > 0) { @@ -271,7 +280,7 @@ function updateIsExtensions(entityTypeText:string){
- {#if !isExtensions} +

Data Structure

@@ -307,7 +316,7 @@ function updateIsExtensions(entityTypeText:string){
- + {#if !isExtensions}

Extension

+ + Date: Thu, 27 Nov 2025 15:04:30 +0100 Subject: [PATCH 021/490] #2195 add label to dataset edit view --- .../BExIS.Web.Shell.Svelte/package-lock.json | 8 +- .../package-lock.json | 89 ++----------------- .../src/routes/edit/+page.svelte | 2 +- .../src/routes/edit/AdvancedEntity.svelte | 3 +- .../package-lock.json | 4 +- 5 files changed, 18 insertions(+), 88 deletions(-) diff --git a/Console/BExIS.Web.Shell.Svelte/package-lock.json b/Console/BExIS.Web.Shell.Svelte/package-lock.json index 3823b38fa0..974a3330e2 100644 --- a/Console/BExIS.Web.Shell.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell.Svelte/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "hasInstallScript": true, "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.58", + "@bexis2/bexis2-core-ui": "0.4.60", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.58", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.58.tgz", - "integrity": "sha512-u7g8+e0hEV4Eu4VxsT/Fpv+YVxoUSYV3a01wwE2dg2GbwF7Th5QxHTiN6AisvcVO7N2XIBmkBwE5RjEgXB7ihw==", + "version": "0.4.60", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.60.tgz", + "integrity": "sha512-D/Ytgpzj51uxCu+TEROF4PxmfHE7ONaGDeQINj083dtaalS0l/u3w7kWUIeTn5D8u6oLUg/FywVzqyd0bCXkpA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json index e23fcf350a..5b478c44cd 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json @@ -11,7 +11,7 @@ "license": "ISC", "dependencies": { "@bexis2/bexis2-core-ui": "0.4.60", - "@bexis2/bexis2-rpm-ui": "0.2.14", + "@bexis2/bexis2-rpm-ui": "0.2.15", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", @@ -119,13 +119,13 @@ } }, "node_modules/@bexis2/bexis2-rpm-ui": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-rpm-ui/-/bexis2-rpm-ui-0.2.14.tgz", - "integrity": "sha512-DpDKDSod9hPiPIbsa6uMZj27BaMqPIxe+48W2CUW2YaJeVm17B2FbXwpzRILH5udbjqBJmga8AEkTc8GE4+i8A==", + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-rpm-ui/-/bexis2-rpm-ui-0.2.15.tgz", + "integrity": "sha512-vCQK1M2pd7KdGzIP9QpNclFx1Y37ckNjgZbwcHQOmxOtMA+CRe6MEHintKDNlO8lXEWSYv29KDAIVqcdPNsDfA==", "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.58", + "@bexis2/bexis2-core-ui": "0.4.60", "@floating-ui/dom": "1.6.8", "@sveltejs/adapter-static": "3.0.2", "@sveltejs/package": "2.3.2", @@ -134,41 +134,6 @@ "svelte-fa": "4.0.2" } }, - "node_modules/@bexis2/bexis2-rpm-ui/node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.58", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.58.tgz", - "integrity": "sha512-u7g8+e0hEV4Eu4VxsT/Fpv+YVxoUSYV3a01wwE2dg2GbwF7Th5QxHTiN6AisvcVO7N2XIBmkBwE5RjEgXB7ihw==", - "license": "ISC", - "dependencies": { - "@codemirror/lang-html": "^6.4.9", - "@codemirror/lang-javascript": "^6.2.2", - "@codemirror/lang-json": "^6.0.1", - "@codemirror/lint": "^6.8.1", - "@codemirror/theme-one-dark": "^6.1.2", - "@floating-ui/dom": "^1.6.8", - "@fortawesome/fontawesome-free": "^6.6.0", - "@fortawesome/fontawesome-svg-core": "^6.6.0", - "@fortawesome/free-regular-svg-icons": "^6.6.0", - "@fortawesome/free-solid-svg-icons": "^6.6.0", - "@sveltejs/kit": "^2.5.19", - "@sveltejs/vite-plugin-svelte": "^3.1.1", - "axios": "^1.7.3", - "codemirror": "^6.0.1", - "dateformat": "^5.0.3", - "delay": "^6.0.0", - "dotenv": "^16.4.5", - "eslint4b-prebuilt": "^6.7.2", - "highlight.js": "^11.10.0", - "highlightjs-svelte": "^1.0.6", - "svelte": "^4.2.18", - "svelte-codemirror-editor": "^1.4.0", - "svelte-fa": "^4.0.2", - "svelte-file-dropzone": "^2.0.7", - "svelte-headless-table": "^0.18.2", - "svelte-select": "5.8.3", - "vest": "^5.4.0" - } - }, "node_modules/@codemirror/autocomplete": { "version": "6.18.0", "resolved": "https://registry.npmjs.org/@codemirror/autocomplete/-/autocomplete-6.18.0.tgz", @@ -5531,53 +5496,17 @@ } }, "@bexis2/bexis2-rpm-ui": { - "version": "0.2.14", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-rpm-ui/-/bexis2-rpm-ui-0.2.14.tgz", - "integrity": "sha512-DpDKDSod9hPiPIbsa6uMZj27BaMqPIxe+48W2CUW2YaJeVm17B2FbXwpzRILH5udbjqBJmga8AEkTc8GE4+i8A==", + "version": "0.2.15", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-rpm-ui/-/bexis2-rpm-ui-0.2.15.tgz", + "integrity": "sha512-vCQK1M2pd7KdGzIP9QpNclFx1Y37ckNjgZbwcHQOmxOtMA+CRe6MEHintKDNlO8lXEWSYv29KDAIVqcdPNsDfA==", "requires": { - "@bexis2/bexis2-core-ui": "0.4.58", + "@bexis2/bexis2-core-ui": "0.4.60", "@floating-ui/dom": "1.6.8", "@sveltejs/adapter-static": "3.0.2", "@sveltejs/package": "2.3.2", "papaparse": "5.4.1", "patch-package": "8.0.0", "svelte-fa": "4.0.2" - }, - "dependencies": { - "@bexis2/bexis2-core-ui": { - "version": "0.4.58", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.58.tgz", - "integrity": "sha512-u7g8+e0hEV4Eu4VxsT/Fpv+YVxoUSYV3a01wwE2dg2GbwF7Th5QxHTiN6AisvcVO7N2XIBmkBwE5RjEgXB7ihw==", - "requires": { - "@codemirror/lang-html": "^6.4.9", - "@codemirror/lang-javascript": "^6.2.2", - "@codemirror/lang-json": "^6.0.1", - "@codemirror/lint": "^6.8.1", - "@codemirror/theme-one-dark": "^6.1.2", - "@floating-ui/dom": "^1.6.8", - "@fortawesome/fontawesome-free": "^6.6.0", - "@fortawesome/fontawesome-svg-core": "^6.6.0", - "@fortawesome/free-regular-svg-icons": "^6.6.0", - "@fortawesome/free-solid-svg-icons": "^6.6.0", - "@sveltejs/kit": "^2.5.19", - "@sveltejs/vite-plugin-svelte": "^3.1.1", - "axios": "^1.7.3", - "codemirror": "^6.0.1", - "dateformat": "^5.0.3", - "delay": "^6.0.0", - "dotenv": "^16.4.5", - "eslint4b-prebuilt": "^6.7.2", - "highlight.js": "^11.10.0", - "highlightjs-svelte": "^1.0.6", - "svelte": "^4.2.18", - "svelte-codemirror-editor": "^1.4.0", - "svelte-fa": "^4.0.2", - "svelte-file-dropzone": "^2.0.7", - "svelte-headless-table": "^0.18.2", - "svelte-select": "5.8.3", - "vest": "^5.4.0" - } - } } }, "@codemirror/autocomplete": { diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte index 81a7cb32e8..168bc99d02 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/+page.svelte @@ -52,7 +52,7 @@
{#if entityTemplate.hasExtension} - + {:else} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte index 1a713fa47e..51eff46344 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte @@ -18,6 +18,7 @@ export let id: number = 0; export let version: number; export let title = ""; + export let entity = ""; export let extensions:ExtensionType[] = [] @@ -61,7 +62,7 @@ - entity + {entity} : {title} diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json index 0680acd960..78c585c55b 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bexis2/bexis2-rpm-ui", - "version": "0.2.14", + "version": "0.2.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bexis2/bexis2-rpm-ui", - "version": "0.2.14", + "version": "0.2.15", "hasInstallScript": true, "license": "ISC", "dependencies": { From 6fd697a171e645af12e8bf5d32810dc1f39e0bf5 Mon Sep 17 00:00:00 2001 From: Erik Kleinsteuber Date: Fri, 12 Dec 2025 11:25:13 +0100 Subject: [PATCH 022/490] 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 023/490] #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 2441214a0de5a3eda3042512a3fd06576fc345f0 Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 20 Jan 2026 10:38:48 +0100 Subject: [PATCH 024/490] #2195 start integrate place for new view and small inprovments --- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 4 +- .../src/models/View.ts | 59 ++++- .../src/routes/edit/AdvancedEntity.svelte | 2 +- .../src/routes/edit/Header.svelte | 7 + .../src/routes/view/+page.svelte | 99 ++++---- .../src/routes/view/Header.svelte | 29 ++- .../src/routes/view/Hooks.svelte | 25 ++ .../src/routes/view/Links.svelte | 22 ++ .../src/routes/view/services.js | 17 ++ .../BExIS.Modules.Dcm.UI.csproj | 5 + .../Controllers/ViewController.cs | 236 ++++++++++++++++-- .../Helpers/TagInfoHelper.cs | 104 ++++++++ .../Hooks/LinkEditHook.cs | 18 +- .../Models/View/ViewModel.cs | 97 ++++++- .../Views/View/Index.cshtml | 36 +-- 15 files changed, 642 insertions(+), 118 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Hooks.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/TagInfoHelper.cs diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index dbc22e82db..924ed45785 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -8,9 +8,9 @@
-
+
-
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts index 79132d2f41..801b2bb9ca 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts @@ -1,9 +1,14 @@ -export interface ViewModel { - id: number; - versionId: number; - version: number; - title: string; - hooks: Hook[]; +export interface ViewSettingsModel { + id: number; + versionId: number; + version: number; + title: string; + useTags: boolean; + useMinor: boolean; + hasData: boolean; + dataAggrement: string; + hooks: Hook[]; + labels: { [key: string]: string; }; } export interface Hook { @@ -31,3 +36,45 @@ export enum HookMode { view = 0, edit = 1 } + + +export interface ApiDatasetModel { + id: number; + version: number; + versionId: number; + title: string; + description: string; + dataStructureId: number; + metadataStructureId: number; + isPublic: boolean; + publicationDate: string; + additionalInformations: { [key: string]: string; }; + parties: { [key: string]: { [key: string]: string; }; }; + versionDate: string; + names: any; + links: LinksOverview; +} + +export interface LinksOverview { + from: ReferenceModel[]; + to: ReferenceModel[]; +} + +export interface ReferenceModel { + refId: number; + target: ReferenceElementModel; + source: ReferenceElementModel; + context: string; + referenceType: string; + linkType: string; + category: string; +} + +export interface ReferenceElementModel { + id: number; + version: number; + typeId: number; + type: string; + title: string; + latestVersion: boolean; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte index 51eff46344..980aa3d143 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte @@ -62,7 +62,7 @@ - {entity} : {title} + {entity} {title} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Header.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Header.svelte index 19112dceeb..ff6014f9bc 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Header.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Header.svelte @@ -28,5 +28,12 @@ View +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte index b6b1348814..04964c8bf1 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte @@ -1,17 +1,17 @@ + + +
+ + {#await load()} +
+ +
+ {:then result} + +
-
- -
- - {#if hooks} - - - {#each hooks as hook, i} - {#if hook.status == 2} - {hook.name} - {/if} - {/each} - - - - - - {#each hooks as hook, i} - {#if hook.status == 2} - - {/if} - {/each} - - - {:else} -
- +
+
+ {datamodel.description} +
+
+ test +
- {/if} - + + + + + + {:catch error} + + {/await} +
+ + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte index 2829231543..731575f574 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte @@ -1,11 +1,28 @@ - -

{title}

-Dataset Id: {id} -Version: {version} -version selection -download +
+
+

{title}

+
+
+ + {#if labelKeys && labelKeys.length > 0} + {#each labelKeys as key} + {key} + {/each} + {/if} + +
+
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Hooks.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Hooks.svelte new file mode 100644 index 0000000000..f68ba59e6a --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Hooks.svelte @@ -0,0 +1,25 @@ + + +
+ +{#if hooks && hooks.length > 0} +
more details
+
+ {#each hooks as hook} +
+ +
+ {/each} +
+{:else} +

No hooks available.

+{/if} +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte new file mode 100644 index 0000000000..483349a6a5 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte @@ -0,0 +1,22 @@ + + +{#if types} + {#each types as type} +
+

{type.toUpperCase()}

+
+ {#each links.filter(link => link.linkType === type) as link} + {link.referenceType}{link.target.title} + {/each} +
+
+ {/each} +{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js index 82789f69c9..83c682c61b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js @@ -8,3 +8,20 @@ export const getView = async (id) => { console.error(error); } }; + +export const getApiDataset = async (id, version ) => { + try { + if(version === undefined || version <= 0){ + const response = await Api.get('/api/dataset/'+id); + return response.data; + } + else{ + const response = await Api.get('/api/dataset/'+id+'/version_number/'+version); + return response.data; + } + + + } catch (error) { + console.error(error); + } +}; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj index 77f3c7189a..763075f338 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj @@ -90,6 +90,7 @@ + @@ -788,6 +789,10 @@ {a7fbcc13-7e29-4710-82a1-bd6d6f811fda} BExIS.Utils.Data + + {0F1EC13E-D685-4F4D-A438-52797B0E53A0} + BExIS.Utils.NH + {782b71c1-707f-4ab1-80e9-90d2880635b4} BExIS.Utils diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs index c3b1a6a63c..e5496a7b2e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs @@ -1,17 +1,34 @@ using BExIS.App.Bootstrap.Attributes; +using BExIS.Dim.Helpers.BIOSCHEMA; +using BExIS.Dim.Services; using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Entities.DataStructure; +using BExIS.Dlm.Entities.Party; using BExIS.Dlm.Services.Data; +using BExIS.Dlm.Services.Party; +using BExIS.Modules.Dcm.UI.Helpers; using BExIS.Modules.Dcm.UI.Models.View; using BExIS.Security.Entities.Authorization; +using BExIS.Security.Entities.Subjects; +using BExIS.Security.Services.Authorization; using BExIS.UI.Helpers; using BExIS.UI.Hooks; +using BExIS.Utils.Data; +using BExIS.Utils.Data.Upload; using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; using System.Web.Mvc; +using Vaiona.Persistence.Api; +using Vaiona.Web.Mvc.Modularity; namespace BExIS.Modules.Dcm.UI.Controllers { public class ViewController : Controller { + #region about View + // GET: View /// /// this action loads the main view page of the dataset. @@ -22,19 +39,34 @@ public class ViewController : Controller /// public ActionResult Index(long id, int version = 0) { - string pageId = "view"; string module = "DCM"; - ViewData["PageId"] = pageId; - ViewData["PageScript"] = SvelteHelper.GetPageScript(module, pageId); - ViewData["PageCss"] = SvelteHelper.GetPageCss(module, pageId); - ViewData["id"] = id; ViewData["version"] = version; + ViewData["app"] = SvelteHelper.GetApp(module); + ViewData["start"] = SvelteHelper.GetStart(module); + + // load settings from ddm + var moduleSettings = ModuleManager.GetModuleSettings("Ddm"); + ViewData["use_tags"] = moduleSettings.GetValueByKey("use_tags"); + bool useTags = (bool)ViewData["use_tags"]; + ViewData["use_minor"] = moduleSettings.GetValueByKey("use_minor"); + ViewData["has_data"] = false; + ViewData["data_aggreement"] = moduleSettings.GetValueByKey("data_aggreement"); + + if (version > 0) + { + // load BioSchema Description if exist + string bioschemadescription = getBioSchema(id, version); + if (!string.IsNullOrEmpty(bioschemadescription)) + ViewData["BioSchema"] = bioschemadescription; + } - ViewData["LayoutScript"] = SvelteHelper.GetLayoutScript(module); - ViewData["LayoutCss"] = SvelteHelper.GetLayoutCss(module); - ViewData["LayoutSvelteScript"] = SvelteHelper.GetLayoutSvelteScript(module); + //ToDo + // add bioschema to view data + // has data + // data_aggreement + // check_public_metadata return View(); } @@ -50,7 +82,7 @@ public ActionResult Index(long id, int version = 0) [JsonNetFilter] public JsonResult Load(long id, int version = 0) { - ViewModel model = new ViewModel(); + ViewSettingsModel model = new ViewSettingsModel(); model.Id = id; model.Version = version; @@ -63,6 +95,7 @@ public JsonResult Load(long id, int version = 0) { datasetVersion = datasetManager.GetDatasetLatestVersion(id); model.Version = datasetManager.GetDatasetVersionCount(id); // get number of the latest version + } else // get specific { @@ -70,13 +103,35 @@ public JsonResult Load(long id, int version = 0) datasetVersion = datasetManager.GetDatasetVersion(model.VersionId); // load datasetversion by id } - // get title - model.Title = datasetVersion.Title; + if (datasetVersion != null) + { + model.Labels = getLabels(id, datasetVersion.Id, datasetVersion.Tag?.Nr ?? 0, datasetVersion.Dataset.EntityTemplate.Name); + + // check data + if (datasetVersion.Dataset.DataStructure != null && datasetVersion.Dataset.DataStructure.Self.GetType().Equals(typeof(StructuredDataStructure))) + { + long c = datasetManager.RowCount(datasetVersion.Dataset.Id, null); + ViewData["gridTotal"] = c; + if (c > 0) model.HasData = true; + } + else + { + + if (datasetVersion.ContentDescriptors.Where(c => c.Name.Equals("unstructuredData")).Any()) + { + model.HasData = true; + } + } + - // load all hooks for the edit view - HookManager hooksManager = new HookManager(); - model.Hooks = hooksManager.GetHooksFor("dataset", "details", HookMode.view); + // get title + model.Title = datasetVersion.Title; + // load all hooks for the edit view + HookManager hooksManager = new HookManager(); + model.Hooks = hooksManager.GetHooksFor("dataset", "details", HookMode.view); + + } // run all checks string userName = ""; if (HttpContext.User.Identity.IsAuthenticated) @@ -84,10 +139,65 @@ public JsonResult Load(long id, int version = 0) model.Hooks.ForEach(h => h.Check(id, userName)); + // settings + // load settings from ddm + var moduleSettings = ModuleManager.GetModuleSettings("Ddm"); + model.UseTags = Convert.ToBoolean(moduleSettings.GetValueByKey("use_tags")); + model.UseMinor = Convert.ToBoolean(moduleSettings.GetValueByKey("use_minor")); + model.HasData = false; + model.DataAggrement = moduleSettings.GetValueByKey("data_aggreement").ToString(); + + + + return Json(model, JsonRequestBehavior.AllowGet); } } + public PartialViewResult Tags(long id, int version) + { + if (id <= 0) throw new ArgumentException("id is not valid"); + + ViewData["Id"] = id; + List tags = new List(); + bool hasEditRights = hasUserRights(id, RightType.Write); + + if (version == 0) return PartialView("_tagsView", tags); // return empty list + + + + using (DatasetManager datasetmanager = new DatasetManager()) + { + TagInfoHelper _helper = new TagInfoHelper(); + var versions = datasetmanager.GetDatasetVersions(id); + + var currentVersion = datasetmanager.GetDatasetVersion(id, version); + ViewData["Tag"] = currentVersion.Tag?.Nr; + + if (versions != null) + { + tags = _helper.GetViews(versions, datasetmanager, !hasEditRights); + } + } + + return PartialView("_tagsView", tags); // Replace "_PartialViewName" with your actual name + + } + + private string getBioSchema(long id, int version) + { + if (id <= 0) throw new ArgumentException("id is not valid"); + ViewData["Id"] = id; + + var helper = new BioSchemaHelper(); + string json = helper.GetBioSchemaForDataset(id, version, HttpContext.Request.Url.ToString()); + + return json; // Replace "_PartialViewName" with your actual name + + } + + #endregion about view + /// /// Start from Metadata Hook - view /// @@ -150,9 +260,107 @@ public ActionResult StartDataStructure(long id, int version) return RedirectToAction("ShowPreviewDataStructure", "Data", new { area = "DDM", datasetID = id }); } + + public ActionResult Test() { return PartialView("_test"); } + + #region Helpers + + public bool UserExist() + { + if (HttpContext.User != null && HttpContext.User.Identity != null && !string.IsNullOrEmpty(HttpContext.User.Identity.Name)) return true; + + return false; + } + + public string GetUsernameOrDefault() + { + var username = string.Empty; + try + { + username = HttpContext.User.Identity.Name; + } + catch { } + + return !string.IsNullOrWhiteSpace(username) ? username : "DEFAULT"; + } + + private string getPartyNameOrDefault() + { + var userName = string.Empty; + try + { + userName = HttpContext.User.Identity.Name; + } + catch { } + + if (userName != null) + { + using (var uow = this.GetUnitOfWork()) + using (var partyManager = new PartyManager()) + { + var userRepository = uow.GetReadOnlyRepository(); + var user = userRepository.Query(s => s.Name.ToUpperInvariant() == userName.ToUpperInvariant()).FirstOrDefault(); + + if (user != null) + { + Party party = partyManager.GetPartyByUser(user.Id); + if (party != null) + { + return party.Name; + } + } + } + } + return !string.IsNullOrWhiteSpace(userName) ? userName : "DEFAULT"; + } + + private async Task getVersionId(long datasetId, int versionNr = 0, string versionName = "", double tagNr = 0) + { + + var moduleSettings = ModuleManager.GetModuleSettings("Ddm"); + bool useTags = false; + bool.TryParse(moduleSettings.GetValueByKey("use_tags").ToString(), out useTags); + + return await DatasetVersionHelper.GetVersionId(datasetId, GetUsernameOrDefault(), versionNr, useTags, tagNr); + + } + + private bool hasUserRights(long entityId, RightType rightType) + { + #region security permissions and authorizations check + + using (EntityPermissionManager entityPermissionManager = new EntityPermissionManager()) + return entityPermissionManager.HasEffectiveRightsAsync(GetUsernameOrDefault(), typeof(Dataset), entityId, rightType).Result; + + #endregion security permissions and authorizations check + } + + public Dictionary getLabels(long id, long versionId, double tag, string template) + { + using (var publicationManager = new PublicationManager()) + { + Dictionary keyValuePairs = new Dictionary(); + + var publications = publicationManager.PublicationRepo.Query(p => p.Dataset.Id == id && p.DatasetVersion.Id == versionId && p.ExternalLink != ""); + if (publications != null && publications.Any()) + { + + foreach (var item in publications) + { + keyValuePairs.Add(item.ExternalLink, item.ExternalLinkType); + } + } + + keyValuePairs.Add(template, "template"); + + return keyValuePairs; + } + } + + #endregion } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/TagInfoHelper.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/TagInfoHelper.cs new file mode 100644 index 0000000000..d8c724484d --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/TagInfoHelper.cs @@ -0,0 +1,104 @@ +using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Services.Data; +using BExIS.Modules.Dcm.UI.Models.View; +using System; +using System.Collections.Generic; +using System.Linq; + +namespace BExIS.Modules.Dcm.UI.Helpers +{ + public class TagInfoHelper + { + public Tag Update(TagInfoEditModel model, Tag tag) + { + if (model != null && tag != null) + { + tag.Nr = model.TagNr; + tag.ReleaseDate = model.ReleaseDate; + tag.Final = model.Publish; + + if (tag.Final && model.ReleaseDate == new DateTime()) + { + tag.ReleaseDate = DateTime.Now; + } + } + + return tag; + } + + public List ConvertTo(List versions, DatasetManager datasetManager) + { + List models = new List(); + + foreach (var version in versions) + { + models.Add(ConvertTo(version, datasetManager.GetDatasetVersionNr(version))); + } + + return models; + } + + public TagInfoEditModel ConvertTo(DatasetVersion dsv, int versionNr) + { + TagInfoEditModel model = new TagInfoEditModel(); + + if (dsv != null) + { + model.VersionId = dsv.Id; + model.VersionNr = versionNr; + model.ReleaseNote = dsv.ChangeDescription; + + if(dsv.ModificationInfo != null && !string.IsNullOrEmpty(dsv.ModificationInfo.Comment)) + model.SystemDescription = dsv.ModificationInfo.Comment; + + if (dsv.ModificationInfo != null && !string.IsNullOrEmpty(dsv.ModificationInfo.Performer)) + model.SystemAuthor = dsv.ModificationInfo.Performer; + + model.Show = dsv.Show; + + if(dsv.ModificationInfo?.Timestamp != null) + model.SystemDate = (DateTime)dsv.ModificationInfo?.Timestamp; + + + if (dsv.Tag != null) + { + model.TagId = dsv.Tag.Id; + model.TagNr = dsv.Tag.Nr; + model.ReleaseDate = dsv.Tag.ReleaseDate; + model.Publish = dsv.Tag.Final; + } + } + + return model; + } + + + + public List GetViews(List versions, DatasetManager datasetManager,bool released=false) + { + List models = new List(); + + List tags = versions.Where(v=>v.Tag!=null).Select(v => v.Tag.Nr).Distinct().ToList(); + + foreach (var nr in tags) + { + var tagVersions = versions.OrderByDescending(o=>o.Id).Where(v => v.Tag !=null && v.Show && v.Tag.Nr.Equals(nr)).ToList(); + if (released) + tagVersions = tagVersions.Where(v => v.Show && v.Tag.Final).ToList(); + + if (tagVersions.Any()) + { + models.Add(new TagInfoViewModel() + { + Version = nr, + ReleaseDate = tagVersions.FirstOrDefault().Tag.ReleaseDate, + ReleaseNotes = tagVersions.Select(v => v.ChangeDescription).ToList() + }); + } + + } + + return models; + } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/LinkEditHook.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/LinkEditHook.cs index 169da434d5..c995ca7f20 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/LinkEditHook.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/LinkEditHook.cs @@ -14,19 +14,17 @@ public LinkEditHook() public override void Check(long id, string username) { - // disable for extension entity - checkEntity(id); + - if (Status != HookStatus.Disabled) - { + // check status + checkStatus(id, username); - // check status - checkStatus(id, username); + // check if subject is checked in + // only check if status is open + checkAvailablity(id); - // check if subject is checked in - // only check if status is open - checkAvailablity(id); - } + // disable for extension entity + checkEntity(id); } private void checkStatus(long id, string username) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/ViewModel.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/ViewModel.cs index 73fd8f2dc3..8ef616ca8c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/ViewModel.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/ViewModel.cs @@ -1,23 +1,116 @@ using BExIS.UI.Hooks; +using Newtonsoft.Json; +using System; using System.Collections.Generic; namespace BExIS.Modules.Dcm.UI.Models.View { - public class ViewModel + public class ViewSettingsModel { public long Id { get; set; } public long VersionId { get; set; } public int Version { get; set; } public string Title { get; set; } + + public bool UseTags { get; set; } // use tags, e.g., 1.0, 2.0, 3.0 + public bool UseMinor { get; set; } // use minor tags, e.g., 1.1, 1.2, 1.3 + public bool HasData { get; set; } + + public string DataAggrement { get; set; } + public List Hooks { get; set; } - public ViewModel() + public Dictionary Labels { get; set; } + + public ViewSettingsModel() { Id = 0; Version = 0; VersionId = 0; Title = ""; Hooks = new List(); + UseTags = false; + HasData = false; + DataAggrement = ""; + Labels = new Dictionary(); + } + } + + public class TagInfoViewModel + { + [JsonProperty("version")] + public double Version { get; set; } + [JsonProperty("releaseNotes")] + public List ReleaseNotes { get; set; } + [JsonProperty("releaseDate")] + public DateTime ReleaseDate { get; set; } + + public TagInfoViewModel() + { + Version = 0; + ReleaseNotes = new List(); + } + + } + + public class TagInfoEditModel + { + [JsonProperty("versionId")] + public long VersionId { get; set; } + + [JsonProperty("versionNr")] + public long VersionNr { get; set; } + + + [JsonProperty("releaseNote")] + public string ReleaseNote { get; set; } + [JsonProperty("show")] + public bool Show { get; set; } + + [JsonProperty("tagId")] + public long TagId { get; set; } + + [JsonProperty("tagNr")] + public double TagNr { get; set; } + + [JsonProperty("publish")] + public bool Publish { get; set; } + + [JsonProperty("releaseDate")] + public DateTime ReleaseDate { get; set; } + [JsonProperty("systemDescription")] + public string SystemDescription { get; set; } + [JsonProperty("systemAuthor")] + public string SystemAuthor { get; set; } + [JsonProperty("systemDate")] + public DateTime SystemDate { get; set; } + + [JsonProperty("link")] + public string Link { get; set; } + + public TagInfoEditModel() + { + VersionId = 0; + VersionNr = 0; + TagId = 0; + TagNr = 0; + ReleaseNote = ""; + SystemDescription = ""; + SystemAuthor = ""; + Link = ""; + } + + public TagInfoEditModel(long versionId, long versionNr, double tagNr, string releaseNote, DateTime releaseDate, string systemDescription, string systemAuthor, DateTime systemDate, string link) + { + VersionId = versionId; + VersionNr = versionNr; + TagNr = tagNr; + ReleaseNote = releaseNote; + ReleaseDate = releaseDate; + if (!string.IsNullOrEmpty(systemAuthor)) SystemAuthor = systemAuthor; + if (!string.IsNullOrEmpty(systemDescription)) SystemAuthor = systemDescription; + SystemDate = systemDate; + Link = link; } } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml index 3c6c584a7a..72ca42abee 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml @@ -1,38 +1,18 @@ @{ - ViewBag.Title = "Test"; + ViewBag.Title = "View"; Layout = "~/Themes/Default/Layouts/_svelteLayout.cshtml"; - string page = ViewData["PageScript"].ToString(); - string pagecss = ViewData["PageCss"].ToString(); - string pageId = ViewData["PageId"].ToString(); + long id = 0; + long version = -1; - //string skeletoncss = "../../../Content/skeleton/themes/theme-modern.css"; + if (ViewData["id"] != null) { id = Convert.ToInt64(ViewData["id"]); } - string layoutcss = ""; - if (ViewData["LayoutCss"] != null) - { - layoutcss = ViewData["LayoutCss"].ToString(); - } - - string layoutScript = ViewData["LayoutScript"].ToString(); - - string layoutSvelteScript = ViewData["LayoutSvelteScript"].ToString(); - - long id = Convert.ToInt64(ViewData["id"]); - long version = Convert.ToInt64(ViewData["version"]); + if (ViewData["version"] != null) { version = Convert.ToInt64(ViewData["version"]); } } - - - - - - \ No newline at end of file + @Html.Partial("_sveltePage") +
\ No newline at end of file From c2308c76321b842a5dbadb9622d983f22f6de288 Mon Sep 17 00:00:00 2001 From: Erik Date: Thu, 2 Apr 2026 11:42:32 +0200 Subject: [PATCH 025/490] 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 026/490] 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 027/490] 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 @@ + + - - - + {/each} + {/if} {/if} {/if} {/key} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts index e1e10c9e7e..48953670ff 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts @@ -18,14 +18,10 @@ export function getParentPath(path) { } export function getPartyIdFromParent(path) { - if (typeof path !== 'string' || !path.includes('.')) { - return ''; // Return empty if there's no dot to remove - } + + // get party id from parent path, which is the last number in the path - // Find the position of the very last dot - const lastDotIndex = path.lastIndexOf('.'); + - // Slice the string from the start up to that last dot - return path.substring(0, lastDotIndex); } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte index 38164dc8f7..cc20a6e2a2 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte @@ -123,29 +123,33 @@ const dispatch = createEventDispatcher(); // ### SYSTEM MAPPING ### const systemMappings = getSystemMappingsStore(); + if(systemMappings){ - // remove indices from path to check if the field is mapped to party or key, because in system mapping there are no indices but in the path there are because of arrays - pathWithoutIndices = removeJsonPathIndices(path); + // remove indices from path to check if the field is mapped to party or key, because in system mapping there are no indices but in the path there are because of arrays + pathWithoutIndices = removeJsonPathIndices(path); + console.log("🚀 ~ pathWithoutIndices:", pathWithoutIndices) + console.log("🚀 ~ systemMappings:", systemMappings) - if(systemMappings.partyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ + if(systemMappings.partyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ - isMappedToParty = true; - partyMappingObject = systemMappings.partyMappings.find((mapping: any) => mapping.path == pathWithoutIndices); - isSelector = partyMappingObject.selector; + isMappedToParty = true; + partyMappingObject = systemMappings.partyMappings.find((mapping: any) => mapping.path == pathWithoutIndices); + isSelector = partyMappingObject.selector; - if(isSelector) - { - selectorValue = { - "partyId": 0, - "value": value - } - } + if(isSelector) + { + selectorValue = { + "partyId": 0, + "value": value + } + } - - } + + } - if(systemMappings.keyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ - isMappedToKey = true; + if(systemMappings.keyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ + isMappedToKey = true; + } } // initial check @@ -254,7 +258,6 @@ const dispatch = createEventDispatcher(); {#if (isMappedToParty && !isSelector) || isMappedToKey} {:else if isMappedToParty && isSelector} - {:else if path && simpleComponent.properties} + {#if simpleComponent.properties['#text'].format !== undefined && simpleComponent.properties['#text'].format !== null} @@ -340,6 +344,7 @@ const dispatch = createEventDispatcher(); {:else if simpleComponent.properties['#text'].type === 'string' && simpleComponent.properties['#text'].enum === undefined} + {:else if simpleComponent.properties['#text'].type === 'string' && simpleComponent.properties['#text'].enum} - + {#if !isMulti} - - {#if simpleComponent.properties['#text'].enum.length <= 10} {:else} - {#if isMulti} + Date: Fri, 22 May 2026 08:53:15 +0200 Subject: [PATCH 030/490] #2374 speerate partyselection as component and add partyid to the selection --- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../utils/metadata/mappingHelper.ts | 31 ++++ .../utils/metadata/metadataComponentUtils.ts | 38 +++- .../lib/components/utils/metadata/models.ts | 43 +++++ .../utils/metadata/simpleComponentSuite.ts} | 0 .../src/routes/m/edit/Blocked.svelte | 4 +- .../src/routes/m/edit/PartySelector.svelte | 172 ++++++++++++++++++ .../src/routes/m/edit/helper.ts | 27 --- .../src/routes/m/edit/simpleComponent.svelte | 141 +++----------- .../src/routes/m/edit/types.ts | 23 --- 10 files changed, 307 insertions(+), 174 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/mappingHelper.ts rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/m/edit/simpleComponent.ts => lib/components/utils/metadata/simpleComponentSuite.ts} (100%) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/types.ts diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index cd69442864..04fe409557 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -9,7 +9,7 @@
-
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/mappingHelper.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/mappingHelper.ts new file mode 100644 index 0000000000..33c1c1493c --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/mappingHelper.ts @@ -0,0 +1,31 @@ +import { getSystemMappingsStore, removeJsonPathIndices } from "./metadataComponentUtils"; +import { MappingComponentConfig } from "./models"; + +export function getMappingComponentConfig(path:string, value: any): MappingComponentConfig { + + let mappingConfig: MappingComponentConfig = new MappingComponentConfig(); + const systemMappings = getSystemMappingsStore(); + + if(systemMappings){ + const pathWithoutIndices = removeJsonPathIndices(path); + + if(systemMappings.partyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ + + mappingConfig.isMappedToParty = true; + mappingConfig.partyMappingObject = systemMappings.partyMappings.find((mapping: any) => mapping.path == pathWithoutIndices); + mappingConfig.isSelector = mappingConfig.partyMappingObject.selector; + + if(mappingConfig.isSelector) + { + mappingConfig.selectorValue = { + "partyId": 0, + "value": value + } + } + + + } + } + + return mappingConfig; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts index 8a5530fd51..ee9ba53662 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts @@ -32,6 +32,12 @@ export function getRefByPath(path: string) { path = path + '.@ref'; return getNodeByPath(path); } + +export function getPartyIdByPath(path: string) { + path = path + '.@partyid'; + return getNodeByPath(path); +} + // Set value in an object based on a dot-separated path export function setValueByPath(obj: any, path: string, value: any) { const parts = path.split('.'); @@ -78,10 +84,16 @@ export function updateMetadataStore(path: string, value: any, isMulti?: boolean, } } } + else if(value === undefined || value === null) + { + const parent = getByPath(path); + // console.log("🚀 ~ updateMetadataStore ~ parent:", parent) + parent["@partyid"] = partyid; + } } } - console.log('Updated metadata store:', obj); + //console.log('Updated metadata store:', obj); return obj; } @@ -489,3 +501,27 @@ if (item.maximum && item.maximum != undefined && item.maximum != null && item.ma return simpleComponentValidationItem; } + +export function removeJsonPathIndices(path) { + // Matches a dot followed by one or more digits + // The '\b' ensures we only match whole numbers, not numbers embedded in words + return path.replace(/\.\d+\b/g, ''); +} + +export function getParentPath(path) { + if (typeof path !== 'string' || !path.includes('.')) { + return ''; // Return empty if there's no dot to remove + } + + // Find the position of the very last dot + const lastDotIndex = path.lastIndexOf('.'); + + // Slice the string from the start up to that last dot + return path.substring(0, lastDotIndex); +} + +export function getPartyIdFromParent(path) { + + // get party id from parent path, which is the last number in the path + +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/models.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/models.ts index 82dffdd3da..16b5910158 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/models.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/models.ts @@ -34,3 +34,46 @@ export interface ComplexComponentData { required: boolean; errorMessage: string } + +/* PARTIES */ +export interface SystemMappingEditModel { + partyMappings: PartyMappingModel[]; + keyMappings: KeyMappingModel[]; +} + +export interface PartyMappingModel { + path: string; + parentPath: string; + linkElementId: number; + selector: boolean; + complexity:boolean; + list:PartyMappingResultElementModel[]; +} + +export interface KeyMappingModel { + path: string; + systemKeyName: string; +} + +export interface PartyMappingResultElementModel { + value: string; + partyId: number; +} + +export class MappingComponentConfig { + isMappedToParty: boolean; + isSelector: boolean; + partyMappingObject: any; + isMappedToKey: boolean; + pathWithoutIndices: string; + selectorValue: any + + constructor(){ + this.isMappedToParty = false; + this.isSelector = false; + this.partyMappingObject = null; + this.isMappedToKey = false; + this.pathWithoutIndices = ''; + this.selectorValue = null; + } +} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/simpleComponentSuite.ts similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.ts rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/simpleComponentSuite.ts diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/Blocked.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/Blocked.svelte index 5710bd2668..28370379ee 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/Blocked.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/Blocked.svelte @@ -18,10 +18,8 @@ else if(isPartyMapped){ message = 'This field is mapped to a party and cannot be edited here.'; } - - -blocked + + import { MappingComponentConfig } from "$lib/components/utils/metadata/models"; + import { MultiSelect } from "@bexis2/bexis2-core-ui"; + import { createEventDispatcher, onMount } from 'svelte'; + import suite from '$lib/components/utils/metadata/simpleComponentSuite'; + + import { getParentPath, getPartyIdByPath, removeJsonPathIndices, updateMetadataStore, ValidationStoreSetSimpleTypeValid } from "$lib/components/utils/metadata/metadataComponentUtils"; + + import { getMappingComponentConfig } from "$lib/components/utils/metadata/mappingHelper"; + import { GetPartyValue } from "../services/apiCalls"; + import { systemMappingsStore } from "$lib/components/utils/metadata/stores"; + +const dispatch = createEventDispatcher(); + + export let path: string; + export let value:any; + export let partyId:number; + export let label: string; + export let required: boolean = false; + export let isMulti: boolean = false; + export let mappingComponentConfig: MappingComponentConfig; + export let description: string = ''; + + + + + let partyMappingObject: any = null; + let pathWithoutIndices: string = ''; + let selectorValue: any = null; + let list:any + + // load form result object + let res = suite.get(); + + //$: updateMetadataStore(path, value, isMulti); + + onMount(() => { + + if(!mappingComponentConfig){ + mappingComponentConfig=getMappingComponentConfig(path, value); + } + + + + partyMappingObject = mappingComponentConfig?.partyMappingObject; + pathWithoutIndices = removeJsonPathIndices(path); + list = mappingComponentConfig?.partyMappingObject?.list ?? []; + + if(value) + { + if(mappingComponentConfig.partyMappingObject.complexity){ + // get party id from parent + const parentPath = getParentPath(path); + partyId = getPartyIdByPath(parentPath); + } + else { + // get party id from this + partyId = getPartyIdByPath(path); + } + selectorValue = list.find((item: any) => item.partyId == partyId); + } + + + // initial check + setTimeout(async () => { + if(value == undefined || value == null || value == '') { + //res = suite(value, ''); + } + else { + res = suite(value, path); + } + }, 10); + }) + + + //handle mapping change of party mapping with selector + // we need to update the value with the new selected party and also trigger the validation for this field because maybe there are some validation rules on the party id + async function onUpdateParty(e: any){ + + // console.log("xyz Update Party",value, e.detail); + const partyid = e.detail.partyId; + const newValue = e.detail.value; + + // selectorValue.value = newValue; + // selectorValue.partyId = partyid; + // add some delay so the entityTemplate is updated + // otherwise the values are old + setTimeout(async () => { + // update selected value + // if mapping is simple, set party id + if(!partyMappingObject.complexity){ + //value['@partyid'] = e.detail.selectedItem.partyId; + // console.log("🚀 ~ onUpdateParty ~ simple mapping, add party id to value:", e.detail) + updateMetadataStore(path, newValue, isMulti, undefined, partyid); + + } + else if(partyMappingObject.complexity){ + + // update new value + updateMetadataStore(path, newValue, isMulti, undefined, undefined); + + const parentPath = getParentPath(path); + const parentPathWithoutIndices = removeJsonPathIndices(parentPath); + + // if mapping is complex + // get all partymappings where parent path is the same as the changed one + $systemMappingsStore.partyMappings.filter((mapping: any) => mapping.parentPath == parentPathWithoutIndices && mapping.path !== pathWithoutIndices).forEach(async (mapping: any) => { + // updateMetadataStore(mapping.path, value, isMulti, undefined, e.detail.partyId); + const childvalue = await GetPartyValue(partyid, mapping.linkElementId); + + + const childPathWithIndex = parentPath+"."+mapping.path.split('.').slice(-1)[0]; + + // update child value with new party value + updateMetadataStore(childPathWithIndex, childvalue, isMulti, undefined, undefined); + + // update parent with pary id if not already set + updateMetadataStore(parentPath, null, false, undefined, partyid); + + // update because of validation + updateValue(childvalue, childPathWithIndex) + + + + console.log("🚀 ~ onUpdateParty ~ dispatch reload for path:", selectorValue) + } ) + } + + // trigger reload parent component to update all child components with new values + dispatch("reload"); + + }, 10) + } + + +function updateValue(value: any, _path:string){ + + + console.log("🚀 ~ updateValue ~ value:", value) + + // check changed field + res = suite(value, _path); + //console.log("🚀 ~ onChangeHandler ~ res:", res) + let errorMessage = ''; + if(res.hasErrors(_path)){ + errorMessage = res.getErrors(_path).join('. '); + //console.log("🚀 ~ onChangeHandler ~ errorMessage:", errorMessage) + } + // update validationstore + ValidationStoreSetSimpleTypeValid(_path, res.isValid(_path), errorMessage); + + } + + + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts deleted file mode 100644 index 48953670ff..0000000000 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/helper.ts +++ /dev/null @@ -1,27 +0,0 @@ - -export function removeJsonPathIndices(path) { - // Matches a dot followed by one or more digits - // The '\b' ensures we only match whole numbers, not numbers embedded in words - return path.replace(/\.\d+\b/g, ''); -} - -export function getParentPath(path) { - if (typeof path !== 'string' || !path.includes('.')) { - return ''; // Return empty if there's no dot to remove - } - - // Find the position of the very last dot - const lastDotIndex = path.lastIndexOf('.'); - - // Slice the string from the start up to that last dot - return path.substring(0, lastDotIndex); -} - -export function getPartyIdFromParent(path) { - - // get party id from parent path, which is the last number in the path - - - -} - diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte index cc20a6e2a2..7566e70f63 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte @@ -13,18 +13,17 @@ } from '@bexis2/bexis2-core-ui'; import { SlideToggle } from '@skeletonlabs/skeleton'; import { onMount } from 'svelte'; - import { ValidationStoreAddSimpleComponent, ValidationStoreSetSimpleTypeValid, updateMetadataStore, createSimpleComponentValidationItem, getConfigStore, getSystemMappingsStore } from '$lib/components/utils/metadata/metadataComponentUtils'; + import { ValidationStoreAddSimpleComponent, ValidationStoreSetSimpleTypeValid, updateMetadataStore, createSimpleComponentValidationItem, getConfigStore} from '$lib/components/utils/metadata/metadataComponentUtils'; import { customComponentsCatalog } from '$lib/components/customComponents/componentCatalog'; - import suite from './simpleComponent'; - import type { SimpleComponentData } from '$lib/components/utils/metadata/models'; + import suite from '$lib/components/utils/metadata/simpleComponentSuite'; + import type { MappingComponentConfig, SimpleComponentData } from '$lib/components/utils/metadata/models'; import SveltyPicker from 'svelty-picker'; import {convertDisplayName} from '../metadataShared'; import type { JsonListItem } from '../components/types'; import Blocked from './Blocked.svelte'; - import { getParentPath, removeJsonPathIndices } from './helper'; - import { systemMappingsStore } from '$lib/components/utils/metadata/stores'; - import { GetPartyValue } from '../services/apiCalls'; import { createEventDispatcher } from 'svelte'; + import PartySelector from './PartySelector.svelte'; + import { getMappingComponentConfig } from '$lib/components/utils/metadata/mappingHelper'; //import { en, de } from 'svelty-picker/dist/i18n'; @@ -55,16 +54,8 @@ // update metadata store on value change $: updateMetadataStore(path, value, isMulti); - // System mapping -let isMappedToParty: boolean = false; -let isSelector: boolean = false; -let partyMappingObject: any = null; -let isMappedToKey: boolean = false; -let pathWithoutIndices: string = ''; -let selectorValue: any = null; - -const dispatch = createEventDispatcher(); +let mappingComponentConfig: MappingComponentConfig; onMount(async () => { @@ -120,37 +111,8 @@ const dispatch = createEventDispatcher(); } } - // ### SYSTEM MAPPING ### - const systemMappings = getSystemMappingsStore(); - - if(systemMappings){ - - // remove indices from path to check if the field is mapped to party or key, because in system mapping there are no indices but in the path there are because of arrays - pathWithoutIndices = removeJsonPathIndices(path); - console.log("🚀 ~ pathWithoutIndices:", pathWithoutIndices) - console.log("🚀 ~ systemMappings:", systemMappings) - - if(systemMappings.partyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ - - isMappedToParty = true; - partyMappingObject = systemMappings.partyMappings.find((mapping: any) => mapping.path == pathWithoutIndices); - isSelector = partyMappingObject.selector; - - if(isSelector) - { - selectorValue = { - "partyId": 0, - "value": value - } - } - - - } - - if(systemMappings.keyMappings.some((mapping: any) => mapping.path == pathWithoutIndices)){ - isMappedToKey = true; - } - } + mappingComponentConfig = getMappingComponentConfig(path, value); + //console.log("🚀 ~ mappingComponentConfig:", mappingComponentConfig) // initial check setTimeout(async () => { @@ -174,63 +136,10 @@ const dispatch = createEventDispatcher(); }, 10); } - //handle mapping change of party mapping with selector - // we need to update the value with the new selected party and also trigger the validation for this field because maybe there are some validation rules on the party id - async function onUpdateParty(e: any){ - - console.log("xyz Update Party",value, e.detail); - const partyid = e.detail.partyId; - const newValue = e.detail.value; - // add some delay so the entityTemplate is updated - // otherwise the values are old - setTimeout(async () => { - // update selected value - updateValue(newValue, path); - console.log("🚀 ~ onUpdateParty ~ value after updateValue:", newValue) - - // if mapping is simple, set party id - if(!partyMappingObject.complexity){ - //value['@partyid'] = e.detail.selectedItem.partyId; - console.log("🚀 ~ onUpdateParty ~ simple mapping, add party id to value:", e.detail) - updateMetadataStore(path, newValue, isMulti, undefined, e.detail.partyId); - - } - else if(partyMappingObject.complexity){ - - console.log("🚀 ~ onUpdateParty ~ complex mapping, add party id to value:", e.detail) - - updateMetadataStore(path, newValue, isMulti, undefined, undefined); - console.log("🚀 ~ onUpdateParty ~ value:", newValue) - console.log("🚀 ~ onUpdateParty ~ path:", path) - - console.log("🚀 ~ onUpdateParty ~ complex mapping, need to update all values with same parent path:", e.detail,partyMappingObject) - const parentPath = getParentPath(path); - const parentPathWithoutIndices = removeJsonPathIndices(parentPath); - console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) - // if mapping is complex - // get all partymappings where parent path is the same as the changed one - $systemMappingsStore.partyMappings.filter((mapping: any) => mapping.parentPath == parentPathWithoutIndices && mapping.path !== pathWithoutIndices).forEach(async (mapping: any) => { - // updateMetadataStore(mapping.path, value, isMulti, undefined, e.detail.partyId); - const childvalue = await GetPartyValue(partyid, mapping.linkElementId); - console.log("🚀 ~ onUpdateParty ~ childvalue:", childvalue) - - const childPathWithIndex = parentPath+"."+mapping.path.split('.').slice(-1)[0]; - - console.log("🚀 ~ onUpdateParty ~ updateMetadataStore for path:", childPathWithIndex, childvalue, isMulti, undefined, undefined) - updateMetadataStore(childPathWithIndex, childvalue, isMulti, undefined, undefined); - updateValue(childvalue, childPathWithIndex) - - // trigger reload parent component to update all child components with new values - dispatch("reload"); - } ) - } - }, 10) - } function updateValue(value: any, _path:string){ - //selectorValue.value = value; // check changed field res = suite(value, _path); @@ -255,26 +164,20 @@ const dispatch = createEventDispatcher();
- {#if (isMappedToParty && !isSelector) || isMappedToKey} - - {:else if isMappedToParty && isSelector} - + {#if (mappingComponentConfig && ((mappingComponentConfig.isMappedToParty && !mappingComponentConfig.isSelector) || mappingComponentConfig.isMappedToKey))} + + {:else if mappingComponentConfig && mappingComponentConfig.isMappedToParty && mappingComponentConfig.isSelector} + + {:else if path && simpleComponent.properties} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/types.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/types.ts deleted file mode 100644 index 6f3d45cd13..0000000000 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/types.ts +++ /dev/null @@ -1,23 +0,0 @@ -export interface SystemMappingEditModel { - partyMappings: PartyMappingModel[]; - keyMappings: KeyMappingModel[]; -} - -export interface PartyMappingModel { - path: string; - parentPath: string; - linkElementId: number; - selector: boolean; - complexity:boolean; - list:PartyMappingResultElementModel[]; -} - -export interface KeyMappingModel { - path: string; - systemKeyName: string; -} - -export interface PartyMappingResultElementModel { - value: string; - partyId: number; -} \ No newline at end of file From 717b330e1238dddebaa50f7f55e4edcbdcef01d1 Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 27 May 2026 07:57:05 +0200 Subject: [PATCH 031/490] #2374 add download buttons for json and xml on view --- .../OutputMetadataManager.cs | 51 ++++++++++++++++ .../BExIS.Web.Shell.Svelte/package-lock.json | 8 +-- Console/BExIS.Web.Shell.Svelte/package.json | 2 +- .../package-lock.json | 14 ++--- .../BExIS.Modules.Dcm.UI.Svelte/package.json | 2 +- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 6 +- .../src/routes/m/+page.svelte | 1 + .../src/routes/m/edit/+page.svelte | 2 +- .../routes/m/edit/MetadataFunctions.svelte | 4 +- .../src/routes/m/services/apiCalls.ts | 34 +++++++++++ .../src/routes/m/view/+page.svelte | 58 +++++++++++++++++-- .../Controllers/MController.cs | 56 +++++++++++++++++- .../BExIS.Modules.Dcm.UI/Views/M/View.cshtml | 4 +- .../package-lock.json | 8 +-- .../BExIS.Modules.Ddm.UI.Svelte/package.json | 2 +- .../package-lock.json | 8 +-- .../BExIS.Modules.Dim.UI.Svelte/package.json | 2 +- .../Controllers/API/MetadataOutController.cs | 23 +------- .../package-lock.json | 2 +- .../BExIS.Modules.Pum.UI.Svelte/package.json | 2 +- 20 files changed, 229 insertions(+), 60 deletions(-) diff --git a/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs b/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs index 2b025fd2a8..352ffd68d6 100644 --- a/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs +++ b/Components/IO/BExIS.Io.Transform.Output/OutputMetadataManager.cs @@ -4,6 +4,7 @@ using BExIS.Dlm.Services.MetadataStructure; using BExIS.Xml.Helpers; using BExIS.Xml.Helpers.Mapping; +using Newtonsoft.Json; using System; using System.Collections.Generic; using System.IO; @@ -140,6 +141,56 @@ public static StringBuilder flatten(StringBuilder sb, XElement element, string c return sb; } + /// + /// returns metadata as json string. simplifiedJson: 0,1,2 (0: all metadata, 1: metadata with value and empty, 2: only metadata with value and reference) + /// + /// + /// 0,1,2 + /// + public static string GetMetadataAsJson(XmlDocument metadata, int simplifiedJson) + { + using (DatasetManager datasetManager = new DatasetManager()) + { + string json = ""; + + switch (simplifiedJson) + { + case 0: + { + json = JsonConvert.SerializeObject(metadata.DocumentElement); + break; + } + case 1: + { + XmlMetadataConverter xmlMetadataConverter = new XmlMetadataConverter(); + json = xmlMetadataConverter.ConvertTo(metadata, true).ToString(); + + break; + } + case 2: + { + XmlMetadataConverter xmlMetadataConverter = new XmlMetadataConverter(); + json = xmlMetadataConverter.ConvertTo(metadata).ToString(); + + break; + } + } + + + return json; + } + } + public static string GetMetadataAsJson(long id , int versionNr, int simplifiedJson) + { + using (DatasetManager datasetManager = new DatasetManager()) + { + var datasetVersion = datasetManager.GetDatasetVersion(id, versionNr); + + return GetMetadataAsJson(datasetVersion.Metadata, simplifiedJson); + } + } + + public static string GetSchemaDirectoryPath(long datasetId) { using (DatasetManager datasetManager = new DatasetManager()) diff --git a/Console/BExIS.Web.Shell.Svelte/package-lock.json b/Console/BExIS.Web.Shell.Svelte/package-lock.json index ca61d134dc..3d9398dc57 100644 --- a/Console/BExIS.Web.Shell.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell.Svelte/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "hasInstallScript": true, "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.74", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.74.tgz", - "integrity": "sha512-RGtbDZRDIICzcm7b2b7p8GFrbYlg3CBDDLqNytGO7schfa1Kb6N1MgSmE6Mwqb3hkgTYSVfD9vCwIlp9s1MvWQ==", + "version": "0.4.76", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", + "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell.Svelte/package.json b/Console/BExIS.Web.Shell.Svelte/package.json index 012ccc8f7c..65c46c1d83 100644 --- a/Console/BExIS.Web.Shell.Svelte/package.json +++ b/Console/BExIS.Web.Shell.Svelte/package.json @@ -52,7 +52,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json index abec726fd5..6be2412b88 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", @@ -89,9 +89,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.75", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.75.tgz", - "integrity": "sha512-HhGKtl4YDNaLCth7wf9npX+yfQ3mANmvgCS7T0ypRD5bktvtPSrkOZfu3+q/M0oe7Muyd0+8xEZIFWvMEVxn2A==", + "version": "0.4.76", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", + "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", @@ -5829,9 +5829,9 @@ } }, "@bexis2/bexis2-core-ui": { - "version": "0.4.75", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.75.tgz", - "integrity": "sha512-HhGKtl4YDNaLCth7wf9npX+yfQ3mANmvgCS7T0ypRD5bktvtPSrkOZfu3+q/M0oe7Muyd0+8xEZIFWvMEVxn2A==", + "version": "0.4.76", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", + "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", "requires": { "@codemirror/lang-html": "^6.4.9", "@codemirror/lang-javascript": "^6.2.2", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json index 158a43effb..df7dbb2a07 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json @@ -51,7 +51,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 04fe409557..12b7324649 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -9,9 +9,9 @@
-
-
-
+
+
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/+page.svelte index b940a4bb64..5e159220e0 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/+page.svelte @@ -8,6 +8,7 @@ //export let schemaId: number = 3; export let datasetId: number = 3; + $:datasetId; let mode: 'edit' | 'view' = 'edit'; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte index 88025f1a51..d6f6d2fcca 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte @@ -11,7 +11,7 @@ // import { Page } from '@bexis2/bexis2-core-ui'; import { schemaToJson, setConfigStore, setMetadataStore, setSystemMappingsStore } from '$lib/components/utils/metadata/metadataComponentUtils'; - import type { SystemMappingEditModel } from './types'; + import type { SystemMappingEditModel } from '$lib/components/utils/metadata/models'; // import configJson from './customComponents/config.json'; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte index 3e89a474e5..adba27dbd9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte @@ -1,6 +1,5 @@ @@ -60,14 +96,24 @@ {:then} -
+
-
-
- +
+
+ + +
+
+
+
+ +
-
{/await} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs index 3a2a71902d..5829b42cfc 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs @@ -1,20 +1,27 @@ using BExIS.App.Bootstrap.Attributes; +using BExIS.Dcm.UploadWizard; using BExIS.Dim.Entities.Mappings; using BExIS.Dim.Helpers.Mappings; using BExIS.Dim.Services.Mappings; using BExIS.Dlm.Entities.Data; using BExIS.Dlm.Services.Data; +using BExIS.IO.Transform.Output; +using BExIS.Modules.Dcm.UI.Helpers; using BExIS.Security.Entities.Authorization; using BExIS.UI.Helpers; using BExIS.Utils.Route; +using BExIS.Xml.Helpers; using DocumentFormat.OpenXml.Presentation; using System; using System.Collections.Generic; +using System.IO; using System.Linq; +using System.Text; using System.Web; using System.Web.Http.Results; using System.Web.Mvc; using System.Web.UI.WebControls; +using Vaiona.Utils.Cfg; using Vaiona.Web.Mvc.Modularity; namespace BExIS.Modules.Dcm.UI.Controllers @@ -53,6 +60,7 @@ public ActionResult Edit(long id, int version = 0) return View(); } + #region mapping /// /// load System mappings based on metadatastructure id @@ -166,7 +174,6 @@ private string cleanPath(string path) return n; } - public JsonResult GetPartyValue(long partyId, long linkId) { // not implemented @@ -187,6 +194,53 @@ public JsonResult GetPartyValue(long partyId, long linkId) return Json("", JsonRequestBehavior.AllowGet); } + #endregion + + #region download + + //html + + public ActionResult DownloadAsHtml(long id, int version ) + { + + + return Content("not implemented."); + } + + //flatten + + + //json + public ActionResult DownloadAsJson(long id, int version) + { + try + { + string metadata = OutputMetadataManager.GetMetadataAsJson(id, version, 2); + + byte[] bytes = Encoding.ASCII.GetBytes(metadata); + + return File(bytes, "application/json"); + + } + catch (Exception ex) + { + return Content(ex.Message); + } + } + + + //xml + public ActionResult DownloadAsXml(long id, int version) + { + + + return Content("no metadata xml file is loaded."); + } + + + #endregion + + [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Read)] public ActionResult View(long id, int version = 0) { diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/M/View.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/M/View.cshtml index beb2242886..39c20a376c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/M/View.cshtml +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/M/View.cshtml @@ -3,15 +3,17 @@ Layout = "~/Themes/Default/Layouts/_svelteLayout.cshtml"; long id = 0; + int version = 0; string saveWithErrors = ""; if (ViewData["id"] != null) { id = Convert.ToInt64(ViewData["id"]); } + if (ViewData["version"] != null) { version = Convert.ToInt32(ViewData["version"]); } } -
+
@Html.Partial("_sveltePage")
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json index d7d3ed18b6..762834e088 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", @@ -77,9 +77,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.75", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.75.tgz", - "integrity": "sha512-HhGKtl4YDNaLCth7wf9npX+yfQ3mANmvgCS7T0ypRD5bktvtPSrkOZfu3+q/M0oe7Muyd0+8xEZIFWvMEVxn2A==", + "version": "0.4.76", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", + "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json index e01933a47e..6d4bbd11b4 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@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/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json index 22ed71d98b..ff80eae562 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@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.75", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.75.tgz", - "integrity": "sha512-HhGKtl4YDNaLCth7wf9npX+yfQ3mANmvgCS7T0ypRD5bktvtPSrkOZfu3+q/M0oe7Muyd0+8xEZIFWvMEVxn2A==", + "version": "0.4.76", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", + "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json index 596481f600..c3e1efae25 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@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/DIM/BExIS.Modules.Dim.UI/Controllers/API/MetadataOutController.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/API/MetadataOutController.cs index 4f8f061c7d..1f405f1602 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/API/MetadataOutController.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/API/MetadataOutController.cs @@ -462,28 +462,7 @@ private HttpResponseMessage GetMetadata(long id, long versionId, Format format, { string json = ""; - switch (simplifiedJson) - { - case 0: - { - json = JsonConvert.SerializeObject(xmlDoc.DocumentElement); - break; - } - case 1: - { - XmlMetadataConverter xmlMetadataConverter = new XmlMetadataConverter(); - json = xmlMetadataConverter.ConvertTo(xmlDoc, true).ToString(); - - break; - } - case 2: - { - XmlMetadataConverter xmlMetadataConverter = new XmlMetadataConverter(); - json = xmlMetadataConverter.ConvertTo(xmlDoc).ToString(); - - break; - } - } + json = OutputMetadataManager.GetMetadataAsJson(xmlDoc, simplifiedJson); HttpResponseMessage response = new HttpResponseMessage { Content = new StringContent(json, Encoding.UTF8, "application/json") }; diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json index 8f7ee1bb57..7d968150b3 100644 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@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/PUM/BExIS.Modules.Pum.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package.json index 8ab2ea13a3..87c49108a5 100644 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package.json @@ -52,7 +52,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.75", + "@bexis2/bexis2-core-ui": "0.4.76", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", From 0a9382594a935def24b674c5a61cdcc20f577cfe Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 27 May 2026 08:26:23 +0200 Subject: [PATCH 032/490] #2481 add download flatten and und external format for xml --- .../src/routes/m/services/apiCalls.ts | 21 ++++++++++- .../src/routes/m/view/+page.svelte | 35 ++++++++++++++++--- 2 files changed, 50 insertions(+), 6 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts index 9b8e2c0b63..209e036b39 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts @@ -103,7 +103,7 @@ export const GetMetadataAsXml = async (id: number, version) => { const header = { 'Accept': 'application/xml' } const config = { responseType: 'blob' } - const response = await Api.get('/api/metadata/' + id + "?version=" + version, '', header, config); + const response = await Api.get('/api/metadata/' + id + '/version_number/' + version + '?format=1', '', header, config); // console.log(" response.data.MetadataStructureId:", response); return response.data; @@ -113,4 +113,23 @@ export const GetMetadataAsXml = async (id: number, version) => { } }; +export const GetMetadataAsFlattened = async (id: number, version) => { + try { + + const header = { 'Accept': 'text/plain' } + const config = { responseType: 'blob' } + + //http://localhost:44345/api/metadata/1/version_number/1/?format=3 + const response = await Api.get('/api/metadata/' + id + '/version_number/' + version + '?format=3', '', header, config); + // console.log(" response.data.MetadataStructureId:", response); + + return response.data; + } catch (error) { + console.error(error); + alert("An error occurred while downloading the metadata. Please try again later."); + throw error; + } +}; + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte index 6b6b9e231c..c1c8bb998b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte @@ -58,8 +58,27 @@ async function DownloadMetadata(datasetId: number, versionNumber: number, format: string) { - const type = format === "json" ? 'application/json': 'application/xml' - const filename = format === "json" ? 'metadata.json' : 'metadata.xml'; + let type = ''; + let filename = ''; + + switch(format) { + case "json": + type = 'application/json'; + filename = 'metadata.json'; + break; + case "xml": + type = 'application/xml'; + filename = 'metadata.xml'; + break; + case "flatten": + type = 'text/plain'; + filename = 'metadata_flattened.txt'; + break; + default: + + return; + } + let data = null; if(format === "json") { //helpStore.showNotification("Your download will start shortly. If it doesn't, please check your popup blocker settings.", notificationType.info, 5000); @@ -68,6 +87,9 @@ else if(format === "xml") { //helpStore.showNotification("Your download will start shortly. If it doesn't, please check your popup blocker settings.", notificationType.info, 5000); data = await apiCalls.GetMetadataAsXml(datasetId, versionNumber); + } else if(format === "flatten") { + //helpStore.showNotification("Your download will start shortly. If it doesn't, please check your popup blocker settings.", notificationType.info, 5000); + data = await apiCalls.GetMetadataAsFlattened(datasetId, versionNumber); } if(data) { @@ -103,9 +125,12 @@ - + +
From f376492e302ae6fb8c1fa60616c2f332e1358a64 Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 27 May 2026 08:37:57 +0200 Subject: [PATCH 033/490] #2482 add download html --- .../src/routes/m/view/+page.svelte | 45 +++++++++++++++++-- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte index c1c8bb998b..ca06cd08df 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte @@ -108,11 +108,45 @@ } } + function downloadSectionWithCSS(elementId, filename = 'styled-section.html') { + const element = document.getElementById(elementId); + if (!element) return console.error('Element not found'); + + // 1. Gather all style and link tags from the current page + let cssContent = ''; + const styles = document.querySelectorAll('style, link[rel="stylesheet"]'); + styles.forEach(styleTag => { + cssContent += styleTag.outerHTML + '\n'; + }); + + // 2. Build a complete, self-contained HTML document string + const fullHTML = ` + + + + + Downloaded Section + ${cssContent} + + + ${element.outerHTML} + +`; + + // 3. Trigger the client-side download + const blob = new Blob([fullHTML], { type: 'text/html' }); + const link = document.createElement('a'); + link.href = URL.createObjectURL(blob); + link.download = filename; + link.click(); + URL.revokeObjectURL(link.href); +} + - + {#await load()} {:then} @@ -129,11 +163,15 @@
XML
+ +
-
+
@@ -170,3 +208,4 @@ + From 69bc501f07cbaeea1fc24a01adac7c80020cfa0f Mon Sep 17 00:00:00 2001 From: david schoene Date: Wed, 27 May 2026 11:59:43 +0200 Subject: [PATCH 034/490] #2385 first implemention of import --- .../BExIS.Web.Shell.Svelte/package-lock.json | 8 +- Console/BExIS.Web.Shell.Svelte/package.json | 2 +- .../package-lock.json | 14 +- .../BExIS.Modules.Dcm.UI.Svelte/package.json | 2 +- .../src/routes/m/edit/+page.svelte | 28 ++-- .../routes/m/edit/MetadataFunctions.svelte | 111 +++++++++----- .../src/routes/m/services/apiCalls.ts | 2 +- .../src/routes/m/view/+page.svelte | 1 - .../Controllers/MController.cs | 144 ++++++++++++++++++ .../package-lock.json | 8 +- .../BExIS.Modules.Ddm.UI.Svelte/package.json | 2 +- .../package-lock.json | 8 +- .../BExIS.Modules.Dim.UI.Svelte/package.json | 2 +- .../package-lock.json | 6 +- .../package-lock.json | 4 +- 15 files changed, 265 insertions(+), 77 deletions(-) diff --git a/Console/BExIS.Web.Shell.Svelte/package-lock.json b/Console/BExIS.Web.Shell.Svelte/package-lock.json index 3d9398dc57..588954653d 100644 --- a/Console/BExIS.Web.Shell.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell.Svelte/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "hasInstallScript": true, "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.76", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", - "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", + "version": "0.4.77", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.77.tgz", + "integrity": "sha512-N2gR5vK+vETNFrxmBjADRpNUmV1E1vgPZ/F8RIBqNhlYmfc61HG0eyK++1ozqdbWmvUqxf522u4m6tu9jhosbA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell.Svelte/package.json b/Console/BExIS.Web.Shell.Svelte/package.json index 65c46c1d83..5823ee53f1 100644 --- a/Console/BExIS.Web.Shell.Svelte/package.json +++ b/Console/BExIS.Web.Shell.Svelte/package.json @@ -52,7 +52,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json index 6be2412b88..b29c8bad12 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", @@ -89,9 +89,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.76", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", - "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", + "version": "0.4.78", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.78.tgz", + "integrity": "sha512-2+6Qe20Kml7VWaFzib7/Lhh1viJp/oRknNGCGgLwZ+VwV8gJ0aJBbQ4iLkR32A/mMSYDytEsdbhKDCS6UHxkiQ==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", @@ -5829,9 +5829,9 @@ } }, "@bexis2/bexis2-core-ui": { - "version": "0.4.76", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", - "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", + "version": "0.4.78", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.78.tgz", + "integrity": "sha512-2+6Qe20Kml7VWaFzib7/Lhh1viJp/oRknNGCGgLwZ+VwV8gJ0aJBbQ4iLkR32A/mMSYDytEsdbhKDCS6UHxkiQ==", "requires": { "@codemirror/lang-html": "^6.4.9", "@codemirror/lang-javascript": "^6.2.2", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json index df7dbb2a07..3545b40d9c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json @@ -51,7 +51,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte index d6f6d2fcca..c474e3e8b2 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte @@ -22,6 +22,7 @@ let s: any; let m: any = null; let schema: any = s; + let reload = false; $: schema = s; @@ -56,6 +57,7 @@ } + @@ -64,23 +66,25 @@ {#await load()} {:then} + {#key reload} + +
+ -
- +
+
+ +
+
-
-
-
-
-
- + {/key} {/await} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte index adba27dbd9..850deaae8f 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte @@ -4,14 +4,16 @@ import { faCheck, faSave } from '@fortawesome/free-solid-svg-icons'; import { onMount } from 'svelte'; import * as apiCalls from '../services/apiCalls'; - import { activateShow, getValidationStore, toggleShow } from '$lib/components/utils/metadata/metadataComponentUtils'; + import { activateShow, getValidationStore, setMetadataStore, toggleShow } from '$lib/components/utils/metadata/metadataComponentUtils'; import type { validationStoretype } from '$lib/components/utils/metadata/models'; import {metadataStore, validationStore} from '$lib/components/utils/metadata/stores'; - import { notificationStore, notificationType, TextInput } from '@bexis2/bexis2-core-ui'; + import { FileUploader, notificationStore, notificationType, TextInput, type fileUploaderType } from '@bexis2/bexis2-core-ui'; import {convertDisplayName} from '../metadataShared'; import { goTo } from '$services/BaseCaller'; - import { on } from 'events'; + import { createEventDispatcher } from 'svelte'; + + const dispatch = createEventDispatcher(); export let datasetId: number; @@ -20,6 +22,13 @@ let hasChanged: boolean = true; // need to implement change detection to enable/disable save button based on whether there are unsaved changes or not, for now it's always enabled let showErrorOverview: boolean = false; let comment: string = ''; + let fileUploadType:fileUploaderType = { + accept: [".json", ".xml"], + existingFiles: [], + descriptionType: 0, + multiple: false, + maxSize: 10, // 10MB + }; const unsubscribedMetadata = metadata; @@ -87,43 +96,75 @@ } + function successHandler(e){ + + console.log("🚀 ~ successHandler ~ e:", e) + + const status = e.detail.status; + if(status === 200){ + notificationStore.showNotification({ + notificationType: notificationType.success, + message: 'Metadata successfully imported.', + }); + + console.log("🚀 ~ successHandler ~ metadata:", metadata) + metadata = JSON.parse(String(e.detail.data)); + console.log("🚀 ~ successHandler ~ metadata:", metadata) + setMetadataStore(metadata); + dispatch('metadataUpdated'); + + } + } + + +
-
-
- +
+
+
+ -
- +
+ +
+
+ +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts index 209e036b39..d6777eb24c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/services/apiCalls.ts @@ -87,7 +87,7 @@ export const GetMetadataAsJson = async (id: number, version) => { const header = { 'Accept': 'application/json' } const config = { responseType: 'blob' } - const response = await Api.get('/api/metadata/' + id + "?version=" + version, '', header, config); + const response = await Api.get('/api/metadata/' + id + "?version=" + version + "&simplifiedJson=1", '', header, config); // console.log(" response.data.MetadataStructureId:", response); return response.data; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte index ca06cd08df..6ba83f11d9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/view/+page.svelte @@ -165,7 +165,6 @@ - diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs index 5829b42cfc..f842e7a214 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs @@ -4,6 +4,7 @@ using BExIS.Dim.Helpers.Mappings; using BExIS.Dim.Services.Mappings; using BExIS.Dlm.Entities.Data; +using BExIS.Dlm.Entities.MetadataStructure; using BExIS.Dlm.Services.Data; using BExIS.IO.Transform.Output; using BExIS.Modules.Dcm.UI.Helpers; @@ -11,16 +12,25 @@ using BExIS.UI.Helpers; using BExIS.Utils.Route; using BExIS.Xml.Helpers; +using BExIS.Xml.Helpers.Mapping; +using BEXIS.JSON.Helpers; using DocumentFormat.OpenXml.Presentation; +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; +using Newtonsoft.Json.Schema; using System; using System.Collections.Generic; +using System.Data; using System.IO; using System.Linq; +using System.Net; using System.Text; using System.Web; using System.Web.Http.Results; using System.Web.Mvc; using System.Web.UI.WebControls; +using System.Xml; +using Vaiona.Persistence.Api; using Vaiona.Utils.Cfg; using Vaiona.Web.Mvc.Modularity; @@ -196,6 +206,140 @@ public JsonResult GetPartyValue(long partyId, long linkId) #endregion + #region import + + [HttpPost] + public JsonResult Import(long id) + { + #region check incomming metadata + string errorMessage = ""; + + if (Request.Files.Count > 0) + { + using (var datasetManager = new DatasetManager()) + { + Dataset dataset = datasetManager.GetDataset(id); + long metadataStructureId = dataset.MetadataStructure.Id; + + Stream requestStream; + HttpFileCollectionBase files = Request.Files; + var file = files[0]; // one file only + requestStream = file.InputStream; + #endregion check incomming metadata + string contentType = file.ContentType; + XmlDocument completeMetadata = null; + JSchema schema; + XmlMetadataConverter converter = new XmlMetadataConverter(); + MetadataStructureConverter metadataStructureConverter = new MetadataStructureConverter(); + + + if (contentType.Contains("xml")) + { + #region application/xml + + XmlDocument metadataForImport = new XmlDocument(); + metadataForImport.Load(requestStream); + + // metadataStructure ID + + var metadataStructrueName = this.GetUnitOfWork().GetReadOnlyRepository().Get(metadataStructureId).Name; + + // loadMapping file + var path_mappingFile = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DIM"), XmlMetadataImportHelper.GetMappingFileName(metadataStructureId, TransmissionType.mappingFileImport, metadataStructrueName)); + + // XML mapper + mapping file + var xmlMapperManager = new XmlMapperManager(TransactionDirection.ExternToIntern); + xmlMapperManager.Load(path_mappingFile, "IDIV"); + + // generate intern metadata without internal attributes + var metadataResult = xmlMapperManager.Generate(metadataForImport, 1, true); + + // generate intern template metadata xml with needed attribtes + var xmlMetadatWriter = new XmlMetadataWriter(BExIS.Xml.Helpers.XmlNodeMode.xPath); + var metadataXml = xmlMetadatWriter.CreateMetadataXml(metadataStructureId, + XmlUtility.ToXDocument(metadataResult)); + + var metadataXmlTemplate = XmlMetadataWriter.ToXmlDocument(metadataXml); + + // set attributes FROM metadataXmlTemplate TO metadataResult + completeMetadata = XmlMetadataImportHelper.FillInXmlValues(metadataResult, + metadataXmlTemplate); + + #endregion application/xml + } + else + if (contentType.Contains("json")) + { + #region application/json + + using (var streamReader = new StreamReader(requestStream)) + using (var jsonReader = new JsonTextReader(streamReader)) + { + JsonSerializer serializer = new JsonSerializer(); + + try + { + JObject metadataJson = serializer.Deserialize(jsonReader); + + long mdid = 0; + if (metadataJson.ContainsKey("@id")) + { + if (Int64.TryParse(metadataJson.Property("@id").Value.ToString(), out mdid)) + { + schema = metadataStructureConverter.ConvertToJsonSchema(mdid); + + List notAllowedElements = new List(); + if (converter.HasValidStructure(metadataJson, mdid, out notAllowedElements)) + { + completeMetadata = converter.ConvertTo(metadataJson); + ; + } + else + { + HttpStatusCode statusCode = HttpStatusCode.ExpectationFailed; + errorMessage = "the json does not have the expected structure"; + } + } + else + { + HttpStatusCode statusCode = HttpStatusCode.ExpectationFailed; + errorMessage = "the json does not have the expected structure"; + } + + } + else + { + HttpStatusCode statusCode = HttpStatusCode.ExpectationFailed; + errorMessage = "the json does not contain any information about the metadata structure"; + } + } + catch (JsonReaderException) + { + Console.WriteLine("Invalid JSON."); + } + } + + #endregion application/json + } + + if (completeMetadata != null) + { + HttpStatusCode statusCode = HttpStatusCode.OK; + + string json = ""; + + json = OutputMetadataManager.GetMetadataAsJson(completeMetadata, 1); + return Json(json); + + } + + } + } + #endregion + + return Json(errorMessage); + } + #region download //html diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json index 762834e088..280b73602a 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", @@ -77,9 +77,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.76", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", - "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", + "version": "0.4.77", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.77.tgz", + "integrity": "sha512-N2gR5vK+vETNFrxmBjADRpNUmV1E1vgPZ/F8RIBqNhlYmfc61HG0eyK++1ozqdbWmvUqxf522u4m6tu9jhosbA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json index 6d4bbd11b4..c3be104fa6 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@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/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json index ff80eae562..b6eaaefe20 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@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.76", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", - "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", + "version": "0.4.77", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.77.tgz", + "integrity": "sha512-N2gR5vK+vETNFrxmBjADRpNUmV1E1vgPZ/F8RIBqNhlYmfc61HG0eyK++1ozqdbWmvUqxf522u4m6tu9jhosbA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json index c3e1efae25..d853103436 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.76", + "@bexis2/bexis2-core-ui": "0.4.78", "@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/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json index 7d968150b3..163b2fdba3 100644 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/package-lock.json @@ -78,9 +78,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.75", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.75.tgz", - "integrity": "sha512-HhGKtl4YDNaLCth7wf9npX+yfQ3mANmvgCS7T0ypRD5bktvtPSrkOZfu3+q/M0oe7Muyd0+8xEZIFWvMEVxn2A==", + "version": "0.4.76", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.76.tgz", + "integrity": "sha512-UclJ/3nJsVHXUtFHFDyqGj1Dixnc2LRiguj+lvWpOchnmcqk19NW2Amr21yCxGY5HM/Ngfhe2dvuHCUahvoaYA==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json index 9fdf858489..17433680c2 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI.Svelte/package-lock.json @@ -1,12 +1,12 @@ { "name": "@bexis2/bexis2-rpm-ui", - "version": "0.2.15", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@bexis2/bexis2-rpm-ui", - "version": "0.2.15", + "version": "0.3.0", "hasInstallScript": true, "license": "ISC", "dependencies": { From 0c2401d3ac26bd1e482b5d2629fc56e4a9ee84b3 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 28 May 2026 10:55:38 +0200 Subject: [PATCH 035/490] #2385 fix party type selection issue when get party id --- .../src/routes/m/edit/PartySelector.svelte | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte index ded5d90ece..b2bc000f78 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte @@ -4,7 +4,7 @@ import { createEventDispatcher, onMount } from 'svelte'; import suite from '$lib/components/utils/metadata/simpleComponentSuite'; - import { getParentPath, getPartyIdByPath, removeJsonPathIndices, updateMetadataStore, ValidationStoreSetSimpleTypeValid } from "$lib/components/utils/metadata/metadataComponentUtils"; + import { getByPath, getParentPath, getPartyIdByPath, removeJsonPathIndices, updateMetadataStore, ValidationStoreSetSimpleTypeValid } from "$lib/components/utils/metadata/metadataComponentUtils"; import { getMappingComponentConfig } from "$lib/components/utils/metadata/mappingHelper"; import { GetPartyValue } from "../services/apiCalls"; @@ -49,15 +49,19 @@ const dispatch = createEventDispatcher(); if(value) { if(mappingComponentConfig.partyMappingObject.complexity){ + // get party id from parent + console.log("🚀 ~ onMount ~ path:", path) const parentPath = getParentPath(path); partyId = getPartyIdByPath(parentPath); + } else { // get party id from this partyId = getPartyIdByPath(path); } selectorValue = list.find((item: any) => item.partyId == partyId); + } @@ -115,13 +119,12 @@ const dispatch = createEventDispatcher(); updateMetadataStore(childPathWithIndex, childvalue, isMulti, undefined, undefined); // update parent with pary id if not already set + console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) updateMetadataStore(parentPath, null, false, undefined, partyid); // update because of validation updateValue(childvalue, childPathWithIndex) - - console.log("🚀 ~ onUpdateParty ~ dispatch reload for path:", selectorValue) } ) } From 549057f0d86d7cedd66e261fc70a4010202c2442 Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 28 May 2026 11:26:26 +0200 Subject: [PATCH 036/490] #2385 fix issues in musltiselection --- Console/BExIS.Web.Shell.Svelte/package-lock.json | 8 ++++---- Console/BExIS.Web.Shell.Svelte/package.json | 2 +- .../BExIS.Modules.Dcm.UI.Svelte/package-lock.json | 14 +++++++------- .../DCM/BExIS.Modules.Dcm.UI.Svelte/package.json | 2 +- .../DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../utils/metadata/metadataComponentUtils.ts | 10 ++++++---- .../src/routes/m/edit/simpleComponent.svelte | 11 +++++++---- .../src/routes/m/services/apiCalls.ts | 2 +- .../BExIS.Modules.Ddm.UI.Svelte/package-lock.json | 8 ++++---- .../DDM/BExIS.Modules.Ddm.UI.Svelte/package.json | 2 +- .../BExIS.Modules.Dim.UI.Svelte/package-lock.json | 8 ++++---- .../DIM/BExIS.Modules.Dim.UI.Svelte/package.json | 2 +- 12 files changed, 38 insertions(+), 33 deletions(-) diff --git a/Console/BExIS.Web.Shell.Svelte/package-lock.json b/Console/BExIS.Web.Shell.Svelte/package-lock.json index 588954653d..3a31a2823b 100644 --- a/Console/BExIS.Web.Shell.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell.Svelte/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.1", "hasInstallScript": true, "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", @@ -76,9 +76,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.77", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.77.tgz", - "integrity": "sha512-N2gR5vK+vETNFrxmBjADRpNUmV1E1vgPZ/F8RIBqNhlYmfc61HG0eyK++1ozqdbWmvUqxf522u4m6tu9jhosbA==", + "version": "0.4.81", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.81.tgz", + "integrity": "sha512-agct1DRoTBvmeuXWGd9jmmSgoqrgxPDKYnQNs2dq9pnWUIEtrcLUg342/+KUiijKEmuImUkA8+C6CVSBsUJHrQ==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell.Svelte/package.json b/Console/BExIS.Web.Shell.Svelte/package.json index 5823ee53f1..6a574264ac 100644 --- a/Console/BExIS.Web.Shell.Svelte/package.json +++ b/Console/BExIS.Web.Shell.Svelte/package.json @@ -52,7 +52,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@sveltejs/adapter-static": "3.0.2", "buffer": "6.0.3", "gray-matter": "4.0.3", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json index b29c8bad12..f9b6e4f594 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", @@ -89,9 +89,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.78", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.78.tgz", - "integrity": "sha512-2+6Qe20Kml7VWaFzib7/Lhh1viJp/oRknNGCGgLwZ+VwV8gJ0aJBbQ4iLkR32A/mMSYDytEsdbhKDCS6UHxkiQ==", + "version": "0.4.81", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.81.tgz", + "integrity": "sha512-agct1DRoTBvmeuXWGd9jmmSgoqrgxPDKYnQNs2dq9pnWUIEtrcLUg342/+KUiijKEmuImUkA8+C6CVSBsUJHrQ==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", @@ -5829,9 +5829,9 @@ } }, "@bexis2/bexis2-core-ui": { - "version": "0.4.78", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.78.tgz", - "integrity": "sha512-2+6Qe20Kml7VWaFzib7/Lhh1viJp/oRknNGCGgLwZ+VwV8gJ0aJBbQ4iLkR32A/mMSYDytEsdbhKDCS6UHxkiQ==", + "version": "0.4.81", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.81.tgz", + "integrity": "sha512-agct1DRoTBvmeuXWGd9jmmSgoqrgxPDKYnQNs2dq9pnWUIEtrcLUg342/+KUiijKEmuImUkA8+C6CVSBsUJHrQ==", "requires": { "@codemirror/lang-html": "^6.4.9", "@codemirror/lang-javascript": "^6.2.2", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json index 3545b40d9c..b69c93339c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json @@ -51,7 +51,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 12b7324649..375bc01be1 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -9,7 +9,7 @@
-
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts index ee9ba53662..c95b85467c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts @@ -34,8 +34,10 @@ export function getRefByPath(path: string) { } export function getPartyIdByPath(path: string) { - path = path + '.@partyid'; - return getNodeByPath(path); + + const obj = getNodeByPath(path); + const partyId = obj ? obj['@partyid'] : null; + return partyId; } // Set value in an object based on a dot-separated path @@ -87,13 +89,13 @@ export function updateMetadataStore(path: string, value: any, isMulti?: boolean, else if(value === undefined || value === null) { const parent = getByPath(path); - // console.log("🚀 ~ updateMetadataStore ~ parent:", parent) parent["@partyid"] = partyid; + console.log("🚀 ~ updateMetadataStore ~ parent:", parent) } } } - //console.log('Updated metadata store:', obj); + console.log('Updated metadata store:', obj); return obj; } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte index 7566e70f63..25fb597195 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte @@ -21,7 +21,6 @@ import {convertDisplayName} from '../metadataShared'; import type { JsonListItem } from '../components/types'; import Blocked from './Blocked.svelte'; - import { createEventDispatcher } from 'svelte'; import PartySelector from './PartySelector.svelte'; import { getMappingComponentConfig } from '$lib/components/utils/metadata/mappingHelper'; @@ -131,16 +130,18 @@ let mappingComponentConfig: MappingComponentConfig; // add some delay so the entityTemplate is updated // otherwise the values are old setTimeout(async () => { + console.log("🚀 ~ onChangeHandler ~ value:", value, e) - updateValue(value, e.target.id); - }, 10); + updateValue(value, path); + + }, 10); } function updateValue(value: any, _path:string){ - + // check changed field res = suite(value, _path); //console.log("🚀 ~ onChangeHandler ~ res:", res) @@ -169,6 +170,8 @@ let mappingComponentConfig: MappingComponentConfig; {:else if mappingComponentConfig && mappingComponentConfig.isMappedToParty && mappingComponentConfig.isSelector} { const header = { 'Accept': 'application/json' } const config = { responseType: 'blob' } - const response = await Api.get('/api/metadata/' + id + "?version=" + version + "&simplifiedJson=1", '', header, config); + const response = await Api.get('/api/metadata/' + id + "?version=" + version + "&simplifiedJson=2", '', header, config); // console.log(" response.data.MetadataStructureId:", response); return response.data; diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json index 280b73602a..35bd24f50e 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", @@ -77,9 +77,9 @@ } }, "node_modules/@bexis2/bexis2-core-ui": { - "version": "0.4.77", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.77.tgz", - "integrity": "sha512-N2gR5vK+vETNFrxmBjADRpNUmV1E1vgPZ/F8RIBqNhlYmfc61HG0eyK++1ozqdbWmvUqxf522u4m6tu9jhosbA==", + "version": "0.4.80", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.80.tgz", + "integrity": "sha512-EdJe9Xty3zQMkZv7ppCfYGX82rmYTnM719CeLf9OVYP3cd9S+l89hkZ9JRmH1w5awsf/g5mhPyF/TtY0irbt7A==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json index c3be104fa6..9686b73409 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@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/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json index b6eaaefe20..6d797db031 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package-lock.json @@ -10,7 +10,7 @@ "hasInstallScript": true, "license": "ISC", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@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.77", - "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.77.tgz", - "integrity": "sha512-N2gR5vK+vETNFrxmBjADRpNUmV1E1vgPZ/F8RIBqNhlYmfc61HG0eyK++1ozqdbWmvUqxf522u4m6tu9jhosbA==", + "version": "0.4.80", + "resolved": "https://registry.npmjs.org/@bexis2/bexis2-core-ui/-/bexis2-core-ui-0.4.80.tgz", + "integrity": "sha512-EdJe9Xty3zQMkZv7ppCfYGX82rmYTnM719CeLf9OVYP3cd9S+l89hkZ9JRmH1w5awsf/g5mhPyF/TtY0irbt7A==", "license": "ISC", "dependencies": { "@codemirror/lang-html": "^6.4.9", diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json index d853103436..9c7ee294de 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI.Svelte/package.json @@ -50,7 +50,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.78", + "@bexis2/bexis2-core-ui": "0.4.81", "@floating-ui/dom": "1.6.8", "@fortawesome/free-solid-svg-icons": "6.6.0", "@sveltejs/adapter-static": "3.0.2", From 7249a1eb8143f1ab5da9a3d1a0d3e5a537355881 Mon Sep 17 00:00:00 2001 From: david schoene Date: Fri, 29 May 2026 11:36:09 +0200 Subject: [PATCH 037/490] #2385 fix validation issue, inconsistency by validation store and vest --- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../utils/metadata/metadataComponentUtils.ts | 3 +- .../utils/metadata/simpleComponentSuite.ts | 65 ++++++++++++------- .../src/routes/m/edit/+page.svelte | 13 ++-- .../routes/m/edit/MetadataFunctions.svelte | 26 +++++--- .../src/routes/m/edit/PartySelector.svelte | 9 +-- .../m/edit/complexComponentWrapper.svelte | 14 +++- .../src/routes/m/edit/simpleComponent.svelte | 45 +++++++------ 8 files changed, 109 insertions(+), 68 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 375bc01be1..125fc6c010 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -9,7 +9,7 @@
-
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts index c95b85467c..ff9899d79e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts @@ -95,7 +95,7 @@ export function updateMetadataStore(path: string, value: any, isMulti?: boolean, } } - console.log('Updated metadata store:', obj); + //console.log('Updated metadata store:', obj); return obj; } @@ -460,6 +460,7 @@ export function ValidationStoreSetSimpleTypeValid(path: string, isValid: boolean // Create a SimpleComponentData validation item // based on the provided parameters and simple component properties export function createSimpleComponentValidationItem(path: string, label: string, required: boolean, simpleComponent: any): SimpleComponentData { + let simpleComponentValidationItem: SimpleComponentData = { label: label, path: path, required: required, isValid: false, errorMessage: '' }; let item = simpleComponent.properties['#text']; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/simpleComponentSuite.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/simpleComponentSuite.ts index 17abd86f68..aaaeb91c8c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/simpleComponentSuite.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/simpleComponentSuite.ts @@ -1,70 +1,77 @@ -import { create, test, enforce, only, each } from 'vest'; +import { create, test, enforce, only, each, optional } from 'vest'; import type { validationStoretype } from '$lib/components/utils/metadata/models'; -import { getValidationStore } from '$lib/components/utils/metadata/metadataComponentUtils'; -import { hideStore } from '$lib/components/utils/metadata/stores'; +import { getValidationStore, getValueByPath } from '$lib/components/utils/metadata/metadataComponentUtils'; +import { hideStore, metadataStore } from '$lib/components/utils/metadata/stores'; import { get } from 'svelte/store'; // Get current values from the validation store let validationStoreValues: validationStoretype = getValidationStore(); + // if the elements hidden by hideStore are not validated, we need to get the current values of the hideStore to check in the validation if the field is hidden or not let hideStoreValues: any = get(hideStore); // Define a Vest test suite for validating simple component data // based on the validation rules defined in the validation store -const suite = create((data: any, fieldName: string='') => { +const suite = create((fieldName: string='') => { - if (fieldName) { + if (fieldName!='') { only(fieldName); } - //console.log('Validation Store Values:', validationStoreValues); if (validationStoreValues.simpleTypeValidationItems.length > 0) { // Iterate over each validation item in the store each(validationStoreValues.simpleTypeValidationItems, (item) => { if((fieldName && fieldName == item.path) || fieldName === ''){ - // Validate required field + + const data = getValueByPath(item.path); + console.log("🚀 ~ data:", data) + + //Validate required field if(item.required){ - //console.log('Validating required for field:', item.path); test( item.path, `${item.label} is required`, () => { enforce(data).isNotBlank(); }); } - // Validate minimum length if defined - if(item.minLength != null && item.minLength != undefined){ - //console.log('Validating minLength for field:', item.path); + else + { + optional(item.path); + } + + //Validate minimum length if defined + if(item.minLength != null && item.minLength != undefined && !isEmpty(data)){ + //console.log('Validating minLength for field:', item.path, data); test( item.path, `${item.label} must have a minimum length of ${item.minLength}`, () => { - enforce(data).longerThanOrEquals(item.minLength); - + enforce(data).longerThanOrEquals(item.minLength) }); } // Validate maximum length if defined - if(item.maxLength != null && item.maxLength != undefined){ - //console.log('Validating maxLength for field:', item.path); + if(item.maxLength != null && item.maxLength != undefined && !isEmpty(data)){ + console.log('Validating maxLength for field:', item.path); test( item.path, `${item.label} must have a maximum length of ${item.maxLength}`, () => { enforce(data).shorterThanOrEquals(item.maxLength); }); } - // Validate minimum if defined - if(item.minimum != null && item.minimum != undefined){ - //console.log('Validating minimum for field:', item.path); + // Validate minimum if defined + if(item.minimum != null && item.minimum != undefined && !isEmpty(data)){ + console.log('Validating minimum for field:', item.path); test( item.path, `${item.label} must have a minimum of ${item.minimum}`, () => { enforce(data).greaterThanOrEquals(item.minimum); }); } // Validate maximum if defined - if(item.maximum != null && item.maximum != undefined){ + if(item.maximum != null && item.maximum != undefined && !isEmpty(data)){ //console.log('Validating maximum for field:', item.path); test( item.path, `${item.label} must have a maximum of ${item.maximum}`, () => { enforce(data).lessThanOrEquals(item.maximum); }); } // Validate regex pattern if defined - if(item.regex != '' && item.regex != null && item.regex != undefined){ + if(item.regex != '' && item.regex != null && item.regex != undefined && !isEmpty(data)){ //console.log('Validating regex pattern for field:', item.path); test( item.path, `${item.label} doesn't match the required pattern (${item.regex})`, () => { enforce(data).matches(new RegExp(item.regex!)); @@ -72,15 +79,29 @@ const suite = create((data: any, fieldName: string='') => { } // Validate enum values if defined - if(item.enum && item.enum.length>0){ + if(item.enum && item.enum.length>0 && !isEmpty(data)){ //console.log('Validating regex pattern for field:', item.path); test( item.path, `Invalid ${item.label}. Choose from the list.`, () => { enforce(data).isValueOf(item.enum); }); - } + } + + + test(item.path, 'Valide', () => { + + //console.log("🚀 ~ updateValue Validation for field:", item.path, "with value:", data); + + // Ein leeres return signalisiert Vest: "Dieser Test ist erfolgreich bestanden!a" // + return; + }); + } }); } }); +function isEmpty(value: any) { + return value === null || value === undefined || value === ''; +} + export default suite; \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte index c474e3e8b2..49470d74e5 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte @@ -10,8 +10,9 @@ import Functions from './MetadataFunctions.svelte'; // import { Page } from '@bexis2/bexis2-core-ui'; - import { schemaToJson, setConfigStore, setMetadataStore, setSystemMappingsStore } from '$lib/components/utils/metadata/metadataComponentUtils'; + import { clearValidationStore, getValidationStore, schemaToJson, setConfigStore, setMetadataStore, setSystemMappingsStore } from '$lib/components/utils/metadata/metadataComponentUtils'; import type { SystemMappingEditModel } from '$lib/components/utils/metadata/models'; + import suite from '$lib/components/utils/metadata/simpleComponentSuite'; // import configJson from './customComponents/config.json'; @@ -52,7 +53,14 @@ const systemMappings:SystemMappingEditModel = await apiCalls.GetSystemMappings(datasetInfos.metadataStructureId); console.log("🚀 ~ load ~ systemMappings:", systemMappings) setSystemMappingsStore(systemMappings); + + let v = getValidationStore(); + //clearValidationStore(); + + const res = suite(''); + console.log("🚀 ~ load ~ res:", res.isValid()) + } } @@ -74,9 +82,6 @@ reload = !reload } /> {/if}
- - -
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte index 850deaae8f..4fab6dce58 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte @@ -12,6 +12,7 @@ import {convertDisplayName} from '../metadataShared'; import { goTo } from '$services/BaseCaller'; import { createEventDispatcher } from 'svelte'; + import suite from '$lib/components/utils/metadata/simpleComponentSuite'; const dispatch = createEventDispatcher(); @@ -39,6 +40,9 @@ let disbaleSaveBtn: boolean = false; $:disbaleSaveBtn; + let vestResults:any = null; + $vestResults; + let validationStoreValues: validationStoretype; $:{ validationStoreValues; @@ -54,8 +58,11 @@ }); validationStore.subscribe((s) => { + //console.log("🚀 ~ validationStore subscribe ~ s:", s) validationStoreValues = s; }); + + }); @@ -107,17 +114,15 @@ message: 'Metadata successfully imported.', }); - console.log("🚀 ~ successHandler ~ metadata:", metadata) + //console.log("🚀 ~ successHandler ~ metadata:", metadata) metadata = JSON.parse(String(e.detail.data)); - console.log("🚀 ~ successHandler ~ metadata:", metadata) + //console.log("🚀 ~ successHandler ~ metadata:", metadata) setMetadataStore(metadata); dispatch('metadataUpdated'); } } - - @@ -167,19 +172,21 @@
+ -
+
{#if validationStoreValues} {#key validationStoreValues} - {#if !validationStoreValues.allSimpleRequiredValid} - {#if showErrorOverview}
{#each validationStoreValues.simpleTypeValidationItems.filter(item => item.isValid === false) as item} {/each}
@@ -189,7 +196,6 @@ {/if}
-

edit(obj.detail.type)} config={m} /> - {:catch error} - - {/await} + {/if} From b2d5dae7a9d95384d164f0b3886ba6b08055ee3a Mon Sep 17 00:00:00 2001 From: geofranzi Date: Wed, 10 Jun 2026 10:51:01 +0200 Subject: [PATCH 059/490] #2395 Add updated by userName --- .../AAA/BExIS.Security.Services/Utilities/MessageHelper.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs b/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs index 1430028e41..2cac8ac962 100644 --- a/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs +++ b/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs @@ -247,7 +247,7 @@ public static string GetUpdateDatasetMessage(long datasetid, string title, strin { StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.AppendLine($"{entityname} \"{title}\" with ID {datasetid} was updated"); + stringBuilder.AppendLine($"{entityname} \"{title}\" with ID {datasetid} was updated by {userName}"); if(numberOfRows>0) stringBuilder.AppendLine($"\"{numberOfRows}\" rows have been successfully added/edited."); if(numberOfSkippedRows>0) From 33986e378c6d2093d26a1599a22666f281935a55 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Wed, 10 Jun 2026 12:26:03 +0200 Subject: [PATCH 060/490] #2415 Send email on file upload/modify/delete --- .../Utilities/MessageHelper.cs | 18 ++++++-- .../Helpers/DataASyncUploadHelper.cs | 41 +++++++++++++++---- 2 files changed, 48 insertions(+), 11 deletions(-) diff --git a/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs b/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs index 2cac8ac962..79da7f1fac 100644 --- a/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs +++ b/Components/AAA/BExIS.Security.Services/Utilities/MessageHelper.cs @@ -212,22 +212,32 @@ public static string GetMetadataUpdatHeader(long datasetid, string entityname) return $"{entityname}: Metadata updated (ID {datasetid})"; } - public static string GeFileUpdatHeader(long datasetid) + public static string GeFileUploadHeader(long datasetid) { return $"File was uploaded (ID {datasetid})"; } - public static string GetFileUploaddMessage(long userId, string title, string userName, string filename) + public static string GeFileUpdateHeader(long datasetid) { - return $"User \"{userName}\"(ID {userId}) has uploaded to the dataset \"{title}\" a file: {filename}."; + return $"File(s) were updated (ID {datasetid})"; } - public static string GetFilesUploaddMessage(long userId,string title, string userName, string[] filenames) + public static string GetFileUpdatedMessage(long userId, string title, string userName, string filenames, string type) + { + return $"User \"{userName}\"(ID {userId}) has {type} files to/at the dataset \"{title}\". File(s): {filenames}."; + } + + public static string GetFilesUploadMessage(long userId,string title, string userName, string[] filenames) { var fnames = string.Join(",", filenames); return $"User \"{userName}\"(ID {userId}) has uploaded to the dataset \"{title}\" this files: {fnames}."; } + public static string GetFilesUploadMessage(long userId, string title, string userName, string filename) + { + return $"User \"{userName}\"(ID {userId}) has uploaded to the dataset \"{title}\" this files: {filename}."; + } + public static string GetFileDownloadHeader(long datasetid, long version) { return $"File was downloaded (ID {datasetid}, Version: {version})"; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DataASyncUploadHelper.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DataASyncUploadHelper.cs index a67a7348ae..76b322cca3 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DataASyncUploadHelper.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/DataASyncUploadHelper.cs @@ -409,8 +409,11 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat #region unstructured data string filecomment = ""; + string newFiles = ""; string modcomments = ""; + string modifiedFiles = ""; string deletedComments = ""; + string deletedFiles = ""; if (structureId <= 0) @@ -436,7 +439,7 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat unitOfWork.GetReadOnlyRepository().Load(workingCopy.ContentDescriptors); - + // save all incoming files in content descriptor foreach (var file in Cache.Files) @@ -445,6 +448,7 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat //filenames string fileNames = string.Join(",", Cache.Files.Select(f => f.Name).ToArray()); + newFiles = fileNames; filecomment = "File(s) uploaded (" + fileNames + ")"; } @@ -456,6 +460,7 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat //filenames string fileNames = string.Join(",", Cache.ModifiedFiles.Select(f => f.Name).ToArray()); + modifiedFiles = fileNames; modcomments = "File(s) updated (" + fileNames + ")"; var contentDescriptor = workingCopy.ContentDescriptors.FirstOrDefault(item => item.URI == dynamicStorePath); @@ -479,12 +484,13 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat } if (File.Exists(storePath)) - { + { File.Delete(storePath); } //filenames string fileNames = string.Join(",", Cache.DeleteFiles.Select(f => f.Name).ToArray()); + deletedFiles = fileNames; deletedComments = "File(s) deleted (" + fileNames + ")"; } @@ -517,6 +523,26 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat // ToDo: Get Comment from ui and users dm.CheckInDataset(id, comment, User.Name, ViewCreationBehavior.None, TagType.None); + var user = User; + using (var emailService = new EmailService()) + { + if (!string.IsNullOrEmpty(filecomment)) + emailService.Send(MessageHelper.GeFileUpdateHeader(id), + MessageHelper.GetFileUpdatedMessage(id, title, user.DisplayName, newFiles, "added"), + null, null, new List { GeneralSettings.SystemEmail }); + + if (!string.IsNullOrEmpty(modcomments)) + emailService.Send(MessageHelper.GeFileUpdateHeader(id), + MessageHelper.GetFileUpdatedMessage(id, title, user.DisplayName, modifiedFiles, "modified" ), + null, null, new List { GeneralSettings.SystemEmail }); + + if (!string.IsNullOrEmpty(deletedComments)) + emailService.Send(MessageHelper.GeFileUpdateHeader(id), + MessageHelper.GetFileUpdatedMessage(id, title, user.DisplayName, deletedFiles, "deleted"), + null, null, new List { GeneralSettings.SystemEmail }); + + } + } catch (Exception ex) { @@ -572,15 +598,16 @@ public async Task> FinishUpload(long id, AuditActionType datasetStat } if (Cache.Files.Count == 1) - emailService.Send(MessageHelper.GeFileUpdatHeader(id), - MessageHelper.GetFileUploaddMessage(id,title, user.DisplayName, Cache.Files.FirstOrDefault().Name), + emailService.Send(MessageHelper.GeFileUploadHeader(id), + MessageHelper.GetFilesUploadMessage(id,title, user.DisplayName, Cache.Files.FirstOrDefault().Name), new List { user.Email }, null, new List { GeneralSettings.SystemEmail }); if (Cache.Files.Count > 1) - emailService.Send(MessageHelper.GeFileUpdatHeader(id), - MessageHelper.GetFilesUploaddMessage(id,title, user.DisplayName, Cache.Files.Select(f => f.Name).ToArray()), + emailService.Send(MessageHelper.GeFileUploadHeader(id), + MessageHelper.GetFilesUploadMessage(id,title, user.DisplayName, Cache.Files.Select(f => f.Name).ToArray()), new List { user.Email }, null, new List { GeneralSettings.SystemEmail }); - } + } + } dm.Dispose(); From c2c32d2d2f99b90c57cbf8b25baed1ba3f4a39d3 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Wed, 10 Jun 2026 12:43:19 +0200 Subject: [PATCH 061/490] #2340 Reduce one confirmation click --- .../src/lib/hooks/Submit.svelte | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte index 232861c285..21ada6856b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte @@ -91,13 +91,13 @@ const confirm: ModalSettings = { type: 'confirm', title: 'Submit', - body: 'Are you sure you wish to submit the data?', + body: 'Are you sure you wish to submit the data?

Editing will be disabled until the import is complete. If you are importing a large amount of tabular data it may take a while. You will be notified by email when it is complete.

Once the import is complete, please check the imported data. ', // TRUE if confirm pressed, FALSE if cancel pressed response: (r: boolean) => { if (r === true) { submitBt(); - modalStore.trigger(next); - dispatch('success', { text: 'The import of your data has been started.' }); + // modalStore.trigger(next); + // dispatch('success', { text: 'The import of your data has been started.' }); } } }; @@ -105,7 +105,7 @@ const next: ModalSettings = { type: 'alert', title: 'Import started', - body: 'Editing will be disabled until the upload is complete. If you are uploading a large amount of data, the upload will take a while, and you will be notified by email when it is complete. Please check the data you have uploaded. ', + body: 'Editing will be disabled until the import is complete. If you are importing a large amount of tabular data it may take a while. You will be notified by email when it is complete.

Once the import is complete, please check the imported data you have uploaded. ', buttonTextCancel: 'Ok' // TRUE if confirm pressed, FALSE if cancel pressed }; From 071f5c1010d7920cde9b434cc01c1dcc7c72209e Mon Sep 17 00:00:00 2001 From: geofranzi Date: Wed, 10 Jun 2026 13:24:09 +0200 Subject: [PATCH 062/490] #2432 Remove Placeholder; Add 500ms info before reloading the page --- .../src/lib/hooks/Submit.svelte | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte index 21ada6856b..d632e82d3b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte @@ -123,9 +123,15 @@ if (res.asyncUpload) { dispatch('success', { text: res.asyncUploadMessage }); } - // update store - latestSubmitDate.set(Date.now()); isSubmitting = false; + setTimeout(() => { + + // update store + latestSubmitDate.set(Date.now()); + + console.log('goto view'); + }, 500); + } } @@ -169,19 +175,28 @@ {#await reload()} - + {:then m}
+ {#if !isSubmitting && !canSubmit} + + + {:else} + {/if} {#if isSubmitting}
+ {:else if canSubmit} +
Please click submit to start import.
{/if}
{:catch error} From 1fb77d69bd2fc25db54d601d24b9d6547b1c35d8 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Wed, 10 Jun 2026 13:36:58 +0200 Subject: [PATCH 063/490] #2437 #2414 Change when and which message is shown during file upload --- .../src/lib/components/HookContainer.svelte | 14 ++++++++++++++ .../src/lib/components/data/Files.svelte | 11 +++++++---- .../components/fileupload/FileOverviewItem.svelte | 2 +- .../src/lib/hooks/FileUpload.svelte | 7 ++++++- 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/HookContainer.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/HookContainer.svelte index 708ca95a17..d72bb43917 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/HookContainer.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/HookContainer.svelte @@ -2,6 +2,7 @@ import { onMount } from 'svelte'; import { Alert, Spinner } from '@bexis2/bexis2-core-ui'; + import { fade } from 'svelte/transition'; import { hooksStatus } from '../../routes/edit/stores'; @@ -25,6 +26,17 @@ $: active = false; $: wait = false; + + let timer; + $: if (success) { + // Clear any existing active timer to reset the 3-second clock if a new message arrives + clearTimeout(timer); + + timer = setTimeout(() => { + success = null; + }, 3000); // 3000 milliseconds = 3 seconds + } + onMount(async () => { //active = setActive(status); @@ -109,7 +121,9 @@ {/each} {/if} {#if success} +
+
{/if}
{#if !wait} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte index 91e57b46dc..fc3e32a7db 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte @@ -36,9 +36,9 @@ deletedFiles = [...deletedFiles, e.detail.file]; latestDataDate.set(Date.now()); - const text = 'File removed: ' + e.detail.file.name; + // const text = 'Please click submit to save the changes.'; - dispatch('warning', { text }); + // dispatch('warning', { text }); } function handleRevert(e) { @@ -52,7 +52,7 @@ latestDataDate.set(Date.now()); const text = 'File reverted: ' + e.detail.file.name; - dispatch('warning', { text }); + dispatch('info', { text }); } // async function handleRevert(e, index){ @@ -79,7 +79,7 @@ {#if files.length > 0}
- Existing File(s) + Uploaded File(s)
0}
+
File(s) to delete
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte index b39049096e..887639b169 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte @@ -46,7 +46,7 @@ async function handleSaveFileDescription() { const res = await saveFileDescription(save, id, file); if (res) { - let message = 'Description of ' + file.name + ' is updated.'; + let message = 'Description of ' + file.name + ' was updated.'; dispatch('saved', { text: message }); } } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte index c6095d9fa6..f0bca7e0c1 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte @@ -103,8 +103,13 @@ on:success /> {#if model.fileUploader.existingFiles.length} + + +
- Uploaded File(s) + File(s) ready for tabular data / file import
Date: Wed, 10 Jun 2026 18:35:43 +0200 Subject: [PATCH 064/490] added properties to SpeciesMatchingResult db table #980 --- .../SpeciesMatching/SpeciesMatchingResult.cs | 31 +++++++++++++++++++ .../SpeciesMatchingResult.hbm.xml | 24 ++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs index 848bdd8c22..e3d536d1e8 100644 --- a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs +++ b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs @@ -23,6 +23,37 @@ public class SpeciesMatchingResult : BaseEntity // type of the match (e.g. exact, fuzzy, etc.) public virtual string MatchType { get; set; } + // taxonomic rank of the matched name (e.g. species, genus, etc.) + public virtual string MatchRank { get; set; } + + // unique identifier of the matched name in the external source (e.g. GBIF taxon ID) + public virtual string MatchId { get; set; } + + // authorship of the matched name (e.g. Linnaeus, 1758) + public virtual string MatchAuthorship { get; set; } + + // accepted name if (for example) the matched name is a synonym + public virtual string AcceptedScientificName { get; set; } + + // unique identifier of the accepted name in the external source (e.g. GBIF taxon ID) + public virtual string AcceptedId { get; set; } + + // authorship of the accepted name + public virtual string AcceptedAuthorship { get; set; } + + // higher classification of the matched name (e.g. kingdom, phylum, class, order, family, genus) + public virtual string TaxonKingdom { get; set; } + + public virtual string TaxonPhylum { get; set; } + + public virtual string TaxonClass { get; set; } + + public virtual string TaxonOrder { get; set; } + + public virtual string TaxonFamily { get; set; } + + public virtual string TaxonGenus { get; set; } + // timestamp of the match public virtual DateTime TimestampMatch { get; set; } 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 fda12a6bce..9ff860ec4e 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 @@ -15,6 +15,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + From fa8e0a60f766d070da5d1f48fa5c30bc03269ba9 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 10 Jun 2026 18:38:55 +0200 Subject: [PATCH 065/490] added submit route for data cleaning and edits #980 --- .../BExIS.Modules.SMM.UI.csproj | 1 + .../Controllers/SpeciesController.cs | 54 ++++++++++++++++++ .../src/lib/types/types.ts | 2 +- .../src/routes/tailor_view/+page.svelte | 55 ++++++++++++++++--- .../src/routes/tailor_view/EditSubmit.svelte | 44 +++++++++++++++ .../src/routes/tailor_view/data.ts | 31 +++++++++++ .../src/routes/tailor_view/services.ts | 16 ++++++ .../src/routes/tailor_view/types.ts | 12 ++++ .../Helpers/MatchingResultHelper.cs | 35 ++++++++++++ .../Models/TailorEditsModel.cs | 34 ++++++++++++ 10 files changed, 274 insertions(+), 10 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/TailorEditsModel.cs 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 a7d521d9a9..4ac50c2fd4 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 @@ -139,6 +139,7 @@ + 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 963d77b28d..5676441756 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 @@ -12,6 +12,7 @@ using BExIS.Modules.Smm.UI.Helpers.MatchingAPIs; using BExIS.Modules.Smm.UI.Models; using BExIS.Security.Entities.Authorization; +using BExIS.Security.Entities.Requests; using BExIS.Security.Entities.Subjects; using BExIS.Security.Services.Authorization; using BExIS.Security.Services.Objects; @@ -815,6 +816,59 @@ public JsonResult AcceptMatches(AcceptMatchesRequestModel request) return Json(new { success = true, id = request.DatasetId }); } + [JsonNetFilter] + [HttpPost] + public JsonResult ApplyTailorEdits(long datasetId, long versionId, TailorEdit[] edits) + { + Debug.WriteLine("Received request to apply tailor edits..."); + + if (edits == null) return JsonWithStatus(new { success = false, message = "Request body missing or invalid." }, HttpStatusCode.BadRequest); + + if (!ModelState.IsValid) + { + var realJsonErrors = ModelState + .Where(x => x.Value.Errors.Count > 0) + .SelectMany(x => x.Value.Errors) + // Look specifically for the internal exception thrown by the JSON reader + .Select(e => e.Exception?.ToString() ?? e.ErrorMessage) + .ToList(); + + return JsonWithStatus(new + { + success = false, + message = "The JSON parser crashed.", + details = realJsonErrors + }, HttpStatusCode.BadRequest); + return JsonWithStatus(new { success = false, message = "Validation failed." }, HttpStatusCode.BadRequest); + } + + var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); + if (user == null) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized); + } + + Debug.WriteLine("Received request to apply tailor edits for dataset " + datasetId + " version " + versionId); + + try + { + var result = MatchingResultHelper.ApplyTailorEdits(datasetId, versionId, edits.ToList()); + if (result == false) + { + return JsonWithStatus(new { success = false, id = datasetId, message = "Failed to apply edits." }, HttpStatusCode.InternalServerError); + } + + Debug.WriteLine("Successfully applied tailor edits for dataset " + datasetId + " version " + versionId); + + return Json(new { success = true, id = datasetId }); + } + catch (Exception ex) + { + Debug.WriteLine("Error while applying tailor edits for dataset " + datasetId + " version " + versionId + ": " + ex); + return JsonWithStatus(new { success = false, id = datasetId, message = "Error while applying edits: " + ex.Message }, HttpStatusCode.BadRequest); + } + } + public async Task<(bool IsSuccess, string Content)> TailorDataset(long datasetId, long variableId, string jwtToken) { string url = "http://localhost:44345/api/DataStatistic/" + datasetId.ToString() + "/" + variableId.ToString(); 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 ebda0b7245..a4582da4db 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 @@ -80,7 +80,7 @@ export interface CLBMatchingResult { original_authorship: string, matchType: string, matchIssues: string, - iD: string, + id: string, rank: string, scientificName: string, authorship: string, 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 6030a9cf81..4e4806c0e7 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 @@ -2,7 +2,7 @@ import { ErrorMessage, Page, pageContentLayoutType, positionType, Spinner, type TableConfig } from "@bexis2/bexis2-core-ui"; import { onMount } from "svelte"; import { loadResult } from "./services"; - import { tailorResultStore, tailorCleanedStore, initializeTableData, toggleDataCleaning, cleanConfig, type TailorResultRow } from "./data"; + import { tailorResultStore, tailorCleanedStore, initializeTableData, toggleDataCleaning, cleanConfig, type TailorResultRow, getChangedTailorRows } from "./data"; import { Table } from '@bexis2/bexis2-core-ui'; import ResultTableOptions from "./ResultTableOptions.svelte"; import { Modal, getModalStore } from '@skeletonlabs/skeleton'; @@ -14,15 +14,21 @@ import Fa from 'svelte-fa'; import { getDifference } from "$lib/helper/custom_diff"; import CleanedName from "./cleanedName.svelte"; + import EditSubmit from "./EditSubmit.svelte"; const modalStore = getModalStore(); + let totalCount: number = 1000; + let confirmedCount: number = 0; + let percentage: number = totalCount > 0 ? (confirmedCount / totalCount) * 100 : 0; + + let rowChangesToSubmit: TailorResultRow[]; onMount(() => { async function test() { var responseData = await loadResult($mappingSelection.datasetId, $mappingSelection.versionId); // filter out redundant data and determine column order - let filteredData = responseData.message.map((row: any): TailorResultRow => + let filteredData: TailorResultRow[] = responseData.message.map((row: any): TailorResultRow => { return { id: row.id, @@ -39,18 +45,35 @@ } }); + totalCount = filteredData.length; + confirmedCount = filteredData.filter(item => item.confirmedByUser).length; + percentage = totalCount > 0 ? (confirmedCount / totalCount) * 100 : 0; tailorResultStore.update(() => { return filteredData; }); initializeTableData(filteredData); - console.log(getDifference("Abies spectabilis (D. Don) Mirbel", "Abies spectabilis D. Don")); + console.log("CURRENT STORE STATE: \n", get(tailorCleanedStore)); + console.log("CURRENT RESULT STATE: \n", get(tailorResultStore)); + console.log("CURRENT CHANGED DIFF: \n", getChangedTailorRows()); } test(); }); + function prepareForSubmit() { + rowChangesToSubmit = getChangedTailorRows(); + modalStore.trigger({ + type: 'component', + title: `Submitting user changes`, + component: { + ref: EditSubmit, + props: { changedRows: rowChangesToSubmit } + } + }); + } + const tableActions = (action: CustomEvent<{ row: TailorResultRow; type: string }>) => { const { type, row } = action.detail; switch (type) { @@ -110,25 +133,25 @@ header: "Status", exclude: true }, - timestampMatch: { + timeStampMatch: { header: "Match date", exclude: true }, matchType: { header: "Match type", - exclude: true + // exclude: true }, matchSource: { header: "Match source", - exclude: true + // exclude: true }, matchVersion: { header: "Match version", - exclude: true + // exclude: true }, matchSourceVersion: { header: "Match source version", - exclude: true + // exclude: true }, }, optionsComponent: ResultTableOptions @@ -166,6 +189,20 @@

Global Actions

+
+
+ Confirmed Progress ({confirmedCount}/{totalCount}) + {Math.round(percentage)}% +
+ +
+
+
+
+
@@ -176,7 +213,7 @@
- +
diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte new file mode 100644 index 0000000000..5026875588 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte @@ -0,0 +1,44 @@ + + +
+ + +
You are about to submit {changedRows.length} changed 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/data.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/data.ts index f238a57f02..a258777d44 100644 --- 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 @@ -37,6 +37,37 @@ export function initializeTableData(data: TailorResultRow[]) { tailorCleanedStore.set(processed); } +/** + * This function filters out all effectively changed rows from the TailorTable. Effectively changed means, the row is unconfirmed + * and the EditedName should change either due to data cleaning or manual user changes. + * @returns Array of effectively changed ResultRows + */ +export function getChangedTailorRows(): TailorResultRow[] { + const currentCleaned = get(tailorCleanedStore); + const currentOriginal = get(tailorResultStore); + + const resultStoreMap = new Map( + currentOriginal.map(row => [row.id, row]) + ); + + return currentCleaned.filter(cleanedRow => { + const resultRow = resultStoreMap.get(cleanedRow.id); + + if (!resultRow) return false; + + // Entry needs to be unconfirmed + if (resultRow.confirmedByUser) return false; + + // data cleaning detected and has not been applied yet + const condition1 = !cleanedRow.editedName && cleanedRow.cleanedName !== cleanedRow.originalName; + + // editedName has changed + const condition2 = cleanedRow.editedName !== '' && cleanedRow.editedName !== resultRow.editedName; + + return condition1 || condition2; + }) +} + export function toggleDataCleaning() { const currentRows = get(tailorCleanedStore); 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 index dbac8710f9..8a6d02ca6d 100644 --- 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 @@ -1,4 +1,6 @@ import { Api } from '@bexis2/bexis2-core-ui'; +import type { TailorEdit, TailorEditsRequest } from './types'; +import type { ServiceResult } from '$lib/types/types'; export const loadResult = async (datasetId: number, versionId: number) => { try { @@ -7,4 +9,18 @@ export const loadResult = async (datasetId: number, versionId: number) => { } catch (error) { console.error(error); } +} + +export const submitTailorEdits = async (datasetId: number, versionId: number, payload: TailorEdit[]): Promise> => { + try { + console.log("Applying tailor Edits..."); + console.log("Payload: \n", payload); + const response = await Api.post(`/smm/species/ApplyTailorEdits?datasetId=${datasetId}&versionId=${versionId}`, payload); + + return { success: true, data: response.data } + } catch (error: any) { + console.error(error); + 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/tailor_view/types.ts b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/types.ts index e69de29bb2..887ed38c2b 100644 --- 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 @@ -0,0 +1,12 @@ +export interface TailorEdit { + id: number, + originalName: string, + editedName: string, + cleanedName: string +} + +export type TailorEditsRequest = { + datasetId: number, + versionId: number, + edits: TailorEdit[] +} \ No newline at end of file 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 index e85c415d8e..c862b9cfc4 100644 --- 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 @@ -87,6 +87,41 @@ public static (string FilePath, int RowCount) GenerateUnmatchedCsv(long datasetI return (filepath, writtenCount); } + public static bool ApplyTailorEdits(long datasetId, long versionId, List edits) + { + try + { + using (var smrm = new SpeciesMatchingResultManager()) + using (var uow = smrm.GetUnitOfWork()) + { + var repo = uow.GetRepository(); + foreach (var edit in edits) + { + var entity = repo.Query().FirstOrDefault(e => e.Id == edit.Id && e.Dataset.Id == datasetId && e.DatasetVersionId == versionId && e.ConfirmedByUser == false); + if (entity != null) + { + // TODO: - adapt this when further data cleaning constraints are clearer + // optionally also update other fields + if (edit.EditedName != "") + { + entity.EditedName = edit.EditedName; + } else + { + entity.EditedName = edit.CleanedName; + } + } + } + uow.Commit(); + return true; + } + } + catch (Exception ex) + { + Debug.WriteLine(ex); + return false; + } + } + // Read a ChecklistBank matching CSV file and map rows to CLBMatchingResultFile objects public static List ReadClbMatchingResultFile(string filepath) { diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/TailorEditsModel.cs b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/TailorEditsModel.cs new file mode 100644 index 0000000000..4b366b8dcf --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI/Models/TailorEditsModel.cs @@ -0,0 +1,34 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Smm.UI.Models +{ + public class TailorEdit + { + [Range(1, long.MaxValue, ErrorMessage = "Id must be provided and greater than 0.")] + public long Id { get; set; } + + public string OriginalName { get; set; } + + [DisplayFormat(ConvertEmptyStringToNull = false)] + public string EditedName { get; set; } + + [DisplayFormat(ConvertEmptyStringToNull = false)] + public string CleanedName { get; set; } + } + + public class TailorEditsModel + { + [Range(1, long.MaxValue, ErrorMessage = "DatasetId must be provided and greater than 0.")] + public long DatasetId { get; set; } + + [Range(1, long.MaxValue, ErrorMessage = "VersionId must be provided and greater than 0.")] + public long VersionId { get; set; } + + [Required(ErrorMessage = "At least one edit must be provided.")] + public List Edits { get; set; } = new List(); + } +} \ No newline at end of file From e8292f4e8603f696a2ea089aeb33b32713fab8eb Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 10 Jun 2026 18:47:42 +0200 Subject: [PATCH 066/490] tidy up #980 --- .../Controllers/SpeciesController.cs | 26 ++++--------------- .../Helpers/MatchingResultHelper.cs | 1 - 2 files changed, 5 insertions(+), 22 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 5676441756..5eaba3b3c6 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 @@ -820,27 +820,11 @@ public JsonResult AcceptMatches(AcceptMatchesRequestModel request) [HttpPost] public JsonResult ApplyTailorEdits(long datasetId, long versionId, TailorEdit[] edits) { - Debug.WriteLine("Received request to apply tailor edits..."); + // Debug.WriteLine("Received request to apply tailor edits..."); if (edits == null) return JsonWithStatus(new { success = false, message = "Request body missing or invalid." }, HttpStatusCode.BadRequest); - if (!ModelState.IsValid) - { - var realJsonErrors = ModelState - .Where(x => x.Value.Errors.Count > 0) - .SelectMany(x => x.Value.Errors) - // Look specifically for the internal exception thrown by the JSON reader - .Select(e => e.Exception?.ToString() ?? e.ErrorMessage) - .ToList(); - - return JsonWithStatus(new - { - success = false, - message = "The JSON parser crashed.", - details = realJsonErrors - }, HttpStatusCode.BadRequest); - return JsonWithStatus(new { success = false, message = "Validation failed." }, HttpStatusCode.BadRequest); - } + if (!ModelState.IsValid) return JsonWithStatus(new { success = false, message = "Validation failed." }, HttpStatusCode.BadRequest); var user = ResolveUserAndRights(datasetId, out ActionResult errorResult); if (user == null) @@ -848,7 +832,7 @@ public JsonResult ApplyTailorEdits(long datasetId, long versionId, TailorEdit[] return JsonWithStatus(new { success = false, id = datasetId, message = "Authentification error." }, HttpStatusCode.Unauthorized); } - Debug.WriteLine("Received request to apply tailor edits for dataset " + datasetId + " version " + versionId); + // Debug.WriteLine("Received request to apply tailor edits for dataset " + datasetId + " version " + versionId); try { @@ -858,13 +842,13 @@ public JsonResult ApplyTailorEdits(long datasetId, long versionId, TailorEdit[] return JsonWithStatus(new { success = false, id = datasetId, message = "Failed to apply edits." }, HttpStatusCode.InternalServerError); } - Debug.WriteLine("Successfully applied tailor edits for dataset " + datasetId + " version " + versionId); + // Debug.WriteLine("Successfully applied tailor edits for dataset " + datasetId + " version " + versionId); return Json(new { success = true, id = datasetId }); } catch (Exception ex) { - Debug.WriteLine("Error while applying tailor edits for dataset " + datasetId + " version " + versionId + ": " + ex); + // Debug.WriteLine("Error while applying tailor edits for dataset " + datasetId + " version " + versionId + ": " + ex); return JsonWithStatus(new { success = false, id = datasetId, message = "Error while applying edits: " + ex.Message }, HttpStatusCode.BadRequest); } } 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 index c862b9cfc4..ec86b5ade1 100644 --- 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 @@ -117,7 +117,6 @@ public static bool ApplyTailorEdits(long datasetId, long versionId, List Date: Wed, 10 Jun 2026 18:56:59 +0200 Subject: [PATCH 067/490] redirect and closing modal store #980 --- .../src/routes/tailor_view/EditSubmit.svelte | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte index 5026875588..27f7cd118d 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte @@ -4,6 +4,7 @@ import { submitTailorEdits } from "./services"; import { mappingSelection } from '../../lib/stores/selectionStore'; import { type TailorEdit, type TailorEditsRequest } from "./types"; + import { goto } from "$app/navigation"; export let changedRows: TailorResultRow[]; const modalStore = getModalStore(); @@ -25,11 +26,12 @@ const response = await submitTailorEdits($mappingSelection.datasetId, $mappingSelection.versionId, payload); if (!response.success) { - console.log("ERROR"); + // TODO: - handling } else { - console.log("SUCCESS"); - console.log(response); + goto('/progress_overview'); } + + modalStore.close(); } From 664361df57566d6fb7c0ea7eddff80f550261545 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 10 Jun 2026 19:02:28 +0200 Subject: [PATCH 068/490] fixed store update overwrite bug #980 --- .../src/routes/progress_overview/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 4994147477..e0a160ac3a 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 @@ -98,7 +98,7 @@ return; } console.log(responseMatch); - mappingSelection.update(s => ({ stepId: responseMatch.data.data?.stepId })); + mappingSelection.update(s => ({ ...s, stepId: responseMatch.data.data?.stepId })); } From 0d8ad9a99301bf2e16579a662cc70e8f3910ce69 Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 10 Jun 2026 19:49:46 +0200 Subject: [PATCH 069/490] returning db entries together with matching results #980 --- .../Controllers/SpeciesController.cs | 39 ++++++++++++++++++- .../src/routes/matchingresult/+page.svelte | 2 +- 2 files changed, 39 insertions(+), 2 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 5eaba3b3c6..20cb9e3615 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 @@ -769,7 +769,44 @@ public JsonResult ViewMatchingResult(long datasetId, long versionId, int stepId) MatchingApiBase apiBase = matchingApiProvider.GetApi(apiIdentifier); var matchingResults = apiBase.ReadResultFile(filepath); - return Json(new { success = true, data = matchingResults }, JsonRequestBehavior.AllowGet); + // If matching results were read, build a set of IDs from the file and then + // query the SpeciesMatchingResult table for the subset of rows that belong + // to this dataset/version and whose IDs are present in the matching result file. + List dbResults = null; + + if (matchingResults != null && matchingResults.Count > 0) + { + try + { + // collect ids from matching result rows + var idsFromFile = new HashSet(); + foreach (var m in matchingResults) + { + if (string.IsNullOrWhiteSpace(m.Original_ID)) continue; + if (long.TryParse(m.Original_ID, out long mid)) idsFromFile.Add(mid); + } + + Debug.WriteLine("Creating HashSet from file MatchingResultRows:"); + Debug.WriteLine(idsFromFile.Count); + + using (var smrm = new SpeciesMatchingResultManager()) + { + var repo = smrm.GetBulkUnitOfWork().GetReadOnlyRepository(); + + // query only the subset matching dataset/version and the ids from file + dbResults = repo.Query() + .Where(r => r.Dataset.Id == datasetId && r.DatasetVersionId == versionId && idsFromFile.Contains(r.Id)) + .ToList(); + } + } + catch (Exception ex) + { + Debug.WriteLine("Error while querying SpeciesMatchingResult subset: " + ex.Message); + dbResults = null; // fall back to null on error + } + } + + return Json(new { success = true, matchingResults = matchingResults, speciesMatchingResults = dbResults }, JsonRequestBehavior.AllowGet); } catch (ArgumentException ex) { 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 index 26fcecf325..d80e047ad1 100644 --- 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 @@ -29,7 +29,7 @@ throw new Error(response.error); } else { console.log(response.data); - var responseData: GenericMatchingResult[] = response.data.data; + var responseData: GenericMatchingResult[] = response.data.matchingResults; var orderedTableData = responseData.map((row: any): GenericMatchingResult => { return { original_ID: row.original_ID, From c4981baf1226e50d0973d03d8fb74579254abfde Mon Sep 17 00:00:00 2001 From: Erik Date: Wed, 10 Jun 2026 20:49:27 +0200 Subject: [PATCH 070/490] refactor and added new fields to tailor view table #980 --- .../SpeciesMatching/SpeciesMatchingResult.cs | 4 +- .../src/lib/types/types.ts | 44 ++++++++++ .../src/routes/tailor_view/+page.svelte | 83 ++++++++++++++----- .../src/routes/tailor_view/EditResult.svelte | 5 +- .../src/routes/tailor_view/EditSubmit.svelte | 4 +- .../src/routes/tailor_view/data.ts | 29 ++----- 6 files changed, 123 insertions(+), 46 deletions(-) diff --git a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs index e3d536d1e8..698e25cdf2 100644 --- a/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs +++ b/Components/DLM/BExIS.Dlm.Entities/SpeciesMatching/SpeciesMatchingResult.cs @@ -29,7 +29,7 @@ public class SpeciesMatchingResult : BaseEntity // unique identifier of the matched name in the external source (e.g. GBIF taxon ID) public virtual string MatchId { get; set; } - // authorship of the matched name (e.g. Linnaeus, 1758) + // authorship of the matched name public virtual string MatchAuthorship { get; set; } // accepted name if (for example) the matched name is a synonym @@ -54,7 +54,7 @@ public class SpeciesMatchingResult : BaseEntity public virtual string TaxonGenus { get; set; } - // timestamp of the match + // timestamp of the match (can vary by hours due to processing and queue times on different APIs) public virtual DateTime TimestampMatch { get; set; } // source of the match (e.g. Catalogue of Life, GBIF, etc.) 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 a4582da4db..460418853d 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 @@ -47,6 +47,50 @@ export interface MatchingFileStatus { jobKeyPresent: boolean, } +export type SpeciesMatchingRow = { + // database row id + id: number, + // original unchanged name (used for matching if EditedName is empty, and for display purposes) + originalName: string, + // helper to apply data cleaning and better overview (field itself does not exist in db) + cleanedName: string, + // edited name after data cleaning + manual corrections (used for matching) + editedName: string, + // indicates whether the match has been confirmed by the user + confirmedByUser: boolean, + // unique identifier of the matched name in the external source (e.g. GBIF taxon ID) + matchId: string, + // matched name from the external source (the result) + matchedName: string, + // authorship of the matched name + matchAuthorship: string, + // taxonomic rank of the matched name (e.g. species, genus, etc.) + matchRank: string, + // type of the match (e.g. exact, fuzzy, etc.) + matchType: string, + // taxonomic status of the matched name (e.g. accepted, synonym, etc.) + status: string, + // accepted name if (for example) the matched name is a synonym + acceptedScientificName: string, + // unique identifier of the accepted name in the external source (e.g. GBIF taxon ID) + acceptedId: string, + // authorship of the accepted name + acceptedAuthorship: string, + // higher classification of the matched name (e.g. kingdom, phylum, class, order, family, genus) + taxonKingdom: string, + taxonPhylum: string, + taxonClass: string, + taxonOrder: string, + taxonFamily: string, + taxonGenus: string, + // source of the match (e.g. Catalogue of Life, GBIF, etc.) + matchSource: string, + // version of the source used for matching + matchSourceVersion: string, + // timestamp of the match (can vary by hours due to processing and queue times on different APIs) + timeStampMatch: string +} + export interface GenericMatchingResult { original_ID?: string, original_scientificName: string, 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 4e4806c0e7..75434d7025 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 @@ -2,7 +2,8 @@ import { ErrorMessage, Page, pageContentLayoutType, positionType, Spinner, type TableConfig } from "@bexis2/bexis2-core-ui"; import { onMount } from "svelte"; import { loadResult } from "./services"; - import { tailorResultStore, tailorCleanedStore, initializeTableData, toggleDataCleaning, cleanConfig, type TailorResultRow, getChangedTailorRows } from "./data"; + import { tailorResultStore, tailorCleanedStore, initializeTableData, toggleDataCleaning, cleanConfig, getChangedTailorRows } from "./data"; + import { type SpeciesMatchingRow } from "$lib/types/types"; import { Table } from '@bexis2/bexis2-core-ui'; import ResultTableOptions from "./ResultTableOptions.svelte"; import { Modal, getModalStore } from '@skeletonlabs/skeleton'; @@ -21,27 +22,40 @@ let confirmedCount: number = 0; let percentage: number = totalCount > 0 ? (confirmedCount / totalCount) * 100 : 0; - let rowChangesToSubmit: TailorResultRow[]; + let rowChangesToSubmit: SpeciesMatchingRow[]; onMount(() => { async function test() { var responseData = await loadResult($mappingSelection.datasetId, $mappingSelection.versionId); // filter out redundant data and determine column order - let filteredData: TailorResultRow[] = responseData.message.map((row: any): TailorResultRow => - { + let filteredData: SpeciesMatchingRow[] = responseData.message.map((row: any): SpeciesMatchingRow => + { return { id: row.id, originalName: row.originalName, - editedName: row.editedName, - cleanedName: row.cleanedName, - confirmedByUser: row.confirmedByUser, - matchedName: row.matchedName, - matchType: row.matchType, - status: row.status, - matchSource: row.matchSource, - matchSourceVersion: row.matchSourceVersion, - timeStampMatch: row.timeStampMatch + editedName: row.editedName ?? "", + cleanedName: row.cleanedName ?? "", + confirmedByUser: row.confirmedByUser ?? false, + matchType: row.matchType ?? "", + matchedName: row.matchedName ?? "", + matchAuthorship: row.matchAuthorship ?? "", + status: row.status ?? "", + matchRank: row.matchRank ?? "", + acceptedScientificName: row.acceptedScientificName ?? "", + acceptedId: row.acceptedId ?? "", + acceptedAuthorship: row.acceptedAuthorship ?? "", + taxonKingdom: row.taxonKingdom ?? "", + taxonPhylum: row.taxonPhylum ?? "", + taxonClass: row.taxonClass ?? "", + taxonOrder: row.taxonOrder ?? "", + taxonFamily: row.taxonFamily ?? "", + taxonGenus: row.taxonGenus ?? "", + matchId: row.matchId ?? "", + matchSource: row.matchSource ?? "", + matchSourceVersion: row.matchSourceVersion ?? "", + timeStampMatch: row.timeStampMatch ?? "" + } }); @@ -53,10 +67,6 @@ }); initializeTableData(filteredData); - - console.log("CURRENT STORE STATE: \n", get(tailorCleanedStore)); - console.log("CURRENT RESULT STATE: \n", get(tailorResultStore)); - console.log("CURRENT CHANGED DIFF: \n", getChangedTailorRows()); } test(); @@ -74,7 +84,7 @@ }); } - const tableActions = (action: CustomEvent<{ row: TailorResultRow; type: string }>) => { + const tableActions = (action: CustomEvent<{ row: SpeciesMatchingRow; type: string }>) => { const { type, row } = action.detail; switch (type) { case 'UPDATE': @@ -93,7 +103,7 @@ } }; - const tableConfig: TableConfig = { + const tableConfig: TableConfig = { id: 'resultRows', data: tailorCleanedStore, resizable: "columns", @@ -127,6 +137,7 @@ header: "Confirmed by user" }, datasetVersionId: { + header: "Dataset Version ID", exclude: true }, status: { @@ -141,6 +152,40 @@ header: "Match type", // exclude: true }, + matchRank: { + header: "Match rank" + }, + matchAuthorship: { + header: "Match authorship" + }, + acceptedScientificName: { + header: "Accepted scientific name" + }, + acceptedId: { + header: "Accepted ID", + exclude: true, + }, + acceptedAuthorship: { + header: "Accepted authorship", + }, + taxonKingdom: { + header: "Kingdom" + }, + taxonPhylum: { + header: "Phylum" + }, + taxonClass: { + header: "Class" + }, + taxonOrder: { + header: "Order" + }, + taxonFamily: { + header: "Family" + }, + taxonGenus: { + header: "Genus" + }, matchSource: { header: "Match source", // exclude: true 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 index d74d818df5..a982ea515a 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/EditResult.svelte @@ -1,9 +1,10 @@ @@ -110,7 +110,7 @@ >

Progress Overview

-

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

+

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

{#if tailorError} @@ -134,10 +134,10 @@ {:else} - {#if !data.hasMappingProgress} -

No mapping progress data available. Something went wrong.

+ {#if !data.hasMatchingProgress} +

No matching progress data available. Something went wrong.

{:else} - {#if data.mappingProgress.steps.length == 0} + {#if data.matchingProgress.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.

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 a68bf98083..4f315075f7 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,11 +1,11 @@ -import type { HeaderMappings, MappingProgress } from "$lib/types/types" +import type { HeaderMappings, MatchingProgress } from "$lib/types/types" export interface ProgressOverview { success: boolean, hasHeaderMappings: boolean, - hasMappingProgress: boolean, + hasMatchingProgress: boolean, isTailored: boolean, headerMappings: HeaderMappings, - mappingProgress: MappingProgress + matchingProgress: MatchingProgress } 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 ff5b307990..f7bb884278 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 @@ -9,7 +9,7 @@ import { SlideToggle } from "@skeletonlabs/skeleton"; import EditResult from "./EditResult.svelte"; import { faPen, faMousePointer } from "@fortawesome/free-solid-svg-icons"; - import { mappingSelection } from '../../lib/stores/selectionStore'; + import { matchingSelection } from '../../lib/stores/selectionStore'; import { get } from "svelte/store"; import Fa from 'svelte-fa'; import CleanedName from "./cleanedName.svelte"; @@ -24,7 +24,7 @@ async function load() { - var responseData = await loadResult($mappingSelection.datasetId, $mappingSelection.versionId); + var responseData = await loadResult($matchingSelection.datasetId, $matchingSelection.versionId); // filter out redundant data and determine column order let filteredData: SpeciesMatchingRow[] = responseData.message.map((row: any): SpeciesMatchingRow => diff --git a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte index 82b0c0d050..894c1e2b49 100644 --- a/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte +++ b/Console/BExIS.Web.Shell/Areas/SMM/BExIS.Modules.Smm.UI.Svelte/src/routes/tailor_view/EditSubmit.svelte @@ -1,7 +1,7 @@ diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte index 1dac9bbdf9..40f7019325 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte @@ -17,7 +17,7 @@ const dispatch = createEventDispatcher(); export let path: string; export let value:any; - export let partyId:number; + let partyId:number; export let label: string; export let required: boolean = false; export let isMulti: boolean = false; @@ -56,10 +56,10 @@ const dispatch = createEventDispatcher(); if(mappingComponentConfig.partyMappingObject.complexity){ // get party id from parent - //console.log("🚀 ~ onMount ~ path:", path) + console.log("🚀 ~ onMount ~ path:", path) const parentPath = getParentPath(path); partyId = getPartyIdByPath(parentPath); - //alert(partyId); + //alert(partyId); } else { @@ -113,6 +113,10 @@ const dispatch = createEventDispatcher(); console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) const parentPathWithoutIndices = removeJsonPathIndices(parentPath); + // update parent with pary id if not already set + console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) + updateMetadataStore(parentPath, null, false, undefined, partyid); + // if mapping is complex // get all partymappings where parent path is the same as the changed one $systemMappingsStore.partyMappings.filter((mapping: any) => mapping.parentPath == parentPathWithoutIndices && mapping.path !== pathWithoutIndices).forEach(async (mapping: any) => { @@ -125,10 +129,6 @@ const dispatch = createEventDispatcher(); // update child value with new party value updateMetadataStore(childPathWithIndex, childvalue, isMulti, undefined, undefined); - // update parent with pary id if not already set - console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) - updateMetadataStore(parentPath, null, false, undefined, partyid); - // update because of validation updateValue(childvalue, childPathWithIndex) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte index ba996a7136..ab8caa4967 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte @@ -87,6 +87,10 @@ let mappingComponentConfig: MappingComponentConfig; }); } + mappingComponentConfig = getMappingComponentConfig(path, value); + + + //#### VALIDATION #### // create validation item and add to store let simpleComponentValidationItem: SimpleComponentData = createSimpleComponentValidationItem(path, label, required, simpleComponent); @@ -95,8 +99,6 @@ let mappingComponentConfig: MappingComponentConfig; ValidationStoreAddSimpleComponent(simpleComponentValidationItem); - - //#### CONFIGURATION #### config = getConfigStore(); // check if this component is an anchor point @@ -114,9 +116,7 @@ let mappingComponentConfig: MappingComponentConfig; } } - mappingComponentConfig = getMappingComponentConfig(path, value); - //console.log("🚀 ~ mappingComponentConfig:", mappingComponentConfig) - + // initial check setTimeout(async () => { @@ -163,13 +163,13 @@ let mappingComponentConfig: MappingComponentConfig; {#if isVisible && !isAnchor}
+ {#if (mappingComponentConfig && ((mappingComponentConfig.isMappedToParty && !mappingComponentConfig.isSelector) || mappingComponentConfig.isMappedToKey))} {:else if mappingComponentConfig && mappingComponentConfig.isMappedToParty && mappingComponentConfig.isSelector} + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs index ccf86b4a49..509bd34f56 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs @@ -8,6 +8,7 @@ using BExIS.Dlm.Services.Data; using BExIS.IO.Transform.Output; using BExIS.Modules.Dcm.UI.Helpers; +using BExIS.Modules.Dcm.UI.Models; using BExIS.Security.Entities.Authorization; using BExIS.UI.Helpers; using BExIS.Utils.Route; @@ -120,18 +121,25 @@ public JsonResult LoadSystemMappings(long id) // get party mappings var partymappings = mappings.Where(m => m.Target.Type == LinkElementType.PartyCustomType).ToList(); + //partymappings = partymappings.GroupBy(obj => obj.Target).Select(g => g.First()).ToList(); var keymappings = mappings.Where(m => m.Target.Type == LinkElementType.Key && ints.Contains(m.Target.ElementId)).ToList(); - var presult = partymappings.Select(m => new + List presult = new List(); + + foreach (var m in partymappings) { - Path = cleanPath(m.Source.XPath), - ParentPath = getParentPath(cleanPath(m.Source.XPath)), // use tha path from the source and create tha parent path because parent is allways one level up. - LinkElementId = m.Source.Id, - Selector = MappingUtils.PartyAttrIsMain(m.Source.ElementId, m.Source.Type), - Complexity = m.Source.ElementId != m.Parent.Source.ElementId, - List = getList(m.Source.ElementId, m.Source.Type) + PartyMappingResultModel x = new PartyMappingResultModel(); + x.Path = cleanPath(m.Source.XPath); + x.ParentPath = getParentPath(cleanPath(m.Source.XPath)); // use tha path from the source and create tha parent path because parent is allways one level up. + x.LinkElementId = m.Source.Id; + x.Selector = MappingUtils.PartyAttrIsMain(m.Source.ElementId, m.Source.Type); + x.Complexity = m.Source.ElementId != m.Parent.Source.ElementId; + x.List = getList(m.Source.ElementId, m.Source.Type); + + presult.Add(x); + } + - }).ToList(); var kresult = keymappings.Select(m => new { @@ -164,7 +172,7 @@ private List getList(long id, LinkElementType type) if (MappingUtils.PartyAttrIsMain(id, type)) { x = MappingUtils.GetAllMatchesInSystem(id, type, ""); - //x = x.Distinct(e => e.Id); + x = x.GroupBy(e => e.PartyId).Select(g => g.First()).ToList(); } return x; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/MModel.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/MModel.cs new file mode 100644 index 0000000000..17798adce4 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/MModel.cs @@ -0,0 +1,27 @@ +using BExIS.Dim.Entities.Mappings; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Dcm.UI.Models +{ + public class MModel + { + + } + + public class PartyMappingResultModel + { + public string Path { get; set; } + public string ParentPath { get; set; } + public long LinkElementId { get; set; } + + public bool Selector { get; set; } + public bool Complexity { get; set; } + + public List List { get; set; } + + public PartyMappingResultModel() { } + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/MappingHelper.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/MappingHelper.cs index 9020e78558..71e7fc778b 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/MappingHelper.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/MappingHelper.cs @@ -1008,11 +1008,11 @@ public static LinkElement CreateIfNotExistLinkElement(LinkElementModel leModel, .FirstOrDefault(le => le.ElementId.Equals(leModel.ElementId) && le.Type.Equals(leModel.Type) && - le.Complexity.Equals(leModel.Complexity) - //le.Parent.Id.Equals(parentId) + le.Complexity.Equals(leModel.Complexity)&& + le.XPath == leModel.XPath ); - if (element.XPath == null || !element.XPath.Equals(leModel.XPath)) + if (element.XPath == null/* || !element.XPath.Equals(leModel.XPath)*/) { element.XPath = leModel.XPath; mappingManager.UpdateLinkElement(element); @@ -1211,9 +1211,11 @@ private static List getParametersAsLinkElementModels(ICollecti public static bool ExistLinkElementModel(LinkElementModel leModel, List leModels) { + if (leModels.Any(le => le.ElementId.Equals(leModel.ElementId) && le.Type.Equals(leModel.Type) && - le.Complexity.Equals(leModel.Complexity))) + le.Complexity.Equals(leModel.Complexity) && + le.XPath == leModel.XPath)) { return true; } @@ -1224,13 +1226,15 @@ public static bool ExistLinkElementModel(LinkElementModel leModel, List le.ElementId.Equals(leModel.ElementId) && le.Type.Equals(leModel.Type) && - le.Complexity.Equals(leModel.Complexity))) + le.Complexity.Equals(leModel.Complexity)&& + le.XPath == leModel.XPath + )) + { return true; } From 65d51f1beb6ad27589ed221604ba2a4eb90aab64 Mon Sep 17 00:00:00 2001 From: david schoene Date: Mon, 15 Jun 2026 16:50:10 +0200 Subject: [PATCH 090/490] #2385 change upload from dropzone to filebutton and check exception --- .../routes/m/edit/MetadataFunctions.svelte | 55 ++++++++++++-- .../Controllers/MController.cs | 75 ++++++++++++------- .../Helpers/DimSeedDataGenerator.cs | 2 +- .../Mappings/MappingManager.cs | 4 +- 4 files changed, 102 insertions(+), 34 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte index c2060b58f6..12ab492947 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataFunctions.svelte @@ -1,18 +1,19 @@ @@ -162,13 +198,22 @@
-
- + +
+ Upload new metadata to update the form. This will override all unsaved changes. Current supported formats are .json and .xml. +
+ +
+ + + +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs index 509bd34f56..3de607de7c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/MController.cs @@ -7,6 +7,7 @@ using BExIS.Dlm.Entities.MetadataStructure; using BExIS.Dlm.Services.Data; using BExIS.IO.Transform.Output; +using BExIS.IO.Transform.Validation.Exceptions; using BExIS.Modules.Dcm.UI.Helpers; using BExIS.Modules.Dcm.UI.Models; using BExIS.Security.Entities.Authorization; @@ -254,7 +255,7 @@ public JsonResult Import(long id) JSchema schema; XmlMetadataConverter converter = new XmlMetadataConverter(); MetadataStructureConverter metadataStructureConverter = new MetadataStructureConverter(); - + long mdid = 0; if (contentType.Contains("xml")) { @@ -263,30 +264,45 @@ public JsonResult Import(long id) XmlDocument metadataForImport = new XmlDocument(); metadataForImport.Load(requestStream); - // metadataStructure ID + if (metadataForImport.DocumentElement.HasAttribute("id")) + { + mdid = Convert.ToInt64(metadataForImport.DocumentElement.GetAttribute("id")); + } + + if (mdid == metadataStructureId) + { + + // metadataStructure ID - var metadataStructrueName = this.GetUnitOfWork().GetReadOnlyRepository().Get(metadataStructureId).Name; + var metadataStructrueName = this.GetUnitOfWork().GetReadOnlyRepository().Get(metadataStructureId).Name; - // loadMapping file - var path_mappingFile = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DIM"), XmlMetadataImportHelper.GetMappingFileName(metadataStructureId, TransmissionType.mappingFileImport, metadataStructrueName)); + // loadMapping file + var path_mappingFile = Path.Combine(AppConfiguration.GetModuleWorkspacePath("DIM"), XmlMetadataImportHelper.GetMappingFileName(metadataStructureId, TransmissionType.mappingFileImport, metadataStructrueName)); - // XML mapper + mapping file - var xmlMapperManager = new XmlMapperManager(TransactionDirection.ExternToIntern); - xmlMapperManager.Load(path_mappingFile, "IDIV"); + // XML mapper + mapping file + var xmlMapperManager = new XmlMapperManager(TransactionDirection.ExternToIntern); + xmlMapperManager.Load(path_mappingFile, "IDIV"); - // generate intern metadata without internal attributes - var metadataResult = xmlMapperManager.Generate(metadataForImport, 1, true); + // generate intern metadata without internal attributes + var metadataResult = xmlMapperManager.Generate(metadataForImport, 1, true); - // generate intern template metadata xml with needed attribtes - var xmlMetadatWriter = new XmlMetadataWriter(BExIS.Xml.Helpers.XmlNodeMode.xPath); - var metadataXml = xmlMetadatWriter.CreateMetadataXml(metadataStructureId, - XmlUtility.ToXDocument(metadataResult)); + // generate intern template metadata xml with needed attribtes + var xmlMetadatWriter = new XmlMetadataWriter(BExIS.Xml.Helpers.XmlNodeMode.xPath); + var metadataXml = xmlMetadatWriter.CreateMetadataXml(metadataStructureId, + XmlUtility.ToXDocument(metadataResult)); - var metadataXmlTemplate = XmlMetadataWriter.ToXmlDocument(metadataXml); + var metadataXmlTemplate = XmlMetadataWriter.ToXmlDocument(metadataXml); - // set attributes FROM metadataXmlTemplate TO metadataResult - completeMetadata = XmlMetadataImportHelper.FillInXmlValues(metadataResult, - metadataXmlTemplate); + // set attributes FROM metadataXmlTemplate TO metadataResult + completeMetadata = XmlMetadataImportHelper.FillInXmlValues(metadataResult, + metadataXmlTemplate); + + } + else + { + Response.StatusCode = (int)HttpStatusCode.ExpectationFailed; + errorMessage = "The metadata ID is either invalid or does not match the expected structure ID ({metadataStructureId})."; + } #endregion application/xml } @@ -304,10 +320,10 @@ public JsonResult Import(long id) { JObject metadataJson = serializer.Deserialize(jsonReader); - long mdid = 0; + if (metadataJson.ContainsKey("@id")) { - if (Int64.TryParse(metadataJson.Property("@id").Value.ToString(), out mdid)) + if (Int64.TryParse(metadataJson.Property("@id").Value.ToString(), out mdid) && mdid == metadataStructureId) { schema = metadataStructureConverter.ConvertToJsonSchema(mdid); @@ -315,24 +331,24 @@ public JsonResult Import(long id) if (converter.HasValidStructure(metadataJson, mdid, out notAllowedElements)) { completeMetadata = converter.ConvertTo(metadataJson); - ; + } else { - HttpStatusCode statusCode = HttpStatusCode.ExpectationFailed; + Response.StatusCode = (int)HttpStatusCode.ExpectationFailed; errorMessage = "the json does not have the expected structure"; } } else { - HttpStatusCode statusCode = HttpStatusCode.ExpectationFailed; - errorMessage = "the json does not have the expected structure"; + Response.StatusCode = (int)HttpStatusCode.ExpectationFailed; + errorMessage = string.Format("The metadata ID is either invalid or does not match the expected structure ID ({0}).",metadataStructureId); } } else { - HttpStatusCode statusCode = HttpStatusCode.ExpectationFailed; + Response.StatusCode = (int)HttpStatusCode.ExpectationFailed; errorMessage = "the json does not contain any information about the metadata structure"; } } @@ -360,7 +376,14 @@ public JsonResult Import(long id) } #endregion - return Json(errorMessage); + // 2. Return the JSON error payload + return Json(new + { + success = false, + message = errorMessage, // Optional: Remove this in production for security reasons + error = errorMessage // Optional: Remove this in production for security reasons + }, JsonRequestBehavior.AllowGet); + } #region download diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs index 9a97365863..c974d598ea 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Helpers/DimSeedDataGenerator.cs @@ -1428,7 +1428,7 @@ private LinkElement createLinkELementIfNotExist( LinkElementComplexity complexity, string xpath) { - LinkElement element = mappingManager.GetLinkElement(id, name, type); + LinkElement element = mappingManager.GetLinkElement(id, name, type, xpath); if(xpath.StartsWith("/")) xpath = xpath.Substring(1); diff --git a/Modules/DIM/BExIS.Dim.Services/Mappings/MappingManager.cs b/Modules/DIM/BExIS.Dim.Services/Mappings/MappingManager.cs index ef7a1cce60..cc2bca032a 100644 --- a/Modules/DIM/BExIS.Dim.Services/Mappings/MappingManager.cs +++ b/Modules/DIM/BExIS.Dim.Services/Mappings/MappingManager.cs @@ -107,9 +107,9 @@ public LinkElement GetLinkElement(long elementid, LinkElementType type) return this.GetUnitOfWork().GetReadOnlyRepository().Get().FirstOrDefault(le => le.ElementId.Equals(elementid) && le.Type.Equals(type)); } - public LinkElement GetLinkElement(long elementid, string name, LinkElementType type) + public LinkElement GetLinkElement(long elementid, string name, LinkElementType type, string path) { - return this.GetUnitOfWork().GetReadOnlyRepository().Get().FirstOrDefault(le => le.ElementId.Equals(elementid) && le.Name.Equals(name) && le.Type.Equals(type)); + return this.GetUnitOfWork().GetReadOnlyRepository().Get().FirstOrDefault(le => le.ElementId.Equals(elementid) && le.Name.Equals(name) && le.Type.Equals(type) && le.XPath == path); } public IEnumerable GetLinkElements() From 42f665166d3324a42673a94123eda8bb1a845fbb Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 15 Jun 2026 21:20:59 +0200 Subject: [PATCH 091/490] #2500 Remove hook redirects --- .../Controllers/Hooks/AttachmentUploadController.cs | 8 +++++--- .../Controllers/Hooks/DataController.cs | 7 +++++-- .../Controllers/Hooks/DataDescriptionController.cs | 8 +++++--- .../Controllers/Hooks/FileUploadController.cs | 7 +++++-- .../Controllers/Hooks/MetadataController.cs | 7 +++++-- .../Controllers/Hooks/SubmitController.cs | 6 ++++-- .../Controllers/Hooks/ValidationController.cs | 6 ++++-- 7 files changed, 33 insertions(+), 16 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/AttachmentUploadController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/AttachmentUploadController.cs index 64e4641164..97ca5cd6dc 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/AttachmentUploadController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/AttachmentUploadController.cs @@ -44,10 +44,12 @@ public AttachmentUploadController(UserManager userManager) /// entry for hook /// /// - public ActionResult Start(long id, int version) + [JsonNetFilter] + public JsonResult Start(long id, int version) { - //return View(); - return RedirectToAction("load", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Load(id, version); + return jsonResult; } // GET: FileUpload diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataController.cs index ebcefb2df8..4d137236bb 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataController.cs @@ -21,9 +21,12 @@ namespace BExIS.Modules.Dcm.UI.Controllers public class DataController : Controller { // GET: Data - public ActionResult Start(long id, int version) + [JsonNetFilter] + public JsonResult Start(long id, int version) { - return RedirectToAction("load", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Load(id, version ); + return jsonResult; } [JsonNetFilter] diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs index 11643a4d0e..7e36557827 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs @@ -30,10 +30,12 @@ public class DataDescriptionController : Controller /// entry for hook /// /// - public ActionResult Start(long id, int version) + [JsonNetFilter] + public JsonResult Start(long id, int version) { - //return View(); - return RedirectToAction("load", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Load(id, version); + return jsonResult; } // GET: FileUpload diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/FileUploadController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/FileUploadController.cs index 78723e68e3..2285566f41 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/FileUploadController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/FileUploadController.cs @@ -34,9 +34,12 @@ public class FileUploadController : Controller /// entry for hook /// /// - public ActionResult Start(long id, int version) + [JsonNetFilter] + public JsonResult Start(long id, int version) { - return RedirectToAction("load", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Load(id, version); + return jsonResult; } // GET: FileUpload diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/MetadataController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/MetadataController.cs index 2b61d49c21..2976cdf622 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/MetadataController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/MetadataController.cs @@ -12,9 +12,12 @@ public class MetadataController : Controller { [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Write)] - public ActionResult Start(long id, int version) + [JsonNetFilter] + public JsonResult Start(long id, int version) { - return RedirectToAction("load", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Load(id, version); + return jsonResult; } [JsonNetFilter] diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/SubmitController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/SubmitController.cs index b2515a7093..3dd27eddb9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/SubmitController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/SubmitController.cs @@ -46,9 +46,11 @@ public ActionResult Index() /// [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Write)] [JsonNetFilter] - public ActionResult Start(long id, int version = 0) + public JsonResult Start(long id, int version) { - return RedirectToAction("Load", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Load(id, version); + return jsonResult; } [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Write)] diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/ValidationController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/ValidationController.cs index efec39b6a8..be59fc9c2c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/ValidationController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/ValidationController.cs @@ -44,9 +44,11 @@ public ActionResult Index() /// [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Write)] [JsonNetFilter] - public ActionResult Start(long id, int version = 0) + public JsonResult Start(long id, int version) { - return RedirectToAction("Validate", new { id, version }); + // return RedirectToAction("load", new { id, version }); + var jsonResult = Validate(id, version); + return jsonResult; } [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Write)] From a751fc93ff49bb145e97964df38ce859d355c657 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 15 Jun 2026 21:50:40 +0200 Subject: [PATCH 092/490] #2490 Reduce calls for Submit and change messages --- .../src/lib/hooks/Attachment.svelte | 11 +- .../src/lib/hooks/DataDescription.svelte | 61 ++-- .../src/lib/hooks/Submit.svelte | 282 +++++++++++------- .../src/models/SubmitModels.ts | 5 +- 4 files changed, 221 insertions(+), 138 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Attachment.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Attachment.svelte index 64858309fd..fbcbff8807 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Attachment.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Attachment.svelte @@ -21,9 +21,9 @@ let model: FileUploadModel; $: model; - onMount(async () => { - load(); - }); + let mounted = false; + + $: loading = false; $: existError = false; @@ -31,6 +31,7 @@ const dispatch = createEventDispatcher(); async function load() { + model = await getHookStart(hook.start, id, version); start = hook.start; @@ -39,7 +40,9 @@ async function reload(e) { /* load data*/ - load(); + + await load(); + } function success(e) { diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte index 2759ce8902..0fbee0b51c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte @@ -17,47 +17,52 @@ let model: DataDescriptionModel; $: model; $: loading = false; + let isMounted = false; // Flag to track if the component has been mounted + // Reactive statement: Only runs if isMounted is true AND the store changes + $: if (isMounted && $latestFileUploadDate > 0) { + reloadByFileUpdate(); + } + + $: if (isMounted && $latestDataDescriptionDate > 0) { + load(); + } + + let errorMessage: any = null; const dispatch = createEventDispatcher(); onMount(async () => { - load(); - latestFileUploadDate.subscribe((s) => { - if (s > 0) { - reloadByFileUpdate(); - } - }); - latestDataDescriptionDate.subscribe((s) => { - if (s > 0) { - reload(); - } - }); + await load(); + isMounted = true; }); async function load() { - model = await getHookStart(hook.start, id, version); + loading = true; + try { + model = await getHookStart(hook.start, id, version); + dispatch('dateChanged', { lastModification: model.lastModification }); + } catch (error) { + console.error("Failed to fetch data description:", error); + errorMessage = error; + } finally { + loading = false; + } + } - dispatch('dateChanged', { lastModification: model.lastModification }); + async function reloadByFileUpdate() { + if (model && model.structureId === 0) { + await load(); + } } - async function reload() { - load(); - } - - async function reloadByFileUpdate() { - // only when strutcure is not set update model - if (model && model.structureId == 0) { - load(); - } - } -{#await getHookStart(hook.start, id, version)} +{#if loading} -{:then a} +{:else if model} {#if model && model.structureId > 0} @@ -75,6 +80,6 @@ {:else} not available {/if} -{:catch error} - -{/await} +{:else if errorMessage} + +{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte index d632e82d3b..c4a7ad732c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte @@ -3,9 +3,8 @@ import { getHookStart } from '$services/HookCaller'; import { submit } from '../../routes/edit/services'; import type { SubmitModel, submitResponceType } from '$models/SubmitModels'; - import GoToView from '$lib/components/submit/GoTo.svelte'; - import { Modal, getModalStore } from '@skeletonlabs/skeleton'; + import { getModalStore } from '@skeletonlabs/skeleton'; const modalStore = getModalStore(); import type { ModalSettings } from '@skeletonlabs/skeleton'; @@ -19,97 +18,107 @@ } from '../../routes/edit/stores'; import { onMount, createEventDispatcher } from 'svelte'; - import { goto } from '$app/navigation'; - import PlaceHolderHookContent from './placeholder/PlaceHolderHookContent.svelte'; export let id = 0; export let version = 1; - export let status = 0; - export let displayName = ''; export let start = ''; - export let description = ''; const dispatch = createEventDispatcher(); let model: SubmitModel; $: model; + // boolean to control if submit button should be enabled based on the content of the submit model let canSubmit: boolean = false; $: canSubmit; + // boolean to control if submit is in progress to disable button and show loading state let isSubmitting: boolean = false; - onMount(async () => { - latestFileUploadDate.subscribe((s) => { - if (s > 0) { - reload(); - } - }); - latestDataDescriptionDate.subscribe((s) => { - if (s > 0) { - reload(); - } - }); - latestFileReaderDate.subscribe((s) => { - if (s > 0) { - reload(); - } - }); - latestValidationDate.subscribe((s) => { - if (s > 0) { - reload(); - } - }); + // text for submit button and confirm modal, will be set based on the content of the submit model in the activateSubmit function + let submitText = ''; + let confirmText = 'Please confirm if you wish to proceed.'; - latestDataDate.subscribe((s) => { - console.log('🚀 ~ latestDataDate.subscribe ~ s:', s); + // only run reactive reloads after initial load has completed + let mounted = false; - if (s > 0) { - reload(); - } - }); + // loading state for initial load and reloads, to show spinner and avoid showing stale data while loading + let loading = true; + + // timeout reference for debounced reloads to avoid multiple reloads in quick succession when multiple stores are updated + let reloadTimeout: NodeJS.Timeout; + + // array of store values to trigger reactive reload when any of them changes, used in combination with the mounted flag to only trigger reloads after initial load is done + $: storeTriggers = [ + $latestFileUploadDate, + $latestDataDescriptionDate, + $latestFileReaderDate, + $latestValidationDate, + $latestDataDate + ]; + $: if (mounted && storeTriggers.some((date) => date > 0)) { + debouncedReload(); + } + + // function to debounce reloads when multiple store values are updated in quick succession, to avoid multiple reloads and only reload once after all updates are done + function debouncedReload() { + // Clear any previous scheduled reload + clearTimeout(reloadTimeout); + + // Schedule a new reload 50ms from now + reloadTimeout = setTimeout(() => { + console.log('Debounced reload triggered'); + reload(); + }, 50); + } + + onMount(async () => { + mounted = true; }); + // function to load the submit model from the server based on the hook start action and update the canSubmit state based on the content of the model async function reload() { - console.log('reload submit', start, id, version); - console.log('latestDataDate', latestDataDate); + //console.trace('reload submit', start, id, version); + + loading = true; + //console.log('reload submit', start, id, version); + //console.log('latestDataDate', latestDataDate); + + // Clear the model to show loading state (null is not working) + model = {} as SubmitModel; canSubmit = false; - console.log(' before hook'); + // isSubmitting = false; + //console.log(' before hook'); model = await getHookStart(start, id, version); - console.log(' before activateSubmit', canSubmit); - - canSubmit = activateSubmit(); - console.log(' after activateSubmit', canSubmit); + //console.log(' before activateSubmit', canSubmit); - console.log('reload submit', model); + canSubmit = await activateSubmit(); + //console.log(' after activateSubmit', canSubmit); - return model; + loading = false; + // return model; } - const confirm: ModalSettings = { - type: 'confirm', - title: 'Submit', - body: 'Are you sure you wish to submit the data?

Editing will be disabled until the import is complete. If you are importing a large amount of tabular data it may take a while. You will be notified by email when it is complete.

Once the import is complete, please check the imported data. ', - // TRUE if confirm pressed, FALSE if cancel pressed - response: (r: boolean) => { - if (r === true) { - submitBt(); - // modalStore.trigger(next); - // dispatch('success', { text: 'The import of your data has been started.' }); - } - } - }; + // function to open a confirm modal before submitting, the modal will call the submitBt function if the user confirms + function openConfirmModal() { + const confirm: ModalSettings = { + type: 'confirm', + title: submitText, + body: confirmText, - const next: ModalSettings = { - type: 'alert', - title: 'Import started', - body: 'Editing will be disabled until the import is complete. If you are importing a large amount of tabular data it may take a while. You will be notified by email when it is complete.

Once the import is complete, please check the imported data you have uploaded. ', - buttonTextCancel: 'Ok' - // TRUE if confirm pressed, FALSE if cancel pressed - }; + // TRUE if confirm pressed, FALSE if cancel pressed + response: (r: boolean) => { + if (r === true) { + submitBt(); + } + } + }; + modalStore.trigger(confirm); + } + // function to call the submit API and handle the response, showing success or error messages based on the result and updating the stores to trigger reloads of the data after submit async function submitBt() { isSubmitting = true; canSubmit = false; @@ -125,80 +134,145 @@ } isSubmitting = false; setTimeout(() => { - // update store - latestSubmitDate.set(Date.now()); - - console.log('goto view'); - }, 500); - + latestSubmitDate.set(Date.now()); + // reload to update view after submit + }, 1000); } } - // return a boolean value for 2 different cases for submit - //1. upload files only - //2. updload data with data structure - function activateSubmit() { - //check use case 1 + // function to determine if submit button should be enabled and set the submit button text based on the content of the submit model, this is a simplified example and should be adapted to the actual use cases and model content + async function activateSubmit() { + var returnValue = false; + // File Upload without structure console.log('🚀 ~ activateSubmit ~ model:', model); if (model.hasStructrue == false && model.files.length > 0) { - return true; + submitText = 'Import File(s)'; + returnValue = true; } - //check use case 2 + // Update Description of a file if (model.hasStructrue == false && model.modifiedFiles?.length > 0) { - return true; + if (submitText.includes('Import File(s)')) { + submitText = 'Import and Update Description'; + } else { + submitText = 'Update Description'; + returnValue = true; + } } - //check use case 3 - console.log( - '🚀 ~ activateSubmit ~ model.hasStructrue:', - model.hasStructrue, - model.deletedFiles - ); + // Delete Files if (model.hasStructrue == false && model.deleteFiles?.length > 0) { + if (submitText.includes('Import File(s)') || submitText.includes('Update Description')) { + submitText += ' and Delete File(s)'; + } else { + submitText = 'Delete File(s)'; + } return true; } - //check use case 4 + // File Upload with structure if ( model.hasStructrue == true && model.files.length > 0 && model.allFilesReadable && model.isDataValid ) { - return true; + if ( + submitText.includes('Import File(s)') || + submitText.includes('Update Description') || + submitText.includes('Delete File(s)') + ) { + submitText += ' and Start import/update of tabular data'; + } else { + submitText = 'Start adding/update of tabular data'; + } + ((confirmText = + 'Editing will be disabled until the import is complete. If you are importing a large amount of tabular data it may take a while. You will be notified by email when it is complete.

Once the import is complete, please check the imported data. '), + (returnValue = true)); } - return false; + return returnValue; } -{#await reload()} +{#if loading} -{:then m} -
- {#if !isSubmitting && !canSubmit} +{:else} + {#if !isSubmitting && canSubmit} +
+ {#if canSubmit && model.modifiedFiles?.length > 0} + + {/if} +
+
+ {#if model.hasStructrue == false && model.files.length > 0} + + {/if} +
+
+ {#if model.hasStructrue == false && model.deleteFiles?.length > 0} + + {/if} +
+
+ {#if model.hasStructrue == true && model.files.length > 0 && model.allFilesReadable && model.isDataValid} + + {/if} +
+ {#if !isSubmitting && !canSubmit} + {:else} - + {/if} - {#if isSubmitting} + {#if isSubmitting && !canSubmit}
- {:else if canSubmit} -
Please click submit to start import.
{/if}
-{:catch error} - -{/await} +{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/SubmitModels.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/SubmitModels.ts index 24fd89ace2..da242dcc6d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/SubmitModels.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/SubmitModels.ts @@ -1,7 +1,8 @@ -import { asciiFileReaderInfoType, fileInfoType } from '@bexis2/bexis2-core-ui'; -import { sortedError } from './Models'; +import type { asciiFileReaderInfoType, fileInfoType } from '@bexis2/bexis2-core-ui'; +import type { sortedError } from './Models'; export interface SubmitModel { + deletedFiles: fileInfoType[]; id: number; title: string; isDataValid: boolean; From e9ed64b3c4d35e4f8b7808428407b29987ac6bdc Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 15 Jun 2026 21:53:46 +0200 Subject: [PATCH 093/490] #2437 #2414 Remove description changed message --- .../src/lib/components/data/Files.svelte | 9 ++++---- .../datadescription/NameTableCol.svelte | 5 +++-- .../components/fileupload/FileOverview.svelte | 4 ++++ .../fileupload/FileOverviewItem.svelte | 10 ++++++++- .../src/lib/hooks/FileUpload.svelte | 22 +++++++++---------- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte index fc3e32a7db..4dc7de3656 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/Files.svelte @@ -25,7 +25,9 @@ function handleSave(e) { console.log('handleSave', e); latestDataDate.set(Date.now()); - dispatch('success', { text: e.detail.text }); + if (e.detail.text != "noAltertText") { + dispatch('success', { text: e.detail.text }); + } } function handleRemove(e) { console.log('handleRemove', e.detail.file); @@ -85,6 +87,7 @@ {id} bind:files {descriptionType} + descriptionSave={false} {remove} {save} on:success={handleSave} @@ -95,9 +98,6 @@ {#if deletedFiles && deletedFiles.length > 0}
-
File(s) to delete
@@ -110,6 +110,7 @@ {...file} remove={revert} {descriptionType} + descriptionSave={false} faIcon={faUndo} on:removed={handleRevert} /> diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/NameTableCol.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/NameTableCol.svelte index 808f55e4fc..741d47d574 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/NameTableCol.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/NameTableCol.svelte @@ -5,12 +5,13 @@ export let value; export let row; - console.log(row); + // console.log(row);
{value} {#if row.original.isKeys} - + {/if} +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverview.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverview.svelte index 1b91b07cb2..fd93328347 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverview.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverview.svelte @@ -14,6 +14,8 @@ // add description to file display row export let descriptionType; + export let descriptionSave = true; + let withDescription: boolean; const dispatch = createEventDispatcher(); @@ -42,6 +44,7 @@ } async function handleSave(e) { + dispatch('success', { text: e.detail.text }); } @@ -79,6 +82,7 @@ on:removed={(e) => handleRemoveFile(e, index)} on:saved={handleSave} {withDescription} + {descriptionSave} /> {/each} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte index 887639b169..9c2131c1e6 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/fileupload/FileOverviewItem.svelte @@ -12,6 +12,7 @@ export let file: FileInfo; export let withDescription; + export let descriptionSave = true; const dispatch = createEventDispatcher(); // action to save description @@ -44,9 +45,16 @@ } async function handleSaveFileDescription() { + const res = await saveFileDescription(save, id, file); if (res) { - let message = 'Description of ' + file.name + ' was updated.'; + let message = ''; + if (!descriptionSave) { + message = "noAltertText"; + } + else{ + message = 'Description of ' + file.name + ' was updated.'; + } dispatch('saved', { text: message }); } } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte index f0bca7e0c1..e4466ab431 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/FileUpload.svelte @@ -48,12 +48,14 @@ mounted = true; }); - $: loading = false; + $: loading = true; const dispatch = createEventDispatcher(); async function load() { + loading = true; model = await getHookStart(hook.start, id, version); + console.log('🚀 ~ load ~ model .aaaa:', model); start = hook.start; loading = false; @@ -87,9 +89,9 @@
- {#await load()} + {#if loading} - {:then result} + {:else} - {#if model.fileUploader.existingFiles.length} - - + {#if model.fileUploader.existingFiles.length > 0}
File(s) ready for tabular data / file import @@ -115,6 +113,7 @@ {id} files={model.fileUploader.existingFiles} descriptionType={model.fileUploader.descriptionType} + descriptionSave={false} {save} {remove} on:success={success} @@ -129,7 +128,8 @@ /> {/if} {/if} - {:catch error} - - {/await} + {#if error} + + {/if} + {/if}
From f5efa930a9301da88e8891e0dd6713d69798b6a8 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 15 Jun 2026 21:55:50 +0200 Subject: [PATCH 094/490] #2465 Search Card View: Add dataset ID --- .../src/lib/components/Card.svelte | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Card.svelte b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Card.svelte index cf5f5b05ba..9557250d7c 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Card.svelte +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Card.svelte @@ -93,14 +93,22 @@ {#if title && title.length > 0} {title} {/if} + - +
+

+ + ID: + {id} + +

{#if date && date.length > 0} - {dateLabel}: + {dateLabel}: {date} {/if}

+

From 760ff6e401b9fba6ebc31a55903251b30bdf7ab5 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Tue, 16 Jun 2026 00:06:29 +0200 Subject: [PATCH 095/490] #2490 Remove the reload artefact --- .../src/lib/hooks/Submit.svelte | 68 ++++++++++++------- 1 file changed, 44 insertions(+), 24 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte index c4a7ad732c..b4489d8130 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Submit.svelte @@ -35,6 +35,9 @@ // boolean to control if submit is in progress to disable button and show loading state let isSubmitting: boolean = false; + // boolean to prevent the "Done..." message from showing a second time after the store reload runs + let hasSubmitted: boolean = false; + // text for submit button and confirm modal, will be set based on the content of the submit model in the activateSubmit function let submitText = ''; let confirmText = 'Please confirm if you wish to proceed.'; @@ -95,6 +98,9 @@ //console.log(' before activateSubmit', canSubmit); canSubmit = await activateSubmit(); + if (canSubmit) { + hasSubmitted = false; + } //console.log(' after activateSubmit', canSubmit); loading = false; @@ -122,6 +128,7 @@ async function submitBt() { isSubmitting = true; canSubmit = false; + hasSubmitted = false; // reset in case of retry const res: submitResponceType = await submit(id); //console.log("submit",res); @@ -134,6 +141,7 @@ } isSubmitting = false; setTimeout(() => { + hasSubmitted = true; // update store latestSubmitDate.set(Date.now()); // reload to update view after submit @@ -144,7 +152,7 @@ // function to determine if submit button should be enabled and set the submit button text based on the content of the submit model, this is a simplified example and should be adapted to the actual use cases and model content async function activateSubmit() { var returnValue = false; - // File Upload without structure + // File Upload without structure console.log('🚀 ~ activateSubmit ~ model:', model); if (model.hasStructrue == false && model.files.length > 0) { submitText = 'Import File(s)'; @@ -161,7 +169,7 @@ } } - // Delete Files + // Delete Files if (model.hasStructrue == false && model.deleteFiles?.length > 0) { if (submitText.includes('Import File(s)') || submitText.includes('Update Description')) { submitText += ' and Delete File(s)'; @@ -171,7 +179,7 @@ return true; } - // File Upload with structure + // File Upload with structure if ( model.hasStructrue == true && model.files.length > 0 && @@ -203,12 +211,14 @@

{#if canSubmit && model.modifiedFiles?.length > 0} @@ -217,12 +227,14 @@
{#if model.hasStructrue == false && model.files.length > 0} {/if} @@ -230,12 +242,14 @@
{#if model.hasStructrue == false && model.deleteFiles?.length > 0} {/if} @@ -243,25 +257,31 @@
{#if model.hasStructrue == true && model.files.length > 0 && model.allFilesReadable && model.isDataValid} {/if}
{/if}
- {#if !isSubmitting && !canSubmit} - \ No newline at end of file From bc0a778640eaf992607e82389d811ab09d213cca Mon Sep 17 00:00:00 2001 From: geofranzi Date: Tue, 16 Jun 2026 23:52:15 +0200 Subject: [PATCH 105/490] #2505 Add SessionState(SessionStateBehavior.ReadOnly --- .../Controllers/ComponentConfigController.cs | 3 +++ .../Controllers/CreateController.cs | 4 +++- .../Controllers/EditController.cs | 5 +++- .../Controllers/EntityTemplatesController.cs | 3 +++ .../Controllers/TagInfoController.cs | 2 ++ .../Controllers/ConstraintsController.cs | 2 ++ .../Controllers/DataStructureController.cs | 3 +++ .../Controllers/DataTypeController.cs | 2 ++ .../Controllers/DimensionController.cs | 3 +++ .../Controllers/ExternalLinkController.cs | 3 +++ .../Controllers/FileController.cs | 3 +++ .../Controllers/MeaningController.cs | 3 +++ .../Controllers/StructuresController.cs | 2 ++ .../Controllers/UnitController.cs | 3 +++ .../Controllers/VariableTemplateController.cs | 2 ++ .../Controllers/AccountController.cs | 7 ++++++ .../Controllers/FooterController.cs | 2 ++ .../Controllers/HeaderController.cs | 2 ++ .../Controllers/HelpController.cs | 2 ++ .../Controllers/HomeController.cs | 2 ++ .../Controllers/JSController.cs | 2 ++ .../Controllers/MenuController.cs | 23 +++++++++++++++---- .../Controllers/SettingsController.cs | 2 ++ .../Controllers/TokensController.cs | 2 ++ 24 files changed, 80 insertions(+), 7 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ComponentConfigController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ComponentConfigController.cs index 9db541e92e..f32cd8dc93 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ComponentConfigController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ComponentConfigController.cs @@ -4,11 +4,14 @@ using System.Collections.Generic; using System.IO; using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Utils.Cfg; namespace BExIS.Modules.Dcm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class ComponentConfigController : Controller { public ActionResult Index(long id = 0) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs index bff9d489a1..b671917ab6 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/CreateController.cs @@ -1,4 +1,4 @@ -using BExIS.App.Bootstrap.Attributes; +using BExIS.App.Bootstrap.Attributes; using BExIS.Dim.Entities.Mappings; using BExIS.Dim.Helpers.Mappings; using BExIS.Dim.Services.Mappings; @@ -29,9 +29,11 @@ using System.Xml.XPath; using Vaiona.Entities.Common; using BExIS.Utils.Config; +using System.Web.SessionState; namespace BExIS.Modules.Dcm.UI.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class CreateController : Controller { private readonly UserManager _userManager; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs index a2e089b1a2..38b76c17e7 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs @@ -9,12 +9,15 @@ using System; using System.Collections.Generic; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Dcm.UI.Controllers -{ +{ + [SessionState(SessionStateBehavior.ReadOnly)] public class EditController : Controller { // GET: Edit + [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Write)] public ActionResult Index(long id, int version = 0) { diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs index 8d2ce0a23a..455f32313a 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs @@ -18,11 +18,14 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; using Telerik.Web.Mvc.Extensions; using Vaiona.Web.Extensions; namespace BExIS.Modules.Dcm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class EntityTemplatesController : Controller { private readonly GroupManager _groupManager; diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/TagInfoController.cs b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/TagInfoController.cs index 109b78ab16..9e77aa8c14 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/TagInfoController.cs +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/TagInfoController.cs @@ -15,6 +15,7 @@ using System.Linq; using System.Web.Mvc; using System.Web.Routing; +using System.Web.SessionState; using Telerik.Web.Mvc.Extensions; using Vaiona.Web.Mvc; using Vaiona.Web.Mvc.Modularity; @@ -22,6 +23,7 @@ namespace BExIS.Modules.Ddm.UI.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class TagInfoController : BaseController { private readonly UserManager _userManager; diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ConstraintsController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ConstraintsController.cs index 552c031f44..fc86ae40a8 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ConstraintsController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ConstraintsController.cs @@ -16,10 +16,12 @@ using System.Data; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; using System.Web.UI.WebControls; namespace BExIS.Modules.Rpm.UI.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class ConstraintsController : Controller { private readonly UserManager _userManager; diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataStructureController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataStructureController.cs index 191624313d..45b317e2fe 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataStructureController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataStructureController.cs @@ -26,6 +26,7 @@ using System.Text; using System.Web; using System.Web.Mvc; +using System.Web.SessionState; using System.Web.UI.HtmlControls; using Vaiona.Utils.Cfg; using Vaiona.Web.Mvc.Data; @@ -33,6 +34,8 @@ namespace BExIS.Modules.Rpm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class DataStructureController : Controller { public ActionResult Index() diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataTypeController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataTypeController.cs index 0c91dcada1..2abfe8e392 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataTypeController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DataTypeController.cs @@ -8,9 +8,11 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Rpm.UI.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class DataTypeController : Controller { public ActionResult Index() diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DimensionController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DimensionController.cs index 38aec4d6cf..143fdb5e82 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DimensionController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/DimensionController.cs @@ -7,9 +7,12 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Rpm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class DimensionController : Controller { public ActionResult Index() diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ExternalLinkController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ExternalLinkController.cs index 19885e609c..1a6dc30039 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ExternalLinkController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/ExternalLinkController.cs @@ -9,9 +9,12 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Rpm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class ExternalLinkController : Controller { // GET: ExternalLink diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/FileController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/FileController.cs index 1c6a478061..9a57ed551e 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/FileController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/FileController.cs @@ -11,6 +11,7 @@ using System.Linq; using System.Web; using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Utils.Cfg; using Vaiona.Web.Mvc.Data; using BExIS.UI.Models; @@ -19,6 +20,8 @@ namespace BExIS.Modules.Rpm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class FileController : Controller { // GET: File diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/MeaningController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/MeaningController.cs index b2e879c445..739e02d2e4 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/MeaningController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/MeaningController.cs @@ -9,9 +9,12 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Rpm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class MeaningController : Controller { // GET: Meanings diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/StructuresController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/StructuresController.cs index 8b6131a5ce..36b43a36db 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/StructuresController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/StructuresController.cs @@ -6,10 +6,12 @@ using System.Net; using System.Web.Http; using System.Web.Http.Description; +using System.Web.SessionState; using Vaiona.Persistence.Api; namespace BExIS.Modules.Rpm.UI.Controllers { + [System.Web.Mvc.SessionState(SessionStateBehavior.ReadOnly)] public class StructuresController : ApiController { // GET: api/Structures diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/UnitController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/UnitController.cs index c01ed1ed43..0ea6eb0a12 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/UnitController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/UnitController.cs @@ -14,9 +14,12 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Rpm.UI.Controllers { + + [SessionState(SessionStateBehavior.ReadOnly)] public class UnitController : Controller { public ActionResult Index() diff --git a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/VariableTemplateController.cs b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/VariableTemplateController.cs index 71198b1568..02921bab88 100644 --- a/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/VariableTemplateController.cs +++ b/Console/BExIS.Web.Shell/Areas/RPM/BExIS.Modules.Rpm.UI/Controllers/VariableTemplateController.cs @@ -9,9 +9,11 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Modules.Rpm.UI.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class VariableTemplateController : Controller { // GET: VariableTemplate diff --git a/Console/BExIS.Web.Shell/Controllers/AccountController.cs b/Console/BExIS.Web.Shell/Controllers/AccountController.cs index f66504aabd..ec32b43729 100644 --- a/Console/BExIS.Web.Shell/Controllers/AccountController.cs +++ b/Console/BExIS.Web.Shell/Controllers/AccountController.cs @@ -331,6 +331,13 @@ public async Task Login(LoginViewModel model, string returnUrl) authManager.SignIn(new AuthenticationProperties { IsPersistent = model.RememberMe }, new ClaimsIdentity(identity) ); + // Forcefully remove the old cache if it exists + string cacheKey = "Menu_" + user.UserName; + if (HttpContext.Cache[cacheKey] != null) + { + HttpContext.Cache.Remove(cacheKey); + } + return RedirectToLocal(returnUrl); case SignInStatus.LockedOut: diff --git a/Console/BExIS.Web.Shell/Controllers/FooterController.cs b/Console/BExIS.Web.Shell/Controllers/FooterController.cs index 2cf514bd70..7dc9371fc2 100644 --- a/Console/BExIS.Web.Shell/Controllers/FooterController.cs +++ b/Console/BExIS.Web.Shell/Controllers/FooterController.cs @@ -1,9 +1,11 @@ using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Web.Extensions; using Vaiona.Web.Mvc.Models; namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class FooterController : Controller { // GET: footer diff --git a/Console/BExIS.Web.Shell/Controllers/HeaderController.cs b/Console/BExIS.Web.Shell/Controllers/HeaderController.cs index f40a3ec521..1b49f04925 100644 --- a/Console/BExIS.Web.Shell/Controllers/HeaderController.cs +++ b/Console/BExIS.Web.Shell/Controllers/HeaderController.cs @@ -1,8 +1,10 @@ using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Web.Extensions; namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class HeaderController : Controller { // GET: Header diff --git a/Console/BExIS.Web.Shell/Controllers/HelpController.cs b/Console/BExIS.Web.Shell/Controllers/HelpController.cs index c257f11011..e5089eabf2 100644 --- a/Console/BExIS.Web.Shell/Controllers/HelpController.cs +++ b/Console/BExIS.Web.Shell/Controllers/HelpController.cs @@ -1,9 +1,11 @@ using BExIS.UI.Helpers; using BExIS.Utils.Config; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class HelpController : Controller { // GET: Help diff --git a/Console/BExIS.Web.Shell/Controllers/HomeController.cs b/Console/BExIS.Web.Shell/Controllers/HomeController.cs index 7c2f69b462..8e134c20bf 100644 --- a/Console/BExIS.Web.Shell/Controllers/HomeController.cs +++ b/Console/BExIS.Web.Shell/Controllers/HomeController.cs @@ -12,6 +12,7 @@ using System.IO; using System.Web; using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Web.Extensions; using Vaiona.Web.Mvc.Data; using Vaiona.Web.Mvc.Models; @@ -19,6 +20,7 @@ namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class HomeController : Controller { private readonly UserManager _userManager; diff --git a/Console/BExIS.Web.Shell/Controllers/JSController.cs b/Console/BExIS.Web.Shell/Controllers/JSController.cs index f67e2a2590..e324b680ca 100644 --- a/Console/BExIS.Web.Shell/Controllers/JSController.cs +++ b/Console/BExIS.Web.Shell/Controllers/JSController.cs @@ -1,7 +1,9 @@ using System.Web.Mvc; +using System.Web.SessionState; namespace SessionTimeout.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class JSController : Controller { // GET: JS diff --git a/Console/BExIS.Web.Shell/Controllers/MenuController.cs b/Console/BExIS.Web.Shell/Controllers/MenuController.cs index 9bdc2c940d..5d470d6d26 100644 --- a/Console/BExIS.Web.Shell/Controllers/MenuController.cs +++ b/Console/BExIS.Web.Shell/Controllers/MenuController.cs @@ -1,4 +1,4 @@ -using BExIS.App.Bootstrap.Extensions; +using BExIS.App.Bootstrap.Extensions; using BExIS.App.Bootstrap.Helpers; using BExIS.Security.Entities.Subjects; using BExIS.Security.Services.Subjects; @@ -9,10 +9,12 @@ using System.Linq; using System.Web; using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Web.Extensions; namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class MenuController : Controller { private readonly UserManager _userManager; @@ -53,9 +55,10 @@ public JsonResult Index() } - if (Session["Menu"] != null) + string cacheKey = $"Menu_{userName}"; + if (isAuthenticated && HttpContext.Cache[cacheKey] != null) { - return Json((Menu)Session["Menu"], JsonRequestBehavior.AllowGet); + return Json((Menu)HttpContext.Cache[cacheKey], JsonRequestBehavior.AllowGet); } @@ -82,8 +85,18 @@ public JsonResult Index() if (Session.GetTenant().ExtendedMenus != null) menu.Extended = MenuHelper.ExtendedMenu(Session.GetTenant().ExtendedMenus.Element("ExtendedMenu")); - // set menu to session if user is authenticated - if(!string.IsNullOrEmpty(userName) && isAuthenticated) Session["Menu"] = menu; + // set menu to cache if user is authenticated + if (!string.IsNullOrEmpty(userName) && isAuthenticated) + { + // This expires exactly 20 minutes from now, no matter what + HttpContext.Cache.Insert( + cacheKey, + menu, + null, + DateTime.Now.AddMinutes(20), // Absolute expiration set to 20 mins + System.Web.Caching.Cache.NoSlidingExpiration // Disable sliding expiration +); + } return Json(menu, JsonRequestBehavior.AllowGet); } diff --git a/Console/BExIS.Web.Shell/Controllers/SettingsController.cs b/Console/BExIS.Web.Shell/Controllers/SettingsController.cs index b64ba46a0e..48d7ce5f32 100644 --- a/Console/BExIS.Web.Shell/Controllers/SettingsController.cs +++ b/Console/BExIS.Web.Shell/Controllers/SettingsController.cs @@ -8,12 +8,14 @@ using System.Collections.Generic; using System.Linq; using System.Web.Mvc; +using System.Web.SessionState; using Vaiona.Utils.Cfg; using Vaiona.Web.Mvc.Modularity; using ModuleSettings = Vaiona.Web.Mvc.Modularity.ModuleSettings; namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class SettingsController : Controller { private readonly UserManager _userManager; diff --git a/Console/BExIS.Web.Shell/Controllers/TokensController.cs b/Console/BExIS.Web.Shell/Controllers/TokensController.cs index 937462869e..be0f291cf0 100644 --- a/Console/BExIS.Web.Shell/Controllers/TokensController.cs +++ b/Console/BExIS.Web.Shell/Controllers/TokensController.cs @@ -13,9 +13,11 @@ using System.Threading.Tasks; using System.Web.Helpers; using System.Web.Mvc; +using System.Web.SessionState; namespace BExIS.Web.Shell.Controllers { + [SessionState(SessionStateBehavior.ReadOnly)] public class TokensController : Controller { private readonly UserManager _userManager; From 202db47d65be95061028908f817f514a74482fd5 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Wed, 17 Jun 2026 09:40:09 +0200 Subject: [PATCH 106/490] #2505 undo session readonly for settings --- Console/BExIS.Web.Shell/Controllers/SettingsController.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/Console/BExIS.Web.Shell/Controllers/SettingsController.cs b/Console/BExIS.Web.Shell/Controllers/SettingsController.cs index 48d7ce5f32..4d3ee9d57c 100644 --- a/Console/BExIS.Web.Shell/Controllers/SettingsController.cs +++ b/Console/BExIS.Web.Shell/Controllers/SettingsController.cs @@ -15,7 +15,6 @@ namespace BExIS.Web.Shell.Controllers { - [SessionState(SessionStateBehavior.ReadOnly)] public class SettingsController : Controller { private readonly UserManager _userManager; From 3ef08638992dd7d84248a050775420c472fd711a Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 18 Jun 2026 11:50:20 +0200 Subject: [PATCH 107/490] #2385 change update metadata by subscribtion via store, change input container by bexis2.core.ui update --- Console/BExIS.Web.Shell.Svelte/package.json | 2 +- .../BExIS.Modules.Dcm.UI.Svelte/package.json | 2 +- .../utils/metadata/metadataComponentUtils.ts | 4 +- .../src/routes/m/edit/PartySelector.svelte | 18 +- .../m/edit/complexComponentWrapper.svelte | 16 +- .../src/routes/m/edit/simpleComponent.svelte | 419 +++++++++--------- .../m/edit/simpleComponentWrapper.svelte | 7 + .../Controllers/MController.cs | 3 +- .../BExIS.Modules.Ddm.UI.Svelte/package.json | 2 +- .../BExIS.Modules.Dim.UI.Svelte/package.json | 2 +- .../BExIS.Modules.Pum.UI.Svelte/package.json | 2 +- .../BExIS.Modules.Rpm.UI.Svelte/package.json | 2 +- pnpm-lock.yaml | 52 +-- 13 files changed, 255 insertions(+), 276 deletions(-) diff --git a/Console/BExIS.Web.Shell.Svelte/package.json b/Console/BExIS.Web.Shell.Svelte/package.json index 06dabadcb4..a82e44bca2 100644 --- a/Console/BExIS.Web.Shell.Svelte/package.json +++ b/Console/BExIS.Web.Shell.Svelte/package.json @@ -30,7 +30,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.82", + "@bexis2/bexis2-core-ui": "0.4.83", "buffer": "6.0.3", "gray-matter": "4.0.3", "marked": "^15.0.12", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json index e32650f415..9768cbe41c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json @@ -24,7 +24,7 @@ }, "type": "module", "dependencies": { - "@bexis2/bexis2-core-ui": "0.4.82", + "@bexis2/bexis2-core-ui": "0.4.83", "@bexis2/bexis2-rpm-ui": "0.3.0", "@floating-ui/dom": "1.7.6", "@ts4nfdi/terminology-service-suite-js": "^6.12.4", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts index 7451b9956c..d4ea8aa225 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts @@ -86,11 +86,11 @@ export function updateMetadataStore(path: string, value: any, isMulti?: boolean, } } } - else if((value === undefined || value === null) && partyid !== undefined && partyid !== null &&partyid>0) + else if((value === undefined || value === null) && partyid !== undefined && partyid !== null) { const parent = getByPath(path); - console.log("🚀 ~ updateMetadataStore ~ parent:", parent) parent["@partyid"] = partyid; + //console.log("🚀 ~ updateMetadataStore ~ parent:", parent) } } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte index 40f7019325..90c82125e9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/PartySelector.svelte @@ -87,8 +87,8 @@ const dispatch = createEventDispatcher(); // we need to update the value with the new selected party and also trigger the validation for this field because maybe there are some validation rules on the party id async function onUpdateParty(e: any){ - console.log("onUpdateParty",value, e.detail); - const partyid = e.detail.partyId; + //console.log("onUpdateParty",value, e.detail); + const partyid = e.detail.partyId? e.detail.partyId : 0; const newValue = e.detail.value; // selectorValue.value = newValue; @@ -110,12 +110,10 @@ const dispatch = createEventDispatcher(); updateMetadataStore(path, newValue, isMulti, undefined, undefined); const parentPath = getParentPath(path); - console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) const parentPathWithoutIndices = removeJsonPathIndices(parentPath); - // update parent with pary id if not already set - console.log("🚀 ~ onUpdateParty ~ parentPath:", parentPath) - updateMetadataStore(parentPath, null, false, undefined, partyid); + // update parent with pary id if not already set + updateMetadataStore(parentPath, null, false, undefined, partyid); // if mapping is complex // get all partymappings where parent path is the same as the changed one @@ -123,7 +121,6 @@ const dispatch = createEventDispatcher(); // updateMetadataStore(mapping.path, value, isMulti, undefined, e.detail.partyId); const childvalue = await GetPartyValue(partyid, mapping.linkElementId); - const childPathWithIndex = parentPath+"."+mapping.path.split('.').slice(-1)[0]; // update child value with new party value @@ -132,12 +129,12 @@ const dispatch = createEventDispatcher(); // update because of validation updateValue(childvalue, childPathWithIndex) - console.log("🚀 ~ onUpdateParty ~ dispatch reload for path:", selectorValue) + //console.log("🚀 ~ onUpdateParty ~ dispatch reload for path:", selectorValue) } ) } // trigger reload parent component to update all child components with new values - dispatch("reload"); + //dispatch("reload"); }, 100) } @@ -174,8 +171,9 @@ function updateValue(value: any, _path:string){ itemLabel="value" bind:target={selectorValue} isMulti={false} - clearable={required ? false : true} + clearable={true} on:change={onUpdateParty} + on:clear={onUpdateParty} invalid={res.hasErrors(path)} feedback={res.getErrors(path)} description={description} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/complexComponentWrapper.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/complexComponentWrapper.svelte index f088c44783..2463f7ecd5 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/complexComponentWrapper.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/complexComponentWrapper.svelte @@ -21,19 +21,8 @@ ? complexComponent.required : []; -let reloading = false; - - - -function reloadFn(){ - setTimeout(() => { - reloading = !reloading; - }, 500); -} - - -{#key reloading} + {#if complexComponent && complexComponent.type === 'object' && complexComponent.properties} {#each Object.entries(complexComponent.properties) as [key, value]} {@const p = path = path ? path + '.' + key : key} @@ -62,7 +51,7 @@ function reloadFn(){
- reloadFn()} /> +
@@ -74,4 +63,3 @@ function reloadFn(){ {/if} -{/key} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte index 23d9d91260..ec913ad599 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte @@ -7,18 +7,26 @@ Dropdown, helpStore, CodeEditor, - MultiSelect - } from '@bexis2/bexis2-core-ui'; import { SlideToggle } from '@skeletonlabs/skeleton'; import { onMount } from 'svelte'; - import { ValidationStoreAddSimpleComponent, ValidationStoreSetSimpleTypeValid, updateMetadataStore, createSimpleComponentValidationItem, getConfigStore, getValidationStore} from '$lib/components/utils/metadata/metadataComponentUtils'; + import { + ValidationStoreAddSimpleComponent, + ValidationStoreSetSimpleTypeValid, + updateMetadataStore, + createSimpleComponentValidationItem, + getConfigStore, + getValidationStore + } from '$lib/components/utils/metadata/metadataComponentUtils'; import { customComponentsCatalog } from '$lib/components/customComponents/componentCatalog'; import suite from '$lib/components/utils/metadata/simpleComponentSuite'; - import type { MappingComponentConfig, SimpleComponentData } from '$lib/components/utils/metadata/models'; + import type { + MappingComponentConfig, + SimpleComponentData + } from '$lib/components/utils/metadata/models'; import SveltyPicker from 'svelty-picker'; - import {convertDisplayName} from '../metadataShared'; + import { convertDisplayName } from '../metadataShared'; import type { JsonListItem } from '../components/types'; import Blocked from './Blocked.svelte'; import PartySelector from './PartySelector.svelte'; @@ -31,8 +39,8 @@ export let required: boolean = false; export let value: any; export let label: string; - export let isMulti:boolean = false; // for array of simple types, that should use multiselect ui component - + export let isMulti: boolean = false; // for array of simple types, that should use multiselect ui component + let date: Date = undefined as unknown as Date; // load form result object let res = suite.get(); @@ -46,166 +54,165 @@ // if mulitselect for array of simple types, create items array for multiselect component // we need to convert the enum of the schema to a list entry of the jsons because we more informations on each value then only the value // like ref and partyid - let jsonItems: JsonListItem[] = []; + let jsonItems: JsonListItem[] = []; // set overall validity - $: ValidationStoreSetSimpleTypeValid(path, res.isValid(path), res.hasErrors(path) ? res.getErrors(path).join('. ') : ''); + $: ValidationStoreSetSimpleTypeValid( + path, + res.isValid(path), + res.hasErrors(path) ? res.getErrors(path).join('. ') : '' + ); // update metadata store on value change $: updateMetadataStore(path, value, isMulti); // System mapping -let mappingComponentConfig: MappingComponentConfig; + let mappingComponentConfig: MappingComponentConfig; onMount(async () => { - - //console.log('🚀 ~ onMount ~ simpleComponent:', value) - - // checks for date - if(simpleComponent.properties['#text'].format === 'date' || simpleComponent.properties['#text'].format === 'datetime' || simpleComponent.properties['#text'].format === 'date and time' || simpleComponent.properties['#text'].format === 'time'){ - // console.log("date format detected, set date value", value, value as Date); - date = value !== undefined || value == '' ? value as Date : Date.now() as unknown as Date; - // console.log("date format detected, set date", date); - - } - - // numeric - set min and max if exist in schema - if(simpleComponent.properties['#text'].minimum !== undefined){ - min = simpleComponent.properties['#text'].minimum; + //console.log('🚀 ~ onMount ~ simpleComponent:', value) + + // checks for date + if ( + simpleComponent.properties['#text'].format === 'date' || + simpleComponent.properties['#text'].format === 'datetime' || + simpleComponent.properties['#text'].format === 'date and time' || + simpleComponent.properties['#text'].format === 'time' + ) { + // console.log("date format detected, set date value", value, value as Date); + date = value !== undefined || value == '' ? (value as Date) : (Date.now() as unknown as Date); + // console.log("date format detected, set date", date); + } + + // numeric - set min and max if exist in schema + if (simpleComponent.properties['#text'].minimum !== undefined) { + min = simpleComponent.properties['#text'].minimum; + } + if (simpleComponent.properties['#text'].maximum !== undefined) { + max = simpleComponent.properties['#text'].maximum; + } + + if (isMulti && simpleComponent.properties['#text'].enum) { + jsonItems = simpleComponent.properties['#text'].enum.map((item: any) => { + return { + '@ref': '', + '@partyid': 0, + '#text': item + }; + }); + } + + mappingComponentConfig = getMappingComponentConfig(path, value); + + //#### VALIDATION #### + // create validation item and add to store + let simpleComponentValidationItem: SimpleComponentData = createSimpleComponentValidationItem( + path, + label, + required, + simpleComponent + ); + //console.log("🚀 ~ onMount ~ simpleComponentValidationItem:", simpleComponentValidationItem ) + // add to validation store + ValidationStoreAddSimpleComponent(simpleComponentValidationItem); + + //#### CONFIGURATION #### + config = getConfigStore(); + // check if this component is an anchor point + //console.log("check for anchorpoin", config) + for (const component of config.components) { + //console.log("ghjgJ", component.globalSettings.anchorpoint, path) + if (component.globalSettings.anchorpoint == path) { + isAnchor = true; + customComponent = customComponentsCatalog[component.meta.component_name].component; } - if(simpleComponent.properties['#text'].maximum !== undefined){ - max = simpleComponent.properties['#text'].maximum; - } - - if(isMulti && simpleComponent.properties['#text'].enum){ - jsonItems = simpleComponent.properties['#text'].enum.map((item: any) => { - return { - "@ref": '', - "@partyid": 0, - "#text": item - } - - }); - } - - mappingComponentConfig = getMappingComponentConfig(path, value); - - - - //#### VALIDATION #### - // create validation item and add to store - let simpleComponentValidationItem: SimpleComponentData = createSimpleComponentValidationItem(path, label, required, simpleComponent); - //console.log("🚀 ~ onMount ~ simpleComponentValidationItem:", simpleComponentValidationItem ) - // add to validation store - ValidationStoreAddSimpleComponent(simpleComponentValidationItem); - - - //#### CONFIGURATION #### - config = getConfigStore(); - // check if this component is an anchor point - //console.log("check for anchorpoin", config) - for (const component of config.components) { - //console.log("ghjgJ", component.globalSettings.anchorpoint, path) - if (component.globalSettings.anchorpoint == path){ - isAnchor = true; - customComponent = customComponentsCatalog[component.meta.component_name].component; - } - for (const variable of component.mode.variables.variable) { - if (variable.JSONPath == path && variable.is_visible == false){ - isVisible = false; - } + for (const variable of component.mode.variables.variable) { + if (variable.JSONPath == path && variable.is_visible == false) { + isVisible = false; } } + } - - // initial check - setTimeout(async () => { - - updateValue(value, path); - }, 100); + // initial check + setTimeout(async () => { + updateValue(value, path); + }, 100); }); //change event: if input change check also validation only on the field // e.target.id is the id of the input component function onChangeHandler(e: any) { // add some delay so the entityTemplate is updated - // otherwise the values are old - setTimeout(async () => { - - updateValue(value, path); - - }, 10); + // otherwise the values are old + setTimeout(async () => { + updateValue(value, path); + }, 10); } + function updateValue(value: any, _path: string) { + // check changed field only + res = suite(_path); + setTimeout(async () => { + //console.log("🚀 ~ updateValue ~ res:",res, res.isValid(_path), path, value) - function updateValue(value: any, _path:string){ - - // check changed field only - res = suite(_path); - - setTimeout(async () => { - //console.log("🚀 ~ updateValue ~ res:",res, res.isValid(_path), path, value) - - let errorMessage = ''; - if(res.hasErrors(_path)){ - errorMessage = res.getErrors(_path).join('. '); - } + let errorMessage = ''; + if (res.hasErrors(_path)) { + errorMessage = res.getErrors(_path).join('. '); + } - // update validationstore - ValidationStoreSetSimpleTypeValid(_path, res.isValid(_path), errorMessage); - }, 10); + // update validationstore + ValidationStoreSetSimpleTypeValid(_path, res.isValid(_path), errorMessage); + }, 10); } - - {#if isVisible && !isAnchor} -
- - - - {#if (mappingComponentConfig && ((mappingComponentConfig.isMappedToParty && !mappingComponentConfig.isSelector) || mappingComponentConfig.isMappedToKey))} - - {:else if mappingComponentConfig && mappingComponentConfig.isMappedToParty && mappingComponentConfig.isSelector} - +
+ + {#if mappingComponentConfig && ((mappingComponentConfig.isMappedToParty && !mappingComponentConfig.isSelector) || mappingComponentConfig.isMappedToKey)} + + {:else if mappingComponentConfig && mappingComponentConfig.isMappedToParty && mappingComponentConfig.isSelector} - - {:else if path && simpleComponent.properties} - + /> + {:else if path && simpleComponent.properties} - {#if simpleComponent.properties['#text'].format !== undefined && simpleComponent.properties['#text'].format !== null} + {#if simpleComponent.properties['#text'].format !== undefined && simpleComponent.properties['#text'].format !== null} {#if simpleComponent.properties['#text'].format.toLowerCase() === 'date'} - + - {convertDisplayName(label)} - + {convertDisplayName(label)} + + inputClasses="input variant-form-material dark:bg-zinc-700 bg-zinc-50 placeholder:text-gray-400 w-32" + on:change={onChangeHandler} + /> - + {:else if simpleComponent.properties['#text'].format.toLowerCase() === 'datetime' || simpleComponent.properties['#text'].format.toLowerCase() === 'date and time'} - + - {convertDisplayName(label)} + {convertDisplayName(label)} + on:change={onChangeHandler} + /> - + {:else if simpleComponent.properties['#text'].format.toLowerCase() === 'time'} - + - {convertDisplayName(label)} + {convertDisplayName(label)} + on:change={onChangeHandler} + /> - - {:else if simpleComponent.properties['#text'].type === 'string' &&simpleComponent.properties['#text'].format.toLowerCase() === 'textarea' || simpleComponent.properties['#text'].format.toLowerCase() === 'text' || (simpleComponent.properties['#text'].type === 'string' && value.length >= 25)} - diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tableShow.svelte b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tableShow.svelte index e5354e063e..a61f15aee7 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tableShow.svelte +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tableShow.svelte @@ -28,6 +28,7 @@
{#if currentRow && currentRow.tagId > 0} Date: Mon, 6 Jul 2026 10:10:45 +0200 Subject: [PATCH 174/490] #2525 Fix Data Structure Validation: Error message to long and hard to read - extent info about 1000 errors --- .../src/lib/components/validation/ValidationResult.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte index ff85f44eb2..8392e92103 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte @@ -134,7 +134,7 @@ role="status" > Please correct your data and upload again or edit the data structure accordingly. Validation - will be performed again based on the changes. + will be performed again based on the changes. {#if selected.errors.length > 990} Only the first ~1000 errors are shown. {/if}
{#each selected.errors as error} From 577bd81d7d49468062013b97baad82ec62b91750 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 6 Jul 2026 10:18:01 +0200 Subject: [PATCH 175/490] #2525 Fix Data Structure Validation: Error message to long and hard to read - split error and warning. --- .../src/lib/components/validation/Message.svelte | 3 ++- .../src/lib/components/validation/ValidationResult.svelte | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte index 02ac46b5ad..2263e61923 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte @@ -4,11 +4,12 @@ export let title; export let count; export let messages; + export let type; -
{count} Errors
+
{count} {type === 'error' ? 'Errors' : 'Warnings'}
{title}
    diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte index 8392e92103..977b245b11 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/ValidationResult.svelte @@ -134,14 +134,14 @@ role="status" > Please correct your data and upload again or edit the data structure accordingly. Validation - will be performed again based on the changes. {#if selected.errors.length > 990} Only the first ~1000 errors are shown. {/if} + will be performed again based on the changes. {#if selected.errors.length > 990} Only the first ~1000 errors are shown. {/if} {#if selected.warnings.length > 990} Only the first ~1000 warnings are shown. {/if}
{#each selected.errors as error} - + {/each} {#each selected.warnings as warning} - + {/each}
{/if} From 5381e137b82529a70133e740f8126ee39cc697de Mon Sep 17 00:00:00 2001 From: david schoene Date: Mon, 6 Jul 2026 13:16:12 +0200 Subject: [PATCH 176/490] #907 add citaion download --- Components/IO/BExIS.Io/IoHelper.cs | 4 + .../package-lock.json | 510 ++++++++++++++++++ .../BExIS.Modules.Dcm.UI.Svelte/package.json | 1 + .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../src/routes/+layout.ts | 2 +- .../src/routes/view/+page.svelte | 4 + .../view/citation/CitationDownload.svelte | 94 ++++ .../src/routes/view/services.js | 21 +- .../BExIS.Modules.Dcm.UI.csproj | 2 +- .../Controllers/ViewController.cs | 64 +++ .../Hooks/MetadataViewHook.cs | 2 +- .../Models/View/CitationModels.cs | 20 + .../{M/View.cshtml => View/Metadata.cshtml} | 0 .../Models/CitationModels.cs | 1 + pnpm-lock.yaml | 8 + 15 files changed, 730 insertions(+), 5 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/CitationDownload.svelte rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/{M/View.cshtml => View/Metadata.cshtml} (100%) diff --git a/Components/IO/BExIS.Io/IoHelper.cs b/Components/IO/BExIS.Io/IoHelper.cs index 345ce4ed12..6b55209307 100644 --- a/Components/IO/BExIS.Io/IoHelper.cs +++ b/Components/IO/BExIS.Io/IoHelper.cs @@ -73,6 +73,9 @@ public static string GetFileName(FileType type, long datasetId, int versionNr, case FileType.Attachments: downloadName = string.Format("{0}_{1}_{2}_attachment_{3}", appName, datasetId, versionOrTagLabel, title); break; + case FileType.Citation: + downloadName = string.Format("{0}_{1}_{2}_citation", appName, datasetId, versionOrTagLabel, title); + break; case FileType.Bundle: downloadName = string.Format("{0}_{1}_{2}_{3}_{4}", appName, datasetId, versionOrTagLabel, downloadTitle, downloadDate); break; @@ -100,6 +103,7 @@ public enum FileType Attachments, Bundle, Manifest, + Citation, None } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json new file mode 100644 index 0000000000..db158f7e59 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package-lock.json @@ -0,0 +1,510 @@ +{ + "name": "@bexis2/bexis2-dcm-ui", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "@bexis2/bexis2-dcm-ui", + "version": "1.0.0", + "hasInstallScript": true, + "license": "ISC", + "dependencies": { + "@bexis2/bexis2-core-ui": "0.4.92", + "@bexis2/bexis2-rpm-ui": "0.4.0", + "@floating-ui/dom": "1.7.6", + "@fortawesome/free-brands-svg-icons": "^7.3.0", + "@ts4nfdi/terminology-service-suite-js": "^6.12.4", + "@xyflow/svelte": "^0.1.39", + "ajv": "^8.20.0", + "ajv-formats": "^3.0.1", + "js-file-download": "^0.4.12", + "svelte-adapter-github": "1.0.0-next.0", + "svelte-fa": "4.0.4", + "svelte-headless-table": "0.18.3", + "svelte-select": "5.8.3", + "svelty-picker": "^5.2.12", + "vest": "5.4.0" + } + }, + "../../../../../node_modules/.pnpm/@bexis2+bexis2-core-ui@0.4._a4ac9dd8000f937e890ec2bb3d2c500f/node_modules/@bexis2/bexis2-core-ui": { + "version": "0.4.92", + "license": "ISC", + "dependencies": { + "@codemirror/lang-html": "^6.4.9", + "@codemirror/lang-javascript": "^6.2.2", + "@codemirror/lang-json": "^6.0.1", + "@codemirror/lint": "^6.8.1", + "@codemirror/theme-one-dark": "^6.1.2", + "@floating-ui/dom": "^1.6.8", + "@fortawesome/fontawesome-free": "^6.6.0", + "@fortawesome/fontawesome-svg-core": "^6.6.0", + "@fortawesome/free-regular-svg-icons": "^6.6.0", + "@fortawesome/free-solid-svg-icons": "^6.6.0", + "@sveltejs/kit": "^2.5.19", + "@sveltejs/vite-plugin-svelte": "^3.1.1", + "axios": "^1.7.3", + "codemirror": "^6.0.1", + "dateformat": "^5.0.3", + "delay": "^6.0.0", + "dotenv": "^16.4.5", + "eslint4b-prebuilt": "^6.7.2", + "highlight.js": "^11.10.0", + "highlightjs-svelte": "^1.0.6", + "svelte": "^4.2.18", + "svelte-codemirror-editor": "^1.4.0", + "svelte-fa": "^4.0.2", + "svelte-file-dropzone": "^2.0.7", + "svelte-headless-table": "^0.18.2", + "svelte-select": "5.8.3", + "svelty-picker": "^5.2.12", + "vest": "^5.4.0" + }, + "devDependencies": { + "@playwright/test": "^1.45.3", + "@skeletonlabs/skeleton": "^2.10.2", + "@skeletonlabs/tw-plugin": "^0.4.0", + "@sveltejs/adapter-auto": "^3.2.2", + "@sveltejs/adapter-static": "^3.0.2", + "@sveltejs/package": "^2.3.2", + "@tailwindcss/forms": "^0.5.7", + "@tailwindcss/typography": "^0.5.13", + "@types/node": "^22.0.2", + "@typescript-eslint/eslint-plugin": "^8.0.0", + "@typescript-eslint/parser": "^8.0.0", + "autoprefixer": "^10.4.19", + "eslint": "^9.8.0", + "eslint-config-prettier": "^9.1.0", + "postcss": "^8.4.40", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.6", + "raw-loader": "^4.0.2", + "svelte": "^4.2.18", + "svelte-check": "^3.8.5", + "tailwindcss": "^3.4.7", + "tslib": "^2.6.3", + "typescript": "^5.5.4", + "vite": "^5.3.5", + "vitest": "^2.0.5" + } + }, + "../../../../../node_modules/.pnpm/@bexis2+bexis2-rpm-ui@0.4.0_c584dae657ec0dcc3aef2f6429689cca/node_modules/@bexis2/bexis2-rpm-ui": { + "version": "0.4.0", + "license": "ISC", + "dependencies": { + "@bexis2/bexis2-core-ui": "0.4.88", + "@floating-ui/dom": "1.7.6", + "papaparse": "5.5.2", + "svelte-fa": "4.0.4" + }, + "devDependencies": {} + }, + "../../../../../node_modules/.pnpm/@floating-ui+dom@1.7.6/node_modules/@floating-ui/dom": { + "version": "1.7.6", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + }, + "devDependencies": { + "@types/react": "^18.3.19", + "@types/react-dom": "^18.3.1", + "@vitejs/plugin-react": "^4.3.4", + "config": "0.0.0", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "react-router-dom": "^6.21.1" + } + }, + "../../../../../node_modules/.pnpm/@fortawesome+free-brands-svg-icons@7.3.0/node_modules/@fortawesome/free-brands-svg-icons": { + "version": "7.3.0", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "7.3.0" + }, + "engines": { + "node": ">=6" + } + }, + "../../../../../node_modules/.pnpm/@ts4nfdi+terminology-service-suite-js@6.12.4/node_modules/@ts4nfdi/terminology-service-suite-js": { + "version": "6.12.4", + "license": "MIT", + "dependencies": { + "patch-package": "^8.0.0" + }, + "devDependencies": { + "@elastic/datemath": "^5.0.3", + "@elastic/eui": "^102.1.0", + "@emotion/css": "^11.13.5", + "@emotion/react": "^11.13.5", + "@google/model-viewer": "^4.0.0", + "@ts4nfdi/terminology-service-suite": "file:../react", + "axios": "^1.1.2", + "moment": "^2.30.1", + "react": "^18.3", + "react-dom": "^18.3", + "react-query": "^3.39.2", + "react-router": "^6.3.0", + "three": "^0.182.0", + "vis-data": "^7.1.9", + "vis-network": "^9.1.9" + } + }, + "../../../../../node_modules/.pnpm/@xyflow+svelte@0.1.39_svelte@4.2.20/node_modules/@xyflow/svelte": { + "version": "0.1.39", + "license": "MIT", + "dependencies": { + "@svelte-put/shortcut": "3.1.1", + "@xyflow/system": "0.0.59", + "classcat": "^5.0.4" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^3.1.1", + "@sveltejs/kit": "^2.5.4", + "@sveltejs/package": "^2.3.0", + "@typescript-eslint/eslint-plugin": "^7.2.0", + "@typescript-eslint/parser": "^7.2.0", + "autoprefixer": "^10.4.18", + "cssnano": "^6.1.0", + "dotenv": "^16.4.5", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "postcss": "^8.4.35", + "postcss-cli": "^11.0.0", + "postcss-combine-duplicated-selectors": "^10.0.3", + "postcss-import": "^16.0.1", + "postcss-nested": "^6.0.1", + "postcss-rename": "^0.6.1", + "prettier": "^3.2.5", + "prettier-plugin-svelte": "^3.2.2", + "svelte": "^4.2.12", + "svelte-check": "^3.6.7", + "svelte-eslint-parser": "^0.33.1", + "svelte-preprocess": "^5.1.3", + "tslib": "^2.6.2", + "typescript": "5.4.5" + }, + "peerDependencies": { + "svelte": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "../../../../../node_modules/.pnpm/ajv-formats@3.0.1_ajv@8.20.0/node_modules/ajv-formats": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "devDependencies": { + "@ajv-validator/config": "^0.3.0", + "@types/jest": "^26.0.5", + "@types/node": "^14.10.1", + "@typescript-eslint/eslint-plugin": "^3.7.0", + "@typescript-eslint/parser": "^3.7.0", + "ajv": "^8.0.0", + "eslint": "^7.5.0", + "eslint-config-prettier": "^6.11.0", + "husky": "^4.2.5", + "jest": "^26.1.0", + "json-schema-test": "^2.0.0", + "lint-staged": "^10.2.11", + "prettier": "^2.3.2", + "ts-jest": "^26.1.3", + "typescript": "^4.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "../../../../../node_modules/.pnpm/ajv@8.20.0/node_modules/ajv": { + "version": "8.20.0", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "devDependencies": { + "@ajv-validator/config": "^0.5.0", + "@rollup/plugin-commonjs": "^25.0.7", + "@rollup/plugin-json": "^6.1.0", + "@rollup/plugin-node-resolve": "^15.2.3", + "@rollup/plugin-typescript": "^11.1.6", + "@types/chai": "^4.3.11", + "@types/mocha": "^10.0.6", + "@types/node": "^20.11.30", + "@types/require-from-string": "^1.2.3", + "@typescript-eslint/eslint-plugin": "^7.3.1", + "@typescript-eslint/parser": "^7.3.1", + "ajv-formats": "^3.0.1", + "browserify": "^17.0.0", + "chai": "^4.4.1", + "cross-env": "^7.0.3", + "dayjs": "^1.11.10", + "dayjs-plugin-utc": "^0.1.2", + "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "glob": "^10.3.10", + "husky": "^9.0.11", + "jimp": "^0.22.10", + "js-beautify": "^1.15.1", + "json-schema-test": "^2.0.0", + "karma": "^6.4.2", + "karma-chrome-launcher": "^3.2.0", + "karma-mocha": "^2.0.1", + "lint-staged": "^15.2.2", + "mocha": "^10.3.0", + "module-from-string": "^3.3.0", + "node-fetch": "^3.3.2", + "nyc": "^15.1.0", + "prettier": "3.0.3", + "re2": "^1.20.9", + "rollup": "^2.79.1", + "rollup-plugin-terser": "^7.0.2", + "ts-node": "^10.9.2", + "tsify": "^5.0.4", + "typescript": "5.3.3", + "uri-js": "^4.4.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "../../../../../node_modules/.pnpm/svelte-adapter-github@1.0.0-next.0/node_modules/svelte-adapter-github": { + "version": "1.0.0-next.0", + "license": "MIT", + "devDependencies": { + "@sveltejs/kit": "next", + "@types/node": "^16.11.36", + "sirv": "^2.0.2", + "svelte": "^3.48.0", + "typescript": "^4.8.2", + "uvu": "^0.5.3", + "vite": "^3.1.1" + } + }, + "../../../../../node_modules/.pnpm/svelte-fa@4.0.4_svelte@4.2.20/node_modules/svelte-fa": { + "version": "4.0.4", + "license": "MIT", + "devDependencies": { + "@cweili/fa-test-util": "^1.0.0", + "@sveltejs/adapter-static": "^3.0.5", + "@sveltejs/kit": "^2.5.28", + "@sveltejs/package": "^2.3.5", + "@sveltejs/vite-plugin-svelte": "^3.1.2", + "@testing-library/svelte": "^5.2.1", + "@types/eslint": "^9.6.1", + "@vitest/coverage-v8": "^2.1.1", + "bootstrap": "^5.3.2", + "eslint": "^9.11.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.44.0", + "globals": "^15.9.0", + "highlight.js": "^11.9.0", + "jsdom": "^25.0.1", + "prettier": "^3.3.3", + "prettier-plugin-svelte": "^3.2.6", + "publint": "^0.2.11", + "sass": "1.83.0", + "svelte": "^4.2.19", + "svelte-check": "^4.0.2", + "typescript": "5.7", + "typescript-eslint": "^8.6.0", + "vite": "^5.4.7", + "vitest": "^2.1.1" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0" + } + }, + "../../../../../node_modules/.pnpm/svelte-headless-table@0.18.3_svelte@4.2.20/node_modules/svelte-headless-table": { + "version": "0.18.3", + "license": "MIT", + "dependencies": { + "svelte-keyed": "^2.0.0", + "svelte-render": "^2.0.1", + "svelte-subscribe": "^2.0.1" + }, + "devDependencies": { + "@sveltejs/adapter-auto": "^3.0.0", + "@sveltejs/kit": "^2.0.0", + "@sveltejs/package": "^2.0.0", + "@sveltejs/vite-plugin-svelte": "^3.0.0", + "@testing-library/jest-dom": "^6.1.6", + "@testing-library/svelte": "^4.0.5", + "@types/eslint": "8.56.0", + "@types/faker": "^5.5.9", + "@typescript-eslint/eslint-plugin": "^6.0.0", + "@typescript-eslint/parser": "^6.0.0", + "@vitest/coverage-v8": "^1.1.1", + "eslint": "^8.56.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-svelte": "^2.35.1", + "faker": "^5.5.3", + "prettier": "^3.1.1", + "prettier-plugin-svelte": "^3.1.2", + "publint": "^0.1.9", + "svelte": "^4.2.7", + "svelte-check": "^3.6.0", + "tslib": "^2.4.1", + "typescript": "^5.0.0", + "vite": "^5.0.3", + "vitest": "^1.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0" + } + }, + "../../../../../node_modules/.pnpm/svelte-select@5.8.3/node_modules/svelte-select": { + "version": "5.8.3", + "license": "ISC", + "dependencies": { + "svelte-floating-ui": "1.5.8" + }, + "devDependencies": { + "@rollup/plugin-alias": "^4.0.3", + "@sveltejs/adapter-auto": "2.0.0", + "@sveltejs/adapter-static": "2.0.1", + "@sveltejs/kit": "1.15.0", + "@sveltejs/package": "^1.0.2", + "autoprefixer": "^10.4.14", + "cross-env": "^7.0.3", + "find-in-files": "^0.5.0", + "fuse.js": "^6.6.2", + "prettier": "~2.8.7", + "prettier-plugin-svelte": "^2.10.0", + "release-it": "^15.10.0", + "rollup": "^3.20.2", + "rollup-plugin-cleaner": "^1.0.0", + "rollup-plugin-css-only": "^4.3.0", + "rollup-plugin-node-resolve": "^5.2.0", + "rollup-plugin-postcss": "^4.0.2", + "rollup-plugin-replace": "^2.2.0", + "rollup-plugin-svelte": "^7.1.4", + "sirv-cli": "^2.0.2", + "svelte": "^3.58.0", + "svelte-highlight": "^7.2.1", + "svelte-preprocess": "^5.0.3", + "svelte-tiny-virtual-list": "^2.0.5", + "svelte2tsx": "^0.6.10", + "tape-modern": "^1.1.2", + "typescript": "^4.9.5", + "vite": "^4.2.1" + } + }, + "../../../../../node_modules/.pnpm/svelty-picker@5.2.12_svelte@4.2.20/node_modules/svelty-picker": { + "version": "5.2.12", + "dependencies": { + "@floating-ui/dom": "^1.4" + }, + "devDependencies": { + "@bitmachina/highlighter": "1.0.0-alpha.5", + "@jridgewell/sourcemap-codec": "https://github.com/xiaoxiangmoe/sourcemap-codec/tarball/main", + "@prgm/sveltekit-progress-bar": "^1.0.1", + "@sveltejs/adapter-auto": "^2.1.1", + "@sveltejs/adapter-static": "^2.0.3", + "@sveltejs/kit": "^2.5.7", + "@sveltejs/package": "^2.3.7", + "@sveltejs/repl": "^0.5.0", + "@sveltejs/site-kit": "^5.2.2", + "@sveltejs/vite-plugin-svelte": "^2.5.3", + "autoprefixer": "^10.4.17", + "mdsvex": "^0.11.0", + "postcss": "^8.4.35", + "postcss-load-config": "^4.0.2", + "publint": "^0.1.16", + "shiki": "^0.14.7", + "svelte": "5.0.0-next.125", + "svelte-check": "^3.6.4", + "tailwindcss": "^3.4.1", + "tslib": "^2.8.1", + "typescript": "^5.7.2", + "vite": "^4.5.2", + "vite-plugin-node-polyfills": "^0.9.0" + }, + "peerDependencies": { + "svelte": "^3.53.0 || ^4.0.0 || ^5.0.0" + } + }, + "../../../../../node_modules/.pnpm/vest@5.4.0/node_modules/vest": { + "version": "5.4.0", + "license": "MIT", + "dependencies": { + "context": "^3.0.30", + "n4s": "^5.0.25", + "vast": "^1.0.39", + "vest-utils": "^1.3.0", + "vestjs-runtime": "^1.4.0" + } + }, + "node_modules/@bexis2/bexis2-core-ui": { + "resolved": "../../../../../node_modules/.pnpm/@bexis2+bexis2-core-ui@0.4._a4ac9dd8000f937e890ec2bb3d2c500f/node_modules/@bexis2/bexis2-core-ui", + "link": true + }, + "node_modules/@bexis2/bexis2-rpm-ui": { + "resolved": "../../../../../node_modules/.pnpm/@bexis2+bexis2-rpm-ui@0.4.0_c584dae657ec0dcc3aef2f6429689cca/node_modules/@bexis2/bexis2-rpm-ui", + "link": true + }, + "node_modules/@floating-ui/dom": { + "resolved": "../../../../../node_modules/.pnpm/@floating-ui+dom@1.7.6/node_modules/@floating-ui/dom", + "link": true + }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "resolved": "../../../../../node_modules/.pnpm/@fortawesome+free-brands-svg-icons@7.3.0/node_modules/@fortawesome/free-brands-svg-icons", + "link": true + }, + "node_modules/@ts4nfdi/terminology-service-suite-js": { + "resolved": "../../../../../node_modules/.pnpm/@ts4nfdi+terminology-service-suite-js@6.12.4/node_modules/@ts4nfdi/terminology-service-suite-js", + "link": true + }, + "node_modules/@xyflow/svelte": { + "resolved": "../../../../../node_modules/.pnpm/@xyflow+svelte@0.1.39_svelte@4.2.20/node_modules/@xyflow/svelte", + "link": true + }, + "node_modules/ajv": { + "resolved": "../../../../../node_modules/.pnpm/ajv@8.20.0/node_modules/ajv", + "link": true + }, + "node_modules/ajv-formats": { + "resolved": "../../../../../node_modules/.pnpm/ajv-formats@3.0.1_ajv@8.20.0/node_modules/ajv-formats", + "link": true + }, + "node_modules/js-file-download": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/js-file-download/-/js-file-download-0.4.12.tgz", + "integrity": "sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==", + "license": "MIT" + }, + "node_modules/svelte-adapter-github": { + "resolved": "../../../../../node_modules/.pnpm/svelte-adapter-github@1.0.0-next.0/node_modules/svelte-adapter-github", + "link": true + }, + "node_modules/svelte-fa": { + "resolved": "../../../../../node_modules/.pnpm/svelte-fa@4.0.4_svelte@4.2.20/node_modules/svelte-fa", + "link": true + }, + "node_modules/svelte-headless-table": { + "resolved": "../../../../../node_modules/.pnpm/svelte-headless-table@0.18.3_svelte@4.2.20/node_modules/svelte-headless-table", + "link": true + }, + "node_modules/svelte-select": { + "resolved": "../../../../../node_modules/.pnpm/svelte-select@5.8.3/node_modules/svelte-select", + "link": true + }, + "node_modules/svelty-picker": { + "resolved": "../../../../../node_modules/.pnpm/svelty-picker@5.2.12_svelte@4.2.20/node_modules/svelty-picker", + "link": true + }, + "node_modules/vest": { + "resolved": "../../../../../node_modules/.pnpm/vest@5.4.0/node_modules/vest", + "link": true + } + } +} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json index 0a1bc017d3..f037760b13 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/package.json @@ -32,6 +32,7 @@ "@xyflow/svelte": "^0.1.39", "ajv": "^8.20.0", "ajv-formats": "^3.0.1", + "js-file-download": "^0.4.12", "svelte-adapter-github": "1.0.0-next.0", "svelte-fa": "4.0.4", "svelte-headless-table": "0.18.3", diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 8386ebe508..53c3b78caf 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -8,7 +8,7 @@
-
+
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/+layout.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/+layout.ts index 261fcadac2..7b216004ba 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/+layout.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/+layout.ts @@ -5,7 +5,7 @@ export async function load({ fetch }) { if (import.meta.env.DEV) { // setApiConfig('http://mv-bexis.bioimbgle.uni-jena.de/', 'majoho', 'Mjh271181#'); // setApiConfig('https://rc.bexis2.uni-jena.de/', 'admin', '123456'); - setApiConfig('http://localhost:44345', '', ''); + setApiConfig('http://localhost:44345', 'admin', '123456'); } return {}; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte index e3781a8a87..2122d14b9f 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte @@ -22,6 +22,7 @@ import InProcess from './error/InProcess.svelte'; import NotExist from './error/NotExist.svelte'; import InternalServer from './error/InternalServer.svelte'; + import CitationDownload from './citation/CitationDownload.svelte'; let title = ''; @@ -100,6 +101,9 @@ {model.description}
+ + + +import Fa from "svelte-fa"; +import { faDownload, faCopy } from "@fortawesome/free-solid-svg-icons"; +import {CitationFormat} from "$models/View"; + import { getCitationOptions, getCitationText } from "../services"; + import fileDownload from "js-file-download"; + import { onMount } from "svelte"; + +export let id = 0; +export let version = 0;; +export let tag = 0; + + let selectedFormat:number = -1; + $:selectedFormat, console.log("🚀 ~ selectedFormat:", selectedFormat, downloadAccess), downloadAccess = selectedFormat !== ''?true:false; + + let filename = `entity_${id}_${version}.txt`; + + let downloadFormats = [ + { + 'label': 'APA', + 'format': 'apa', + 'value': CitationFormat.APA, + }, + { + 'label': 'RIS', + 'format': 'ris', + 'value': CitationFormat.RIS, + }, + { + 'label': 'Text', + 'format': 'txt', + 'value': CitationFormat.Text, + }, + { + 'label': 'BibTeX', + 'format': 'bib', + 'value': CitationFormat.Bibtex, + } +]; +$:downloadFormats, console.log("🚀 ~ downloadFormats:", downloadFormats) + +let downloadAccess = selectedFormat !== -1?true:false; // user has access to download the dataset +console.log("🚀 ~ downloadAccess:", downloadAccess) + +onMount(async() => { + console.log("🚀 ~ downloadAccess:", downloadAccess) + const res = await getCitationOptions(id, version, tag); + console.log("🚀 ~ res:", res) + + downloadFormats = res.formats; + filename = res.fileName; + +}); + + +async function downloadCitationFn() +{ + const res = await getCitationText(id, version, tag, selectedFormat); + + navigator.clipboard.writeText(res) + .then(() => { + console.log('Text copied successfully!'); + + const format = downloadFormats.find(f => f.value === selectedFormat)?.format || 'txt'; + + fileDownload(res, `${filename}.${format}`); + + }) + .catch(err => { + console.error('Failed to copy text: ', err); + }); +} + + + + + + +{#if downloadFormats.length > 0} +
+

Citation

+ +
+ + + +
+
+{/if} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js index 2d38186fb7..29a5de4090 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js @@ -64,6 +64,24 @@ export const getDeleted = async (id) => { } }; +export const getCitationText = async (id, version, tag, format) => { + try { + const response = await Api.get(`api/datasets/${id}/version_number/${version}/citations?format=${format}`); + return response.data; + } catch (error) { + console.error(error); + } +}; + +export const getCitationOptions = async (id, version, tag ) => { + try { + const response = await Api.get(`/dcm/view/getcitationoptions?id=${id}&version=${version}&tag=${tag}`); + return response.data; + } catch (error) { + console.error(error); + } +}; + export const downloadZip = async (id, format, version = -1, withFilter = false, withUnits = false) => { try { const config = { responseType: 'blob' } @@ -92,4 +110,5 @@ export const sendRequest = async (id, intension) => { } catch (error) { console.error(error); } -}; \ No newline at end of file +}; + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj index 3605b6fb24..e182cb08cd 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj @@ -479,7 +479,7 @@ - + Web.config diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs index c1ab6ffc6a..0a0330c42e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs @@ -14,6 +14,7 @@ using BExIS.Dlm.Entities.Party; using BExIS.Dlm.Services.Data; using BExIS.Dlm.Services.Party; +using BExIS.IO; using BExIS.IO.Transform.Output; using BExIS.Modules.Dcm.UI.Helpers; using BExIS.Modules.Dcm.UI.Helpers.View; @@ -36,6 +37,7 @@ using BExIS.Xml.Helpers.Mapping; using BEXIS.JSON.Helpers; using DocumentFormat.OpenXml.Drawing.Diagrams; +using DocumentFormat.OpenXml.EMMA; using DocumentFormat.OpenXml.Office2013.Excel; using DocumentFormat.OpenXml.Vml.Spreadsheet; using Microsoft.AspNet.Identity; @@ -493,6 +495,68 @@ public JsonResult Citation(long id, int version) } + [JsonNetFilter] + public JsonResult GetCitationOptions(long id, int version, double tag) + { + if(id<=0)throw new ArgumentException("id is not valid"); + CitationFormatOptions model = new CitationFormatOptions(); + + using (var datasetManager = new DatasetManager()) + { + var datasetVersion = datasetManager.GetDatasetVersion(id, version); + + if (datasetVersion == null) throw new ArgumentException("Version noi"); + + long datastructureId = datasetVersion.Dataset.DataStructure != null ? datasetVersion.Dataset.DataStructure.Id : -1; + var moduleSettings = ModuleManager.GetModuleSettings("Ddm"); + var useTags = Convert.ToBoolean(moduleSettings.GetValueByKey("use_tags")); + var useMinor = Convert.ToBoolean(moduleSettings.GetValueByKey("use_minor")); + + string filename = IOHelper.GetFileName(FileType.Citation, id, version, datastructureId, "", tag, useTags, useMinor); + model.FileName = filename; + + foreach (CitationFormat format in Enum.GetValues(typeof(CitationFormat))) + { + + CitationDataModel m = CitationsHelper.CreateCitationDataModel(datasetVersion, format); + if (CitationsHelper.IsCitationDataModelValid(m)) + { + string f = ""; + + switch (format.ToString()) + { + case "APA": + f = "apa"; + break; + case "RIS": + f = "ris"; + break; + case "Text": + f = "txt"; + break; + case "Bibtex": + f = "bib"; + break; + //default: f = "txt"; + default: f = "txt"; + break; + }; + + model.Formats.Add(new CitationListItem() + { + Label = format.ToString(), + Format = f, + Value = format + }); + + } + } + } + + return Json(model, JsonRequestBehavior.AllowGet); + } + + #region version [JsonNetFilter] diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/MetadataViewHook.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/MetadataViewHook.cs index 599c97f322..2373c5f799 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/MetadataViewHook.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/MetadataViewHook.cs @@ -6,7 +6,7 @@ public class MetadataViewHook : Hook { public MetadataViewHook() { - Start = "/dcm/view/start"; + Start = "/dcm/view/metadata"; } public override void Check(long id, string username) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/CitationModels.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/CitationModels.cs index 3989bf0fed..b259b8d6c1 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/CitationModels.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/View/CitationModels.cs @@ -38,6 +38,26 @@ public class CitaionModelJson public CitationDataModel Data { get; set; } } + public class CitationFormatOptions + { + public string FileName { get; set; } + public List Formats { get; set; } + + public CitationFormatOptions() + { + Formats = new List(); + } + + } + + public class CitationListItem + { + public string Label { get; set; } + public string Format { get; set; } + public CitationFormat Value { get; set; } + } + + [XmlRoot("data")] public class CitationDataModel diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/M/View.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Metadata.cshtml similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/M/View.cshtml rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Metadata.cshtml diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Models/CitationModels.cs b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Models/CitationModels.cs index add3e08c6d..576c959a5a 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Models/CitationModels.cs +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Models/CitationModels.cs @@ -31,6 +31,7 @@ public enum CitationFormat Bibtex } + [XmlRoot("data")] public class CitationDataModel diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 616a5a164a..3cbef65d8a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -171,6 +171,9 @@ importers: ajv-formats: specifier: ^3.0.1 version: 3.0.1(ajv@8.20.0) + js-file-download: + specifier: ^0.4.12 + version: 0.4.12 svelte-adapter-github: specifier: 1.0.0-next.0 version: 1.0.0-next.0 @@ -1725,6 +1728,9 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + js-file-download@0.4.12: + resolution: {integrity: sha512-rML+NkoD08p5Dllpjo0ffy4jRHeY6Zsapvr/W86N7E0yuzAO6qa5X9+xog6zQNlH102J7IXljNY2FtS6Lj3ucg==} + js-yaml@3.14.2: resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} hasBin: true @@ -4107,6 +4113,8 @@ snapshots: jiti@1.21.7: {} + js-file-download@0.4.12: {} + js-yaml@3.14.2: dependencies: argparse: 1.0.10 From 655659306ff849cffbebe5b37b52b889a727fc64 Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 7 Jul 2026 10:29:11 +0200 Subject: [PATCH 177/490] #907 all hooks render now view instead of partial views. fix citation header --- Components/IO/BExIS.Io/IoHelper.cs | 25 +++ .../src/models/View.ts | 4 +- .../src/routes/view/citation/Text.svelte | 16 +- .../Legacy/AttachmentsController.cs | 2 +- .../Controllers/ViewController.cs | 11 +- .../Helpers/View/CitationsHelper.cs | 14 ++ .../Attachments/_datasetAttachements.cshtml | 5 + .../Controllers/DataController.cs | 4 +- .../Controllers/ExportController.cs | 176 ++++++++++++------ .../Controllers/PublishController.cs | 2 +- .../Models/Download/GeneralMetadataModel.cs | 3 + .../Controllers/UserPermissionsController.cs | 10 +- 12 files changed, 194 insertions(+), 78 deletions(-) diff --git a/Components/IO/BExIS.Io/IoHelper.cs b/Components/IO/BExIS.Io/IoHelper.cs index 6b55209307..efb4dc69f9 100644 --- a/Components/IO/BExIS.Io/IoHelper.cs +++ b/Components/IO/BExIS.Io/IoHelper.cs @@ -91,6 +91,31 @@ public static string GetFileName(FileType type, long datasetId, int versionNr, return downloadName; } + public static string GetExtensionFileName(FileType type, long datasetId, + int versionNr, + long datastructureId, string extType, long extId, int extVersionNr, double tagNr = 0, bool useTags = false) + { + string appName = GeneralSettings.ApplicationName; + if (string.IsNullOrEmpty(appName)) appName = "BEXIS2"; + + string downloadName = "no title available"; + string versionOrTagLabel = useTags ? "t" + tagNr : "v" + versionNr; + + switch (type) + { + case FileType.DataStructure: + downloadName = string.Format("{0}_{1}_{2}_{3}_{4}_datastructure", appName, datasetId, versionOrTagLabel, extType, extId); + break; + case FileType.PrimaryData: + // filename should contain: application name, dataset ID, and version ID + downloadName = string.Format("{0}_{1}_{2}_{3}_{4}_data", appName, datasetId, versionOrTagLabel, extType, extId); + break; + + } + + return downloadName; + } + } public enum FileType diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts index 31c4ab73f5..d68aa2b018 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/View.ts @@ -148,8 +148,8 @@ export interface CitationDataModel { tag: string; projects: string[]; year: string; - dOI: string; - uRL: string; + doi: string; + url: string; authors: string[]; entryType: string; entityName: string; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte index e3aca345d4..1a8e759007 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte @@ -1,13 +1,16 @@ -
Citation: -
+
Citation: +
{model.authors} ({model.year}): {model.title}. Version {model.version}. {model.publisher}. {model.entityName}. - {model.uRL} - + {model.url}
+
copyDivContentToClipboard('citation-title')} on:keydown={()=> copyDivContentToClipboard('citation-title')} + id="citation-copy" title="Copy citation to clipboard" role="button" tabindex="0"> + +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/AttachmentsController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/AttachmentsController.cs index 74db6a25f4..c3fb579a92 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/AttachmentsController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Legacy/AttachmentsController.cs @@ -84,7 +84,7 @@ public ActionResult DatasetAttachements(long datasetId, long versionId) ViewBag.maxFileNameLength = 260 - storepath.Length - 2; - return PartialView("_datasetAttachements", LoadDatasetModel(versionId)); + return View("_datasetAttachements", LoadDatasetModel(versionId)); } [BExISEntityAuthorize(typeof(Dataset), "datasetId", RightType.Read)] diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs index 0a0330c42e..2903ce9fac 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs @@ -449,6 +449,7 @@ public JsonResult Citation(long id, int version) string conceptName = "Citation_" + citationSettings.ReadCitationFormat; var concept = conceptManager.FindByName(conceptName); + model.Data = CitationsHelper.CreateCitationDataModel(datasetVersion); if (model.Data == null) @@ -474,15 +475,19 @@ public JsonResult Citation(long id, int version) return Json(model, JsonRequestBehavior.AllowGet); } - - if (!CitationsHelper.IsCitationDataModelValid(model.Data)) + else // call citation with format { + model.Data = CitationsHelper.CreateReadCitationDataModel(datasetVersion, citationSettings.ReadCitationFormat); + } + if (CitationsHelper.IsCitationDataModelValid(model.Data)) + { + model.Format = citationSettings.ReadCitationFormat; return Json(model, JsonRequestBehavior.AllowGet); } - model.Format = citationSettings.ReadCitationFormat; + return Json(model, JsonRequestBehavior.AllowGet); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/View/CitationsHelper.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/View/CitationsHelper.cs index 9adf5ad4c8..2b219a5bfb 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/View/CitationsHelper.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/View/CitationsHelper.cs @@ -6,6 +6,7 @@ using BExIS.Modules.Dcm.UI.Models.View; using BExIS.Security.Services.Authorization; using BExIS.Security.Services.Objects; +using DocumentFormat.OpenXml.Spreadsheet; using NameParser; using System; using System.Collections.Generic; @@ -131,6 +132,19 @@ public static CitationDataModel CreateCitationDataModel(DatasetVersion datasetVe } } + public static CitationDataModel CreateReadCitationDataModel(DatasetVersion datasetVersion, ReadCitationFormat readformat) + { + if (Enum.TryParse(readformat.ToString(), out CitationFormat format)) + { + + return CreateCitationDataModel(datasetVersion, format); + } + else + { + return null; + } + } + public static bool IsCitationDataModelValid(CitationDataModel model) { try diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/Attachments/_datasetAttachements.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/Attachments/_datasetAttachements.cshtml index 12886e5c53..034a8f099b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/Attachments/_datasetAttachements.cshtml +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/Attachments/_datasetAttachements.cshtml @@ -21,6 +21,11 @@ int maxFileNameLength = (int)(ViewBag.maxFileNameLength); } + +
+ +
+
diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs index 1e5e089a3e..e561f02cbf 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI/Controllers/DataController.cs @@ -831,7 +831,7 @@ public ActionResult ShowPrimaryData(long datasetID, int versionId) sds.Variables = sds.Variables.OrderBy(v => v.OrderNo).ToList(); - return PartialView(ShowPrimaryDataModel.Convert( + return View(ShowPrimaryDataModel.Convert( datasetID, versionId, title, @@ -849,7 +849,7 @@ public ActionResult ShowPrimaryData(long datasetID, int versionId) return RedirectToAction("multimediaData", "ShowMultimediaData", new RouteValueDictionary { { "area", "MMM" }, { "datasetID", datasetID }, { "versionId", versionId } }); else return - PartialView(ShowPrimaryDataModel.Convert(datasetID, + View(ShowPrimaryDataModel.Convert(datasetID, versionId, title, null, diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/ExportController.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/ExportController.cs index bc4c2ab903..b4eb7b4fff 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/ExportController.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/ExportController.cs @@ -1,4 +1,5 @@ using BExIS.App.Bootstrap; +using BExIS.Dim.Entities.Export.GBIF; using BExIS.Dim.Entities.Publications; using BExIS.Dim.Helpers; using BExIS.Dim.Helpers.Export; @@ -17,16 +18,19 @@ using BExIS.Modules.Dim.UI.Models.Export; using BExIS.Security.Entities.Subjects; using BExIS.Security.Entities.Versions; +using BExIS.Security.Services.Objects; using BExIS.Security.Services.Utilities; using BExIS.UI.Helpers; using BExIS.Utils.Config; using BExIS.Utils.Extensions; +using BExIS.Utils.Files; using BExIS.Utils.Models; using BExIS.Utils.NH.Querying; using BExIS.Xml.Helpers; using ICSharpCode.SharpZipLib.Zip; using Newtonsoft.Json; using System; +using System.Collections.Generic; using System.Data; using System.Globalization; using System.IO; @@ -36,9 +40,10 @@ using System.Text; using System.Web.Mvc; using System.Web.Routing; +using System.Web.UI.WebControls; using System.Xml; using Telerik.Web.Mvc; -using Vaelastrasz.Library.Models; + using Vaiona.Logging; using Vaiona.Persistence.Api; using Vaiona.Utils.Cfg; @@ -195,10 +200,8 @@ public ActionResult SimpleDataStructure(long id) public ActionResult GenerateZip(long id, long versionid, string format, bool withFilter = false, bool withUnits = false, bool useTags = false, bool useMinor = false) { XmlDatasetHelper xmlDatasetHelper = new XmlDatasetHelper(); - DatasetManager dm = new DatasetManager(); - DataStructureManager dataStructureManager = new DataStructureManager(); - PublicationManager publicationManager = new PublicationManager(); SubmissionManager publishingManager = new SubmissionManager(); + List files = new List(); bool isFilterInUse = filterInUse(); string filteredFilePath = ""; @@ -207,18 +210,21 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit try { - using (var datasetManager = new DatasetManager()) + using(var datasetManager = new DatasetManager()) + using(var entityReferenceManager = new EntityReferenceManager()) + using(var dataStructureManager = new DataStructureManager()) + using(var publicationManager = new PublicationManager()) { long datasetVersionId = versionid; long dataStructureId = 0; - int datasetVersionNumber = dm.GetDatasetVersionNr(datasetVersionId); + int datasetVersionNumber = datasetManager.GetDatasetVersionNr(datasetVersionId); DatasetVersion datasetVersion = datasetManager.GetDatasetVersion(datasetVersionId); - double tagNr = datasetVersion.Tag!=null?datasetVersion.Tag.Nr:0; + double tagNr = datasetVersion.Tag != null ? datasetVersion.Tag.Nr : 0; string title = ""; - + #region Metadata @@ -238,7 +244,7 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit // check the data sturcture type ... - if (!string.IsNullOrEmpty(format) && datasetVersion.Dataset.DataStructure.Self is StructuredDataStructure && dm.GetDataTuplesCount(datasetVersion.Id) > 0) + if (!string.IsNullOrEmpty(format) && datasetVersion.Dataset.DataStructure.Self is StructuredDataStructure && datasetManager.GetDataTuplesCount(datasetVersion.Id) > 0) { OutputDataManager odm = new OutputDataManager(); @@ -270,7 +276,7 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit } } - + #endregion @@ -282,7 +288,7 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit DataStructure dataStructure = dataStructureManager.StructuredDataStructureRepo.Get(dataStructureId); string dataStructurePath = ""; - dataStructurePath = storeGeneratedFilePathToContentDiscriptor(id, datasetVersion,"datastructure", ".json"); + dataStructurePath = storeGeneratedFilePathToContentDiscriptor(id, datasetVersion, "datastructure", ".json"); string datastructureFilePath = AsciiWriter.CreateFile(dataStructurePath); // generate json @@ -290,10 +296,10 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit AsciiWriter.AllTextToFile(datastructureFilePath, json); // generate txt - dataStructurePath = storeGeneratedFilePathToContentDiscriptor(id, datasetVersion,"datastructure", ".csv"); + dataStructurePath = storeGeneratedFilePathToContentDiscriptor(id, datasetVersion, "datastructure", ".csv"); datastructureFilePath = AsciiWriter.CreateFile(dataStructurePath); - string txt = OutputDataStructureManager.GenerateDataStructureAsText(dataStructureId); + string txt = OutputDataStructureManager.GenerateDataStructureAsText(dataStructureId); AsciiWriter.AllTextToFile(datastructureFilePath, txt); @@ -306,11 +312,11 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit #region zip file - string zipName = IOHelper.GetFileName(FileType.Bundle, id, datasetVersionNumber, dataStructureId, title,tagNr,useTags,useMinor); //publishingManager.GetZipFileName(id, datasetVersionNumber); + string zipName = IOHelper.GetFileName(FileType.Bundle, id, datasetVersionNumber, dataStructureId, title, tagNr, useTags, useMinor); //publishingManager.GetZipFileName(id, datasetVersionNumber); // add suffix if filter is in use if (isFilterInUse & withFilter) zipName += "_filtered"; - string zipPath = Path.Combine(publishingManager.GetDirectoryPath(id, brokerName), zipName+".zip"); + string zipPath = Path.Combine(publishingManager.GetDirectoryPath(id, brokerName), zipName + ".zip"); FileHelper.CreateDicrectoriesIfNotExist(Path.GetDirectoryName(zipPath)); using (var zipFileStream = new FileStream(zipPath, FileMode.Create)) @@ -327,35 +333,39 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit string name = cd.URI.Split('\\').Last(); string ext = Path.GetExtension(name).ToLower(); - if(cd.Name.StartsWith("generated") && !cd.Name.Equals(dataName)) continue; + if (cd.Name.StartsWith("generated") && !cd.Name.Equals(dataName)) continue; if (FileHelper.FileExist(path)) { //if (!archive.Entries.Any(entry => entry.Name.EndsWith(name))) //{ - if (cd.Name.Equals("metadata")) - { - name = IOHelper.GetFileName(FileType.Metadata, id, datasetVersionNumber, dataStructureId,"", tagNr, useTags, useMinor) + ext; - } - else if (cd.Name.Equals("datastructure")) - { - name = IOHelper.GetFileName(FileType.DataStructure, id, datasetVersionNumber, dataStructureId,"", tagNr, useTags, useMinor) + ext; - } - else if (cd.Name.Contains("generated")) - { - name = IOHelper.GetFileName(FileType.PrimaryData, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor) + ext; - } - else // all other files from unstructured and attachments - // get filename from path - // the files stay with there original file names - { - name = Path.GetFileName(cd.URI); - } - - - // if data is filtered, do not add full data file - if (cd.Name.Contains("generated") == false || (cd.Name.Contains("generated") && withFilter == false)) - archive.AddFileToArchive(path, name); + if (cd.Name.Equals("metadata")) + { + name = IOHelper.GetFileName(FileType.Metadata, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor) + ext; + } + else if (cd.Name.Equals("datastructure")) + { + name = IOHelper.GetFileName(FileType.DataStructure, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor) + ext; + } + else if (cd.Name.Contains("generated")) + { + name = IOHelper.GetFileName(FileType.PrimaryData, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor) + ext; + } + else // all other files from unstructured and attachments + // get filename from path + // the files stay with there original file names + { + name = Path.GetFileName(cd.URI); + } + + + // if data is filtered, do not add full data file + if (cd.Name.Contains("generated") == false || (cd.Name.Contains("generated") && withFilter == false)) + { + archive.AddFileToArchive(path, name); + files.Add(name); + } + //} } } @@ -365,9 +375,10 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit { string path = Path.Combine(AppConfiguration.DataPath, filteredFilePath); string ext = Path.GetExtension(filteredFilePath).ToLower(); - string name = IOHelper.GetFileName(FileType.PrimaryData, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor)+"_filtered"+ ext; + string name = IOHelper.GetFileName(FileType.PrimaryData, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor) + "_filtered" + ext; archive.AddFileToArchive(filteredFilePath, name); + files.Add(name); } @@ -375,7 +386,64 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit // xml schema string xsdPath = OutputMetadataManager.GetSchemaDirectoryPath(id); if (Directory.Exists(xsdPath)) + { archive.AddFolderToArchive(xsdPath, "Schema"); + files.Add("Schema"); + } + + #region extensions + + var links = new List() { "extension" }; + var refs = entityReferenceManager.ReferenceRepository.Get().Where(r => r.SourceEntityId == datasetVersion.Dataset.EntityTemplate.EntityType.Id && r.SourceId == datasetVersion.Dataset.Id && links.Contains(r.LinkType)).ToList(); + // add data from linked datasets links + List extentions = new List(); + var outputDataManager = new OutputDataManager(); + + foreach (var r in refs) + { + if (links.Contains(r.LinkType)) + { + var ext = datasetManager.GetDataset(r.TargetId); + var structureId = ext.DataStructure == null ? 0 : ext.DataStructure.Id; + + int versionNr = r.TargetVersion; + + if (versionNr == 0) + { + var latestVersion = datasetManager.GetDatasetLatestVersion(r.TargetId); + versionNr = datasetManager.GetDatasetVersionNr(latestVersion.Id); + + } + + var refVersion = datasetManager.GetDatasetVersion(r.TargetId, versionNr); + + string rPath = outputDataManager.GenerateAsciiFile(ext.Id, refVersion.Id, format, false, false); + + if (System.IO.File.Exists(rPath)) + { + // reigister it maybe in the general metadata json + string extensionName = IOHelper.GetExtensionFileName(FileType.PrimaryData, id, datasetVersionNumber, dataStructureId, r.ReferenceType, r.TargetId, versionNr, tagNr, useTags); + string extPath = "Extension/"+extensionName; + archive.AddFileToArchive(rPath, extPath); + files.Add(extPath); + } + } + } + + #endregion + + #region terms and conditions + + string termsPath = this.Session.GetTenant().GetResourcePath("terms"); + + if (!string.IsNullOrEmpty(termsPath) && System.IO.File.Exists(termsPath)) + { + archive.AddFileToArchive(termsPath, "terms.txt"); + files.Add("terms.txt"); + } + + #endregion terms and conditions + #region manifest // manifest @@ -389,16 +457,19 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit datasetModel.DownloadInformation.DownloadedBy = getPartyNameOrDefault(); // set filter info - if(isFilterInUse) + if (isFilterInUse) datasetModel.DownloadInformation.DownloadedFilter = getFilterQuery(); - if(datasetModel.DownloadInformation.DownloadedBy == "DEFAULT") datasetModel.DownloadInformation.DownloadedBy = "ANONYMOUS"; + if (datasetModel.DownloadInformation.DownloadedBy == "DEFAULT") datasetModel.DownloadInformation.DownloadedBy = "ANONYMOUS"; + + // set files + datasetModel.Files = files; string manifest = JsonConvert.SerializeObject(datasetModel); - + if (manifest != null) { - string manifestFileName = IOHelper.GetFileName(FileType.Manifest, id, datasetVersionNumber, dataStructureId,"", tagNr, useTags, useMinor); + string manifestFileName = IOHelper.GetFileName(FileType.Manifest, id, datasetVersionNumber, dataStructureId, "", tagNr, useTags, useMinor); string manifestPath = OutputDatasetManager.GetDynamicDatasetStorePath(id, datasetVersionNumber, "general_metadata", ".json"); string fullFilePath = Path.Combine(AppConfiguration.DataPath, manifestPath); @@ -406,20 +477,13 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit if (!Directory.Exists(directory)) FileHelper.CreateDicrectoriesIfNotExist(directory); - System.IO.File.WriteAllText(fullFilePath, manifest, System.Text.Encoding.UTF8); + System.IO.File.WriteAllText(fullFilePath, manifest, System.Text.Encoding.UTF8); archive.AddFileToArchive(fullFilePath, manifestFileName + ".json"); } #endregion - #region terms and conditions - - string termsPath = this.Session.GetTenant().GetResourcePath("terms"); - if(!string.IsNullOrEmpty(termsPath) && System.IO.File.Exists(termsPath)) - archive.AddFileToArchive(termsPath, "terms.txt"); - - #endregion terms and conditions title = datasetVersion.Title; title = String.IsNullOrEmpty(title) ? "unknown" : title; @@ -448,15 +512,9 @@ public ActionResult GenerateZip(long id, long versionid, string format, bool wit LoggerFactory.LogCustom("Error: " + ex.Message); throw ex; } - finally - { - dm.Dispose(); - dataStructureManager.Dispose(); - publicationManager.Dispose(); - } - } + } private string getCDTypeName(string mimeType) { diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs index b6d59a4139..aa804a13ab 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Controllers/PublishController.cs @@ -35,7 +35,7 @@ public ActionResult Start(long id, int version = 0) [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Read)] public ActionResult StartView(long id, int version = 0) { - return RedirectToAction("getPublishDataPartialView", "Submission", new { datasetId = id, versionId = version }); + return RedirectToAction("getPublishDataView", "Submission", new { datasetId = id, versionId = version }); } } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/Download/GeneralMetadataModel.cs b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/Download/GeneralMetadataModel.cs index 76e8cdb678..9b228d729f 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/Download/GeneralMetadataModel.cs +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Models/Download/GeneralMetadataModel.cs @@ -1,4 +1,6 @@ using BExIS.Dim.Helpers.Models; +using BExIS.UI.Helpers; +using System.Collections.Generic; using System.Reflection; namespace BExIS.Modules.Dim.UI.Models.Download @@ -7,6 +9,7 @@ public class GeneralMetadataModel : ApiDatasetModel { //public ApiDatasetModel Dataset { get; set; } public DatasetDownloadInfoModel DownloadInformation { get; set; } + public List Files { get; set; } public GeneralMetadataModel() : base() { diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs index 6551884479..a417d1072d 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/UserPermissionsController.cs @@ -29,7 +29,7 @@ public ActionResult StartView(long id, int version = 0) { using (var entityManager = new EntityManager()) { - return RedirectToAction("SubjectsPartialView", "UserPermissions", new { EntityId = entityManager.FindByName("Dataset").Id, InstanceId = id }); + return RedirectToAction("SubjectsView", "UserPermissions", new { EntityId = entityManager.FindByName("Dataset").Id, InstanceId = id }); } } @@ -69,10 +69,10 @@ public async Task RemoveRightFromEntityPermission(long subjectId, long entityId, } } - public ActionResult SubjectsPartialView(long entityId, long instanceId) - { - return PartialView("_Subjects", new EntityInstanceModel() { EntityId = entityId, InstanceId = instanceId }); - } + //public ActionResult SubjectsPartialView(long entityId, long instanceId) + //{ + // return PartialView("_Subjects", new EntityInstanceModel() { EntityId = entityId, InstanceId = instanceId }); + //} public ActionResult SubjectsView(long entityId, long instanceId) { From 465a1d46eecc857f6e50436b37378255eff7856f Mon Sep 17 00:00:00 2001 From: david schoene Date: Thu, 9 Jul 2026 11:08:19 +0200 Subject: [PATCH 178/490] #907 change location of hooks for edit mode in hooks/edit to create alsoo view hooks add description and data to view, enhance data description view --- .../components/datadescription/Show.svelte | 17 ++- .../{ => table}/NameTableCol.svelte | 0 .../datadescription/table/TableBool.svelte | 6 ++ .../lib/hooks/{ => edit}/Attachment.svelte | 0 .../src/lib/hooks/{ => edit}/Data.svelte | 2 +- .../hooks/{ => edit}/DataDescription.svelte | 3 +- .../lib/hooks/{ => edit}/FileUpload.svelte | 2 +- .../src/lib/hooks/{ => edit}/Link.svelte | 0 .../src/lib/hooks/{ => edit}/Metadata.svelte | 0 .../lib/hooks/{ => edit}/Permission.svelte | 0 .../src/lib/hooks/{ => edit}/Publish.svelte | 0 .../src/lib/hooks/{ => edit}/Submit.svelte | 4 +- .../lib/hooks/{ => edit}/Validation.svelte | 4 +- .../placeholder/PlaceHolderHookContent.svelte | 0 .../placeholder/PlaceholderHook.svelte | 0 .../src/lib/hooks/view/Data.svelte | 45 ++++++++ .../src/lib/hooks/view/DataDescription.svelte | 31 ++++++ .../hooks/view/Link.svelte} | 2 +- .../src/lib/hooks/view/Metadata.svelte | 20 ++++ .../src/models/DataDescription.ts | 15 ++- .../src/routes/edit/Data.svelte | 12 +-- .../src/routes/edit/Hooks.svelte | 8 +- .../src/routes/edit/PlaceholderPage.svelte | 2 +- .../src/routes/view/+page.svelte | 100 +++++++++++++++--- .../src/routes/view/Header.svelte | 59 ++++++++--- .../src/routes/view/License.svelte | 23 ++-- .../view/citation/CitationDownload.svelte | 4 +- .../src/routes/view/citation/Text.svelte | 6 +- .../src/routes/view/download/Download.svelte | 2 +- .../src/routes/view/error/Deleted.svelte | 7 +- .../Hooks/DataDescriptionController.cs | 9 +- .../BExIS.Modules.Dcm.UI/Hooks/DataHook.cs | 2 +- .../Hooks/DataStructurePreviewHook.cs | 2 +- .../Models/Edit/DataDescriptionModel.cs | 5 + .../DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml | 4 +- .../SAM/BExIS.Modules.Sam.UI/Sam.Manifest.xml | 4 +- 36 files changed, 314 insertions(+), 86 deletions(-) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/{ => table}/NameTableCol.svelte (100%) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/table/TableBool.svelte rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Attachment.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Data.svelte (95%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/DataDescription.svelte (98%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/FileUpload.svelte (98%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Link.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Metadata.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Permission.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Publish.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Submit.svelte (99%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/Validation.svelte (96%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/placeholder/PlaceHolderHookContent.svelte (100%) rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/{ => edit}/placeholder/PlaceholderHook.svelte (100%) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Data.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte rename Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/{routes/view/Links.svelte => lib/hooks/view/Link.svelte} (92%) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Metadata.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte index 33703142e8..a284ff3383 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/Show.svelte @@ -4,7 +4,8 @@ import { Table } from '@bexis2/bexis2-core-ui'; import type { TableConfig } from '@bexis2/bexis2-core-ui'; import { writable } from 'svelte/store'; - import NameTableCol from './NameTableCol.svelte'; + import NameTableCol from './table/NameTableCol.svelte'; + import TableBool from './table/TableBool.svelte'; export let id; //enityid export let title; @@ -22,6 +23,11 @@ variableStore.set(variables); console.log('🚀 ~ variables:', variables); + // if this component is called in context of edit and the user has the permission to edit, then enable edit + // otherwise, disable edit + const path = window.location.pathname; + enableEdit = (path.includes('edit')) && enableEdit; + const variableConfig: TableConfig = { id: 'variables', data: variableStore, @@ -42,7 +48,14 @@ }, dataType: { header: 'Data Type' - } + }, + isOptional: { + header: 'Optional', + disableFiltering: true, + instructions: { + renderComponent: TableBool + } + }, } }; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/NameTableCol.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/table/NameTableCol.svelte similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/NameTableCol.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/table/NameTableCol.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/table/TableBool.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/table/TableBool.svelte new file mode 100644 index 0000000000..c6a76fd9c0 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/table/TableBool.svelte @@ -0,0 +1,6 @@ + + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Attachment.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/Attachment.svelte similarity index 100% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Attachment.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/Attachment.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/Data.svelte similarity index 95% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/Data.svelte index cb9f1bb751..3a852dee07 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/Data.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/Data.svelte @@ -6,7 +6,7 @@ import PrimaryData from '$lib/components/data/PrimaryData.svelte'; import PlaceHolderHookContent from './placeholder/PlaceHolderHookContent.svelte'; import { ErrorMessage } from '@bexis2/bexis2-core-ui'; - import { latestSubmitDate, latestDataDate } from '../../routes/edit/stores'; + import { latestSubmitDate, latestDataDate } from '../../../routes/edit/stores'; export let id = 0; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/DataDescription.svelte similarity index 98% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/DataDescription.svelte index 0fbee0b51c..4af224e774 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/DataDescription.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/edit/DataDescription.svelte @@ -1,6 +1,6 @@ + +

Data

+ +
+ {#await load()} + + {:then result} + {#if model.hasStructure} + + {:else} + + {/if} + {:catch error} + + {/await} +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte new file mode 100644 index 0000000000..cc38f13f5b --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte @@ -0,0 +1,31 @@ + + +

Data Description

+ +
+ {#if model && model.isStructured} + + {/if} + + +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte similarity index 92% rename from Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte rename to Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte index a57c80a38c..4327494b7d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Links.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte @@ -1,5 +1,5 @@ + + + + {description} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/DataDescription.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/DataDescription.ts index dea634f7f5..e7873471b9 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/DataDescription.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/models/DataDescription.ts @@ -17,9 +17,14 @@ export interface DataDescriptionModel { } export interface VariableModel { - id: number; - name: string; - unit: string; - dataType: string; - isKey: boolean; + id: number; + name: string; + description: string; + unit: string; + dataType: string; + category: string; + missingValues: string; + meanings: string; + isOptional: boolean; + isKeys: boolean; } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Data.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Data.svelte index 81cf5c97aa..ff9eb06be2 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Data.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Data.svelte @@ -2,12 +2,12 @@ import Hook from '$lib/components/Hook.svelte'; import HookContainer from '$lib/components/HookContainer.svelte'; - import Validation from '$lib/hooks/Validation.svelte'; - import FileUpload from '$lib/hooks/FileUpload.svelte'; - import DataDescription from '$lib/hooks/DataDescription.svelte'; - import Submit from '$lib/hooks/Submit.svelte'; - import Metadata from '$lib/hooks/Metadata.svelte'; - import Data from '$lib/hooks/Data.svelte'; + import Validation from '$lib/hooks/edit/Validation.svelte'; + import FileUpload from '$lib/hooks/edit/FileUpload.svelte'; + import DataDescription from '$lib/hooks/edit/DataDescription.svelte'; + import Submit from '$lib/hooks/edit/Submit.svelte'; + import Metadata from '$lib/hooks/edit/Metadata.svelte'; + import Data from '$lib/hooks/edit/Data.svelte'; import { Spinner } from '@bexis2/bexis2-core-ui'; import Fa from 'svelte-fa'; import { faAngleRight } from '@fortawesome/free-solid-svg-icons'; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte index 3717b62635..1fdb081ac0 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/Hooks.svelte @@ -1,12 +1,12 @@ diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte index 2122d14b9f..04394e2f72 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte @@ -1,7 +1,7 @@ @@ -94,12 +142,26 @@ {:then result} -
+
-
- {model.description} -
+ + {#if metadataHook} +
+ +
+ {/if} +
@@ -128,10 +190,24 @@
- + {#if linkHook } + + {/if} + + + + {#if dataDescriptionHook && model.dataStructureId !== undefined && model.dataStructureId > 0} + + {/if} + + {#if dataHook && model.hasData} + + + {/if} - {#if model.downloadAccess} - + + {#if model.downloadAccess && addtionalhooks && addtionalhooks.length > 0 } + {/if} {:catch error} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte index 3b2526b1b6..a079bc42a5 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte @@ -3,6 +3,8 @@ import { faPen } from "@fortawesome/free-solid-svg-icons"; import Citation from "./Citation.svelte"; import License from "./License.svelte"; + import { goTo } from "$services/BaseCaller"; + export let id; export let version; @@ -11,15 +13,17 @@ import Citation from "./Citation.svelte"; export let license = ""; export let isPartOfCollection:boolean = false; export let hasEditRight:boolean = false; + export let isPublic:boolean = false; + export let publicationDate:string = ''; const labelKeys = Object.keys(labels); - + console.log("🚀 ~ labels:", labels) -
-
- +
+ +
{#if hasEditRight}
{/if} -
-
- {#if labelKeys && labelKeys.length > 0} - {#each labelKeys as key} - {key} - {/each} - {/if} - {#if isPartOfCollection} - part of collection - {/if} +
+ {#if isPublic} +
+ Published {new Date(publicationDate).toLocaleDateString()} +
+ {/if} + {#if labelKeys && labelKeys.length > 0} + {#each labelKeys as key} + {#if labels[key] === 'DOI'} + {key} + {:else} + {key} + {/if} + {/each} + {/if} - {#if license} - - {/if} + {#if isPartOfCollection} + part of collection + {/if} + + {#if license} + + {/if} +
+ + + + +
+ + +
+ + +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/License.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/License.svelte index 183e48257a..0993d4e0f7 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/License.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/License.svelte @@ -41,24 +41,21 @@ const l = license.toUpperCase(); - +
+{l} {#if l === 'CC BY'} - + {:else if l === 'CC BY-SA'} - + {:else if l === 'CC BY-ND'} - + {:else if l === 'CC BY-NC'} - + {:else if l === 'CC BY-NC-SA'} - + {:else if l === 'CC BY-NC-ND'} - + {:else if l === 'CC'} - - -{:else } -{l} - + {/if} - \ No newline at end of file +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/CitationDownload.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/CitationDownload.svelte index fb7f6807ba..87e7decd66 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/CitationDownload.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/CitationDownload.svelte @@ -11,7 +11,7 @@ export let version = 0;; export let tag = 0; let selectedFormat:number = -1; - $:selectedFormat, console.log("🚀 ~ selectedFormat:", selectedFormat, downloadAccess), downloadAccess = selectedFormat !== ''?true:false; + $:selectedFormat, console.log("🚀 ~ selectedFormat:", selectedFormat, downloadAccess), downloadAccess = selectedFormat !== -1?true:false; let filename = `entity_${id}_${version}.txt`; @@ -87,7 +87,7 @@ async function downloadCitationFn() {/each} - +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte index 1a8e759007..a842e62f13 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/citation/Text.svelte @@ -24,9 +24,8 @@ - -
Citation: -
+
+
{model.authors} ({model.year}): {model.title}. @@ -39,6 +38,7 @@ id="citation-copy" title="Copy citation to clipboard" role="button" tabindex="0">
+
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte index 7744d80fb1..05fee9c3ed 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte @@ -132,7 +132,7 @@ function sendDataTo(data, name, type) {/each} - +
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/error/Deleted.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/error/Deleted.svelte index f8be2fd733..d3225ee694 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/error/Deleted.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/error/Deleted.svelte @@ -2,10 +2,9 @@ import { onMount } from 'svelte'; import {getDeleted} from '../services.js'; - import Links from '../Links.svelte'; + import type { DeletedModel } from '../types.js'; - import PlaceHolderHookContent from '$lib/hooks/placeholder/PlaceHolderHookContent.svelte'; - import { Alert, TablePlaceholder } from '@bexis2/bexis2-core-ui'; + import Link from '$lib/hooks/view/Link.svelte'; export let id: number; @@ -77,7 +76,7 @@
- + {/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs index 3fd7678fc2..2ba273cbdc 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs @@ -79,9 +79,14 @@ public JsonResult Load(long id, int version) { Id = variable.Id, Name = variable.Label, + Description = variable.Description, DataType = variable.DataType.Name, - Unit = variable.Unit.Name, - IsKeys = variable.IsKey + Unit = variable.Unit != null ? variable.Unit.Abbreviation:"n/a", + IsKeys = variable.IsKey, + IsOptional = variable.IsValueOptional, + Category = variable.VariableTemplate != null ? variable.VariableTemplate.Label : "n/a", + MissingValues = variable.MissingValues != null ? String.Join(", ", variable.MissingValues.Select(m => m.DisplayName)) : "n/a", + Meanings = variable.Meanings != null ? String.Join(", ", variable.Meanings.Select(m => m.Name)) : "n/a" }); } diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataHook.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataHook.cs index d5fbf6bde4..a3eaf023f3 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataHook.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataHook.cs @@ -8,7 +8,7 @@ public class DataHook : Hook { public DataHook() { - Start = "/dcm/view/startData"; + Start = "/dcm/data/start"; } public override void Check(long id, string username) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataStructurePreviewHook.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataStructurePreviewHook.cs index dedc982b0b..5ee0a6ef4f 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataStructurePreviewHook.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Hooks/DataStructurePreviewHook.cs @@ -8,7 +8,7 @@ public class DataStructurePreviewHook : Hook { public DataStructurePreviewHook() { - Start = "/dcm/view/StartDataStructure"; + Start = "/dcm/datadescription/start"; } public override void Check(long id, string username) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/Edit/DataDescriptionModel.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/Edit/DataDescriptionModel.cs index 08c0c29641..a1076401fb 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/Edit/DataDescriptionModel.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Models/Edit/DataDescriptionModel.cs @@ -63,8 +63,13 @@ public class VariableModel { public long Id { get; set; } public string Name { get; set; } + public string Description { get; set; } public string Unit { get; set; } public string DataType { get; set; } + public string Category { get; set; } + public string MissingValues { get; set; } + public string Meanings { get; set; } + public bool IsOptional { get; set; } public bool IsKeys { get; set; } } } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml index d6baad3326..eb2308e7c5 100644 --- a/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml +++ b/Console/BExIS.Web.Shell/Areas/DIM/BExIS.Modules.Dim.UI/Dim.Manifest.xml @@ -56,14 +56,14 @@ - + type="BExIS.Modules.Dim.UI.Hooks.PublishViewHook, BExIS.Modules.DIM.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />--> - + type="BExIS.Modules.Sam.UI.Hooks.UserPermissionsViewHook, BExIS.Modules.SAM.UI, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />--> Date: Thu, 9 Jul 2026 14:31:52 +0200 Subject: [PATCH 179/490] #2527 Change data structure validation messages --- .../DataStructure/Constraint.cs | 10 +++++----- .../ValueCheck/DataTypeCheck.cs | 18 +++++++++--------- .../ValueValidation/DomainValidation.cs | 2 +- .../lib/components/validation/Message.svelte | 2 +- 4 files changed, 16 insertions(+), 16 deletions(-) diff --git a/Components/DLM/BExIS.Dlm.Entities/DataStructure/Constraint.cs b/Components/DLM/BExIS.Dlm.Entities/DataStructure/Constraint.cs index 310b87fc1c..b9268b23fa 100644 --- a/Components/DLM/BExIS.Dlm.Entities/DataStructure/Constraint.cs +++ b/Components/DLM/BExIS.Dlm.Entities/DataStructure/Constraint.cs @@ -318,8 +318,8 @@ public override string FormalDescription /// NA public PatternConstraint() { - defaultMessageTemplate = "Value(s) does not match the pattern. The value should match {0} {1}."; - defaultNegatedMessageTemplate = "Value(s) matches the pattern, but the constraint is negated. The value should not match {0} {1}."; + defaultMessageTemplate = "Value does not match the pattern. The value should match {0} {1}."; + defaultNegatedMessageTemplate = "Value matches the pattern, but the constraint is negated. The value should not match {0} {1}."; CaseSensitive = true; } @@ -426,7 +426,7 @@ public override string FormalDescription { if (Negated) { - return (string.Format("The value must be {0} {1} or {2} {3}.", (!LowerboundIncluded ? "less than or equal to" : "less than"), Lowerbound // if boundaries are not included in the constarint, they are part of the negated + return (string.Format("The value must be {0} ({1}) or {2} ({3}).", (!LowerboundIncluded ? "less than or equal to" : "less than"), Lowerbound // if boundaries are not included in the constarint, they are part of the negated , (!UpperboundIncluded ? "greater than or equal to" : "greater than"), Upperbound )); } @@ -451,8 +451,8 @@ public override string FormalDescription /// public RangeConstraint() { - defaultMessageTemplate = "Value(s) out of allowed range. The value should be between {0} {1} and {2} {3}."; - defaultNegatedMessageTemplate = "Value(s) within range, but the constraint is negated. The value should be {1} {0} or {3} {2}."; + defaultMessageTemplate = "Value out of allowed range. The value should be between {0} ({1}) and {2} ({3})."; + defaultNegatedMessageTemplate = "Value within range, but the constraint is negated. The value should be {1} ({0}) or {3} ({2})."; } public RangeConstraint(ConstraintProviderSource provider, string constraintSelectionPredicate, string cultureId diff --git a/Components/IO/BExIS.Io.Transform.Validation/ValueCheck/DataTypeCheck.cs b/Components/IO/BExIS.Io.Transform.Validation/ValueCheck/DataTypeCheck.cs index 93e16fcf32..6f88d8bb07 100644 --- a/Components/IO/BExIS.Io.Transform.Validation/ValueCheck/DataTypeCheck.cs +++ b/Components/IO/BExIS.Io.Transform.Validation/ValueCheck/DataTypeCheck.cs @@ -97,7 +97,7 @@ public object Execute(string value, int row=0) } else { - return new Error(ErrorType.Value, "Can not convert to " + dataType + ". Check the current data type of the variable.", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid data type. Expected: Integer (e.g., 1, 2, 3).", new object[] { name, value, row, dataType }); } } @@ -129,11 +129,11 @@ public object Execute(string value, int row=0) } else { - return new Error(ErrorType.Value, "False decimal character.", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid decimal separator. Currently expected: point.", new object[] { name, value, row, dataType }); } } - return new Error(ErrorType.Value, "Can not convert to " + dataType + ".", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid data type. Expected: Number (e.g., 1.5, 2.0).", new object[] { name, value, row, dataType }); } if (decimalCharacter.Equals(DecimalCharacter.comma)) @@ -155,18 +155,18 @@ public object Execute(string value, int row=0) } else { - return new Error(ErrorType.Value, "False decimal character.", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid decimal separator. Currently expected: comma.", new object[] { name, value, row, dataType }); } } - return new Error(ErrorType.Value, "Can not convert to " + dataType + ".", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid data type. Expected: Number (e.g., 1.5, 2.0).", new object[] { name, value, row, dataType }); } return Convert.ToDouble(value); } catch (Exception ex) { - return new Error(ErrorType.Value, "Can not convert to " + dataType + ".", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid data type. Expected: Number (e.g., 1.5, 2.0).", new object[] { name, value, row, dataType }); } } @@ -190,9 +190,9 @@ public object Execute(string value, int row=0) } } if (!string.IsNullOrEmpty(pattern)) - return new Error(ErrorType.Value, "Can not convert to " + dataType + ".", new object[] { name, value, row, dataType, pattern }); + return new Error(ErrorType.Value, "Invalid date format. Expected: " + pattern, new object[] { name, value, row, dataType, pattern }); else - return new Error(ErrorType.Value, "Can not convert to " + dataType + ".", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid data type. Expected: DateTime.", new object[] { name, value, row, dataType }); } case "Char": @@ -223,7 +223,7 @@ public object Execute(string value, int row=0) } else { - return new Error(ErrorType.Value, "Can not convert to " + dataType + ".", new object[] { name, value, row, dataType }); + return new Error(ErrorType.Value, "Invalid data type. Expected: Boolean.", new object[] { name, value, row, dataType }); } } } diff --git a/Components/IO/BExIS.Io.Transform.Validation/ValueValidation/DomainValidation.cs b/Components/IO/BExIS.Io.Transform.Validation/ValueValidation/DomainValidation.cs index a3eb31fbb5..7f91f74483 100644 --- a/Components/IO/BExIS.Io.Transform.Validation/ValueValidation/DomainValidation.cs +++ b/Components/IO/BExIS.Io.Transform.Validation/ValueValidation/DomainValidation.cs @@ -70,7 +70,7 @@ public Error Execute(object value, int row) if (value != null) { if (CheckList.Contains(value.ToString())) return null; - else return new Error(ErrorType.Value, "Value is not in domain", new object[] { name, value, row, dataType }); + else return new Error(ErrorType.Value, "Value is not in domain list.", new object[] { name, value, row, dataType }); } return null; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte index 2263e61923..57ce07c7fa 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/validation/Message.svelte @@ -9,7 +9,7 @@ -
{count} {type === 'error' ? 'Errors' : 'Warnings'}
+
{count} {count === 1 ? (type === 'error' ? 'Error' : 'Warning') : (type === 'error' ? 'Errors' : 'Warnings')}
{title}
    From 8a6809abb6b7c592d8d4295dafbca9f8ca4e837b Mon Sep 17 00:00:00 2001 From: david schoene Date: Fri, 10 Jul 2026 15:13:20 +0200 Subject: [PATCH 180/490] #907 add data and dadaescription view page, --- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 + .../lib/components/data/PrimaryData.svelte | 2 + .../datadescription/ShowHeader.svelte | 20 ++++---- .../src/lib/components/utils/Back.svelte | 8 +++ .../src/lib/hooks/view/Data.svelte | 17 +++++-- .../src/lib/hooks/view/DataDescription.svelte | 25 ++++++--- .../src/lib/hooks/view/Link.svelte | 7 ++- .../src/routes/view/+page.svelte | 16 ++++-- .../src/routes/view/Citation.svelte | 3 +- .../src/routes/view/Header.svelte | 6 +-- .../routes/view/datadescription/+page.svelte | 39 ++++++++++++++ .../src/routes/view/services.js | 51 ++++++++++++++----- .../src/services/BaseCaller.js | 16 ++++-- .../BExIS.Modules.Dcm.UI.csproj | 2 + .../Hooks/DataDescriptionController.cs | 3 ++ .../Controllers/ViewController.cs | 44 +++++++++++++++- .../Views/View/Data.cshtml | 23 +++++++++ .../Views/View/DataDescription.cshtml | 22 ++++++++ .../Views/View/Index.cshtml | 6 ++- 19 files changed, 263 insertions(+), 49 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/Back.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/datadescription/+page.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Data.cshtml create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/DataDescription.cshtml diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 53c3b78caf..988ad71e26 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -9,6 +9,8 @@
    +
    +
    diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/PrimaryData.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/PrimaryData.svelte index 3afcffb091..8fa8a5c3e3 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/PrimaryData.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/PrimaryData.svelte @@ -5,6 +5,8 @@ import { createEventDispatcher } from 'svelte'; export let id: number | undefined = undefined; + export let version: number | undefined = undefined; + type ServerTableType = { id: number; name: string; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/ShowHeader.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/ShowHeader.svelte index ae4610be84..60df7fb0c5 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/ShowHeader.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/datadescription/ShowHeader.svelte @@ -87,22 +87,24 @@
    + {#if enableEdit} - {#if enableEdit} + - {/if} - {#if hasData === false} - - {/if} + + {#if hasData === false} + + {/if} + {/if}
    diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/Back.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/Back.svelte new file mode 100644 index 0000000000..44c139eb78 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/Back.svelte @@ -0,0 +1,8 @@ + + + + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Data.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Data.svelte index fd8d9f8e4f..fa59a55654 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Data.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Data.svelte @@ -4,7 +4,9 @@ import { onMount } from "svelte"; import PlaceHolderHookContent from "../edit/placeholder/PlaceHolderHookContent.svelte"; import PrimaryData from "$lib/components/data/PrimaryData.svelte"; - import Files from "$lib/components/data/Files.svelte"; + import FilesView from "$lib/components/data/FilesView.svelte"; + import Fa from "svelte-fa"; + import { faMaximize } from "@fortawesome/free-solid-svg-icons"; export let id = 0; @@ -23,19 +25,26 @@ -

    Data

    +
    +

    Data

    +
    + +
    + +
    {#await load()} {:then result} {#if model.hasStructure} + + {:else} - {/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte index cc38f13f5b..69197462c6 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/DataDescription.svelte @@ -1,12 +1,16 @@ -

    Data Description

    + +
    +

    Data Description

    +
    + +
    +
    - {#if model && model.isStructured} - - {/if} - + + {#if model && model.isStructured} + + {/if}
    \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte index 4327494b7d..63a2d559d7 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte @@ -3,6 +3,7 @@ export let links:ReferenceModel[] = []; + console.log("🚀 ~ links:", links) const types = links.map(link => link.linkType).filter((value, index, self) => self.indexOf(value) === index); @@ -22,7 +23,11 @@

    {type.toUpperCase()}

    {#each links.filter(link => link.linkType === type) as link} -
    {link.referenceType}{link.target.title}
    +
    {link.referenceType} + {link.target.type} + {link.target.title} + {link.context} +
    {/each}
    diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte index 04394e2f72..b128b81bd7 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/+page.svelte @@ -34,6 +34,7 @@ let container; let id: number; let version: number = 0; + let tag: number = 0; let model: ViewModel; let isPartOfCollection: boolean = false; @@ -62,13 +63,14 @@ container = document.getElementById('view'); id = container?.getAttribute('dataset'); version = container?.getAttribute('version'); + tag = container?.getAttribute('tag'); - console.log('start view', id, version); + console.log('start view', id, version, tag); //setup api // setApiConfig('https://localhost:44345', 'davidschoene', '123456'); // load data from server - const res = await getView(id); + const res = await getView(id, version, tag); if(res?.status==200) { @@ -77,6 +79,7 @@ title = model.title; version = model.version; id = model.id; + tag = model.tag; console.log('model',model); console.log('hooks', hooks); @@ -145,6 +148,7 @@
    - + + + + {/if} {#if dataDescriptionHook && model.dataStructureId !== undefined && model.dataStructureId > 0} - + {/if} {#if dataHook && model.hasData} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Citation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Citation.svelte index 91520567c3..56aa74be07 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Citation.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Citation.svelte @@ -8,6 +8,7 @@ export let id; export let version; + export let tag; let data:CitationDataModel; let citationComponent; @@ -15,7 +16,7 @@ onMount(async () => { - const res:CitationModel = await getCitation(id, version); + const res:CitationModel = await getCitation(id, version, tag); console.log('citation', res); console.log('format', res.format, ReadCitationFormat.Default); diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte index a079bc42a5..aa52e01750 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte @@ -8,6 +8,7 @@ import Citation from "./Citation.svelte"; export let id; export let version; + export let tag; export let title = ''; export let labels:{ [key: string]: string; } = {}; export let license = ""; @@ -43,7 +44,7 @@ import Citation from "./Citation.svelte"; {#if labelKeys && labelKeys.length > 0} {#each labelKeys as key} {#if labels[key] === 'DOI'} - {key} + {key} {:else} {key} {/if} @@ -64,8 +65,7 @@ import Citation from "./Citation.svelte";
    - - +
    diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/datadescription/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/datadescription/+page.svelte new file mode 100644 index 0000000000..b2f144461a --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/datadescription/+page.svelte @@ -0,0 +1,39 @@ + + + + + + + {#if model && model.isStructured} + + {/if} + + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js index 29a5de4090..849a9a3a2c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/services.js @@ -1,8 +1,8 @@ import { Api } from '@bexis2/bexis2-core-ui'; // get model for View page -export const getView = async (id) => { +export const getView = async (id, version, tag) => { try { - const response = await Api.get('/dcm/view/load?id=' + id); + const response = await Api.get('/dcm/view/load?id=' + id + '&version=' + version + '&tag=' + tag); console.log("🚀 ~ getView ~ response:", response) return response; } catch (error) { @@ -11,26 +11,28 @@ export const getView = async (id) => { } }; -export const getApiDataset = async (id, version ) => { +export const getApiDataset = async (id, version, tag ) => { try { - if(version === undefined || version <= 0){ - const response = await Api.get('/api/dataset/'+id); - return response.data; - } - else{ - const response = await Api.get('/api/dataset/'+id+'/version_number/'+version); - return response.data; - } + + let url = '/api/dataset/'+id; + if(version >= 0 && (tag === undefined || tag <= 0)){ //load by version + url = '/api/dataset/'+id+'/version_number/'+version + } + else if(tag >= 0){ //load by tag + url = '/api/dataset/'+id+'/tag/'+tag + } + const response = await Api.get(url); + return response.data; } catch (error) { console.error(error); } }; -export const getCitation = async (id, version) => { +export const getCitation = async (id, version, tag) => { try { - const response = await Api.get('/dcm/view/citation?id=' + id+'&version=' + version); + const response = await Api.get('/dcm/view/citation?id=' + id+'&version=' + version+'&tag=' + tag); return response.data; } catch (error) { console.error(error); @@ -66,7 +68,16 @@ export const getDeleted = async (id) => { export const getCitationText = async (id, version, tag, format) => { try { - const response = await Api.get(`api/datasets/${id}/version_number/${version}/citations?format=${format}`); + + let url = '/api/dataset/'+id; + if(version >= 0 && (tag === undefined || tag <= 0)){ //load by version + url = '/api/dataset/'+id+'/version_number/'+version + } + else if(tag >= 0){ //load by tag + url = '/api/dataset/'+id+'/tag/'+tag + } + + const response = await Api.get(`${url}/citations?format=${format}`); return response.data; } catch (error) { console.error(error); @@ -82,6 +93,16 @@ export const getCitationOptions = async (id, version, tag ) => { } }; +export const getDataDescription = async (id, version) => { + try { + const response = await Api.get(`/dcm/datadescription/Load?id=${id}&version=${version}`); + return response.data; + } catch (error) { + console.error(error); + } +}; + + export const downloadZip = async (id, format, version = -1, withFilter = false, withUnits = false) => { try { const config = { responseType: 'blob' } @@ -112,3 +133,5 @@ export const sendRequest = async (id, intension) => { } }; + + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/BaseCaller.js b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/BaseCaller.js index ec81838d7a..91934f65af 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/BaseCaller.js +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/BaseCaller.js @@ -1,6 +1,6 @@ // Implementations for all the calls for the pokemon endpoints. //import Api from "./Api"; -import { host } from '@bexis2/bexis2-core-ui'; +import { host, Api } from '@bexis2/bexis2-core-ui'; // go to a internal action export const goTo = async (url, intern = true) => { @@ -15,8 +15,6 @@ export const goTo = async (url, intern = true) => { } }; -import { Api } from '@bexis2/bexis2-core-ui'; - export const getToken = async () => { try { const response = await Api.get('/tokens/get'); @@ -26,3 +24,15 @@ export const getToken = async () => { throw error; } }; + +export const goToEntity = async (url, id, version, tag) => { + + if(version>=0 && tag==0){ + goTo(`${url}?id=${id}&version=${version}`); + } + + if(version==0 && tag!=0){ + goTo(`${url}?${id}&tag=${tag}`); + } +}; + diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj index e182cb08cd..912250548c 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/BExIS.Modules.Dcm.UI.csproj @@ -480,6 +480,8 @@ + + Web.config diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs index 2ba273cbdc..527438a729 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/DataDescriptionController.cs @@ -7,6 +7,7 @@ using BExIS.Modules.Dcm.UI.Models.Edit; using BExIS.Security.Services.Authorization; using BExIS.Security.Services.Objects; +using BExIS.UI.Helpers; using BExIS.UI.Hooks; using BExIS.UI.Hooks.Caches; using BExIS.UI.Hooks.Logs; @@ -28,6 +29,8 @@ namespace BExIS.Modules.Dcm.UI.Controllers [SessionState(SessionStateBehavior.ReadOnly)] public class DataDescriptionController : Controller { + + /// /// entry for hook /// diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs index 2903ce9fac..4081c11c94 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/ViewController.cs @@ -88,6 +88,7 @@ public ViewController(UserManager userManager) /// /// /// + /// /// public ActionResult Index(long id, int version = 0, double tag = 0) { @@ -98,6 +99,7 @@ public ActionResult Index(long id, int version = 0, double tag = 0) ViewData["id"] = id; ViewData["version"] = version; + ViewData["tag"] = tag; ViewData["app"] = SvelteHelper.GetApp(module); ViewData["start"] = SvelteHelper.GetStart(module); @@ -1138,6 +1140,29 @@ public JsonResult Import(long id) #endregion + #region Data + [BExISEntityAuthorize(typeof(Dataset), "id", RightType.Read)] + + // load in seperate page + public ActionResult Data(long id, int version = 0) + { + + if (id == 0) throw new ArgumentException("id is not valid"); + + string module = "DCM"; + + ViewData["id"] = id; + ViewData["version"] = version; + + using (var datasetManager = new DatasetManager()) + { + ViewData["versionId"] = datasetManager.GetDatasetVersionId(id, version); + } + + + + return View(); + } /// /// Start from Data Hook - view /// @@ -1172,6 +1197,23 @@ public ActionResult StartData(long id, int version) } } + #endregion + + #region data description + // load in seperate page + public ActionResult DataDescription(long id, int version = 0) + { + + if (id == 0) throw new ArgumentException("id is not valid"); + + string module = "DCM"; + + ViewData["id"] = id; + ViewData["version"] = version; + + + return View(); + } public ActionResult StartDataStructure(long id, int version) { @@ -1180,7 +1222,7 @@ public ActionResult StartDataStructure(long id, int version) return RedirectToAction("ShowPreviewDataStructure", "Data", new { area = "DDM", datasetID = id }); } - + #endregion public ActionResult Test() { diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Data.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Data.cshtml new file mode 100644 index 0000000000..227839110f --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Data.cshtml @@ -0,0 +1,23 @@ +@{ + ViewBag.Title = "Edit"; + Layout = "~/Themes/Default/Layouts/_svelteLayout.cshtml"; + + long id = 0; + long version = 0; + long versionId = 0; + + if (ViewData["id"] != null) { id = Convert.ToInt64(ViewData["id"]); } + + if (ViewData["version"] != null) { version = Convert.ToInt64(ViewData["version"]); } + if (ViewData["versionId"] != null) { versionId = Convert.ToInt64(ViewData["versionId"]); } + +} + + +
    + + @Html.Partial("_sveltePage") + +
    \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/DataDescription.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/DataDescription.cshtml new file mode 100644 index 0000000000..5970f16755 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/DataDescription.cshtml @@ -0,0 +1,22 @@ +@{ + 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"]); } + +} + + +hello +
    + + @Html.Partial("_sveltePage") + +
    \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml index 39bdae9946..f2a62c2dfd 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Views/View/Index.cshtml @@ -4,11 +4,15 @@ long id = 0; long version = -1; + long tag = 0; if (ViewData["id"] != null) { id = Convert.ToInt64(ViewData["id"]); } if (ViewData["version"] != null) { version = Convert.ToInt64(ViewData["version"]); } + if (ViewData["tag"] != null) { version = Convert.ToInt64(ViewData["tag"]); } + + string bioSchemaInfos = ""; if (ViewData["bioSchema"] != null) { @@ -21,7 +25,7 @@ @Html.Raw(bioSchemaInfos) -
    +
    @Html.Partial("_sveltePage")
    \ No newline at end of file From 820b453c600d47797d8fc70c4df909748551b486 Mon Sep 17 00:00:00 2001 From: david schoene Date: Mon, 13 Jul 2026 09:14:55 +0200 Subject: [PATCH 181/490] #907 add fileview to data --- .gitignore | 2 +- .../src/lib/components/data/FilesView.svelte | 31 ++++++++++++++ .../src/routes/view/data/+page.svelte | 40 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/FilesView.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/data/+page.svelte diff --git a/.gitignore b/.gitignore index 8f8638f478..ddafac5abe 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ # BExIS-specific files [Ww]orkspace/ [Pp]ackages/ -[dD]ata/ +/[dD]ata/ # User-specific files *.suo diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/FilesView.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/FilesView.svelte new file mode 100644 index 0000000000..369e2394a8 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/data/FilesView.svelte @@ -0,0 +1,31 @@ + + +{#if files.length > 0} +
    +
    + {#each files as file, index } +
    + +
    + {index + 1}. + {file.name} + {file.type} + {file.lenght} + {file.description} +
    + {/each} +
    +
    +{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/data/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/data/+page.svelte new file mode 100644 index 0000000000..a8c0f8b6a8 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/data/+page.svelte @@ -0,0 +1,40 @@ + + + + + + + {#if id > 0} + + {:else} +

    No data available

    + {/if} + +
    \ No newline at end of file From 39c0583fce7eca2c9194fe4767c696246652bfe9 Mon Sep 17 00:00:00 2001 From: sventhiel Date: Mon, 13 Jul 2026 09:18:11 +0200 Subject: [PATCH 182/490] #1202 add necessary components into svelte - to render table(s) --- .../lib/components/groupsTableOptions.svelte | 41 ++++++++ .../lib/components/usersTableOptions.svelte | 36 +++++++ .../src/routes/groups/+page.svelte | 81 ++++++++++++++-- .../src/routes/groups/services.js | 14 +++ .../src/routes/groups/types.ts | 19 ++++ .../src/routes/users/+page.svelte | 95 +++++++++++++++++-- .../src/routes/users/services.js | 14 +++ .../src/routes/users/types.ts | 19 ++++ .../BExIS.Modules.Sam.UI.csproj | 2 + .../API/EntityPermissionsController.cs | 11 +++ .../API/FeaturePermissionsController.cs | 11 +++ 11 files changed, 328 insertions(+), 15 deletions(-) create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/groupsTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/usersTableOptions.svelte create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/services.js create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/services.js create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/types.ts create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/EntityPermissionsController.cs create mode 100644 Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/FeaturePermissionsController.cs diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/groupsTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/groupsTableOptions.svelte new file mode 100644 index 0000000000..449f3662cf --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/groupsTableOptions.svelte @@ -0,0 +1,41 @@ + + + +
    + {#each buttons as button} + + {/each} +
    diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/usersTableOptions.svelte b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/usersTableOptions.svelte new file mode 100644 index 0000000000..3b661fd2cb --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/lib/components/usersTableOptions.svelte @@ -0,0 +1,36 @@ + + + +
    + {#each buttons as button} + + {/each} +
    diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/+page.svelte b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/+page.svelte index 5b6a2b5321..f416aa5918 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/+page.svelte @@ -1,10 +1,75 @@ - - + + + +

    Groups

    +
+ \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/services.js b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/services.js new file mode 100644 index 0000000000..ca4c4863ae --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/services.js @@ -0,0 +1,14 @@ +import { Api } from '@bexis2/bexis2-core-ui'; +import { writable } from 'svelte/store'; + +export const groupsStore = writable([]); + +export async function getGroups() { + try { + const response = await Api.get('/api/groups'); + groupsStore.set(await response.data); // Speichere Daten im Store + } catch (err) { + console.error('Fehler beim Laden der Posts:', err); + groupsStore.set([]); // Fehlerfall: leere Liste + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/types.ts b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/types.ts new file mode 100644 index 0000000000..e35f44a02e --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/groups/types.ts @@ -0,0 +1,19 @@ +export interface ReadGroupModel { + id: number; + email: string; + userName: string; + creationDate: string; + modificationDate: string; +} + +export interface CreateGroupModel { + +} + +export interface UpdateGroupModel { + +} + +export interface DeleteGroupModel { + id: number; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/+page.svelte b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/+page.svelte index a5003d03ff..13dbe1a360 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/+page.svelte @@ -1,9 +1,90 @@ - - + + +

Users

+ + {#await reload()} +
+ +
+ {:then} +
+ {:catch error} + + {/await} + + \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/services.js b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/services.js new file mode 100644 index 0000000000..53261167ba --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/services.js @@ -0,0 +1,14 @@ +import { Api } from '@bexis2/bexis2-core-ui'; +import { writable } from 'svelte/store'; + +export const usersStore = writable([]); + +export async function getUsers() { + try { + const response = await Api.get('/api/users'); + usersStore.set(await response.data); // Speichere Daten im Store + } catch (err) { + console.error('Fehler beim Laden der Posts:', err); + usersStore.set([]); // Fehlerfall: leere Liste + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/types.ts b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/types.ts new file mode 100644 index 0000000000..1b1f54b438 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI.Svelte/src/routes/users/types.ts @@ -0,0 +1,19 @@ +export interface ReadUserModel { + id: number; + email: string; + userName: string; + creationDate: string; + modificationDate: string; +} + +export interface CreateUserModel { + +} + +export interface UpdateUserModel { + +} + +export interface DeleteUserModel { + id: number; +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj index 8b03b2165e..ee549442bc 100644 --- a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/BExIS.Modules.Sam.UI.csproj @@ -128,6 +128,8 @@ + + diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/EntityPermissionsController.cs b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/EntityPermissionsController.cs new file mode 100644 index 0000000000..d94aee4c40 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/EntityPermissionsController.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Sam.UI.Controllers.API +{ + public class EntityPermissionsController + { + } +} \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/FeaturePermissionsController.cs b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/FeaturePermissionsController.cs new file mode 100644 index 0000000000..fefc1a3a98 --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/SAM/BExIS.Modules.Sam.UI/Controllers/API/FeaturePermissionsController.cs @@ -0,0 +1,11 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; + +namespace BExIS.Modules.Sam.UI.Controllers.API +{ + public class FeaturePermissionsController + { + } +} \ No newline at end of file From d08d70a4dbacc0d37248edfdaf412f795ecc720e Mon Sep 17 00:00:00 2001 From: sventhiel Date: Mon, 13 Jul 2026 09:32:45 +0200 Subject: [PATCH 183/490] Save work before starting dotnet-version-upgrade --- Console/Workspace | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Console/Workspace b/Console/Workspace index 103c8dd7b1..664b8f5321 160000 --- a/Console/Workspace +++ b/Console/Workspace @@ -1 +1 @@ -Subproject commit 103c8dd7b136d0f4929d806eccd99d38f345e6ca +Subproject commit 664b8f53211ba4808fd3cc579b7f7ff8fa23857c From cbf7819c74ed1ecfcdc04a21e96d1473c2f930f1 Mon Sep 17 00:00:00 2001 From: david schoene Date: Mon, 13 Jul 2026 13:01:41 +0200 Subject: [PATCH 184/490] #2203 add bi-directional link creation --- .../Helpers/EntityReferenceHelper.cs | 45 ++++++++++++++++++- .../Hooks/EntityReferenceController.cs | 4 ++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs b/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs index a706f69cec..20870af1b7 100644 --- a/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs +++ b/Components/Utils/BExIS.Utils.Data/Helpers/EntityReferenceHelper.cs @@ -208,6 +208,39 @@ public EntityReference Convert(CreateSimpleReferenceModel model) return tmp; } + public EntityReference Switch(EntityReference model) + { + EntityReference tmp = new EntityReference(); + + tmp.SourceId = model.TargetId; + tmp.SourceEntityId = model.TargetEntityId; + tmp.SourceVersion = model.TargetVersion; + + tmp.TargetId = model.SourceId; + tmp.TargetEntityId = model.SourceEntityId; + tmp.TargetVersion = model.SourceVersion; + + tmp.Context = model.Context; + + tmp.ReferenceType = model.ReferenceType; + + tmp.CreationDate = DateTime.Now; + + // get additional informations + ReferenceConfigElement config = GetObositeReferenceConfig(model.Category, model.ReferenceType); + + if (config != null) + { + tmp.ReferenceType = config.ReferenceType; + tmp.LinkType = config.LinkType; + tmp.Category = config.Category; + } + + return tmp; + } + + + public SimpleSourceReferenceModel GetSimpleReferenceModel(long id, long typeId, int version) { SimpleSourceReferenceModel tmp = new SimpleSourceReferenceModel(); @@ -375,6 +408,16 @@ public ReferenceConfigElement GetReferenceConfigByType(string type) return null; } + public ReferenceConfigElement GetObositeReferenceConfig(string category, string type) + { + if (_config != null) + { + return _config.ReferenceTypes.Where(e => e.Category.Equals(category) && !e.ReferenceType.Equals(type)).FirstOrDefault(); + } + + return null; + } + /// /// this function return a list of all reference types. This types are listed in the entity reference config.xml in the workspace @@ -385,7 +428,7 @@ public SelectList GetReferencesTypes() if (_config != null) { - var types = _config.ReferenceTypes.Select(e => new SelectListItem() + var types = _config.ReferenceTypes.Where(e => !e.LinkType.Equals("extension")).Select(e => new SelectListItem() { Text = String.IsNullOrEmpty(e.Description) ? e.ReferenceType : e.Description, Value = e.ReferenceType diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs index ea04f7940d..c1295dde78 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/Hooks/EntityReferenceController.cs @@ -132,6 +132,10 @@ public ActionResult Create(CreateSimpleReferenceModel model) EntityReference entityReference = helper.Convert(model); entityReferenceManager.Create(entityReference); + EntityReference entityReferenceObosite = helper.Switch(entityReference); + entityReferenceManager.Create(entityReferenceObosite); + + // if successfuly created a entity link return a json true return Json(true); } From 1afae2182767777ac2defa2d7d041782af40c023 Mon Sep 17 00:00:00 2001 From: david schoene Date: Mon, 13 Jul 2026 15:04:30 +0200 Subject: [PATCH 185/490] #2236 filter list by existing extensions --- .../BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../src/routes/edit/AdvancedEntity.svelte | 25 ++++++--- .../src/routes/edit/ExtensionCreation.svelte | 3 +- .../Controllers/EditController.cs | 52 ++++++++++++++++--- 4 files changed, 64 insertions(+), 18 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 988ad71e26..0944947d31 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -8,7 +8,7 @@
-
+
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte index fd0ce9f6eb..6a8e1f5d09 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/AdvancedEntity.svelte @@ -10,7 +10,8 @@ import ExtensionCreation from './ExtensionCreation.svelte'; import Fa from 'svelte-fa'; import { faTrash } from '@fortawesome/free-solid-svg-icons'; - import { deleteExtension } from './services'; + import { deleteExtension, getExtensionEntityTemplateList } from './services'; + import { onMount } from 'svelte'; const modalStore = getModalStore(); @@ -21,7 +22,8 @@ export let entity = ""; export let extensions:ExtensionType[] = [] - + $: entitytemplates = []; + async function removeExtensionFn( extId, title){ const modal: ModalSettings = { type: 'confirm', @@ -58,6 +60,11 @@ modalStore.trigger(modal); } + onMount(async () => { + + entitytemplates = await getExtensionEntityTemplateList(id); + }); + @@ -72,22 +79,24 @@ {ext.title} {:else} {entity} (Ext.) - {/if} + {/if} {/each} - - + Add Data as Extension - - + {#if entitytemplates.length > 0} + + + Add Data as Extension + + {/if} + {#if tabSet === 0} {:else if tabSet === 100} - + {/if} {#each extensions as ext (ext.id)} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte index cba9cc7ea5..9aba264744 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/edit/ExtensionCreation.svelte @@ -6,13 +6,14 @@ import { Spinner, positionType } from '@bexis2/bexis2-core-ui'; import { createExtensionLink, getExtensionEntityTemplateList } from './services'; - import { goTo } from '$services/BaseCaller'; import type { EntityTemplateModel } from '$models/EntityTemplate'; let entitytemplate: EntityTemplateModel; export let id; + export let entitytemplates = []; + $: entitytemplates = []; // $:systemkeys= []; $: selected = entitytemplate; diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs index c8e829d7ef..3a03523ec3 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EditController.cs @@ -183,17 +183,39 @@ public JsonResult GetExtensionEntityTemplateList(long id) using (var datasetManager = new DatasetManager()) using (var entityTemplateManager = new EntityTemplateManager()) + using (var entityReferenceManager = new EntityReferenceManager()) { - var dataset = datasetManager.GetDataset(id); var template = dataset.EntityTemplate; - var extensions = template.ExtensionList.Select(e=>e.TemplateId); + var entity = template.EntityType; + + + var existingEntityReferences = entityReferenceManager.ReferenceRepository.Query(e => + e.LinkType.Equals("extension") && + e.SourceId.Equals(id) && + e.SourceEntityId.Equals(entity.Id)).ToList(); - foreach (var e in entityTemplateManager.Repo.Query(e => e.Activated && extensions.Contains(e.Id)).ToList()) + var usedEntityTemplateIds = new List(); + + // get used Tempalates + foreach (var e in existingEntityReferences) { - entityTemplateModels.Add(EntityTemplateHelper.ConvertTo(e, false)); + var d = datasetManager.GetDataset(e.TargetId); + var t = d.EntityTemplate; + usedEntityTemplateIds.Add(t.Id); } + + + + var extensions = template.ExtensionList.Where(e=> e.Unique == false || (e.Unique && !usedEntityTemplateIds.Contains(e.TemplateId))).Select(e=>e.TemplateId); + + foreach (var e in entityTemplateManager.Repo.Query(e => e.Activated && extensions.Contains(e.Id)).ToList()) + { + + entityTemplateModels.Add(EntityTemplateHelper.ConvertTo(e, false)); + } + } return Json(entityTemplateModels, JsonRequestBehavior.AllowGet); @@ -213,7 +235,7 @@ public JsonResult CreateExtensionLink(long id, long extensionId) if (id == 0) throw new Exception("id is missing"); if (extensionId == 0) throw new Exception("extensionId is missing"); - + var usedEntityTemplateIds = new List(); // get object var dataset = datasetmanager.GetDataset(id); var extension = datasetmanager.GetDataset(extensionId); @@ -231,13 +253,27 @@ public JsonResult CreateExtensionLink(long id, long extensionId) // check if extension is unique and allready exists if (datasetTemplate.ExtensionList.Any(e => e.TemplateId.Equals(extensionTemplate.Id) && e.Unique)) { - var existingLinks = entityReferenceManager.ReferenceRepository.Query(e => + + var existing = entityReferenceManager.ReferenceRepository.Query(e => e.LinkType.Equals("extension") && + e.TargetId.Equals(extension.Id) && e.SourceId.Equals(id) && e.SourceEntityId.Equals(dataset.EntityTemplate.EntityType.Id) && - e.TargetEntityId.Equals(extension.EntityTemplate.EntityType.Id)).ToList(); + e.TargetEntityId.Equals(extension.EntityTemplate.EntityType.Id)).Any(); + + + + //foreach (var e in existingLinks) + //{ + // var d = datasetmanager.GetDataset(e.TargetId); + // var t = d.EntityTemplate; + // usedEntityTemplateIds.Add(t.Id); + //} + + + //var extensions = datasetTemplate.ExtensionList.Where(e => e.Unique == false || (e.Unique && !usedEntityTemplateIds.Contains(e.TemplateId))).Select(e => e.TemplateId); - if (existingLinks.Count > 0) + if (existing) throw new Exception("This extension is unique and allready exists."); } From 543bb6f1a3be1aa1427694ab4acb6f7277a43bcf Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 13 Jul 2026 17:56:31 +0200 Subject: [PATCH 186/490] #2531 Tags: Hide publish tag toggle if it has no effect --- .../src/routes/taginfo/table/tablePublish.svelte | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tablePublish.svelte b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tablePublish.svelte index ce236e0a30..147cfcf3e6 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tablePublish.svelte +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/routes/taginfo/table/tablePublish.svelte @@ -8,6 +8,9 @@ let currentRow: TagInfoEditModel | undefined; $: currentRow = $tagInfoModelStore.find((x) => x.versionId == row.original.versionId); + // next row is the row with the next version number, if it exists + // It is used to determine if the current row is the last version of a tag, in which case the publish toggle should be shown + $: nextRow = $tagInfoModelStore.find((x) => x.versionNr == row.original.versionNr + 1); // Update the store when the toggle is changed function togglePublish(versionId: number, value: boolean) { @@ -19,7 +22,7 @@
- {#if currentRow && currentRow.tagId > 0} + {#if currentRow && currentRow.tagId > 0 && ((nextRow && nextRow.tagId != currentRow.tagId) || !nextRow)} {/if}
-
+
\ No newline at end of file From fea44e7b6bc9976705934ac41a4067d0096ea809 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 13 Jul 2026 18:09:57 +0200 Subject: [PATCH 187/490] #2529 Search: Number of displayed items not updated on change in card view --- .../src/lib/components/Cards.svelte | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Cards.svelte b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Cards.svelte index 2f24b4a689..fd71a882da 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Cards.svelte +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Cards.svelte @@ -57,6 +57,10 @@ showFirstLastButtons showPreviousNextButtons on:page={(e) => (paginationSettings.page = e.detail)} + on:amount={(e) => { + paginationSettings.limit = e.detail; + paginationSettings.page = 0; + }} /> {/if}
From 26d37703d4ae2879116ca66f3a55c5bfb7c265a4 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Mon, 13 Jul 2026 18:36:15 +0200 Subject: [PATCH 188/490] #2484 Search: Table view - limit abstract length --- .../src/lib/components/Search.svelte | 2 +- .../src/lib/components/tableSearchOverview.svelte | 14 ++++++++++++++ .../BExIS.Modules.Ddm.UI.Svelte/src/lib/helpers.ts | 2 ++ 3 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/tableSearchOverview.svelte diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Search.svelte b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Search.svelte index db30c467d2..64ce1617d6 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Search.svelte +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/Search.svelte @@ -590,7 +590,7 @@ {/if} {#if currentView === 'cards'} - + {/if} {/if} diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/tableSearchOverview.svelte b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/tableSearchOverview.svelte new file mode 100644 index 0000000000..9d08bf3eba --- /dev/null +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/components/tableSearchOverview.svelte @@ -0,0 +1,14 @@ + + +
+ + {#if value.length > 200} + {value.slice(0, 200) + '...'} + {:else} + {value} + {/if} + + +
\ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/helpers.ts b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/helpers.ts index f62d7b784f..bc2c1871a4 100644 --- a/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/helpers.ts +++ b/Console/BExIS.Web.Shell/Areas/DDM/BExIS.Modules.Ddm.UI.Svelte/src/lib/helpers.ts @@ -1,4 +1,5 @@ import type { Columns } from '@bexis2/bexis2-core-ui'; +import tableSearchOverview from '$lib/components/tableSearchOverview.svelte'; export const pascalToCamel = (str: string) => { return str @@ -21,6 +22,7 @@ export const convertTableData = (columns: Columns, rows: any, header: any, visib ...columns, [pascalToCamel(header[index].Name)]: { header: header[index].DisplayName, + instructions: { renderComponent: tableSearchOverview }, exclude } }; From 3eb11a0c5e526b94664609444fcaf837a93de446 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Tue, 14 Jul 2026 00:05:44 +0200 Subject: [PATCH 189/490] #2385 Get save wit error info from backend --- .../src/routes/m/edit/MetadataHeader.svelte | 4 ++-- .../src/services/MetadataCaller.ts | 14 +++++++++++++- .../Controllers/EntityTemplatesController.cs | 13 +++++++++++++ .../Helpers/EntityTemplateHelper.cs | 18 +++++++++++++++++- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataHeader.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataHeader.svelte index c25fdb4659..c4c4569c8d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataHeader.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/MetadataHeader.svelte @@ -78,9 +78,9 @@ function disableSaveFn():boolean { - //console.log("🚀 ~ disableSaveFn ~ hasChanged:", hasChanged, saveWithError) + // console.log("🚀 ~ disableSaveFn ~ hasChanged:", hasChanged, saveWithError) if (hasChanged == false) return true; // when there are changes, the save button is enabled, so return false for disabled - if (saveWithError) return false; // when save with error is allowd, the save button is always enabled + if (saveWithError) return false; // when save with error is allowed, the save button is always enabled if (!validationStoreValues) return true; // if there is no validation result, we consider the form as not valid, so the save button is disabled return !validationStoreValues.allSimpleRequiredValid; // disable save button when the metadata is not valid diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/MetadataCaller.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/MetadataCaller.ts index d0a8bc5b6c..df5a18657e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/MetadataCaller.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/services/MetadataCaller.ts @@ -45,6 +45,19 @@ export const GetDatasetInfoById = async (datasetId: number) => { } }; +export const GetTemplateConfig = async (id: number) => { + try { + + // dcm/entitytemplates/Get?id=5 + const response = await Api.get('/dcm/entitytemplates/GetSimple?id=' + id, ''); + // console.log(" response.data.MetadataStructureId:", response); + return response.data; + } catch (error) { + console.error(error); + throw error; + } +}; + export const SaveMetadata = async (id: number, value: any, comment: string) => { try { console.log(" value:", value); @@ -133,4 +146,3 @@ export const GetMetadataAsFlattened = async (id: number, version) => { }; - diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs index a7d0f1f0d6..f1af48fd01 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Controllers/EntityTemplatesController.cs @@ -78,6 +78,19 @@ public JsonResult Get(long id) } } + [JsonNetFilter] + [HttpGet] + public JsonResult GetSimple(long id) + { + if (id == 0) return Json(new EntityTemplateModelSimple(), JsonRequestBehavior.AllowGet); + + using (var entityTemplateManager = new EntityTemplateManager()) + { + var entityTemplate = entityTemplateManager.Repo.Get(id); + return Json(EntityTemplateHelper.ConvertToSimple(entityTemplate), JsonRequestBehavior.AllowGet); + } + } + [JsonNetFilter] [HttpGet] diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs index f644a64bf9..cdc25f6c8b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI/Helpers/EntityTemplateHelper.cs @@ -51,6 +51,22 @@ public static EntityTemplate ConvertTo(EntityTemplateModel model) return entityTemplate; } + public static object ConvertToSimple(EntityTemplate entityTemplate) + { + var model = new + { + Id = entityTemplate.Id, + Name = entityTemplate.Name, + Description = entityTemplate.Description, + MetadataStructure = entityTemplate.MetadataStructure != null ? new ListItem(entityTemplate.MetadataStructure.Id, entityTemplate.MetadataStructure.Name) : null, + EntityType = entityTemplate.EntityType != null ? new ListItem(entityTemplate.EntityType.Id, entityTemplate.EntityType.Name) : null, + MetadataInvalidSaveMode = entityTemplate.MetadataInvalidSaveMode, + HasDatastructure = entityTemplate.HasDatastructure + }; + + return model; + } + public static EntityTemplate Merge(EntityTemplateModel model) { using (var entityTemplateManager = new EntityTemplateManager()) @@ -117,7 +133,7 @@ public static EntityTemplateModel ConvertTo(EntityTemplate entityTemplate, bool model.EntityType = new ListItem(entityTemplate.EntityType.Id, entityTemplate.EntityType.Name); - // check if subject are allready created, and list them for the view + // check if subject are already created, and list them for the view using (var datasetManager = new DatasetManager()) { long etId = entityTemplate.Id; From 2e6de748aa2144d0e2620dbd7e15d0be1340894b Mon Sep 17 00:00:00 2001 From: geofranzi Date: Tue, 14 Jul 2026 00:08:25 +0200 Subject: [PATCH 190/490] #2385 Fix layout sifts for descriptions; Add convert to display name; --- .../utils/metadata/metadataComponentUtils.ts | 19 ++++ .../src/routes/m/edit/+page.svelte | 91 +++++++++++++------ .../src/routes/m/edit/simpleComponent.svelte | 17 ++-- 3 files changed, 90 insertions(+), 37 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts index cc0cd873ac..4dd526af43 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/components/utils/metadata/metadataComponentUtils.ts @@ -536,10 +536,29 @@ export function getPartyIdFromParent(path) { } export function showDescriptionHandler(e: any, type: 'simple' | 'complex') { + let descriptionTimeout: any; + + // unset current timeout if any + if (descriptionTimeout) { + clearTimeout(descriptionTimeout); + } + + // add a small delay + descriptionTimeout = setTimeout(() => { descriptionStore.set({ type, content: e.detail.description, path: e.detail.id }); console.log('🚀 ~ showDescriptionHandler ~ e.detail.description:', e.detail); + }, 500); } export function hideDescriptionHandler(e: any, type: 'simple' | 'complex') { + let descriptionTimeout: any; + // unset current timeout if any + if (descriptionTimeout) { + clearTimeout(descriptionTimeout); + } + + // add a small delay + descriptionTimeout = setTimeout(() => { descriptionStore.set({ type, content: '', path: '' }); + }, 500); } \ No newline at end of file diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte index f0dba86353..36458eaf2b 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/+page.svelte @@ -40,6 +40,7 @@ faArrowUp } from '@fortawesome/free-solid-svg-icons'; import Fa from 'svelte-fa'; + import { convertDisplayName } from '$lib/components/utils/metadata/metadataShared'; // import configJson from './customComponents/config.json'; export let id: number = 3; @@ -67,7 +68,7 @@ if (id > 0) { let result = await apiCalls.GetDatasetInfoById(id); const datasetInfos = result.data; - // console.log('Dataset infos loaded', datasetInfos); + console.log('Dataset infos loaded', datasetInfos); s = await apiCalls.GetMetadataSchema(datasetInfos.metadataStructureId); console.log('Schema loaded', s); @@ -77,6 +78,12 @@ setMetadataStore(m); const configJson = await apiCalls.GetComponentConfig(datasetInfos.entityTemplateId, 'edit'); setConfigStore(configJson); + console.log('🚀 ~ load ~ configJson:', configJson); + + const templateJson = await apiCalls.GetTemplateConfig(datasetInfos.entityTemplateId); + console.log('🚀 ~ load ~ templateJson:', templateJson); + saveWithError = templateJson?.metadataInvalidSaveMode ?? true; + console.log('🚀 ~ load ~ saveWithError:', saveWithError); const systemMappings: SystemMappingEditModel = await apiCalls.GetSystemMappings( datasetInfos.metadataStructureId @@ -105,7 +112,7 @@ } - + {#await load()} {:then} @@ -125,8 +132,8 @@
-
-
+
+ - -  Scroll to top - - - - {#if $hideStore.length === 0} - - {:else} - - - - {/if} -
-
- +
+ +
+ + {#if $hideStore.length === 0} + + {:else} + + + {/if} +
+ + + +
+
-
- {#if $descriptionStore && $descriptionStore.path && typeof $descriptionStore.content === 'string'} -
+
+

+ Move your cursor over a field or section header to see its description (if available). +

+
+ + {#if $descriptionStore && $descriptionStore.path?.length > 0 && typeof $descriptionStore.content === 'string'} + + {@const parts = $descriptionStore.path.split('.')} + {@const lastItem = parts[parts.length - 1] ?? ''} + {@const isNumeric = lastItem !== '' && !isNaN(lastItem)} + + + {@const targetItem = isNumeric ? (parts[parts.length - 2] ?? '') : lastItem} + +
{#if $descriptionStore.type === 'simple'} -

Field Description

-

{@html $descriptionStore.content}

+

+ Field Description for {convertDisplayName(targetItem, false)} +

+

{@html $descriptionStore.content}

{:else if $descriptionStore.type === 'complex'} -

Section Description

-

{@html $descriptionStore.content}

+

+ Section Description for {convertDisplayName(targetItem, true)} +

+

{@html $descriptionStore.content}

{/if}
{/if} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte index 46bd1c584e..b84c0c82f3 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/m/edit/simpleComponent.svelte @@ -191,7 +191,7 @@ @@ -199,7 +199,7 @@ @@ -240,7 +241,8 @@ inputClasses="input variant-form-material dark:bg-zinc-700 bg-zinc-50 placeholder:text-gray-400 w-32" on:change={onChangeHandler} on:showDescription={handleShowDescription} - on:hideDescription={handleHideDescription } + on:hideDescription={handleHideDescription} + on:input={onChangeHandler} /> @@ -259,6 +261,7 @@ on:change={onChangeHandler} on:showDescription={handleShowDescription} on:hideDescription={handleHideDescription} + on:input={onChangeHandler} /> @@ -301,7 +304,7 @@ {#if simpleComponent.properties['#text'].enum.length <= 10} {label}{convertDisplayName(label)} {/if} {/if} From 2044486645fc6c8714b783d83b9d3f8ad258ea9c Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 14 Jul 2026 09:40:50 +0200 Subject: [PATCH 191/490] #2236 hide extensions when they exist and unique --- .../DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html | 2 +- .../src/lib/hooks/view/Link.svelte | 13 +++++++++++-- .../src/routes/view/Header.svelte | 2 +- 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html index 0944947d31..d523ddf432 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/app.html @@ -13,7 +13,7 @@
-
+
%sveltekit.body%
diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte index 63a2d559d7..f961c3687e 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/lib/hooks/view/Link.svelte @@ -23,9 +23,18 @@

{type.toUpperCase()}

{#each links.filter(link => link.linkType === type) as link} -
{link.referenceType} +
+ {link.referenceType} {link.target.type} - {link.target.title} + {#if link.target.type.toLocaleLowerCase() =='extension'} + + {link.target?.title? link.target.title: "No title available"} + + {:else} + + {link.target?.title? link.target.title: "No title available"} + + {/if} {link.context}
{/each} diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte index aa52e01750..da0618d4ca 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/Header.svelte @@ -27,7 +27,7 @@ import Citation from "./Citation.svelte";
{#if hasEditRight}
- From d6565c1dfd5f79a29136be225e7615deb646a9bc Mon Sep 17 00:00:00 2001 From: david schoene Date: Tue, 14 Jul 2026 09:45:35 +0200 Subject: [PATCH 192/490] #907 fix design of download files button --- .../src/routes/view/download/Download.svelte | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte index 05fee9c3ed..265f2d521d 100644 --- a/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte +++ b/Console/BExIS.Web.Shell/Areas/DCM/BExIS.Modules.Dcm.UI.Svelte/src/routes/view/download/Download.svelte @@ -139,14 +139,13 @@ function sendDataTo(data, name, type) with units -
{:else} -
From 69d15ea0140f99bc20789eca9e905fc74cbd4e12 Mon Sep 17 00:00:00 2001 From: geofranzi Date: Tue, 14 Jul 2026 13:21:20 +0200 Subject: [PATCH 195/490] #2523 - cleanup old code from PUM --- .../components/datastructure/Controls.svelte | 35 - .../datastructure/MissingValue.svelte | 70 -- .../datastructure/MissingValues.svelte | 67 -- .../components/datastructure/Selection.svelte | 651 ------------------ .../lib/components/datastructure/services.ts | 211 ------ .../src/lib/components/datastructure/store.ts | 18 - .../datastructure/structure/Attributes.svelte | 65 -- .../structure/CreateStructure.svelte | 116 ---- .../structure/EditStructure.svelte | 165 ----- .../datastructure/structure/Variables.svelte | 364 ---------- .../datastructure/structure/attributes.ts | 31 - .../variable/ConstraintsDescription.svelte | 16 - .../structure/variable/Container.svelte | 40 -- .../variable/DataTypeDescription.svelte | 21 - .../structure/variable/Footer.svelte | 4 - .../structure/variable/Header.svelte | 81 --- .../variable/MeaningsDescription.svelte | 26 - .../structure/variable/Overview.svelte | 78 --- .../structure/variable/Status.svelte | 16 - .../structure/variable/Variable.svelte | 586 ---------------- .../structure/variable/helper.ts | 188 ----- .../structure/variable/variable.ts | 150 ---- .../src/lib/components/datastructure/types.ts | 135 ---- .../src/lib/components/meaning/stores.ts | 15 - .../src/lib/components/meaning/types.ts | 83 --- .../src/lib/services/BaseCaller.ts | 8 - 26 files changed, 3240 deletions(-) delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Controls.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValue.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValues.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Selection.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/services.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/store.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/Attributes.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/CreateStructure.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/EditStructure.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/Variables.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/attributes.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/ConstraintsDescription.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/Container.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/DataTypeDescription.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/Footer.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/Header.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/MeaningsDescription.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/Overview.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/Status.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/Variable.svelte delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/helper.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/variable/variable.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/types.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/meaning/stores.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/meaning/types.ts delete mode 100644 Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/services/BaseCaller.ts diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Controls.svelte b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Controls.svelte deleted file mode 100644 index 61f2266ab4..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Controls.svelte +++ /dev/null @@ -1,35 +0,0 @@ -
-

Table Controls

-
-
-
- - -
Selection Column(s)
-
left mouse button (click or drag)
-
-
-
- - -
Deselect Column(s)
-
right mouse button (click or drag)
-
-
-
- - -
Select Row
-
double click left mouse button or click arrow
-
-
-
- - -
Deselect Row
-
right mouse button click on arrow
-
-
- -
-
diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValue.svelte b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValue.svelte deleted file mode 100644 index cd738d24a0..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValue.svelte +++ /dev/null @@ -1,70 +0,0 @@ - - -
- -
- -
- - -
- -
- - {#if !disabled} -
- - {#if last} - - {/if} -
- {/if} -
diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValues.svelte b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValues.svelte deleted file mode 100644 index cce093b91a..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/MissingValues.svelte +++ /dev/null @@ -1,67 +0,0 @@ - - -{#if showTitle} - -{/if} - -
- {#if list} - {#each list as item, i} - - remove(i)} - last={list.length - 1 === i} - {disabled} - /> - {/each} - {/if} -
- - diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Selection.svelte b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Selection.svelte deleted file mode 100644 index 1876978449..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/Selection.svelte +++ /dev/null @@ -1,651 +0,0 @@ - - -{#if !model || state.length == 0 || generate == false} - - - {#if !model || state.length == 0 || generate == false} -
- -
- {:else} -
- -
- {/if} -{:else} - - -
- -
-
-
- - - - - - - -
- -
- - -
- - Mark at least Variable and Data -
- - - - - -
- -
- -
- {#each errors as error} - - {/each} -
-
- -
-
- -
-
- -
-
- -
-
- - - - -
- -
-
e.preventDefault()}> - - {#each data as row, r} - - - - {#each row as cell, c} - - {/each} - - {/each} - -
-
- -
-
e.row === r && e.cells[c] === true - )?.type === MARKER_TYPE.VARIABLE} - class:variant-soft-success={selection.find( - (e) => e.row === r && e.cells[c] === true - )?.type === MARKER_TYPE.UNIT} - class:variant-soft-warning={selection.find( - (e) => e.row === r && e.cells[c] === true - )?.type === MARKER_TYPE.DESCRIPTION} - class:variant-soft-secondary={selection.find( - (e) => e.row === r && e.cells[c] === true - )?.type === MARKER_TYPE.MISSING_VALUES} - class:variant-soft-primary={selection.find( - (e) => e.row === r && e.cells[c] === true - )?.type === MARKER_TYPE.DATA} - class:variant-ghost-surface={state[r][c]} - > - {(cell = cell.replaceAll(String.fromCharCode(model.textMarker), ''))} -
-
-
-
- -{/if} - - diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/services.ts b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/services.ts deleted file mode 100644 index 4d2a6c4de4..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/services.ts +++ /dev/null @@ -1,211 +0,0 @@ -// Implementations for all the calls for the pokemon endpoints. -//import Api from "./Api"; -import { Api, host } from '@bexis2/bexis2-core-ui'; - -/****************/ -/* Overview Data structures*/ -/****************/ - -export const getDataStructures = async () => { - try { - const response = await Api.get('/rpm/DataStructure/DataStructures'); - console.log('responce', response.data, Date.now() / 1000); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const get = async (id) => { - try { - const response = await Api.get('/rpm/DataStructure/get?id=' + id); - return response.data; - } catch (error) { - console.error(error); - } -}; - -/****************/ -/* Create*/ -/****************/ -export const load = async (file: string, entityId: number, encoding: number, version: number) => { - console.log(file, entityId, version); - try { - const response = await Api.get( - '/rpm/DataStructure/load?file=' + - file + - '&&encoding=' + - encoding + - '&&entityId=' + - entityId + - '&&version=' + - version - ); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getStructures = async () => { - try { - const response = await Api.get('/rpm/DataStructure/GetStructures'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getDisplayPattern = async () => { - try { - const response = await Api.get('/rpm/DataStructure/GetDisplayPattern'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getDelimeters = async () => { - try { - const response = await Api.get('/rpm/DataStructure/GetDelimters'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const generate = async (data) => { - try { - const response = await Api.post('/rpm/DataStructure/generate', data); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const checkPrimaryKeySet = async (id: number, primaryKeys: number[]) => { - try { - const response = await Api.post('/rpm/DataStructure/checkPrimaryKeySet', { id, primaryKeys }); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const empty = async () => { - try { - const response = await Api.get('/rpm/DataStructure/empty'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const copy = async (id) => { - try { - const response = await Api.get('/rpm/DataStructure/copy?id=' + id); - - console.log('🚀 ~ file: services.js:95 ~ copy ~ response.data:', response.data); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const remove = async (id) => { - try { - const response = await Api.post('/rpm/DataStructure/delete', { id }); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const store = async (data) => { - try { - const response = await Api.post('/rpm/DataStructure/store', data); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const create = async (data) => { - try { - const response = await Api.post('/rpm/DataStructure/create', data); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const save = async (data) => { - try { - const response = await Api.post('/rpm/DataStructure/save', data); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getDataTypes = async () => { - try { - const response = await Api.get('/rpm/DataStructure/getDataTypes'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getUnits = async () => { - try { - const response = await Api.get('/rpm/DataStructure/getUnits'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getUnitsWithDataTypes = async () => { - try { - const response = await Api.get('/rpm/variableTemplate/getUnits'); - return response.data; - } catch (error) { - console.error(error); - } -}; - -export const getVariableTemplates = async () => { - try { - const response = await Api.get('/rpm/DataStructure/getVariableTemplates'); - return response.data; - } catch (error) { - console.error(error); - throw error; - } -}; - -export const getMeanings = async () => { - try { - const response = await Api.get('/rpm/DataStructure/getMeanings'); - return response.data; - } catch (error) { - console.error(error); - throw error; - } -}; - -export const getConstraints = async () => { - try { - const response = await Api.get('/rpm/DataStructure/GetConstraints'); - return response.data; - } catch (error) { - console.error(error); - throw error; - } -}; - -// go to a internal action -export const goTo = async (url: string) => { - window.open(host + url, '_self').focus(); -}; diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/store.ts b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/store.ts deleted file mode 100644 index 70279d90fb..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/store.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { writable } from 'svelte/store'; -import type { listItemType } from '@bexis2/bexis2-core-ui'; -import type { meaningListItemType, templateListItemType, unitListItemType } from './types'; - -export const structureStore = writable([]); -export const displayPatternStore = writable([]); -export const dataTypeStore = writable([]); -export const unitStore = writable([]); -export const templateStore = writable([]); -export const isTemplateRequiredStore = writable(false); -export const isMeaningRequiredStore = writable(false); -export const setByTemplateStore = writable(false); -export const enforcePrimaryKeyStore = writable(false); -export const changeablePrimaryKeyStore = writable(false); -export const meaningsStore = writable([]); -export const constraintsStore = writable([]); - -export const x = writable(1); diff --git a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/Attributes.svelte b/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/Attributes.svelte deleted file mode 100644 index ef65f0b188..0000000000 --- a/Console/BExIS.Web.Shell/Areas/PUM/BExIS.Modules.Pum.UI.Svelte/src/lib/components/datastructure/structure/Attributes.svelte +++ /dev/null @@ -1,65 +0,0 @@ - - -{#if model} -
- - -
-