Merge pull request #928 from specklesystems/dev
.NET Build and Publish / build-windows (push) Has been cancelled
.NET Build and Publish / build-linux (push) Has been cancelled
.NET Build and Publish / deploy-installers (push) Has been cancelled

Update dev into main
This commit is contained in:
Oğuzhan Koral
2025-06-17 12:25:24 +03:00
committed by GitHub
103 changed files with 1942 additions and 2834 deletions
-424
View File
@@ -1,424 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.10.35027.167
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Config", "Config", "{85A13E25-EB29-4F31-8853-B9EE83275B3D}"
ProjectSection(SolutionItems) = preProject
.csharpierrc.yaml = .csharpierrc.yaml
.editorconfig = .editorconfig
codecov.yml = codecov.yml
Directory.Build.props = Directory.Build.props
Directory.Build.targets = Directory.Build.targets
Directory.Packages.props = Directory.Packages.props
global.json = global.json
README.md = README.md
CodeMetricsConfig.txt = CodeMetricsConfig.txt
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "DUI3", "DUI3", "{FD4D6594-D81E-456F-8F2E-35B09E04A755}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Revit", "Revit", "{D92751C8-1039-4005-90B2-913E55E0B8BD}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Sdk", "Sdk", "{2E00592E-558D-492D-88F9-3ECEE4C0C7DA}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2023", "Connectors\Revit\Speckle.Connectors.Revit2023\Speckle.Connectors.Revit2023.csproj", "{01F98733-7352-47AD-A594-537D979DE3DE}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Connectors.RevitShared", "Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.shproj", "{DC570FFF-6FE5-47BD-8BC1-B471A6067786}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RevitShared", "Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.shproj", "{E1C43415-3200-45F4-8BF9-A4DD7D7F2ED6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2023.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2023.DependencyInjection\Speckle.Converters.Revit2023.DependencyInjection.csproj", "{83EAD6F0-3CB3-456A-AD81-072127D0DE0E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2023", "Converters\Revit\Speckle.Converters.Revit2023\Speckle.Converters.Revit2023.csproj", "{26391930-F86F-47E0-A5F6-B89919E38CE1}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.DUI", "DUI3\Speckle.Connectors.DUI\Speckle.Connectors.DUI.csproj", "{D81C0B87-F0C1-4297-A147-02F001FB7E1E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Autofac", "Sdk\Speckle.Autofac\Speckle.Autofac.csproj", "{C9D4CA21-182B-4ED2-81BB-280A6FD713F6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Utils", "Sdk\Speckle.Connectors.Utils\Speckle.Connectors.Utils.csproj", "{7291B93C-615D-42DE-B8C1-3F9DF643E0FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Common", "Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj", "{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Rhino", "Rhino", "{9584AEE5-CD59-46E6-93E6-2DC2B5285B75}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Rhino7", "Connectors\Rhino\Speckle.Connectors.Rhino7\Speckle.Connectors.Rhino7.csproj", "{1E2644A9-6B31-4350-8772-CEAAD6EE0B21}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Rhino7", "Converters\Rhino\Speckle.Converters.Rhino7\Speckle.Converters.Rhino7.csproj", "{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Rhino7.DependencyInjection", "Converters\Rhino\Speckle.Converters.Rhino7.DependencyInjection\Speckle.Converters.Rhino7.DependencyInjection.csproj", "{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.ArcGIS3", "Connectors\ArcGIS\Speckle.Connectors.ArcGIS3\Speckle.Connectors.ArcGIS3.csproj", "{A97F7177-86C7-4B38-A6ED-DA51BF762471}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.ArcGIS3", "Converters\ArcGIS\Speckle.Converters.ArcGIS3\Speckle.Converters.ArcGIS3.csproj", "{139F7A79-69E4-4B8A-B2A5-6A30A66C495C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.ArcGIS3.DependencyInjection", "Converters\ArcGIS\Speckle.Converters.ArcGIS3.DependencyInjection\Speckle.Converters.ArcGIS3.DependencyInjection.csproj", "{7DFF1591-237D-499E-A767-EE37B93FB958}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ArcGIS", "ArcGIS", "{CCF48B65-33D1-4E8B-A57B-E03394730B21}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Autocad2023", "Connectors\Autocad\Speckle.Connectors.Autocad2023\Speckle.Connectors.Autocad2023.csproj", "{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Connectors.AutocadShared", "Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.shproj", "{41BC679F-887F-44CF-971D-A5502EE87DB0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Common.DependencyInjection", "Sdk\Speckle.Converters.Common.DependencyInjection\Speckle.Converters.Common.DependencyInjection.csproj", "{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Autocad", "Autocad", "{804E065F-914C-414A-AF84-009312C3CFF6}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.AutocadShared", "Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.shproj", "{9ADD1B7A-6401-4202-8613-F668E2FBC0A4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2023", "Converters\Autocad\Speckle.Converters.Autocad2023\Speckle.Converters.Autocad2023.csproj", "{631C295A-7CCF-4B42-8686-7034E31469E7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2023.DependencyInjection", "Converters\Autocad\Speckle.Converters.Autocad2023.DependencyInjection\Speckle.Converters.Autocad2023.DependencyInjection.csproj", "{D940853C-003A-482C-BDB0-665367F274A0}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.DUI.WebView", "DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj", "{7420652C-3046-4F38-BE64-9B9E69D76FA2}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Build", "Build\Build.csproj", "{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "HostApps", "HostApps", "{42826721-9A18-4762-8BA9-F1429DD5C5B1}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Build", "Build", "{59E8E8F3-4E42-4E92-83B3-B1C2AB901D18}"
ProjectSection(SolutionItems) = preProject
.github\workflows\ci.yml = .github\workflows\ci.yml
.github\workflows\main.yml = .github\workflows\main.yml
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Civil3d2024", "Connectors\Autocad\Speckle.Connectors.Civil3d2024\Speckle.Connectors.Civil3d2024.csproj", "{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.Civil3dShared", "Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.shproj", "{35175682-DA83-4C0A-A49D-B191F5885D8E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Civil3d2024.DependencyInjection", "Converters\Civil3d\Speckle.Converters.Civil3d2024.DependencyInjection\Speckle.Converters.Civil3d2024.DependencyInjection.csproj", "{80F965C4-E2A8-4F54-985D-73D06E45F9CE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2024", "Converters\Autocad\Speckle.Converters.Autocad2024\Speckle.Converters.Autocad2024.csproj", "{C2DE264A-AA87-4012-B954-17E3F403A237}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Autocad2024.DependencyInjection", "Converters\Autocad\Speckle.Converters.Autocad2024.DependencyInjection\Speckle.Converters.Autocad2024.DependencyInjection.csproj", "{AF507D61-6766-4C20-9F58-23DC29508219}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Civil3d2024", "Converters\Civil3d\Speckle.Converters.Civil3d2024\Speckle.Converters.Civil3d2024.csproj", "{25172C49-7AA4-4739-BB07-69785094C379}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RhinoShared", "Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.shproj", "{E1C43415-3200-45F4-8BF9-A4DD7D7F2ED9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Rhino7.Tests", "Converters\Rhino\Speckle.Converters.Rhino7.Tests\Speckle.Converters.Rhino7.Tests.csproj", "{AC2DB416-F05C-4296-9040-56D6AD4FCD27}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2023.Tests", "Converters\Revit\Speckle.Converters.Revit2023.Tests\Speckle.Converters.Revit2023.Tests.csproj", "{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Testing", "Sdk\Speckle.Testing\Speckle.Testing.csproj", "{A3869243-B462-4986-914B-94E407D8D20F}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RevitShared.DependencyInjection", "Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.shproj", "{6067BA60-D279-4156-8AE1-6B44E2D19187}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2024", "Connectors\Revit\Speckle.Connectors.Revit2024\Speckle.Connectors.Revit2024.csproj", "{617BD3C7-87D9-4D28-8AC9-4910945BB9FC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2024", "Converters\Revit\Speckle.Converters.Revit2024\Speckle.Converters.Revit2024.csproj", "{67B888D9-C6C4-49F1-883C-5B964151D889}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2024.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2024.DependencyInjection\Speckle.Converters.Revit2024.DependencyInjection.csproj", "{7F3055BA-70AA-424C-8748-345AF35127E9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023", "2023", "{E9DEBA00-50A4-485D-BA65-D8AB3E3467AB}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2024", "2024", "{57F59C0C-5687-4AF9-AE1C-1933B539F0E4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{FC224610-32D3-454E-9BC1-1219FE8ACD5F}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Converters.RevitShared.Tests", "Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.shproj", "{E1C43415-3202-45F4-8BF9-A4DD7D7F2ED6}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2024.Tests", "Converters\Revit\Speckle.Converters.Revit2024.Tests\Speckle.Converters.Revit2024.Tests.csproj", "{C32274D9-1B66-4D5C-82F9-EB3F10F46752}"
EndProject
Project("{D954291E-2A0B-460D-934E-DC6B0785DB48}") = "Speckle.Connectors.RevitShared.Cef", "Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.shproj", "{6A40CBE4-ECAB-4CED-9917-5C64CBF75DA6}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2025", "2025", "{8AC2AD6D-6C74-4B24-8DF6-42717FC9B804}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2025", "Connectors\Revit\Speckle.Connectors.Revit2025\Speckle.Connectors.Revit2025.csproj", "{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2025", "Converters\Revit\Speckle.Converters.Revit2025\Speckle.Converters.Revit2025.csproj", "{4D40A101-07E6-4FF2-8934-83434932591D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2025.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2025.DependencyInjection\Speckle.Converters.Revit2025.DependencyInjection.csproj", "{20751904-0DFC-4126-BF2A-834B53841010}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Connectors.Revit2022", "Connectors\Revit\Speckle.Connectors.Revit2022\Speckle.Connectors.Revit2022.csproj", "{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2022", "Converters\Revit\Speckle.Converters.Revit2022\Speckle.Converters.Revit2022.csproj", "{19424B55-058C-4E9C-B86F-700AEF9EAEC3}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2022.DependencyInjection", "Converters\Revit\Speckle.Converters.Revit2022.DependencyInjection\Speckle.Converters.Revit2022.DependencyInjection.csproj", "{881D71A3-D276-4108-98C6-0FFD32129B9C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2022", "2022", "{0AF38BA3-65A0-481B-8CBB-B82E406E1575}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Connectors.DUI.Tests", "DUI3\Speckle.Connectors.DUI.Tests\Speckle.Connectors.DUI.Tests.csproj", "{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Speckle.Converters.Revit2022.Tests", "Converters\Revit\Speckle.Converters.Revit2022.Tests\Speckle.Converters.Revit2022.Tests.csproj", "{D8069A23-AD2E-4C9E-8574-7E8C45296A46}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2023", "2023", "{2D5AE63D-85C0-43D1-84BF-04418ED93F63}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "2024", "2024", "{2F45036E-D817-41E9-B82F-DBE013EC95D0}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Civil3d", "Civil3d", "{91D70DE1-DC8E-4AE1-B100-0671D6263FC5}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Shared", "Shared", "{4721AA15-AF6E-4A62-A2C3-65564DC563E6}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{01F98733-7352-47AD-A594-537D979DE3DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{01F98733-7352-47AD-A594-537D979DE3DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{01F98733-7352-47AD-A594-537D979DE3DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{01F98733-7352-47AD-A594-537D979DE3DE}.Release|Any CPU.Build.0 = Release|Any CPU
{83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{83EAD6F0-3CB3-456A-AD81-072127D0DE0E}.Release|Any CPU.Build.0 = Release|Any CPU
{26391930-F86F-47E0-A5F6-B89919E38CE1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{26391930-F86F-47E0-A5F6-B89919E38CE1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{26391930-F86F-47E0-A5F6-B89919E38CE1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{26391930-F86F-47E0-A5F6-B89919E38CE1}.Release|Any CPU.Build.0 = Release|Any CPU
{D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D81C0B87-F0C1-4297-A147-02F001FB7E1E}.Release|Any CPU.Build.0 = Release|Any CPU
{C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C9D4CA21-182B-4ED2-81BB-280A6FD713F6}.Release|Any CPU.Build.0 = Release|Any CPU
{7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7291B93C-615D-42DE-B8C1-3F9DF643E0FC}.Release|Any CPU.Build.0 = Release|Any CPU
{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434}.Release|Any CPU.Build.0 = Release|Any CPU
{1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E2644A9-6B31-4350-8772-CEAAD6EE0B21}.Release|Any CPU.Build.0 = Release|Any CPU
{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5}.Release|Any CPU.Build.0 = Release|Any CPU
{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D}.Release|Any CPU.Build.0 = Release|Any CPU
{A97F7177-86C7-4B38-A6ED-DA51BF762471}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A97F7177-86C7-4B38-A6ED-DA51BF762471}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A97F7177-86C7-4B38-A6ED-DA51BF762471}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A97F7177-86C7-4B38-A6ED-DA51BF762471}.Release|Any CPU.Build.0 = Release|Any CPU
{139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{139F7A79-69E4-4B8A-B2A5-6A30A66C495C}.Release|Any CPU.Build.0 = Release|Any CPU
{7DFF1591-237D-499E-A767-EE37B93FB958}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7DFF1591-237D-499E-A767-EE37B93FB958}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7DFF1591-237D-499E-A767-EE37B93FB958}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7DFF1591-237D-499E-A767-EE37B93FB958}.Release|Any CPU.Build.0 = Release|Any CPU
{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Debug|Any CPU.Build.0 = Debug|Any CPU
{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Release|Any CPU.ActiveCfg = Release|Any CPU
{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395}.Release|Any CPU.Build.0 = Release|Any CPU
{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B}.Release|Any CPU.Build.0 = Release|Any CPU
{631C295A-7CCF-4B42-8686-7034E31469E7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{631C295A-7CCF-4B42-8686-7034E31469E7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{631C295A-7CCF-4B42-8686-7034E31469E7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{631C295A-7CCF-4B42-8686-7034E31469E7}.Release|Any CPU.Build.0 = Release|Any CPU
{D940853C-003A-482C-BDB0-665367F274A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D940853C-003A-482C-BDB0-665367F274A0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D940853C-003A-482C-BDB0-665367F274A0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D940853C-003A-482C-BDB0-665367F274A0}.Release|Any CPU.Build.0 = Release|Any CPU
{7420652C-3046-4F38-BE64-9B9E69D76FA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7420652C-3046-4F38-BE64-9B9E69D76FA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7420652C-3046-4F38-BE64-9B9E69D76FA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7420652C-3046-4F38-BE64-9B9E69D76FA2}.Release|Any CPU.Build.0 = Release|Any CPU
{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89}.Release|Any CPU.Build.0 = Release|Any CPU
{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1}.Release|Any CPU.Build.0 = Release|Any CPU
{80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{80F965C4-E2A8-4F54-985D-73D06E45F9CE}.Release|Any CPU.Build.0 = Release|Any CPU
{C2DE264A-AA87-4012-B954-17E3F403A237}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C2DE264A-AA87-4012-B954-17E3F403A237}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C2DE264A-AA87-4012-B954-17E3F403A237}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C2DE264A-AA87-4012-B954-17E3F403A237}.Release|Any CPU.Build.0 = Release|Any CPU
{AF507D61-6766-4C20-9F58-23DC29508219}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AF507D61-6766-4C20-9F58-23DC29508219}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF507D61-6766-4C20-9F58-23DC29508219}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF507D61-6766-4C20-9F58-23DC29508219}.Release|Any CPU.Build.0 = Release|Any CPU
{25172C49-7AA4-4739-BB07-69785094C379}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{25172C49-7AA4-4739-BB07-69785094C379}.Debug|Any CPU.Build.0 = Debug|Any CPU
{25172C49-7AA4-4739-BB07-69785094C379}.Release|Any CPU.ActiveCfg = Release|Any CPU
{25172C49-7AA4-4739-BB07-69785094C379}.Release|Any CPU.Build.0 = Release|Any CPU
{AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AC2DB416-F05C-4296-9040-56D6AD4FCD27}.Release|Any CPU.Build.0 = Release|Any CPU
{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Debug|Any CPU.Build.0 = Debug|Any CPU
{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Release|Any CPU.ActiveCfg = Release|Any CPU
{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051}.Release|Any CPU.Build.0 = Release|Any CPU
{A3869243-B462-4986-914B-94E407D8D20F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A3869243-B462-4986-914B-94E407D8D20F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3869243-B462-4986-914B-94E407D8D20F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3869243-B462-4986-914B-94E407D8D20F}.Release|Any CPU.Build.0 = Release|Any CPU
{617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{617BD3C7-87D9-4D28-8AC9-4910945BB9FC}.Release|Any CPU.Build.0 = Release|Any CPU
{67B888D9-C6C4-49F1-883C-5B964151D889}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{67B888D9-C6C4-49F1-883C-5B964151D889}.Debug|Any CPU.Build.0 = Debug|Any CPU
{67B888D9-C6C4-49F1-883C-5B964151D889}.Release|Any CPU.ActiveCfg = Release|Any CPU
{67B888D9-C6C4-49F1-883C-5B964151D889}.Release|Any CPU.Build.0 = Release|Any CPU
{7F3055BA-70AA-424C-8748-345AF35127E9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7F3055BA-70AA-424C-8748-345AF35127E9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7F3055BA-70AA-424C-8748-345AF35127E9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7F3055BA-70AA-424C-8748-345AF35127E9}.Release|Any CPU.Build.0 = Release|Any CPU
{C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C32274D9-1B66-4D5C-82F9-EB3F10F46752}.Release|Any CPU.Build.0 = Release|Any CPU
{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C}.Release|Any CPU.Build.0 = Release|Any CPU
{4D40A101-07E6-4FF2-8934-83434932591D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4D40A101-07E6-4FF2-8934-83434932591D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4D40A101-07E6-4FF2-8934-83434932591D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4D40A101-07E6-4FF2-8934-83434932591D}.Release|Any CPU.Build.0 = Release|Any CPU
{20751904-0DFC-4126-BF2A-834B53841010}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{20751904-0DFC-4126-BF2A-834B53841010}.Debug|Any CPU.Build.0 = Debug|Any CPU
{20751904-0DFC-4126-BF2A-834B53841010}.Release|Any CPU.ActiveCfg = Release|Any CPU
{20751904-0DFC-4126-BF2A-834B53841010}.Release|Any CPU.Build.0 = Release|Any CPU
{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Debug|Any CPU.ActiveCfg = Debug|x64
{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Debug|Any CPU.Build.0 = Debug|x64
{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Release|Any CPU.ActiveCfg = Debug|x64
{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36}.Release|Any CPU.Build.0 = Debug|x64
{19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{19424B55-058C-4E9C-B86F-700AEF9EAEC3}.Release|Any CPU.Build.0 = Release|Any CPU
{881D71A3-D276-4108-98C6-0FFD32129B9C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{881D71A3-D276-4108-98C6-0FFD32129B9C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{881D71A3-D276-4108-98C6-0FFD32129B9C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{881D71A3-D276-4108-98C6-0FFD32129B9C}.Release|Any CPU.Build.0 = Release|Any CPU
{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885}.Release|Any CPU.Build.0 = Release|Any CPU
{D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D8069A23-AD2E-4C9E-8574-7E8C45296A46}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{D92751C8-1039-4005-90B2-913E55E0B8BD} = {42826721-9A18-4762-8BA9-F1429DD5C5B1}
{01F98733-7352-47AD-A594-537D979DE3DE} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB}
{DC570FFF-6FE5-47BD-8BC1-B471A6067786} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F}
{E1C43415-3200-45F4-8BF9-A4DD7D7F2ED6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F}
{83EAD6F0-3CB3-456A-AD81-072127D0DE0E} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB}
{26391930-F86F-47E0-A5F6-B89919E38CE1} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB}
{D81C0B87-F0C1-4297-A147-02F001FB7E1E} = {FD4D6594-D81E-456F-8F2E-35B09E04A755}
{C9D4CA21-182B-4ED2-81BB-280A6FD713F6} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA}
{7291B93C-615D-42DE-B8C1-3F9DF643E0FC} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA}
{8AEF06C0-CA5C-4460-BC2D-ADE5F35D0434} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA}
{9584AEE5-CD59-46E6-93E6-2DC2B5285B75} = {42826721-9A18-4762-8BA9-F1429DD5C5B1}
{1E2644A9-6B31-4350-8772-CEAAD6EE0B21} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75}
{65A2F556-F14A-49F3-8A92-7F2E1E7ED3B5} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75}
{9C1ECA1D-DE98-4FB7-92D0-FC45BB308E5D} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75}
{A97F7177-86C7-4B38-A6ED-DA51BF762471} = {CCF48B65-33D1-4E8B-A57B-E03394730B21}
{139F7A79-69E4-4B8A-B2A5-6A30A66C495C} = {CCF48B65-33D1-4E8B-A57B-E03394730B21}
{7DFF1591-237D-499E-A767-EE37B93FB958} = {CCF48B65-33D1-4E8B-A57B-E03394730B21}
{CCF48B65-33D1-4E8B-A57B-E03394730B21} = {42826721-9A18-4762-8BA9-F1429DD5C5B1}
{11F7D41B-AFCA-4D29-BC08-285A14BF3A3B} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA}
{804E065F-914C-414A-AF84-009312C3CFF6} = {42826721-9A18-4762-8BA9-F1429DD5C5B1}
{7420652C-3046-4F38-BE64-9B9E69D76FA2} = {FD4D6594-D81E-456F-8F2E-35B09E04A755}
{C50AA3E3-8C31-4131-9DEC-1D8B377D5A89} = {59E8E8F3-4E42-4E92-83B3-B1C2AB901D18}
{E1C43415-3200-45F4-8BF9-A4DD7D7F2ED9} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75}
{AC2DB416-F05C-4296-9040-56D6AD4FCD27} = {9584AEE5-CD59-46E6-93E6-2DC2B5285B75}
{68CF9BDF-94AC-4D2D-A7BD-D1C064F97051} = {E9DEBA00-50A4-485D-BA65-D8AB3E3467AB}
{A3869243-B462-4986-914B-94E407D8D20F} = {2E00592E-558D-492D-88F9-3ECEE4C0C7DA}
{6067BA60-D279-4156-8AE1-6B44E2D19187} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F}
{617BD3C7-87D9-4D28-8AC9-4910945BB9FC} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4}
{67B888D9-C6C4-49F1-883C-5B964151D889} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4}
{7F3055BA-70AA-424C-8748-345AF35127E9} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4}
{E9DEBA00-50A4-485D-BA65-D8AB3E3467AB} = {D92751C8-1039-4005-90B2-913E55E0B8BD}
{57F59C0C-5687-4AF9-AE1C-1933B539F0E4} = {D92751C8-1039-4005-90B2-913E55E0B8BD}
{FC224610-32D3-454E-9BC1-1219FE8ACD5F} = {D92751C8-1039-4005-90B2-913E55E0B8BD}
{E1C43415-3202-45F4-8BF9-A4DD7D7F2ED6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F}
{C32274D9-1B66-4D5C-82F9-EB3F10F46752} = {57F59C0C-5687-4AF9-AE1C-1933B539F0E4}
{6A40CBE4-ECAB-4CED-9917-5C64CBF75DA6} = {FC224610-32D3-454E-9BC1-1219FE8ACD5F}
{8AC2AD6D-6C74-4B24-8DF6-42717FC9B804} = {D92751C8-1039-4005-90B2-913E55E0B8BD}
{A6DE3DA0-B242-4F49-AEF0-4E26AF92D16C} = {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804}
{4D40A101-07E6-4FF2-8934-83434932591D} = {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804}
{20751904-0DFC-4126-BF2A-834B53841010} = {8AC2AD6D-6C74-4B24-8DF6-42717FC9B804}
{7F1FDCF2-0CE8-4119-B3C1-F2CC6D7E1C36} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575}
{19424B55-058C-4E9C-B86F-700AEF9EAEC3} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575}
{881D71A3-D276-4108-98C6-0FFD32129B9C} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575}
{0AF38BA3-65A0-481B-8CBB-B82E406E1575} = {D92751C8-1039-4005-90B2-913E55E0B8BD}
{EB83A3A3-F9B6-4281-8EBF-F7289FB5D885} = {FD4D6594-D81E-456F-8F2E-35B09E04A755}
{D8069A23-AD2E-4C9E-8574-7E8C45296A46} = {0AF38BA3-65A0-481B-8CBB-B82E406E1575}
{2D5AE63D-85C0-43D1-84BF-04418ED93F63} = {804E065F-914C-414A-AF84-009312C3CFF6}
{89C4CBC7-1606-40DE-B6DA-FBE3AAC98395} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63}
{631C295A-7CCF-4B42-8686-7034E31469E7} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63}
{D940853C-003A-482C-BDB0-665367F274A0} = {2D5AE63D-85C0-43D1-84BF-04418ED93F63}
{2F45036E-D817-41E9-B82F-DBE013EC95D0} = {804E065F-914C-414A-AF84-009312C3CFF6}
{C2DE264A-AA87-4012-B954-17E3F403A237} = {2F45036E-D817-41E9-B82F-DBE013EC95D0}
{AF507D61-6766-4C20-9F58-23DC29508219} = {2F45036E-D817-41E9-B82F-DBE013EC95D0}
{91D70DE1-DC8E-4AE1-B100-0671D6263FC5} = {804E065F-914C-414A-AF84-009312C3CFF6}
{CA8EAE01-AB9F-4EC1-B6F3-73721487E9E1} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5}
{25172C49-7AA4-4739-BB07-69785094C379} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5}
{80F965C4-E2A8-4F54-985D-73D06E45F9CE} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5}
{35175682-DA83-4C0A-A49D-B191F5885D8E} = {91D70DE1-DC8E-4AE1-B100-0671D6263FC5}
{4721AA15-AF6E-4A62-A2C3-65564DC563E6} = {804E065F-914C-414A-AF84-009312C3CFF6}
{41BC679F-887F-44CF-971D-A5502EE87DB0} = {4721AA15-AF6E-4A62-A2C3-65564DC563E6}
{9ADD1B7A-6401-4202-8613-F668E2FBC0A4} = {4721AA15-AF6E-4A62-A2C3-65564DC563E6}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {EE253116-7070-4E9A-BCE8-2911C251B8C8}
EndGlobalSection
GlobalSection(SharedMSBuildProjectFiles) = preSolution
Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{01f98733-7352-47ad-a594-537d979de3de}*SharedItemsImports = 5
Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{01f98733-7352-47ad-a594-537d979de3de}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{19424b55-058c-4e9c-b86f-700aef9eaec3}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{20751904-0dfc-4126-bf2a-834b53841010}*SharedItemsImports = 5
Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{25172c49-7aa4-4739-bb07-69785094c379}*SharedItemsImports = 5
Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.projitems*{25172c49-7aa4-4739-bb07-69785094c379}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{26391930-f86f-47e0-a5f6-b89919e38ce1}*SharedItemsImports = 5
Converters\Civil3d\Speckle.Converters.Civil3dShared\Speckle.Converters.Civil3dShared.projitems*{35175682-da83-4c0a-a49d-b191f5885d8e}*SharedItemsImports = 13
Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{41bc679f-887f-44cf-971d-a5502ee87db0}*SharedItemsImports = 13
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{4d40a101-07e6-4ff2-8934-83434932591d}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{6067ba60-d279-4156-8ae1-6b44e2d19187}*SharedItemsImports = 13
Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{617bd3c7-87d9-4d28-8ac9-4910945bb9fc}*SharedItemsImports = 5
Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{617bd3c7-87d9-4d28-8ac9-4910945bb9fc}*SharedItemsImports = 5
Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{631c295a-7ccf-4b42-8686-7034e31469e7}*SharedItemsImports = 5
Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.projitems*{65a2f556-f14a-49f3-8a92-7f2e1e7ed3b5}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{67b888d9-c6c4-49f1-883c-5b964151d889}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{68cf9bdf-94ac-4d2d-a7bd-d1c064f97051}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{68cf9bdf-94ac-4d2d-a7bd-d1c064f97051}*SharedItemsImports = 5
Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{6a40cbe4-ecab-4ced-9917-5c64cbf75da6}*SharedItemsImports = 13
Connectors\Revit\Speckle.Connectors.RevitShared.Cef\Speckle.Connectors.RevitShared.Cef.projitems*{7f1fdcf2-0ce8-4119-b3c1-f2cc6d7e1c36}*SharedItemsImports = 5
Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{7f1fdcf2-0ce8-4119-b3c1-f2cc6d7e1c36}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{7f3055ba-70aa-424c-8748-345af35127e9}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{83ead6f0-3cb3-456a-ad81-072127d0de0e}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.DependencyInjection\Speckle.Converters.RevitShared.DependencyInjection.projitems*{881d71a3-d276-4108-98c6-0ffd32129b9c}*SharedItemsImports = 5
Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{89c4cbc7-1606-40de-b6da-fbe3aac98395}*SharedItemsImports = 5
Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{9add1b7a-6401-4202-8613-f668e2fbc0a4}*SharedItemsImports = 13
Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{a6de3da0-b242-4f49-aef0-4e26af92d16c}*SharedItemsImports = 5
Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.projitems*{ac2db416-f05c-4296-9040-56d6ad4fcd27}*SharedItemsImports = 5
Converters\Autocad\Speckle.Converters.AutocadShared\Speckle.Converters.AutocadShared.projitems*{c2de264a-aa87-4012-b954-17e3f403a237}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{c32274d9-1b66-4d5c-82f9-eb3f10f46752}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{c32274d9-1b66-4d5c-82f9-eb3f10f46752}*SharedItemsImports = 5
Connectors\Autocad\Speckle.Connectors.AutocadShared\Speckle.Connectors.AutocadShared.projitems*{ca8eae01-ab9f-4ec1-b6f3-73721487e9e1}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{d8069a23-ad2e-4c9e-8574-7e8c45296a46}*SharedItemsImports = 5
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{d8069a23-ad2e-4c9e-8574-7e8c45296a46}*SharedItemsImports = 5
Connectors\Revit\Speckle.Connectors.RevitShared\Speckle.Connectors.RevitShared.projitems*{dc570fff-6fe5-47bd-8bc1-b471a6067786}*SharedItemsImports = 13
Converters\Revit\Speckle.Converters.RevitShared\Speckle.Converters.RevitShared.projitems*{e1c43415-3200-45f4-8bf9-a4dd7d7f2ed6}*SharedItemsImports = 13
Converters\Rhino\Speckle.Converters.RhinoShared\Speckle.Converters.RhinoShared.projitems*{e1c43415-3200-45f4-8bf9-a4dd7d7f2ed9}*SharedItemsImports = 13
Converters\Revit\Speckle.Converters.RevitShared.Tests\Speckle.Converters.RevitShared.Tests.projitems*{e1c43415-3202-45f4-8bf9-a4dd7d7f2ed6}*SharedItemsImports = 13
EndGlobalSection
EndGlobal
+59 -29
View File
@@ -1,48 +1,49 @@
using Microsoft.Build.Construction;
using Microsoft.VisualStudio.SolutionPersistence.Model;
using Microsoft.VisualStudio.SolutionPersistence.Model;
using Microsoft.VisualStudio.SolutionPersistence.Serializer;
namespace Build;
public static class Solutions
{
private static bool ValidProjects(KeyValuePair<string, ProjectInSolution> projectInSolution) =>
projectInSolution.Value.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat;
public static void CompareConnectorsToLocal()
#pragma warning disable CA1802
#pragma warning disable IDE1006
private static readonly string DIRECTORY = Environment.CurrentDirectory;
#pragma warning restore IDE1006
#pragma warning restore CA1802
public static async Task CompareConnectorsToLocal()
{
var localSln = SolutionFile.Parse(Path.Combine(Environment.CurrentDirectory, "Local.sln"));
var connectorsSln = SolutionFile.Parse(Path.Combine(Environment.CurrentDirectory, "Speckle.Connectors.sln"));
var localProjects = localSln.ProjectsByGuid.Where(ValidProjects).ToDictionary();
var localSln = await GetSolution("Local.sln");
var connectorsSln = await GetSolution("Speckle.Connectors.sln");
var localProjects = localSln.SolutionProjects.ToList();
foreach ((string? _, ProjectInSolution? value) in connectorsSln.ProjectsByGuid.Where(ValidProjects))
foreach (var value in connectorsSln.SolutionProjects)
{
var localProject = localProjects.Values.FirstOrDefault(x => x.ProjectName == value.ProjectName);
var localProject = localProjects.FirstOrDefault(x => x.ActualDisplayName == value.ActualDisplayName);
if (localProject is null)
{
throw new InvalidOperationException($"Could not find in LOCAL solution: {value.ProjectName}");
throw new InvalidOperationException($"Could not find in LOCAL solution: {value.ActualDisplayName}");
}
if (value.ProjectName != localProject.ProjectName)
if (value.ActualDisplayName != localProject.ActualDisplayName)
{
throw new InvalidOperationException(
"Projects with different names have same Guid in solution: "
+ value.ProjectName
+ value.ActualDisplayName
+ " and "
+ localProject.ProjectName
+ localProject.ActualDisplayName
);
}
localProjects.Remove(localProjects.Single(x => x.Value.ProjectName == value.ProjectName).Key);
localProjects.Remove(localProjects.Single(x => x.ActualDisplayName == value.ActualDisplayName));
}
void CheckAndRemoveKnown(string projectName)
{
var localProject = localProjects.Values.FirstOrDefault(x => x.ProjectName == projectName);
var localProject = localProjects.FirstOrDefault(x => x.ActualDisplayName == projectName);
if (localProject is null)
{
throw new InvalidOperationException($"Could not find in LOCAL solution: {projectName}");
}
localProjects.Remove(localProjects.Single(x => x.Value.ProjectName == projectName).Key);
localProjects.Remove(localProjects.Single(x => x.ActualDisplayName == projectName));
}
CheckAndRemoveKnown("Speckle.Objects");
@@ -51,7 +52,7 @@ public static class Solutions
if (localProjects.Count != 0)
{
throw new InvalidOperationException(
"Could not find in CONNECTOR solution: " + localProjects.First().Value.ProjectName
"Could not find in CONNECTOR solution: " + localProjects.First().ActualDisplayName
);
}
}
@@ -61,9 +62,9 @@ public static class Solutions
await GenerateLocalSlnx();
foreach (var group in Consts.ProjectGroups)
{
var path = group.Projects[0].ProjectPath.Split('/');
var folder = $"/{path[0]}/{path[1]}/";
await GenerateConnector(group.HostAppSlug, folder);
var connectors = await GetFullSlnx();
var slug = group.HostAppSlug;
await GenerateConnector(connectors, group, string.Concat(slug[0].ToString().ToUpper(), slug.AsSpan(1)));
}
}
@@ -73,16 +74,20 @@ public static class Solutions
connectors.AddProject("..\\speckle-sharp-sdk\\src\\Speckle.Objects\\Speckle.Objects.csproj");
connectors.AddProject("..\\speckle-sharp-sdk\\src\\Speckle.Sdk\\Speckle.Sdk.csproj");
connectors.AddProject("..\\speckle-sharp-sdk\\src\\Speckle.Sdk.Dependencies\\Speckle.Sdk.Dependencies.csproj");
var sln = Path.Combine("C:\\Users\\adam\\Git\\speckle-sharp-connectors", "Local.slnx");
var sln = Path.Combine(DIRECTORY, "Local.slnx");
await SolutionSerializers.SlnXml.SaveAsync(sln, connectors, default);
sln = Path.Combine(Environment.CurrentDirectory, "Local.sln");
sln = Path.Combine(DIRECTORY, "Local.sln");
await SolutionSerializers.SlnFileV12.SaveAsync(sln, connectors, default);
var revit = Consts.ProjectGroups.Single(x => x.HostAppSlug.Equals("revit"));
await GenerateConnector(connectors, revit, "Revit.Local");
await GenerateMacSolutions();
}
public static async Task GenerateConnector(string slug, string folder)
public static async Task GenerateConnector(SolutionModel connectors, ProjectGroup group, string? name)
{
slug = string.Concat(slug[0].ToString().ToUpper(), slug.AsSpan(1));
var connectors = await GetFullSlnx();
var path = group.Projects[0].ProjectPath.Split('/');
var folder = $"/{path[0]}/{path[1]}/";
var foldersToRemove = connectors
.SolutionFolders.Where(x =>
//need base folder
@@ -95,13 +100,38 @@ public static class Solutions
{
connectors.RemoveFolder(folderToRemove);
}
var sln = Path.Combine(Environment.CurrentDirectory, $"Speckle.{slug}.slnx");
var sln = Path.Combine(DIRECTORY, $"Speckle.{name}.slnx");
await SolutionSerializers.SlnXml.SaveAsync(sln, connectors, default);
}
public static async Task<SolutionModel> GetFullSlnx()
{
var connectorsSln = Path.Combine(Environment.CurrentDirectory, "Speckle.Connectors.slnx");
var connectorsSln = Path.Combine(DIRECTORY, "Speckle.Connectors.slnx");
return await SolutionSerializers.SlnXml.OpenAsync(connectorsSln, default);
}
public static async Task<SolutionModel> GetSolution(string solutionName)
{
var connectorsSln = Path.Combine(DIRECTORY, solutionName);
return await SolutionSerializers.SlnFileV12.OpenAsync(connectorsSln, default);
}
public static async Task GenerateMacSolutions()
{
var connectors = await GetFullSlnx();
var foldersToRemove = connectors
.SolutionFolders.Where(x =>
//need base folder
!x.Path.Equals("/Connectors/")
//don't grab all
&& (x.Path.StartsWith("/Connectors/"))
)
.ToList();
foreach (var folderToRemove in foldersToRemove)
{
connectors.RemoveFolder(folderToRemove);
}
var sln = Path.Combine(DIRECTORY, $"Speckle.Connectors.Mac.slnx");
await SolutionSerializers.SlnXml.SaveAsync(sln, connectors, default);
}
}
@@ -1,119 +1,58 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Sdk;
namespace Speckle.Connectors.Autocad.Bindings;
public abstract class AutocadReceiveBaseBinding : IReceiveBinding
public abstract class AutocadReceiveBaseBinding(
IBrowserBridge parent,
ICancellationManager cancellationManager,
IThreadContext threadContext,
IReceiveOperationManagerFactory receiveOperationManagerFactory
) : IReceiveBinding
{
public string Name => "receiveBinding";
public IBrowserBridge Parent { get; }
public IBrowserBridge Parent { get; } = parent;
private readonly DocumentModelStore _store;
private readonly ICancellationManager _cancellationManager;
private readonly IServiceProvider _serviceProvider;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<AutocadReceiveBinding> _logger;
private readonly ISpeckleApplication _speckleApplication;
private readonly IThreadContext _threadContext;
private ReceiveBindingUICommands Commands { get; }
protected AutocadReceiveBaseBinding(
DocumentModelStore store,
IBrowserBridge parent,
ICancellationManager cancellationManager,
IServiceProvider serviceProvider,
IOperationProgressManager operationProgressManager,
ILogger<AutocadReceiveBinding> logger,
ISpeckleApplication speckleApplication,
IThreadContext threadContext
)
{
_store = store;
_cancellationManager = cancellationManager;
_serviceProvider = serviceProvider;
_operationProgressManager = operationProgressManager;
_logger = logger;
_speckleApplication = speckleApplication;
_threadContext = threadContext;
Parent = parent;
Commands = new ReceiveBindingUICommands(parent);
}
private ReceiveBindingUICommands Commands { get; } = new(parent);
protected abstract void InitializeSettings(IServiceProvider serviceProvider);
public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId);
public async Task Receive(string modelCardId) =>
await _threadContext.RunOnMainAsync(async () => await ReceiveInternal(modelCardId));
await threadContext.RunOnMainAsync(async () => await ReceiveInternal(modelCardId));
private async Task ReceiveInternal(string modelCardId)
{
using var scope = _serviceProvider.CreateScope();
InitializeSettings(scope.ServiceProvider);
try
{
// Get receiver card
if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
using var manager = receiveOperationManagerFactory.Create();
await manager.Process(
Commands,
modelCardId,
InitializeSettings,
async (_, processor) =>
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No download model card was found.");
try
{
// Disable document activation (document creation and document switch)
// Not disabling results in DUI model card being out of sync with the active document
// The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue
Application.DocumentManager.DocumentActivationEnabled = false;
return await processor();
}
finally
{
// reenable document activation
Application.DocumentManager.DocumentActivationEnabled = true;
// regenerate doc to flush graphics, sometimes some objects (ellipses, nurbs curves) do not appear fully visible after receive.
// Adding a regen (must be run on main thread) here, but it doesn't seem to work:
// it's run on main thread, tried sending the "regen" string to execute, also tried regen after every object bake, but still can't fix.
// the objects should appear visible if you manually call the "regen" command after the operation finishes, or click on a view on the view cube which also calls regen.
Application.DocumentManager.CurrentDocument.Editor.Regen();
}
}
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
// Disable document activation (document creation and document switch)
// Not disabling results in DUI model card being out of sync with the active document
// The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue
Application.DocumentManager.DocumentActivationEnabled = false;
// Receive host objects
var operationResults = await scope
.ServiceProvider.GetRequiredService<ReceiveOperation>()
.Execute(
modelCard.GetReceiveInfo(_speckleApplication.Slug),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
await Commands.SetModelReceiveResult(
modelCardId,
operationResults.BakedObjectIds,
operationResults.ConversionResults
);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
return;
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
finally
{
// reenable document activation
Application.DocumentManager.DocumentActivationEnabled = true;
// regenerate doc to flush graphics, sometimes some objects (ellipses, nurbs curves) do not appear fully visible after receive.
// Adding a regen (must be run on main thread) here, but it doesn't seem to work:
// it's run on main thread, tried sending the "regen" string to execute, also tried regen after every object bake, but still can't fix.
// the objects should appear visible if you manually call the "regen" command after the operation finishes, or click on a view on the view cube which also calls regen.
Application.DocumentManager.CurrentDocument.Editor.Regen();
}
);
}
}
@@ -1,13 +1,10 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Sdk;
namespace Speckle.Connectors.Autocad.Bindings;
@@ -16,26 +13,13 @@ public sealed class AutocadReceiveBinding : AutocadReceiveBaseBinding
private readonly IAutocadConversionSettingsFactory _autocadConversionSettingsFactory;
public AutocadReceiveBinding(
DocumentModelStore store,
IBrowserBridge parent,
ICancellationManager cancellationManager,
IServiceProvider serviceProvider,
IOperationProgressManager operationProgressManager,
ILogger<AutocadReceiveBinding> logger,
IAutocadConversionSettingsFactory autocadConversionSettingsFactory,
ISpeckleApplication speckleApplication,
IThreadContext threadContext
IThreadContext threadContext,
IReceiveOperationManagerFactory receiveOperationManagerFactory
)
: base(
store,
parent,
cancellationManager,
serviceProvider,
operationProgressManager,
logger,
speckleApplication,
threadContext
)
: base(parent, cancellationManager, threadContext, receiveOperationManagerFactory)
{
_autocadConversionSettingsFactory = autocadConversionSettingsFactory;
}
@@ -1,23 +1,16 @@
using System.Collections.Concurrent;
using System.Diagnostics.CodeAnalysis;
using Autodesk.AutoCAD.DatabaseServices;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.HostApp.Extensions;
using Speckle.Connectors.Autocad.Operations.Send;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Settings;
using Speckle.Sdk;
using Speckle.Sdk.Common;
namespace Speckle.Connectors.Autocad.Bindings;
@@ -33,14 +26,11 @@ public abstract class AutocadSendBaseBinding : ISendBinding
private readonly DocumentModelStore _store;
private readonly List<ISendFilter> _sendFilters;
private readonly ICancellationManager _cancellationManager;
private readonly IServiceProvider _serviceProvider;
private readonly ISendConversionCache _sendConversionCache;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<AutocadSendBinding> _logger;
private readonly ISpeckleApplication _speckleApplication;
private readonly IThreadContext _threadContext;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
private readonly IAppIdleManager _idleManager;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
/// <summary>
/// Used internally to aggregate the changed objects' id. Note we're using a concurrent dictionary here as the expiry check method is not thread safe, and this was causing problems. See:
@@ -55,27 +45,21 @@ public abstract class AutocadSendBaseBinding : ISendBinding
IBrowserBridge parent,
IEnumerable<ISendFilter> sendFilters,
ICancellationManager cancellationManager,
IServiceProvider serviceProvider,
ISendConversionCache sendConversionCache,
IOperationProgressManager operationProgressManager,
ILogger<AutocadSendBinding> logger,
ISpeckleApplication speckleApplication,
IThreadContext threadContext,
ITopLevelExceptionHandler topLevelExceptionHandler,
IAppIdleManager idleManager
IAppIdleManager idleManager,
ISendOperationManagerFactory sendOperationManagerFactory
)
{
_store = store;
_serviceProvider = serviceProvider;
_cancellationManager = cancellationManager;
_sendFilters = sendFilters.ToList();
_sendConversionCache = sendConversionCache;
_operationProgressManager = operationProgressManager;
_logger = logger;
_speckleApplication = speckleApplication;
_threadContext = threadContext;
_topLevelExceptionHandler = topLevelExceptionHandler;
_idleManager = idleManager;
_sendOperationManagerFactory = sendOperationManagerFactory;
Parent = parent;
Commands = new SendBindingUICommands(parent);
@@ -152,55 +136,17 @@ public abstract class AutocadSendBaseBinding : ISendBinding
{
try
{
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No publish model card was found.");
}
using var scope = _serviceProvider.CreateScope();
InitializeSettings(scope.ServiceProvider);
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
using var manager = _sendOperationManagerFactory.Create();
// Disable document activation (document creation and document switch)
// Not disabling results in DUI model card being out of sync with the active document
// The DocumentActivated event isn't usable probably because it is pushed to back of main thread queue
Application.DocumentManager.DocumentActivationEnabled = false;
// Get elements to convert
List<AutocadRootObject> autocadObjects = Application.DocumentManager.CurrentDocument.GetObjects(
modelCard.SendFilter.NotNull().RefreshObjectIds()
await manager.Process(
Commands,
modelCardId,
(sp, card) => InitializeSettings(sp),
card => Application.DocumentManager.CurrentDocument.GetObjects(card.SendFilter.NotNull().RefreshObjectIds())
);
if (autocadObjects.Count == 0)
{
// Handle as CARD ERROR in this function
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
}
var sendResult = await scope
.ServiceProvider.GetRequiredService<SendOperation<AutocadRootObject>>()
.Execute(
autocadObjects,
modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
return;
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
finally
{
@@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Threading;
@@ -9,7 +8,6 @@ using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Converters.Autocad;
using Speckle.Converters.Common;
using Speckle.Sdk;
namespace Speckle.Connectors.Autocad.Bindings;
@@ -22,29 +20,23 @@ public sealed class AutocadSendBinding : AutocadSendBaseBinding
IBrowserBridge parent,
IEnumerable<ISendFilter> sendFilters,
ICancellationManager cancellationManager,
IServiceProvider serviceProvider,
ISendConversionCache sendConversionCache,
IOperationProgressManager operationProgressManager,
ILogger<AutocadSendBinding> logger,
IAutocadConversionSettingsFactory autocadConversionSettingsFactory,
ISpeckleApplication speckleApplication,
IThreadContext threadContext,
ITopLevelExceptionHandler topLevelExceptionHandler,
IAppIdleManager appIdleManager
IAppIdleManager appIdleManager,
ISendOperationManagerFactory sendOperationManagerFactory
)
: base(
store,
parent,
sendFilters,
cancellationManager,
serviceProvider,
sendConversionCache,
operationProgressManager,
logger,
speckleApplication,
threadContext,
topLevelExceptionHandler,
appIdleManager
appIdleManager,
sendOperationManagerFactory
)
{
_autocadConversionSettingsFactory = autocadConversionSettingsFactory;
@@ -7,7 +7,6 @@ using Speckle.Connectors.Common.Extensions;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Common.Operations.Receive;
using Speckle.Converters.Common;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Dependencies;
using Speckle.Sdk.Models;
@@ -28,7 +27,8 @@ public class AutocadHostObjectBuilder(
IAutocadMaterialBaker materialBaker,
IAutocadColorBaker colorBaker,
AutocadContext autocadContext,
RootObjectUnpacker rootObjectUnpacker
RootObjectUnpacker rootObjectUnpacker,
IReceiveConversionHandler conversionHandler
) : IHostObjectBuilder
{
public Task<HostObjectBuilderResult> Build(
@@ -90,11 +90,11 @@ public class AutocadHostObjectBuilder(
var count = 0;
foreach (var (layerPath, atomicObject) in atomicObjectsWithPath)
{
string objectId = atomicObject.applicationId ?? atomicObject.id.NotNull();
onOperationProgressed.Report(new("Converting objects", (double)++count / atomicObjects.Count));
cancellationToken.ThrowIfCancellationRequested();
try
var ex = conversionHandler.TryConvert(() =>
{
cancellationToken.ThrowIfCancellationRequested();
string objectId = atomicObject.applicationId ?? atomicObject.id.NotNull();
IReadOnlyCollection<Entity> convertedObjects = ConvertObject(atomicObject, layerPath, baseLayerPrefix);
applicationIdMap[objectId] = convertedObjects;
@@ -109,8 +109,8 @@ public class AutocadHostObjectBuilder(
);
bakedObjectIds.UnionWith(convertedObjects.Select(e => e.GetSpeckleApplicationId()));
}
catch (Exception ex) when (!ex.IsFatal())
});
if (ex != null)
{
results.Add(new(Status.ERROR, atomicObject, null, null, ex));
}
@@ -17,7 +17,7 @@ namespace Speckle.Connectors.Autocad.Plugin;
public class AutocadCommand
{
private static PaletteSet? PaletteSet { get; set; }
private static readonly Guid s_id = new("3223E594-1B09-4E54-B3DD-8EA0BECE7BA5");
private static readonly Guid s_id = new("7C27DD2B-86E8-4D31-B3DE-B34B267B1DC8");
public ServiceProvider? Container { get; private set; }
private IDisposable? _disposableLogger;
public const string COMMAND_STRING = "Speckle";
@@ -1,15 +1,12 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.Bindings;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Converters.Autocad;
using Speckle.Converters.Civil3dShared;
using Speckle.Converters.Common;
using Speckle.Sdk;
namespace Speckle.Connectors.Civil3dShared.Bindings;
@@ -19,27 +16,14 @@ public sealed class Civil3dReceiveBinding : AutocadReceiveBaseBinding
private readonly IAutocadConversionSettingsFactory _autocadConversionSettingsFactory;
public Civil3dReceiveBinding(
DocumentModelStore store,
IBrowserBridge parent,
ICancellationManager cancellationManager,
IServiceProvider serviceProvider,
IOperationProgressManager operationProgressManager,
ILogger<AutocadReceiveBinding> logger,
ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory,
IAutocadConversionSettingsFactory autocadConversionSettingsFactory,
ISpeckleApplication speckleApplication,
IThreadContext threadContext
IThreadContext threadContext,
IReceiveOperationManagerFactory receiveOperationManagerFactory
)
: base(
store,
parent,
cancellationManager,
serviceProvider,
operationProgressManager,
logger,
speckleApplication,
threadContext
)
: base(parent, cancellationManager, threadContext, receiveOperationManagerFactory)
{
_civil3dConversionSettingsFactory = civil3dConversionSettingsFactory;
_autocadConversionSettingsFactory = autocadConversionSettingsFactory;
@@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Autocad.Bindings;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
@@ -11,7 +10,6 @@ using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Converters.Autocad;
using Speckle.Converters.Civil3dShared;
using Speckle.Converters.Common;
using Speckle.Sdk;
namespace Speckle.Connectors.Civil3dShared.Bindings;
@@ -25,30 +23,24 @@ public sealed class Civil3dSendBinding : AutocadSendBaseBinding
IBrowserBridge parent,
IEnumerable<ISendFilter> sendFilters,
ICancellationManager cancellationManager,
IServiceProvider serviceProvider,
ISendConversionCache sendConversionCache,
IOperationProgressManager operationProgressManager,
ILogger<AutocadSendBinding> logger,
ICivil3dConversionSettingsFactory civil3dConversionSettingsFactory,
IAutocadConversionSettingsFactory autocadConversionSettingsFactory,
ISpeckleApplication speckleApplication,
IThreadContext threadContext,
ITopLevelExceptionHandler topLevelExceptionHandler,
IAppIdleManager appIdleManager
IAppIdleManager appIdleManager,
ISendOperationManagerFactory sendOperationManagerFactory
)
: base(
store,
parent,
sendFilters,
cancellationManager,
serviceProvider,
sendConversionCache,
operationProgressManager,
logger,
speckleApplication,
threadContext,
topLevelExceptionHandler,
appIdleManager
appIdleManager,
sendOperationManagerFactory
)
{
_civil3dConversionSettingsFactory = civil3dConversionSettingsFactory;
@@ -1,22 +1,14 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.CSiShared.HostApp;
using Speckle.Connectors.CSiShared.Utils;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Settings;
using Speckle.Converters.Common;
using Speckle.Converters.CSiShared;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Logging;
namespace Speckle.Connectors.CSiShared.Bindings;
@@ -26,43 +18,28 @@ public sealed class CsiSharedSendBinding : ISendBinding
public SendBindingUICommands Commands { get; }
public IBrowserBridge Parent { get; }
private readonly DocumentModelStore _store;
private readonly IServiceProvider _serviceProvider;
private readonly List<ISendFilter> _sendFilters;
private readonly ICancellationManager _cancellationManager;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<CsiSharedSendBinding> _logger;
private readonly ICsiApplicationService _csiApplicationService;
private readonly ICsiConversionSettingsFactory _csiConversionSettingsFactory;
private readonly ISpeckleApplication _speckleApplication;
private readonly ISdkActivityFactory _activityFactory;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
public CsiSharedSendBinding(
DocumentModelStore store,
IBrowserBridge parent,
IEnumerable<ISendFilter> sendFilters,
IServiceProvider serviceProvider,
ICancellationManager cancellationManager,
IOperationProgressManager operationProgressManager,
ILogger<CsiSharedSendBinding> logger,
ICsiConversionSettingsFactory csiConversionSettingsFactory,
ISpeckleApplication speckleApplication,
ISdkActivityFactory activityFactory,
ICsiApplicationService csiApplicationService
ICsiApplicationService csiApplicationService,
ISendOperationManagerFactory sendOperationManagerFactory
)
{
_store = store;
_serviceProvider = serviceProvider;
_sendFilters = sendFilters.ToList();
_cancellationManager = cancellationManager;
_operationProgressManager = operationProgressManager;
_logger = logger;
Parent = parent;
Commands = new SendBindingUICommands(parent);
_csiConversionSettingsFactory = csiConversionSettingsFactory;
_speckleApplication = speckleApplication;
_activityFactory = activityFactory;
_csiApplicationService = csiApplicationService;
_sendOperationManagerFactory = sendOperationManagerFactory;
}
public List<ISendFilter> GetSendFilters() => _sendFilters;
@@ -71,52 +48,15 @@ public sealed class CsiSharedSendBinding : ISendBinding
public async Task Send(string modelCardId)
{
using var activity = _activityFactory.Start();
try
{
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
{
throw new InvalidOperationException("No publish model card was found.");
}
using var scope = _serviceProvider.CreateScope();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<CsiConversionSettings>>()
.Initialize(_csiConversionSettingsFactory.Create(_csiApplicationService.SapModel));
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
List<ICsiWrapper> wrappers = modelCard
.SendFilter.NotNull()
.RefreshObjectIds()
.Select(DecodeObjectIdentifier)
.ToList();
if (wrappers.Count == 0)
{
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
}
var sendResult = await scope
.ServiceProvider.GetRequiredService<SendOperation<ICsiWrapper>>()
.Execute(
wrappers,
modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
return;
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
using var manager = _sendOperationManagerFactory.Create();
await manager.Process(
Commands,
modelCardId,
(sp, _) =>
sp.GetRequiredService<IConverterSettingsStore<CsiConversionSettings>>()
.Initialize(_csiConversionSettingsFactory.Create(_csiApplicationService.SapModel)),
card => card.SendFilter.NotNull().RefreshObjectIds().Select(DecodeObjectIdentifier).ToList()
);
}
private ICsiWrapper DecodeObjectIdentifier(string encodedId)
@@ -1,5 +1,4 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connector.Navisworks.Operations.Send.Filters;
using Speckle.Connector.Navisworks.Operations.Send.Settings;
using Speckle.Connector.Navisworks.Services;
@@ -9,7 +8,6 @@ using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
@@ -18,7 +16,6 @@ using Speckle.Converter.Navisworks.Settings;
using Speckle.Converters.Common;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Logging;
namespace Speckle.Connector.Navisworks.Bindings;
@@ -30,45 +27,36 @@ public class NavisworksSendBinding : ISendBinding
public SendBindingUICommands Commands { get; }
private readonly DocumentModelStore _store;
private readonly IServiceProvider _serviceProvider;
private readonly ICancellationManager _cancellationManager;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<NavisworksSendBinding> _logger;
private readonly ISpeckleApplication _speckleApplication;
private readonly ISdkActivityFactory _activityFactory;
private readonly INavisworksConversionSettingsFactory _conversionSettingsFactory;
private readonly ToSpeckleSettingsManagerNavisworks _toSpeckleSettingsManagerNavisworks;
private readonly IElementSelectionService _selectionService;
private readonly IThreadContext _threadContext;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
public NavisworksSendBinding(
DocumentModelStore store,
IBrowserBridge parent,
IServiceProvider serviceProvider,
ICancellationManager cancellationManager,
IOperationProgressManager operationProgressManager,
ILogger<NavisworksSendBinding> logger,
ISpeckleApplication speckleApplication,
ISdkActivityFactory activityFactory,
INavisworksConversionSettingsFactory conversionSettingsFactory,
ToSpeckleSettingsManagerNavisworks toSpeckleSettingsManagerNavisworks,
IElementSelectionService selectionService,
IThreadContext threadContext
IThreadContext threadContext,
ISendOperationManagerFactory sendOperationManagerFactory
)
{
Parent = parent;
Commands = new SendBindingUICommands(parent);
_store = store;
_serviceProvider = serviceProvider;
_cancellationManager = cancellationManager;
_operationProgressManager = operationProgressManager;
_logger = logger;
_speckleApplication = speckleApplication;
_activityFactory = activityFactory;
_conversionSettingsFactory = conversionSettingsFactory;
_toSpeckleSettingsManagerNavisworks = toSpeckleSettingsManagerNavisworks;
_selectionService = selectionService;
_threadContext = threadContext;
_sendOperationManagerFactory = sendOperationManagerFactory;
SubscribeToNavisworksEvents();
}
@@ -78,7 +66,8 @@ public class NavisworksSendBinding : ISendBinding
public List<ISendFilter> GetSendFilters() =>
[
new NavisworksSelectionFilter() { IsDefault = true },
new NavisworksSavedSetsFilter(new ElementSelectionService())
new NavisworksSavedSetsFilter(new ElementSelectionService()),
new NavisworksSavedViewsFilter(new ElementSelectionService())
];
public List<ICardSetting> GetSendSettings() =>
@@ -95,60 +84,13 @@ public class NavisworksSendBinding : ISendBinding
private async Task SendInternal(string modelCardId)
{
using var activity = _activityFactory.Start();
try
{
var modelCard = GetModelCard(modelCardId);
using var scope = _serviceProvider.CreateScope();
InitializeConverterSettings(scope, modelCard);
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
var progress = _operationProgressManager.CreateOperationProgressEventHandler(
Parent,
modelCard.ModelCardId.NotNull(),
cancellationItem.Token
);
var navisworksModelItems = await GetNavisworksModelItems(modelCard, progress);
var sendResult = await ExecuteSendOperation(
scope,
modelCard,
navisworksModelItems,
progress,
cancellationItem.Token
);
await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
finally
{
// otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI.
_cancellationManager.CancelOperation(modelCardId);
}
using var manager = _sendOperationManagerFactory.Create();
await manager.Process(Commands, modelCardId, InitializeConverterSettings, GetNavisworksModelItems);
}
private SenderModelCard GetModelCard(string modelCardId) =>
_store.GetModelById(modelCardId) as SenderModelCard
?? throw new InvalidOperationException("No publish model card was found.");
private void InitializeConverterSettings(IServiceScope scope, SenderModelCard modelCard) =>
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<NavisworksConversionSettings>>()
private void InitializeConverterSettings(IServiceProvider serviceProvider, SenderModelCard modelCard) =>
serviceProvider
.GetRequiredService<IConverterSettingsStore<NavisworksConversionSettings>>()
.Initialize(
_conversionSettingsFactory.Create(
originMode: _toSpeckleSettingsManagerNavisworks.GetOriginMode(modelCard),
@@ -159,7 +101,7 @@ public class NavisworksSendBinding : ISendBinding
)
);
private async Task<List<NAV.ModelItem>> GetNavisworksModelItems(
private async Task<IReadOnlyList<NAV.ModelItem>> GetNavisworksModelItems(
SenderModelCard modelCard,
IProgress<CardProgress> onOperationProgressed
)
@@ -68,6 +68,7 @@ public static class NavisworksConnectorServiceRegistration
// register filters
serviceCollection.AddScoped<ISendFilter, NavisworksSelectionFilter>();
serviceCollection.AddScoped<ISendFilter, NavisworksSavedSetsFilter>();
serviceCollection.AddScoped<ISendFilter, NavisworksSavedViewsFilter>();
serviceCollection.AddScoped<IElementSelectionService, ElementSelectionService>();
}
}
@@ -2,7 +2,6 @@
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Utils;
using Speckle.Converter.Navisworks.Constants;
namespace Speckle.Connector.Navisworks.Operations.Send.Filters;
@@ -85,12 +84,14 @@ public class NavisworksSavedSetsFilter : DiscriminatedObject, ISendFilterSelect
{
List<NAV.SelectionSet> savedSetRecords = [];
CollectSavedSets(NavisworksApp.ActiveDocument.SelectionSets.RootItem, savedSetRecords);
var root = NavisworksApp.ActiveDocument.SelectionSets.RootItem;
CollectSavedSets(root, savedSetRecords);
Items = savedSetRecords
.Select(setRecord =>
{
string hierarchicalName = BuildHierarchicalName(setRecord);
string hierarchicalName = SavedItemHelpers.BuildHierarchicalName(setRecord, root);
return new SendFilterSelectItem(setRecord.Guid.ToString(), hierarchicalName);
})
.ToList();
@@ -103,7 +104,7 @@ public class NavisworksSavedSetsFilter : DiscriminatedObject, ISendFilterSelect
return;
}
foreach (NAV.SavedItem item in ((NAV.FolderItem)parentItem).Children)
foreach (NAV.SavedItem item in ((NAV.GroupItem)parentItem).Children)
{
if (item.IsGroup)
{
@@ -115,18 +116,4 @@ public class NavisworksSavedSetsFilter : DiscriminatedObject, ISendFilterSelect
}
}
}
private static string BuildHierarchicalName(NAV.SavedItem item)
{
var pathParts = new List<string> { item.DisplayName };
var current = item.Parent;
while (current != null && current != NavisworksApp.ActiveDocument.SelectionSets.RootItem)
{
pathParts.Insert(0, current.DisplayName);
current = current.Parent;
}
return string.Join(PathConstants.SET_SEPARATOR, pathParts);
}
}
@@ -0,0 +1,173 @@
using Speckle.Connector.Navisworks.Services;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
using Speckle.Connectors.DUI.Utils;
namespace Speckle.Connector.Navisworks.Operations.Send.Filters;
public class NavisworksSavedViewsFilter : DiscriminatedObject, ISendFilterSelect
{
private readonly IElementSelectionService _selectionService;
public NavisworksSavedViewsFilter(IElementSelectionService selectionService)
{
_selectionService = selectionService;
Items = [];
SelectedItems = [];
GetSavedViews();
}
public string Id { get; set; } = "navisworksSavedViews";
public string Name { get; set; } = "Saved Views";
public string Type { get; set; } = "Select";
public string? Summary { get; set; }
public bool IsDefault { get; set; }
public List<string> SelectedObjectIds { get; set; } = [];
public Dictionary<string, string>? IdMap { get; set; }
public bool IsMultiSelectable { get; set; }
public List<SendFilterSelectItem> SelectedItems { get; set; }
public List<SendFilterSelectItem> Items { get; set; }
public List<string> RefreshObjectIds()
{
List<string> objectIds = [];
if (SelectedItems.Count == 0)
{
return objectIds;
}
var savedViews = NavisworksApp.ActiveDocument.SavedViewpoints;
foreach (var savedViewItem in SelectedItems.Select(item => ResolveSavedView(item.Id)))
{
// Get the visible elements in the saved view.
objectIds.AddRange(ResolvedSavedViewObjects(savedViewItem));
}
return objectIds;
}
private static NAV.SavedViewpoint ResolveSavedView(string savedViewReference)
{
if (Guid.TryParse(savedViewReference, out var guid))
{
// Even though we may have already got a match, that could be to a generic Guid from earlier versions of Navisworks
if (savedViewReference != Guid.Empty.ToString())
{
return (NAV.SavedViewpoint)NavisworksApp.ActiveDocument.SavedViewpoints.ResolveGuid(guid);
}
}
var savedRef = new NAV.SavedItemReference("LcOpSavedViewsElement", savedViewReference);
var resolvedReference = NavisworksApp.ActiveDocument.ResolveReference(savedRef) as NAV.SavedViewpoint;
return resolvedReference
?? throw new SpeckleSendFilterException($"Saved view with reference {savedViewReference} not found.");
}
private IEnumerable<string> ResolvedSavedViewObjects(NAV.SavedViewpoint savedView)
{
var objectIds = new List<string>();
// THIS IS COMMENTED OUT AS IT IS LEGACY DEFENSIVE BEHAVIOUR - DISCUSSION REQUIRED
// if (!savedView.ContainsVisibilityOverrides)
// {
// // We check this again as the view settings may have changed in the saved card.
// // If the saved view does not contain visibility overrides, this is effectively everything in the model.
// // This will need to be the documented behaviour.
// throw new SpeckleSendFilterException(
// "Saved view does not contain visibility overrides. This would effectively publish everything in the model."
// );
// }
NavisworksApp.ActiveDocument.SavedViewpoints.CurrentSavedViewpoint = savedView;
var models = NavisworksApp.ActiveDocument.Models;
NavisworksApp.ActiveDocument.CurrentSelection.Clear();
foreach (var model in models)
{
var rootItem = model.RootItem;
if (!_selectionService.IsVisible(rootItem))
{
// If the root item is hidden, we skip it and its descendants.
continue;
}
objectIds.AddRange(
rootItem.Descendants.Where(_selectionService.IsVisible).Select(_selectionService.GetModelItemPath).ToList()
);
}
return objectIds;
}
/// <summary>
/// Since it is called from constructor, it is re-called whenever UI calls SendBinding.GetSendFilters() on SendFilter dialog.
/// Do not change the behavior/scope of this class on send binding unless make sure the behavior is same. Otherwise, we might not be able to update list of saved sets.
/// </summary>
private void GetSavedViews()
{
List<NAV.SavedViewpoint> savedViewRecords = [];
var root = NavisworksApp.ActiveDocument.SavedViewpoints.RootItem;
CollectSavedViews(root, savedViewRecords);
Items = savedViewRecords
.Select(viewRecord =>
{
var reference = NavisworksApp.ActiveDocument.SavedViewpoints.CreateReference(viewRecord);
// If the guid is effectively empty, we can use the saved view's name as a fallback
var selectItemId =
viewRecord.Guid.ToString() == Guid.Empty.ToString() ? reference.SavedItemId : viewRecord.Guid.ToString();
string hierarchicalName = SavedItemHelpers.BuildHierarchicalName(viewRecord, root);
return new SendFilterSelectItem(selectItemId, hierarchicalName);
})
.ToList();
}
private static void CollectSavedViews(NAV.SavedItem parentItem, List<NAV.SavedViewpoint> collectedSets)
{
if (!parentItem.IsGroup)
{
return;
}
foreach (NAV.SavedItem item in ((NAV.GroupItem)parentItem).Children)
{
switch (item.IsGroup)
{
// THIS IS COMMENTED OUT AS IT IS LEGACY DEFENSIVE BEHAVIOUR - DISCUSSION REQUIRED
// case false when item is NAV.SavedViewpoint { ContainsVisibilityOverrides: false }:
// // If the saved view does not contain visibility overrides, this is effectively everything in the model.
// // This will need to be the documented behaviour.
// break;
case false:
collectedSets.Add((NAV.SavedViewpoint)item);
break;
default: // handles item.IsGroup == true
if (((NAV.GroupItem)item).Children.Count > 0) // Don't add empty groups
{
CollectSavedViews(item, collectedSets);
}
break;
}
}
}
}
@@ -0,0 +1,20 @@
using Speckle.Converter.Navisworks.Constants;
namespace Speckle.Connector.Navisworks.Operations.Send.Filters;
public static class SavedItemHelpers
{
internal static string BuildHierarchicalName(NAV.SavedItem item, NAV.FolderItem? root)
{
var pathParts = new List<string> { item.DisplayName };
var current = item.Parent;
while (current != null && current != root)
{
pathParts.Insert(0, current.DisplayName);
current = current.Parent;
}
return string.Join(PathConstants.SET_SEPARATOR, pathParts);
}
}
@@ -20,6 +20,8 @@
<Compile Include="$(MSBuildThisFileDirectory)HostApp\NavisworksDocumentModelStore.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)HostApp\NavisworksIdleManager.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\NavisworksMaterialUnpacker.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Filters\NavisworksSavedViewsFilter.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\Filters\SavedItemHelpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\GeometryNodeMerger.cs"/>
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\NavisworksHierarchyBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\NavisworksRootObjectBuilder.cs"/>
@@ -15,7 +15,18 @@ public partial class CefSharpPanel : Page, Autodesk.Revit.UI.IDockablePaneProvid
public void ExecuteScript(string script)
{
Browser.Dispatcher.Invoke(() => Browser.ExecuteScriptAsync(script), DispatcherPriority.Background);
Browser.Dispatcher.Invoke(
() =>
{
//avoid exceptions by checking if IBrowser is there
if (!Browser.IsBrowserInitialized || Browser.GetBrowser() is null)
{
return;
}
Browser.ExecuteScriptAsync(script);
},
DispatcherPriority.Background
);
}
public void SendProgress(string script) => ExecuteScript(script);
@@ -1,123 +1,59 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.Revit.Plugin;
using Speckle.Converters.Common;
using Speckle.Converters.RevitShared.Helpers;
using Speckle.Converters.RevitShared.Settings;
using Speckle.Sdk;
namespace Speckle.Connectors.Revit.Bindings;
internal sealed class RevitReceiveBinding : IReceiveBinding
internal sealed class RevitReceiveBinding(
ICancellationManager cancellationManager,
IBrowserBridge parent,
ILogger<RevitReceiveBinding> logger,
IRevitConversionSettingsFactory revitConversionSettingsFactory,
IReceiveOperationManagerFactory receiveOperationManagerFactory
) : IReceiveBinding
{
public string Name => "receiveBinding";
public IBrowserBridge Parent { get; }
public IBrowserBridge Parent { get; } = parent;
private IReceiveBindingUICommands Commands { get; } = new ReceiveBindingUICommands(parent);
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<RevitReceiveBinding> _logger;
private readonly ICancellationManager _cancellationManager;
private readonly DocumentModelStore _store;
private readonly IServiceProvider _serviceProvider;
private readonly IRevitConversionSettingsFactory _revitConversionSettingsFactory;
private readonly ISpeckleApplication _speckleApplication;
private readonly RevitToHostCacheSingleton _revitToHostCacheSingleton;
private ReceiveBindingUICommands Commands { get; }
public RevitReceiveBinding(
DocumentModelStore store,
ICancellationManager cancellationManager,
IBrowserBridge parent,
IServiceProvider serviceProvider,
IOperationProgressManager operationProgressManager,
ILogger<RevitReceiveBinding> logger,
IRevitConversionSettingsFactory revitConversionSettingsFactory,
ISpeckleApplication speckleApplication,
RevitToHostCacheSingleton revitToHostCacheSingleton
)
{
Parent = parent;
_store = store;
_serviceProvider = serviceProvider;
_operationProgressManager = operationProgressManager;
_logger = logger;
_revitConversionSettingsFactory = revitConversionSettingsFactory;
_speckleApplication = speckleApplication;
_cancellationManager = cancellationManager;
_revitToHostCacheSingleton = revitToHostCacheSingleton;
Commands = new ReceiveBindingUICommands(parent);
}
public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId);
public async Task Receive(string modelCardId)
{
try
{
// Get receiver card
if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
using var manager = receiveOperationManagerFactory.Create();
await manager.Process(
Commands,
modelCardId,
(sp) =>
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No download model card was found.");
sp.GetRequiredService<IConverterSettingsStore<RevitConversionSettings>>()
.Initialize(
revitConversionSettingsFactory.Create(
DetailLevelType.Coarse, // TODO figure out
null,
false,
true,
false
)
);
},
async (_, processor) =>
{
try
{
return await processor();
}
catch (SpeckleRevitTaskException ex)
{
await SpeckleRevitTaskException.ProcessException(modelCardId, ex, logger, Commands);
return null;
}
}
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
using var scope = _serviceProvider.CreateScope();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RevitConversionSettings>>()
.Initialize(
_revitConversionSettingsFactory.Create(
DetailLevelType.Coarse, // TODO figure out
null,
false,
true,
false
)
);
// Receive host objects
HostObjectBuilderResult conversionResults = await scope
.ServiceProvider.GetRequiredService<ReceiveOperation>()
.Execute(
modelCard.GetReceiveInfo(_speckleApplication.Slug),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList();
await Commands.SetModelReceiveResult(
modelCardId,
conversionResults.BakedObjectIds,
conversionResults.ConversionResults
);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
}
catch (SpeckleRevitTaskException ex)
{
await SpeckleRevitTaskException.ProcessException(modelCardId, ex, _logger, Commands);
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
finally
{
// otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI.
_cancellationManager.CancelOperation(modelCardId);
}
);
}
}
@@ -1,15 +1,11 @@
using Autodesk.Revit.DB;
using Autodesk.Revit.DB.ExtensibleStorage;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
@@ -32,17 +28,14 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
private readonly RevitContext _revitContext;
private readonly DocumentModelStore _store;
private readonly ICancellationManager _cancellationManager;
private readonly IServiceProvider _serviceProvider;
private readonly ISendConversionCache _sendConversionCache;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ToSpeckleSettingsManager _toSpeckleSettingsManager;
private readonly ILogger<RevitSendBinding> _logger;
private readonly ElementUnpacker _elementUnpacker;
private readonly IRevitConversionSettingsFactory _revitConversionSettingsFactory;
private readonly ISpeckleApplication _speckleApplication;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
private readonly LinkedModelHandler _linkedModelHandler;
private readonly IThreadContext _threadContext;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
/// <summary>
/// Used internally to aggregate the changed objects' id. Note we're using a concurrent dictionary here as the expiry check method is not thread safe, and this was causing problems. See:
@@ -58,18 +51,15 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
DocumentModelStore store,
ICancellationManager cancellationManager,
IBrowserBridge bridge,
IServiceProvider serviceProvider,
ISendConversionCache sendConversionCache,
IOperationProgressManager operationProgressManager,
ToSpeckleSettingsManager toSpeckleSettingsManager,
ILogger<RevitSendBinding> logger,
ElementUnpacker elementUnpacker,
IRevitConversionSettingsFactory revitConversionSettingsFactory,
ISpeckleApplication speckleApplication,
ITopLevelExceptionHandler topLevelExceptionHandler,
LinkedModelHandler linkedModelHandler,
IThreadContext threadContext,
IRevitTask revitTask
IRevitTask revitTask,
ISendOperationManagerFactory sendOperationManagerFactory
)
: base("sendBinding", bridge)
{
@@ -77,17 +67,14 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
_revitContext = revitContext;
_store = store;
_cancellationManager = cancellationManager;
_serviceProvider = serviceProvider;
_sendConversionCache = sendConversionCache;
_operationProgressManager = operationProgressManager;
_toSpeckleSettingsManager = toSpeckleSettingsManager;
_logger = logger;
_elementUnpacker = elementUnpacker;
_revitConversionSettingsFactory = revitConversionSettingsFactory;
_speckleApplication = speckleApplication;
_topLevelExceptionHandler = topLevelExceptionHandler;
_linkedModelHandler = linkedModelHandler;
_threadContext = threadContext;
_sendOperationManagerFactory = sendOperationManagerFactory;
Commands = new SendBindingUICommands(bridge);
// TODO expiry events
@@ -123,69 +110,26 @@ internal sealed class RevitSendBinding : RevitBaseBinding, ISendBinding
public async Task Send(string modelCardId)
{
// Note: removed top level handling thing as it was confusing me
try
{
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
using var manager = _sendOperationManagerFactory.Create();
await manager.Process<DocumentToConvert>(
Commands,
modelCardId,
(sp, card) =>
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No publish model card was found.");
}
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
using var scope = _serviceProvider.CreateScope();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RevitConversionSettings>>()
.Initialize(
_revitConversionSettingsFactory.Create(
_toSpeckleSettingsManager.GetDetailLevelSetting(modelCard),
_toSpeckleSettingsManager.GetReferencePointSetting(modelCard),
_toSpeckleSettingsManager.GetSendParameterNullOrEmptyStringsSetting(modelCard),
_toSpeckleSettingsManager.GetLinkedModelsSetting(modelCard),
_toSpeckleSettingsManager.GetSendRebarsAsVolumetric(modelCard)
)
);
var elementsByTransform = await RefreshElementsIdsOnSender(modelCard.NotNull());
if (elementsByTransform.Count == 0)
{
// Handle as CARD ERROR in this function
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
}
var sendResult = await scope
.ServiceProvider.GetRequiredService<SendOperation<DocumentToConvert>>()
.Execute(
elementsByTransform,
modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
}
catch (SpeckleRevitTaskException ex)
{
await SpeckleRevitTaskException.ProcessException(modelCardId, ex, _logger, Commands);
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
finally
{
// otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI.
_cancellationManager.CancelOperation(modelCardId);
}
sp.GetRequiredService<IConverterSettingsStore<RevitConversionSettings>>()
.Initialize(
_revitConversionSettingsFactory.Create(
_toSpeckleSettingsManager.GetDetailLevelSetting(card),
_toSpeckleSettingsManager.GetReferencePointSetting(card),
_toSpeckleSettingsManager.GetSendParameterNullOrEmptyStringsSetting(card),
_toSpeckleSettingsManager.GetLinkedModelsSetting(card),
_toSpeckleSettingsManager.GetSendRebarsAsVolumetric(card)
)
);
},
async x => await RefreshElementsIdsOnSender(x.NotNull())
);
}
private async Task<List<DocumentToConvert>> RefreshElementsIdsOnSender(SenderModelCard modelCard)
@@ -40,7 +40,8 @@ public sealed class RevitHostObjectBuilder(
ITypedConverter<
(Base atomicObject, IReadOnlyCollection<Matrix4x4> matrix),
DirectShape
> localToGlobalDirectShapeConverter
> localToGlobalDirectShapeConverter,
IReceiveConversionHandler conversionHandler
) : IHostObjectBuilder, IDisposable
{
public Task<HostObjectBuilderResult> Build(
@@ -234,11 +235,9 @@ public sealed class RevitHostObjectBuilder(
foreach (LocalToGlobalMap localToGlobalMap in localToGlobalMaps)
{
cancellationToken.ThrowIfCancellationRequested();
try
var ex = conversionHandler.TryConvert(() =>
{
using var activity = activityFactory.Start("BakeObject");
cancellationToken.ThrowIfCancellationRequested();
// actual conversion happens here!
var result = converter.Convert(localToGlobalMap.AtomicObject);
onOperationProgressed.Report(new("Converting", (double)++count / localToGlobalMaps.Count));
@@ -269,11 +268,10 @@ public sealed class RevitHostObjectBuilder(
{
throw new ConversionException($"Failed to cast {result.GetType()} to direct shape definition wrapper.");
}
}
catch (Exception ex) when (!ex.IsFatal())
});
if (ex is not null)
{
conversionResults.Add(new(Status.ERROR, localToGlobalMap.AtomicObject, null, null, ex));
logger.LogError(ex, $"Failed to convert object of type {localToGlobalMap.AtomicObject.speckle_type}");
}
}
return (new(bakedObjectIds, conversionResults), postBakePaintTargets);
@@ -14,7 +14,7 @@ public class SpeckleRevitTaskException(Exception exception) : SpeckleException("
string modelCardId,
SpeckleRevitTaskException ex,
ILogger<T> logger,
BasicConnectorBindingCommands commands
IReceiveBindingUICommands commands
)
where T : IBinding
{
@@ -66,7 +66,13 @@ public class DeconstructSpeckleParam : GH_Component, IGH_VariableParameterCompon
outputParams = new();
foreach (var key in propGoo.Value.Keys)
{
outputParams.Add(CreateOutputParamByKeyValue(key, propGoo.Value[key].Value, GH_ParamAccess.item));
ISpecklePropertyGoo value = propGoo.Value[key];
object? outputValue = value is SpecklePropertyGoo prop
? prop.Value
: value is SpecklePropertyGroupGoo propGroup
? propGroup
: value;
outputParams.Add(CreateOutputParamByKeyValue(key, outputValue, GH_ParamAccess.item));
}
break;
default:
@@ -0,0 +1,11 @@
using Grasshopper.Kernel.Data;
namespace Speckle.Connectors.GrasshopperShared.Components;
public static class IGH_StructureExtensions
{
public static bool HasInputCountGreaterThan(this IGH_Structure data, int maximumCount, bool skipNulls = false)
{
return data.AllData(skipNulls).Skip(maximumCount).Any();
}
}
@@ -40,7 +40,7 @@ public class CreateSpeckleProperties : VariableParameterComponentBase
protected override void SolveInstance(IGH_DataAccess da)
{
var properties = new Dictionary<string, SpecklePropertyGoo>();
var properties = new Dictionary<string, ISpecklePropertyGoo>();
// Validate for duplicate names
var paramNames = Params.Input.Select(p => p.NickName).ToList();
@@ -71,13 +71,18 @@ public class CreateSpeckleProperties : VariableParameterComponentBase
da.SetData(0, groupGoo);
}
private SpecklePropertyGoo? ExtractPropertyValue(IGH_DataAccess da, int index, string paramName)
private ISpecklePropertyGoo? ExtractPropertyValue(IGH_DataAccess da, int index, string paramName)
{
object? value = null;
da.GetData(index, ref value);
var propertyGoo = new SpecklePropertyGoo();
// check for a group input first
if (value is SpecklePropertyGroupGoo group)
{
return group;
}
var propertyGoo = new SpecklePropertyGoo();
if (value == null)
{
return propertyGoo; // Return empty property
@@ -87,7 +92,7 @@ public class CreateSpeckleProperties : VariableParameterComponentBase
{
AddRuntimeMessage(
GH_RuntimeMessageLevel.Error,
$"Parameter '{paramName}' contains invalid data type. Only strings, numbers, and booleans are supported."
$"Parameter '{paramName}' contains invalid data type. Only strings, numbers, booleans, and other Speckle properties are supported."
);
return null;
}
@@ -62,20 +62,36 @@ public class GetObjectProperties : GH_Component, IGH_VariableParameterComponent
SpeckleObjectWrapperGoo objectWrapperGoo = new();
da.GetData(0, ref objectWrapperGoo);
// flatten object properties, if any
SpecklePropertyGroupGoo properties = objectWrapperGoo.Value.Properties;
if (properties.Value.Count == 0)
{
return;
}
Dictionary<string, SpecklePropertyGoo> flattenedProps = properties.Flatten();
for (int i = 0; i < paths.Count; i++)
{
var name = paths[i];
SpecklePropertyGoo objectProperty = FindProperty(objectWrapperGoo.Value.Properties, name);
da.SetData(i, objectProperty.Value);
if (FindProperty(flattenedProps, name) is SpecklePropertyGoo prop)
{
da.SetData(i, prop.Value);
}
else
{
da.SetData(i, null);
}
}
}
}
private SpecklePropertyGoo FindProperty(SpecklePropertyGroupGoo root, string unifiedPath)
// attempts to find a property by concatenated key, or returns null if not
private SpecklePropertyGoo? FindProperty(Dictionary<string, SpecklePropertyGoo> props, string unifiedPath)
{
if (!root.Value.TryGetValue(unifiedPath, out SpecklePropertyGoo currentGoo))
if (!props.TryGetValue(unifiedPath, out SpecklePropertyGoo currentGoo))
{
return new() { Path = unifiedPath, Value = "" };
return null;
}
return currentGoo;
@@ -29,7 +29,7 @@ public class PropertyGroupPathsSelector : ValueSet<IGH_Goo>
var objectPropertyGroups = VolatileData
.AllData(true)
.OfType<SpeckleObjectWrapperGoo>()
.Select(goo => goo.Value.Properties.Value)
.Select(goo => goo.Value.Properties)
.ToList();
#if RHINO8_OR_GREATER
@@ -39,7 +39,7 @@ public class PropertyGroupPathsSelector : ValueSet<IGH_Goo>
var modelObjects = VolatileData
.AllData(true)
.OfType<ModelObject>()
.Select(mo => new SpeckleObjectWrapperGoo(mo).Value.Properties.Value)
.Select(mo => new SpeckleObjectWrapperGoo(mo).Value.Properties)
.ToList();
objectPropertyGroups.AddRange(modelObjects);
}
@@ -55,13 +55,18 @@ public class PropertyGroupPathsSelector : ValueSet<IGH_Goo>
m_data.AppendRange(paths.Select(s => new GH_String(s)));
}
private static List<string> GetPropertyPaths(List<Dictionary<string, SpecklePropertyGoo>> objectPropertyGroups)
private static List<string> GetPropertyPaths(List<SpecklePropertyGroupGoo> objectPropertyGroups)
{
var result = new HashSet<string>();
foreach (var dict in objectPropertyGroups)
foreach (SpecklePropertyGroupGoo propGroup in objectPropertyGroups)
{
// flatten the props
Dictionary<string, SpecklePropertyGoo> flattenedProps = propGroup.Flatten();
result.AddRange(
dict.Keys.Where(k => !(k.EndsWith(".name") || k.EndsWith(".units") || k.EndsWith(".internalDefinitionName")))
flattenedProps.Keys.Where(k =>
!(k.EndsWith(".name") || k.EndsWith(".units") || k.EndsWith(".internalDefinitionName"))
)
);
}
return result.ToList();
@@ -68,6 +68,16 @@ public class ReceiveAsyncComponent : GH_AsyncComponent
protected override void SolveInstance(IGH_DataAccess da)
{
MultipleResources = Params.Input[0].VolatileData.HasInputCountGreaterThan(1);
if (MultipleResources)
{
AddRuntimeMessage(
GH_RuntimeMessageLevel.Error,
"Only one model can be loaded at a time. To load to multiple models, please use different load components."
);
return;
}
da.DisableGapLogic();
// We need to call this always in here to be able to react and set events :/
ParseInput(da);
@@ -101,6 +111,8 @@ public class ReceiveAsyncComponent : GH_AsyncComponent
}
}
public bool MultipleResources { get; set; }
public override void AppendAdditionalMenuItems(ToolStripDropDown menu)
{
base.AppendAdditionalMenuItems(menu);
@@ -561,14 +573,21 @@ public class ReceiveAsyncComponentAttributes : GH_ComponentAttributes
return GH_ObjectResponse.Handled;
}
if (((ReceiveAsyncComponent)Owner).AutoReceive)
// NOTE: why do we kill auto receive when clicking on the button?
// It's enabled via the context menu, I expect it to be disabled from the same place
// if (((ReceiveAsyncComponent)Owner).AutoReceive)
// {
// ((ReceiveAsyncComponent)Owner).AutoReceive = false;
// Owner.OnDisplayExpired(true);
// return GH_ObjectResponse.Handled;
// }
// TODO: check if owner has null account/client, and call the reset thing SYNC
if ((Owner as ReceiveAsyncComponent)?.MultipleResources == true)
{
((ReceiveAsyncComponent)Owner).AutoReceive = false;
Owner.OnDisplayExpired(true);
return GH_ObjectResponse.Handled;
}
// TODO: check if owner has null account/client, and call the reset thing SYNC
((ReceiveAsyncComponent)Owner).CurrentComponentState = ComponentState.Ready;
Owner.ExpireSolution(true);
return GH_ObjectResponse.Handled;
@@ -101,6 +101,15 @@ public class ReceiveComponent : SpeckleTaskCapableComponent<ReceiveComponentInpu
CancellationToken cancellationToken = default
)
{
var multipleResources = Params.Input[0].VolatileData.HasInputCountGreaterThan(1);
if (multipleResources)
{
AddRuntimeMessage(
GH_RuntimeMessageLevel.Error,
"Only one model can be loaded at a time. To load to multiple models, please use different load components."
);
return new();
}
if (!input.Run)
{
return new();
@@ -16,7 +16,6 @@ using Speckle.Connectors.GrasshopperShared.Properties;
using Speckle.Connectors.GrasshopperShared.Registration;
using Speckle.Sdk;
using Speckle.Sdk.Api;
using Speckle.Sdk.Api.GraphQL.Models;
using Speckle.Sdk.Credentials;
using Speckle.Sdk.Models.Extensions;
@@ -25,15 +24,9 @@ namespace Speckle.Connectors.GrasshopperShared.Components.Operations.Send;
[Guid("52481972-7867-404F-8D9F-E1481183F355")]
public class SendAsyncComponent : GH_AsyncComponent
{
private ResourceCollection<Project>? LastFetchedProjects { get; set; }
private ResourceCollection<Model>? LastFetchedModels { get; set; }
public GhContextMenuButton ProjectContextMenuButton { get; set; }
public GhContextMenuButton ModelContextMenuButton { get; set; }
private ToolStripDropDown? ProjectDropDown { get; set; }
private ToolStripDropDown? ModelDropDown { get; set; }
public SendAsyncComponent()
: base(
"Publish",
@@ -59,8 +52,8 @@ public class SendAsyncComponent : GH_AsyncComponent
public IClient ApiClient { get; set; }
public HostApp.SpeckleUrlModelResource? UrlModelResource { get; set; }
public SpeckleCollectionWrapperGoo? RootCollectionWrapper { get; set; }
public SpeckleUrlModelResource? OutputParam { get; set; }
public bool HasMultipleInputs { get; set; }
protected override void RegisterInputParams(GH_InputParamManager pManager)
{
@@ -136,6 +129,31 @@ public class SendAsyncComponent : GH_AsyncComponent
protected override void SolveInstance(IGH_DataAccess da)
{
var multipleResources = Params.Input[0].VolatileData.HasInputCountGreaterThan(1);
var multipleCollections = Params.Input[1].VolatileData.HasInputCountGreaterThan(1);
HasMultipleInputs = multipleCollections || multipleResources;
if (HasMultipleInputs)
{
var mCollErrText =
"Only one single collection supported. Please group your input collections into one single one before sending.";
var mLinksErrText =
"Only one single model can be published to from this node. To send to multiple models, please use different publish components.";
if (multipleCollections)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, mCollErrText);
}
if (multipleResources)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, mLinksErrText);
}
return;
}
using var scope = PriorityLoader.CreateScopeForActiveDocument();
var accountService = scope.ServiceProvider.GetRequiredService<IAccountService>();
@@ -342,7 +360,7 @@ public class SendComponentWorker : WorkerInstance
{
var sendComponent = (SendAsyncComponent)Parent;
if (sendComponent.JustPastedIn)
if (sendComponent.JustPastedIn || sendComponent.HasMultipleInputs)
{
done();
return;
@@ -519,6 +537,11 @@ public class SendAsyncComponentAttributes : GH_ComponentAttributes
{
if (((RectangleF)ButtonBounds).Contains(e.CanvasLocation))
{
// Ignore button presses on a component with invalid inputs to prevent multiple sends
if ((Owner as SendAsyncComponent)?.HasMultipleInputs == true)
{
return GH_ObjectResponse.Handled;
}
if (((SendAsyncComponent)Owner).AutoSend)
{
((SendAsyncComponent)Owner).AutoSend = false;
@@ -129,6 +129,31 @@ public class SendComponent : SpeckleTaskCapableComponent<SendComponentInput, Sen
CancellationToken cancellationToken = default
)
{
var multipleResources = Params.Input[0].VolatileData.HasInputCountGreaterThan(1);
var multipleCollections = Params.Input[1].VolatileData.HasInputCountGreaterThan(1);
var hasMultipleInputs = multipleCollections || multipleResources;
if (hasMultipleInputs)
{
var mCollErrText =
"Only one single collection supported. Please group your input collections into one single one before sending.";
var mLinksErrText =
"Only one single model can be published to from this node. To send to multiple models, please use multiple publish components.";
if (multipleCollections)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, mCollErrText);
}
if (multipleResources)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, mLinksErrText);
}
return new(null);
}
if (!input.Run)
{
return new(null);
@@ -111,6 +111,7 @@ public class SpeckleSelectModelComponent : GH_Component
catch (SpeckleException e)
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message);
da.AbortComponentSolution();
}
return; // Fast exit!
}
@@ -154,6 +155,7 @@ public class SpeckleSelectModelComponent : GH_Component
ProjectContextMenuButton.Enabled = false;
ModelContextMenuButton.Enabled = false;
VersionContextMenuButton.Enabled = false;
da.AbortComponentSolution();
return;
}
@@ -172,6 +174,7 @@ public class SpeckleSelectModelComponent : GH_Component
{
// Create a workspace flow
SpeckleOperationWizard.CreateNewWorkspaceUIState();
da.AbortComponentSolution();
return;
}
}
@@ -191,6 +194,7 @@ public class SpeckleSelectModelComponent : GH_Component
}
else
{
da.AbortComponentSolution();
return;
}
}
@@ -212,6 +216,8 @@ public class SpeckleSelectModelComponent : GH_Component
{
ModelContextMenuButton.Enabled = false;
VersionContextMenuButton.Enabled = false;
da.AbortComponentSolution();
return;
}
@@ -231,6 +237,7 @@ public class SpeckleSelectModelComponent : GH_Component
if (SpeckleOperationWizard.SelectedModel == null)
{
VersionContextMenuButton.Enabled = false;
da.AbortComponentSolution();
return;
}
@@ -279,10 +286,12 @@ public class SpeckleSelectModelComponent : GH_Component
GH_RuntimeMessageLevel.Error,
string.Join("\n", e.InnerExceptions.Select(innerE => innerE.Message))
);
da.AbortComponentSolution();
}
catch (Exception e) when (!e.IsFatal())
{
AddRuntimeMessage(GH_RuntimeMessageLevel.Error, e.Message);
da.AbortComponentSolution();
}
}
@@ -197,7 +197,7 @@ public class SpeckleOperationWizard
{
return;
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var workspace = client.Workspace.Get(workspaceId).Result;
SelectedWorkspace = workspace;
WorkspaceMenuHandler.RedrawMenuButton(SelectedWorkspace);
@@ -209,7 +209,7 @@ public class SpeckleOperationWizard
{
return;
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var project = client.Project.Get(projectId).Result;
SelectedProject = project;
ProjectMenuHandler.RedrawMenuButton(SelectedProject);
@@ -222,7 +222,7 @@ public class SpeckleOperationWizard
return;
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var model = client.Model.Get(modelId, SelectedProject.id).Result;
SelectedModel = model;
ModelMenuHandler.RedrawMenuButton(SelectedModel);
@@ -235,7 +235,7 @@ public class SpeckleOperationWizard
return;
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var version = client.Version.Get(versionId, SelectedProject.id).Result;
SelectedVersion = version;
VersionMenuHandler?.RedrawMenuButton(SelectedVersion);
@@ -251,7 +251,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<Workspace>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var workspaces = await client.ActiveUser.GetWorkspaces(10, null, new UserWorkspacesFilter(searchText));
WorkspaceMenuHandler.Workspaces = workspaces;
return workspaces;
@@ -267,7 +267,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<Workspace>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var workspaces = client.ActiveUser.GetWorkspaces(10, null, new UserWorkspacesFilter(searchText)).Result;
WorkspaceMenuHandler.Workspaces = workspaces;
return workspaces;
@@ -283,7 +283,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<ProjectWithPermissions>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var workspaceId = SelectedWorkspace?.id ?? null;
var projects = await client.ActiveUser.GetProjectsWithPermissions(
10,
@@ -309,7 +309,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<ProjectWithPermissions>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var workspaceId = SelectedWorkspace?.id ?? null;
var projects = client
.ActiveUser.GetProjectsWithPermissions(
@@ -337,7 +337,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<Model>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var projectWithModels = await client
.Project.GetWithModels(SelectedProject.id, 10, modelsFilter: new ProjectModelsFilter(search: searchText))
.ConfigureAwait(true);
@@ -373,7 +373,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<Version>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var newVersionsResult = await client
.Model.GetWithVersions(SelectedModel.id, SelectedProject.id, versionCount)
.ConfigureAwait(true);
@@ -395,7 +395,7 @@ public class SpeckleOperationWizard
return new ResourceCollection<Version>();
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var newVersionsResult = client.Model.GetWithVersions(SelectedModel.id, SelectedProject.id, versionCount).Result;
if (VersionMenuHandler != null)
{
@@ -411,7 +411,7 @@ public class SpeckleOperationWizard
{
return;
}
IClient client = _clientFactory.Create(SelectedAccount);
using IClient client = _clientFactory.Create(SelectedAccount);
var activeWorkspace = client.ActiveUser.GetActiveWorkspace().Result;
Workspace? selectedWorkspace =
SelectedWorkspace
@@ -124,6 +124,8 @@ public static class GrasshopperHelpers
return el.ToNurbsCurve();
case Sphere sp:
return sp.ToBrep();
case Box box:
return box.ToBrep();
}
throw new SpeckleException("Failed to cast IGH_GeometricGoo to geometry base");
@@ -110,6 +110,7 @@ public class GrasshopperRootObjectBuilder() : IRootObjectBuilder<SpeckleCollecti
private DataObject ConvertWrappersToDataObject(List<SpeckleObjectWrapper> wrappers, string appId)
{
Dictionary<string, object?> props = new();
wrappers.First().Properties.CastTo<Dictionary<string, object?>>(ref props);
return new()
@@ -1,3 +0,0 @@
namespace Speckle.Connectors.GrasshopperShared.Parameters;
internal interface ISpeckleGoo { }
@@ -0,0 +1,8 @@
namespace Speckle.Connectors.GrasshopperShared.Parameters;
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"Design",
"CA1040:Avoid empty interfaces",
Justification = "Needed to identify acceptable values of properties without multiple inheritance"
)]
public interface ISpecklePropertyGoo { }
@@ -7,7 +7,7 @@ using Speckle.Sdk.Models.Collections;
namespace Speckle.Connectors.GrasshopperShared.Parameters;
public partial class SpeckleCollectionWrapperGoo : GH_Goo<SpeckleCollectionWrapper>, ISpeckleGoo //, IGH_PreviewData // can be made previewable later
public partial class SpeckleCollectionWrapperGoo : GH_Goo<SpeckleCollectionWrapper> //, IGH_PreviewData // can be made previewable later
{
private bool CastToModelLayer<T>(ref T target)
{
@@ -222,7 +222,7 @@ public class SpeckleCollectionWrapper : SpeckleWrapper
}
}
public partial class SpeckleCollectionWrapperGoo : GH_Goo<SpeckleCollectionWrapper>, ISpeckleGoo //, IGH_PreviewData // can be made previewable later
public partial class SpeckleCollectionWrapperGoo : GH_Goo<SpeckleCollectionWrapper> //, IGH_PreviewData // can be made previewable later
{
public override IGH_Goo Duplicate() => new SpeckleCollectionWrapperGoo(Value.DeepCopy());
@@ -6,6 +6,7 @@ using Rhino;
using Rhino.DocObjects;
using Rhino.Render;
using Speckle.Sdk;
using SpeckleRenderMaterial = Speckle.Objects.Other.RenderMaterial;
namespace Speckle.Connectors.GrasshopperShared.Parameters;
@@ -13,7 +14,7 @@ namespace Speckle.Connectors.GrasshopperShared.Parameters;
/// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property).
/// The speckle property path is the concatenated string of all original flattened keys with the property delimiter
/// </summary>
public partial class SpeckleMaterialWrapperGoo : GH_Goo<SpeckleMaterialWrapper>, ISpeckleGoo
public partial class SpeckleMaterialWrapperGoo : GH_Goo<SpeckleMaterialWrapper>
{
private bool CastFromModelRenderMaterial(object source)
{
@@ -90,5 +91,40 @@ public partial class SpeckleMaterialWrapperGoo : GH_Goo<SpeckleMaterialWrapper>,
return false;
}
private SpeckleRenderMaterial ToSpeckleRenderMaterial(Rhino.Render.RenderMaterial mat)
{
Rhino.DocObjects.PhysicallyBasedMaterial pbRenderMaterial = mat.ConvertToPhysicallyBased(
RenderTexture.TextureGeneration.Allow
);
// get opacity
// POC: pbr will return opacity = 0 for these because they are not pbr materials, they are transparent materials with IOR. Currently hardcoding 0.2 value in lieu of proper type support in rhino.
double opacity = (mat.SmellsLikeGem || mat.SmellsLikeGlass) ? 0.2 : pbRenderMaterial.Opacity;
string renderMaterialName = mat.Name ?? "default"; // default rhino material has no name
Color diffuse = pbRenderMaterial.BaseColor.AsSystemColor();
Color emissive = mat.TypeName.Equals("Emission")
? pbRenderMaterial.Material.EmissionColor
: pbRenderMaterial.Emission.AsSystemColor(); // pbRenderMaterial.emission gives wrong color for emission materials, and material.emissioncolor gives the wrong value for most others *shrug*
SpeckleRenderMaterial speckleRenderMaterial =
new()
{
name = renderMaterialName,
opacity = opacity,
metalness = pbRenderMaterial.Metallic,
roughness = pbRenderMaterial.Roughness,
diffuse = diffuse.ToArgb(),
emissive = emissive.ToArgb(),
applicationId = mat.Id.ToString(),
["typeName"] = mat.TypeName,
["ior"] = pbRenderMaterial.Material.IndexOfRefraction,
["shine"] = pbRenderMaterial.Material.Shine,
};
return speckleRenderMaterial;
}
}
#endif
@@ -2,7 +2,6 @@ using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Rhino;
using Rhino.DocObjects;
using Rhino.Render;
using Speckle.Connectors.GrasshopperShared.Components;
using Speckle.Connectors.GrasshopperShared.HostApp;
using Speckle.Connectors.GrasshopperShared.Properties;
@@ -61,7 +60,7 @@ public class SpeckleMaterialWrapper : SpeckleWrapper
}
}
public partial class SpeckleMaterialWrapperGoo : GH_Goo<SpeckleMaterialWrapper>, ISpeckleGoo
public partial class SpeckleMaterialWrapperGoo : GH_Goo<SpeckleMaterialWrapper>
{
public override IGH_Goo Duplicate() => throw new NotImplementedException();
@@ -161,40 +160,6 @@ public partial class SpeckleMaterialWrapperGoo : GH_Goo<SpeckleMaterialWrapper>,
return speckleRenderMaterial;
}
private SpeckleRenderMaterial ToSpeckleRenderMaterial(Rhino.Render.RenderMaterial mat)
{
Rhino.DocObjects.PhysicallyBasedMaterial pbRenderMaterial = mat.ConvertToPhysicallyBased(
RenderTexture.TextureGeneration.Allow
);
// get opacity
// POC: pbr will return opacity = 0 for these because they are not pbr materials, they are transparent materials with IOR. Currently hardcoding 0.2 value in lieu of proper type support in rhino.
double opacity = (mat.SmellsLikeGem || mat.SmellsLikeGlass) ? 0.2 : pbRenderMaterial.Opacity;
string renderMaterialName = mat.Name ?? "default"; // default rhino material has no name
Color diffuse = pbRenderMaterial.BaseColor.AsSystemColor();
Color emissive = mat.TypeName.Equals("Emission")
? pbRenderMaterial.Material.EmissionColor
: pbRenderMaterial.Emission.AsSystemColor(); // pbRenderMaterial.emission gives wrong color for emission materials, and material.emissioncolor gives the wrong value for most others *shrug*
SpeckleRenderMaterial speckleRenderMaterial =
new()
{
name = renderMaterialName,
opacity = opacity,
metalness = pbRenderMaterial.Metallic,
roughness = pbRenderMaterial.Roughness,
diffuse = diffuse.ToArgb(),
emissive = emissive.ToArgb(),
applicationId = mat.Id.ToString(),
["typeName"] = mat.TypeName,
["ior"] = pbRenderMaterial.Material.IndexOfRefraction,
["shine"] = pbRenderMaterial.Material.Shine,
};
return speckleRenderMaterial;
}
private SpeckleRenderMaterial ToSpeckleRenderMaterial(Material mat)
{
SpeckleRenderMaterial speckleRenderMaterial =
@@ -11,7 +11,7 @@ using Grasshopper.Rhinoceros.Render;
namespace Speckle.Connectors.GrasshopperShared.Parameters;
public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH_PreviewData, ISpeckleGoo
public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH_PreviewData
{
public SpeckleObjectWrapperGoo(ModelObject mo)
{
@@ -114,10 +114,8 @@ public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH
}
}
foreach (var kvp in Value.Properties.Value)
{
atts.SetUserString(kvp.Key, kvp.Value.Value?.ToString() ?? "");
}
// add props
Value.Properties.AssignToObjectAttributes(atts);
target = (T)(object)atts;
return true;
@@ -165,7 +163,6 @@ public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH
propertyGroup.CastFrom(modelObject.UserText);
// get the object layer
SpeckleCollectionWrapperGoo collWrapperGoo = new();
SpeckleCollectionWrapper? collWrapper = collWrapperGoo.CastFrom(modelObject.Layer)
? collWrapperGoo.Value
@@ -175,9 +172,9 @@ public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH
modelConverted.applicationId = modelObject.Id?.ToString();
modelConverted[Constants.NAME_PROP] = modelObject.Name.ToString();
Dictionary<string, object?> propertyDict = new();
foreach (var entry in propertyGroup.Value)
foreach (var entry in modelObject.UserText)
{
propertyDict.Add(entry.Key, entry.Value.Value);
propertyDict.Add(entry.Key, entry.Value);
}
modelConverted[Constants.PROPERTIES_PROP] = propertyDict;
@@ -172,10 +172,8 @@ public class SpeckleObjectWrapper : SpeckleWrapper
}
}
foreach (var kvp in Properties.Value)
{
att.SetUserString(kvp.Key, kvp.Value.Value?.ToString() ?? "");
}
// add props
Properties.AssignToObjectAttributes(att);
// add to doc
Guid guid = doc.Objects.Add(GeometryBase, att);
@@ -202,10 +200,12 @@ public class SpeckleObjectWrapper : SpeckleWrapper
return false;
}
/*
if (!Properties.Equals(objWrapper.Properties))
{
return false;
}
*/
return true;
}
@@ -226,7 +226,7 @@ public class SpeckleObjectWrapper : SpeckleWrapper
};
}
public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH_PreviewData, ISpeckleGoo
public partial class SpeckleObjectWrapperGoo : GH_Goo<SpeckleObjectWrapper>, IGH_PreviewData
{
public override IGH_Goo Duplicate()
{
@@ -3,7 +3,7 @@ using Grasshopper.Kernel.Types;
namespace Speckle.Connectors.GrasshopperShared.Parameters;
public class SpecklePropertyGoo : GH_Goo<object>, ISpeckleGoo
public class SpecklePropertyGoo : GH_Goo<object>, ISpecklePropertyGoo
{
public override IGH_Goo Duplicate() => throw new NotImplementedException();
@@ -9,10 +9,10 @@ using Rhino.DocObjects;
namespace Speckle.Connectors.GrasshopperShared.Parameters;
/// <summary>
/// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property).
/// The speckle property path is the concatenated string of all original flattened keys with the property delimiter
/// The Speckle Property Group Goo is a nested dictionary of (key, speckle property or property group).
/// The <see cref="Flatten"/> method will use the property delimiter on the keys to flatten the property group into properties.
/// </summary>
public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, SpecklePropertyGoo>>, ISpeckleGoo
public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, ISpecklePropertyGoo>>, ISpecklePropertyGoo
{
private bool CastFromModelObject(object source)
{
@@ -22,7 +22,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, Speckle
return CastFromModelObject(modelObject.UserText);
case ModelUserText userText:
Dictionary<string, SpecklePropertyGoo> dictionary = new();
Dictionary<string, ISpecklePropertyGoo> dictionary = new();
foreach (KeyValuePair<string, string> entry in userText)
{
string key = entry.Key;
@@ -45,14 +45,10 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, Speckle
// grasshopper interface types
if (type == typeof(IGH_ModelContentData))
{
var attributes = new ObjectAttributes();
foreach (var entry in Value)
{
string stringValue = entry.Value.Value?.ToString() ?? "";
attributes.SetUserString(entry.Key, stringValue);
}
ObjectAttributes atts = new();
AssignToObjectAttributes(atts);
var modelObject = new ModelObject(RhinoDoc.ActiveDoc, attributes);
ModelObject modelObject = new(RhinoDoc.ActiveDoc, atts);
target = (T)(object)modelObject;
return true;
}
@@ -1,5 +1,6 @@
using Grasshopper.Kernel;
using Grasshopper.Kernel.Types;
using Rhino.DocObjects;
using Speckle.Connectors.GrasshopperShared.Components;
using Speckle.Connectors.GrasshopperShared.HostApp;
using Speckle.Connectors.GrasshopperShared.Properties;
@@ -7,10 +8,10 @@ using Speckle.Connectors.GrasshopperShared.Properties;
namespace Speckle.Connectors.GrasshopperShared.Parameters;
/// <summary>
/// The Speckle Property Group Goo is a flat dictionary of (speckle property path, speckle property).
/// The speckle property path is the concatenated string of all original flattened keys with the property delimiter
/// The Speckle Property Group Goo is a dictionary of (key, speckle property or property group).
/// Flattened property group keys are the concatenated strings of all nested keys with the property delimiter
/// </summary>
public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, SpecklePropertyGoo>>, ISpeckleGoo
public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, ISpecklePropertyGoo>>, ISpecklePropertyGoo
{
public override IGH_Goo Duplicate() => throw new NotImplementedException();
@@ -25,7 +26,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, Speckle
Value = new();
}
public SpecklePropertyGroupGoo(Dictionary<string, SpecklePropertyGoo> value)
public SpecklePropertyGroupGoo(Dictionary<string, ISpecklePropertyGoo> value)
{
Value = value;
}
@@ -44,14 +45,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, Speckle
return true;
case Dictionary<string, object?> properties:
Dictionary<string, object> flattenedProperties = new();
FlattenDictionary(properties, flattenedProperties, "");
Dictionary<string, SpecklePropertyGoo> speckleProperties = new();
foreach (var kvp in flattenedProperties)
{
speckleProperties.Add(kvp.Key, new() { Value = kvp.Value });
}
Value = speckleProperties;
Value = WrapDictionary(properties);
return true;
}
@@ -68,11 +62,7 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, Speckle
var type = typeof(T);
if (type == typeof(Dictionary<string, object?>))
{
Dictionary<string, object?> dictionary = new();
foreach (var entry in Value)
{
dictionary.Add(entry.Key, entry.Value.Value);
}
Dictionary<string, object?> dictionary = Unwrap();
target = (T)(object)dictionary;
return true;
}
@@ -85,53 +75,104 @@ public partial class SpecklePropertyGroupGoo : GH_Goo<Dictionary<string, Speckle
private bool CastToModelObject<T>(ref T _) => false;
#endif
// Flattens a dictionary that may contain more dictionaries of the same type
private void FlattenDictionary(
Dictionary<string, object?> dict,
Dictionary<string, object> flattenedDict,
/// <summary>
/// Adds this property group to the input object attributes
/// </summary>
/// <param name="atts"></param>
public void AssignToObjectAttributes(ObjectAttributes atts)
{
Dictionary<string, SpecklePropertyGoo> flattenedProps = Flatten();
foreach (var kvp in flattenedProps)
{
atts.SetUserString(kvp.Key, kvp.Value.Value?.ToString() ?? "");
}
}
/// <summary>
/// Flattens the value into a dictionary with concatenated keys
/// </summary>
/// <returns></returns>
public Dictionary<string, SpecklePropertyGoo> Flatten()
{
Dictionary<string, SpecklePropertyGoo> flattenedProps = new();
FlattenWorker(Value, flattenedProps);
return flattenedProps;
}
private void FlattenWorker(
Dictionary<string, ISpecklePropertyGoo> props,
Dictionary<string, SpecklePropertyGoo> flattenedProps,
string keyPrefix = ""
)
{
foreach (var kvp in dict)
foreach (var kvp in props)
{
string newKey = string.IsNullOrEmpty(keyPrefix)
? kvp.Key
: $"{keyPrefix}{Constants.PROPERTY_PATH_DELIMITER}{kvp.Key}";
if (kvp.Value is Dictionary<string, object?> childDict)
switch (kvp.Value)
{
FlattenDictionary(childDict, flattenedDict, newKey);
}
else
{
flattenedDict.Add(newKey, kvp.Value ?? "");
case SpecklePropertyGroupGoo childProps:
FlattenWorker(childProps.Value, flattenedProps, newKey);
break;
case SpecklePropertyGoo prop:
flattenedProps.Add(newKey, prop);
break;
}
}
}
public override bool Equals(object obj)
private Dictionary<string, ISpecklePropertyGoo> WrapDictionary(Dictionary<string, object?> dict)
{
if (obj is not SpecklePropertyGroupGoo propertyGroupGoo || Value.Count != propertyGroupGoo.Value.Count)
{
return false;
}
Dictionary<string, ISpecklePropertyGoo> wrappedDict = new();
foreach (var entry in Value)
foreach (var kvp in dict)
{
if (propertyGroupGoo.Value.TryGetValue(entry.Key, out SpecklePropertyGoo compareProp))
ISpecklePropertyGoo? val;
if (kvp.Value is Dictionary<string, object?> childDict)
{
if (entry.Value.Value != compareProp.Value)
{
return false;
}
SpecklePropertyGroupGoo childPropertyGroup = new();
childPropertyGroup.CastFrom(childDict);
val = childPropertyGroup;
}
else
{
return false;
SpecklePropertyGoo entry = new();
entry.CastFrom(kvp.Value);
val = entry;
}
wrappedDict.Add(kvp.Key, val);
}
return true;
return wrappedDict;
}
/// <summary>
/// Unwraps the value into a Dictionary of equivalent structure
/// </summary>
/// <returns></returns>
public Dictionary<string, object?> Unwrap()
{
Dictionary<string, object?> dict = UnwrapWorker(Value);
return dict;
}
private Dictionary<string, object?> UnwrapWorker(Dictionary<string, ISpecklePropertyGoo> properties)
{
Dictionary<string, object?> dict = new();
foreach (var kvp in properties)
{
object? val = kvp.Value is SpecklePropertyGroupGoo propertyGroup
? UnwrapWorker(propertyGroup.Value)
: kvp.Value is SpecklePropertyGoo property
? property.Value
: null;
dict.Add(kvp.Key, val);
}
return dict;
}
public override int GetHashCode() => base.GetHashCode();
@@ -112,6 +112,12 @@ public class SpeckleVariableParam : Param_GenericObject
// Tell the parent component its layout needs to be recalculated
Attributes.Parent?.ExpireLayout();
// Expire solution when name changes to refresh downstream components
if (AlwaysInheritNames)
{
ExpireSolution(true);
}
}
finally
{
@@ -167,6 +173,9 @@ public class SpeckleVariableParam : Param_GenericObject
if (AlwaysInheritNames && !_isUpdatingName) // Double-check in case it changed
{
TryInheritName();
// downstream components to be refreshed when source names change
OnPingDocument()?.ScheduleSolution(5, _ => ExpireSolution(true));
}
});
}
@@ -16,6 +16,7 @@
<Compile Include="$(MSBuildThisFileDirectory)Components\Collections\CollectionPathsSelector.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Components\Collections\CreateCollection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Components\Collections\ExpandCollection.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Components\IGH_StructureExtensions.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Components\Objects\GetCollectionObjects.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Components\Objects\FilterSpeckleObjects.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Components\ComponentUtils.cs" />
@@ -53,6 +54,7 @@
<Compile Include="$(MSBuildThisFileDirectory)HostApp\Helpers.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\SpeckleResource.cs" />
<Compile Include="$(MSBuildThisFileDirectory)HostApp\SpeckleResourceBuilder.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\Interfaces.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\SpeckleVariableParam.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\SpeckleWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\SpeckleMaterialWrapper.ModelObjects.cs" />
@@ -61,7 +63,6 @@
<Compile Include="..\Speckle.Connectors.GrasshopperShared\HostApp\SpeckleConversionContext.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Receive\GrasshopperReceiveOperation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Operations\Send\GrasshopperSendOperation.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\ISpeckleGoo.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\SpeckleCollectionWrapper.ModelObjects.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\SpeckleCollectionWrapper.cs" />
<Compile Include="$(MSBuildThisFileDirectory)Parameters\SpeckleObjectWrapper.ModelObjects.cs" />
@@ -1,111 +1,53 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Rhino;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Converters.Common;
using Speckle.Converters.Rhino;
using Speckle.Sdk;
namespace Speckle.Connectors.Rhino.Bindings;
public class RhinoReceiveBinding : IReceiveBinding
public class RhinoReceiveBinding(
ICancellationManager cancellationManager,
IBrowserBridge parent,
IRhinoConversionSettingsFactory rhinoConversionSettingsFactory,
IReceiveOperationManagerFactory receiveOperationManagerFactory
) : IReceiveBinding
{
public string Name => "receiveBinding";
public IBrowserBridge Parent { get; }
public IBrowserBridge Parent { get; } = parent;
private readonly ICancellationManager _cancellationManager;
private readonly DocumentModelStore _store;
private readonly IServiceProvider _serviceProvider;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<RhinoReceiveBinding> _logger;
private readonly IRhinoConversionSettingsFactory _rhinoConversionSettingsFactory;
private readonly ISpeckleApplication _speckleApplication;
private ReceiveBindingUICommands Commands { get; }
private ReceiveBindingUICommands Commands { get; } = new(parent);
public RhinoReceiveBinding(
DocumentModelStore store,
ICancellationManager cancellationManager,
IBrowserBridge parent,
IOperationProgressManager operationProgressManager,
ILogger<RhinoReceiveBinding> logger,
IRhinoConversionSettingsFactory rhinoConversionSettingsFactory,
IServiceProvider serviceProvider,
ISpeckleApplication speckleApplication
)
{
Parent = parent;
_store = store;
_operationProgressManager = operationProgressManager;
_logger = logger;
_rhinoConversionSettingsFactory = rhinoConversionSettingsFactory;
_serviceProvider = serviceProvider;
_speckleApplication = speckleApplication;
_cancellationManager = cancellationManager;
Commands = new ReceiveBindingUICommands(parent);
}
public void CancelReceive(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
public void CancelReceive(string modelCardId) => cancellationManager.CancelOperation(modelCardId);
public async Task Receive(string modelCardId)
{
using var scope = _serviceProvider.CreateScope();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
.Initialize(_rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
uint undoRecord = 0;
try
{
// Get receiver card
if (_store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
using var manager = receiveOperationManagerFactory.Create();
await manager.Process(
Commands,
modelCardId,
(sp) =>
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No download model card was found.");
sp.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
.Initialize(rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
},
async (modelName, processor) =>
{
uint undoRecord = 0;
try
{
undoRecord = RhinoDoc.ActiveDoc.BeginUndoRecord($"Receive Speckle model {modelName}");
return await processor();
}
finally
{
RhinoDoc.ActiveDoc.EndUndoRecord(undoRecord);
}
}
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
undoRecord = RhinoDoc.ActiveDoc.BeginUndoRecord($"Receive Speckle model {modelCard.ModelName}");
// Receive host objects
HostObjectBuilderResult conversionResults = await scope
.ServiceProvider.GetRequiredService<ReceiveOperation>()
.Execute(
modelCard.GetReceiveInfo(_speckleApplication.Slug),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList();
await Commands.SetModelReceiveResult(
modelCardId,
conversionResults.BakedObjectIds,
conversionResults.ConversionResults
);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
return;
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
finally
{
RhinoDoc.ActiveDoc.EndUndoRecord(undoRecord);
}
);
}
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
public void CancelSend(string modelCardId) => cancellationManager.CancelOperation(modelCardId);
}
@@ -7,11 +7,8 @@ using Rhino.DocObjects;
using Rhino.DocObjects.Tables;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
@@ -19,9 +16,7 @@ using Speckle.Connectors.DUI.Settings;
using Speckle.Connectors.Rhino.Operations.Send.Filters;
using Speckle.Converters.Common;
using Speckle.Converters.Rhino;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Logging;
namespace Speckle.Connectors.Rhino.Bindings;
@@ -32,16 +27,13 @@ public sealed class RhinoSendBinding : ISendBinding
public IBrowserBridge Parent { get; }
private readonly DocumentModelStore _store;
private readonly IServiceProvider _serviceProvider;
private readonly ICancellationManager _cancellationManager;
private readonly ISendConversionCache _sendConversionCache;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<RhinoSendBinding> _logger;
private readonly IRhinoConversionSettingsFactory _rhinoConversionSettingsFactory;
private readonly ISpeckleApplication _speckleApplication;
private readonly ISdkActivityFactory _activityFactory;
private readonly ITopLevelExceptionHandler _topLevelExceptionHandler;
private readonly IAppIdleManager _idleManager;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
/// <summary>
/// Used internally to aggregate the changed objects' id. Objects in this list will be reconverted.
@@ -65,30 +57,24 @@ public sealed class RhinoSendBinding : ISendBinding
DocumentModelStore store,
IAppIdleManager idleManager,
IBrowserBridge parent,
IServiceProvider serviceProvider,
ICancellationManager cancellationManager,
ISendConversionCache sendConversionCache,
IOperationProgressManager operationProgressManager,
ILogger<RhinoSendBinding> logger,
IRhinoConversionSettingsFactory rhinoConversionSettingsFactory,
ISpeckleApplication speckleApplication,
ISdkActivityFactory activityFactory,
ITopLevelExceptionHandler topLevelExceptionHandler
ITopLevelExceptionHandler topLevelExceptionHandler,
ISendOperationManagerFactory sendOperationManagerFactory
)
{
_store = store;
_idleManager = idleManager;
_serviceProvider = serviceProvider;
_cancellationManager = cancellationManager;
_sendConversionCache = sendConversionCache;
_operationProgressManager = operationProgressManager;
_logger = logger;
_rhinoConversionSettingsFactory = rhinoConversionSettingsFactory;
_speckleApplication = speckleApplication;
Parent = parent;
_topLevelExceptionHandler = topLevelExceptionHandler;
_sendOperationManagerFactory = sendOperationManagerFactory;
Commands = new SendBindingUICommands(parent); // POC: Commands are tightly coupled with their bindings, at least for now, saves us injecting a factory.
_activityFactory = activityFactory;
PreviousUnitSystem = RhinoDoc.ActiveDoc.ModelUnitSystem;
SubscribeToRhinoEvents();
}
@@ -168,7 +154,21 @@ public sealed class RhinoSendBinding : ISendBinding
if (args is RhinoDoc.RenderMaterialAssignmentChangedEventArgs changedEventArgs)
{
ChangedObjectIds[changedEventArgs.ObjectId.ToString()] = 1;
// Update ChangedObjectIdsInGroupsOrLayers (without triggering objects' expiration)
// 1. If Material was changed directly on the object:
if (changedEventArgs.ObjectId != Guid.Empty)
{
ChangedObjectIdsInGroupsOrLayers[changedEventArgs.ObjectId.ToString()] = 1;
}
// 2. If parent Layer material has changed:
else if (changedEventArgs.LayerId != Guid.Empty)
{
var layer = RhinoDoc.ActiveDoc.Layers.FindId(changedEventArgs.LayerId);
foreach (Guid objectId in GetChildObjectIdsFromLayerAndSubLayers(layer))
{
ChangedObjectIdsInGroupsOrLayers[objectId.ToString()] = 1;
}
}
_idleManager.SubscribeToIdle(nameof(RunExpirationChecks), RunExpirationChecks);
}
});
@@ -206,17 +206,10 @@ public sealed class RhinoSendBinding : ISendBinding
}
var layer = RhinoDoc.ActiveDoc.Layers[args.LayerIndex];
var allLayers = args.Document.Layers.Where(l => /* NOTE: layer path may actually be null in some cases (rhino's fault, not ours) */
l.FullPath != null && l.FullPath.Contains(layer.Name)
); // not e imperfect, but layer.GetChildren(true) is valid only in v8 and above; this filter will include the original layer.
foreach (var childLayer in allLayers)
// Record IDs of all sub-objects affected by the LayerTable event (without triggering each objects' expiration)
foreach (Guid objectId in GetChildObjectIdsFromLayerAndSubLayers(layer))
{
var sublayerObjs = RhinoDoc.ActiveDoc.Objects.FindByLayer(childLayer) ?? [];
foreach (var obj in sublayerObjs)
{
ChangedObjectIdsInGroupsOrLayers[obj.Id.ToString()] = 1;
}
ChangedObjectIdsInGroupsOrLayers[objectId.ToString()] = 1;
}
_idleManager.SubscribeToIdle(nameof(RunExpirationChecks), RunExpirationChecks);
await Commands.RefreshSendFilters();
@@ -284,57 +277,25 @@ public sealed class RhinoSendBinding : ISendBinding
public async Task Send(string modelCardId)
{
using var activity = _activityFactory.Start();
using var scope = _serviceProvider.CreateScope();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
.Initialize(_rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc));
try
{
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
using var manager = _sendOperationManagerFactory.Create();
await manager.Process(
Commands,
modelCardId,
(sp, _) =>
sp.GetRequiredService<IConverterSettingsStore<RhinoConversionSettings>>()
.Initialize(_rhinoConversionSettingsFactory.Create(RhinoDoc.ActiveDoc)),
card =>
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No publish model card was found.");
}
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
List<RhinoObject> rhinoObjects = modelCard
.SendFilter.NotNull()
.RefreshObjectIds()
.Select(id => RhinoDoc.ActiveDoc.Objects.FindId(new Guid(id)))
.Where(obj => obj != null)
.ToList();
if (rhinoObjects.Count == 0)
{
// Handle as CARD ERROR in this function
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
}
var sendResult = await scope
.ServiceProvider.GetRequiredService<SendOperation<RhinoObject>>()
.Execute(
rhinoObjects,
modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
return Task.FromResult<IReadOnlyList<RhinoObject>>(
card.SendFilter.NotNull()
.RefreshObjectIds()
.Select(id => RhinoDoc.ActiveDoc.Objects.FindId(new Guid(id)))
.Where(obj => obj != null)
.ToList()
);
await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
return;
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
}
);
}
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
@@ -407,4 +368,20 @@ public sealed class RhinoSendBinding : ISendBinding
var senderModelCardIds = _store.GetSenders().Select(s => s.ModelCardId.NotNull());
await Commands.SetModelsExpired(senderModelCardIds);
}
private IEnumerable<Guid> GetChildObjectIdsFromLayerAndSubLayers(Layer layer)
{
var allLayers = RhinoDoc.ActiveDoc.Layers.Where(l => /* NOTE: layer path may actually be null in some cases (rhino's fault, not ours) */
l.FullPath != null && l.FullPath.Contains(layer.Name)
); // not e imperfect, but layer.GetChildren(true) is valid only in v8 and above; this filter will include the original layer.
foreach (var childLayer in allLayers)
{
var sublayerObjs = RhinoDoc.ActiveDoc.Objects.FindByLayer(childLayer) ?? [];
foreach (var obj in sublayerObjs)
{
yield return obj.Id;
}
}
}
}
@@ -19,8 +19,8 @@ public static class SpeckleAttributeExtensions
ObjectAttributes atts = new() { Name = name };
Dictionary<string, string> userStrings = new();
Dictionary<string, object?> properties = @base is DataObject dataObj
? dataObj.properties
: @base["properties"] as Dictionary<string, object?> ?? new();
? dataObj.properties ?? []
: @base["properties"] as Dictionary<string, object?> ?? [];
FlattenDictionaryToUserStrings(properties, userStrings, "");
foreach (var kvp in userStrings)
{
@@ -40,7 +40,7 @@ public static class SpeckleAttributeExtensions
private static void FlattenDictionaryToUserStrings(
Dictionary<string, object?> dict,
Dictionary<string, string> flattenedDict,
string keyPrefix = ""
string keyPrefix
)
{
foreach (var kvp in dict)
@@ -35,8 +35,10 @@ public class RhinoGroupBaker
{
try
{
var appIds = groupProxy.objects.SelectMany(oldObjId => applicationIdMap[oldObjId]).Select(id => new Guid(id));
var groupName = (groupProxy.name ?? "No Name Group") + $" ({baseLayerName})";
var appIds = groupProxy
.objects.SelectMany(oldObjId => LookupApplicationIds(groupName, oldObjId, applicationIdMap))
.Select(id => new Guid(id));
_converterSettings.Current.Document.Groups.Add(groupName, appIds);
}
catch (Exception ex) when (!ex.IsFatal())
@@ -46,6 +48,20 @@ public class RhinoGroupBaker
}
}
private IEnumerable<string> LookupApplicationIds(
string name,
string oldObjId,
Dictionary<string, IReadOnlyCollection<string>> applicationIdMap
)
{
if (applicationIdMap.TryGetValue(oldObjId, out IReadOnlyCollection<string> value))
{
return value;
}
_logger.LogWarning("Group {group} references an application Id {appId} that cannot be mapped", name, oldObjId);
return [];
}
public void PurgeGroups(string baseLayerName)
{
for (int i = _converterSettings.Current.Document.Groups.Count; i >= 0; i--)
@@ -3,6 +3,7 @@ using Rhino.DocObjects;
using Speckle.Connectors.Common.Operations.Receive;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Models.Collections;
using Layer = Rhino.DocObjects.Layer;
@@ -55,13 +56,13 @@ public class RhinoLayerBaker : TraversalContextUnpacker
foreach (var path in paths)
{
var names = path.Select(o => string.IsNullOrWhiteSpace(o.name) ? "unnamed" : o.name);
var key = string.Join(",", names!);
var key = string.Join(",", names);
uniquePaths[key] = path;
}
foreach (var uniquePath in uniquePaths)
{
var layerIndex = CreateLayerFromPath(uniquePath.Value, baseLayerName);
CreateLayerFromPath(uniquePath.Value, baseLayerName);
}
}
catch (Exception ex) when (!ex.IsFatal())
@@ -90,7 +91,7 @@ public class RhinoLayerBaker : TraversalContextUnpacker
return existingLayerIndex;
}
throw new SpeckleException($"Did not find a layer in the cache with the name {layerFullName}");
throw new ConversionException($"Did not find a layer in the cache with the name '{layerFullName}'");
}
/// <summary>
@@ -159,7 +160,7 @@ public class RhinoLayerBaker : TraversalContextUnpacker
int index = currentDocument.Layers.Add(newLayer);
if (index == -1)
{
throw new SpeckleException($"Could not create layer {currentLayerName}.");
throw new SpeckleException($"Could not create layer '{currentLayerName}'.");
}
_hostLayerCache.Add(currentLayerName, index);
previousLayer = currentDocument.Layers.FindIndex(index); // note we need to get the correct id out, hence why we're double calling this
@@ -89,8 +89,11 @@ public class RhinoMaterialUnpacker
}
else if (material is not null)
{
RenderMaterial convertedRender = ConvertMaterialToRenderMaterial(material);
myMaterial = ConvertRenderMaterialToSpeckle(convertedRender);
RenderMaterial? convertedRender = ConvertMaterialToRenderMaterial(material);
if (convertedRender is not null)
{
myMaterial = ConvertRenderMaterialToSpeckle(convertedRender);
}
}
if (myMaterial is null)
@@ -174,7 +177,7 @@ public class RhinoMaterialUnpacker
}
// converts a rhino material to a rhino render material
private RenderMaterial ConvertMaterialToRenderMaterial(Material material)
private RenderMaterial? ConvertMaterialToRenderMaterial(Material material)
{
// get physically based render material
Material pbMaterial = material;
@@ -11,8 +11,8 @@ using Speckle.Connectors.Rhino.Extensions;
using Speckle.Connectors.Rhino.HostApp;
using Speckle.Converters.Common;
using Speckle.Converters.Rhino;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Models.Collections;
@@ -35,6 +35,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
private readonly RootObjectUnpacker _rootObjectUnpacker;
private readonly ISdkActivityFactory _activityFactory;
private readonly IThreadContext _threadContext;
private readonly IReceiveConversionHandler _conversionHandler;
public RhinoHostObjectBuilder(
IRootToHostConverter converter,
@@ -46,7 +47,8 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
RhinoColorBaker colorBaker,
RhinoGroupBaker groupBaker,
ISdkActivityFactory activityFactory,
IThreadContext threadContext
IThreadContext threadContext,
IReceiveConversionHandler conversionHandler
)
{
_converter = converter;
@@ -59,6 +61,7 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
_groupBaker = groupBaker;
_activityFactory = activityFactory;
_threadContext = threadContext;
_conversionHandler = conversionHandler;
}
#pragma warning disable CA1506
@@ -142,79 +145,73 @@ public class RhinoHostObjectBuilder : IHostObjectBuilder
{
foreach (var (path, obj) in atomicObjectsWithoutInstanceComponentsWithPath)
{
using (var convertActivity = _activityFactory.Start("Converting object"))
onOperationProgressed.Report(
new("Converting objects", (double)++count / atomicObjectsWithoutInstanceComponentsForConverter.Count)
);
var ex = _conversionHandler.TryConvert(() =>
{
onOperationProgressed.Report(
new("Converting objects", (double)++count / atomicObjectsWithoutInstanceComponentsForConverter.Count)
);
// 0: get pre-created layer from cache in layer baker
int layerIndex = _layerBaker.GetLayerIndex(path, baseLayerName);
cancellationToken.ThrowIfCancellationRequested();
try
// 1: create object attributes for baking
ObjectAttributes atts = obj.GetAttributes();
atts.LayerIndex = layerIndex;
// 2: convert
var result = _converter.Convert(obj);
// 3: bake
var conversionIds = new List<string>();
if (result is GeometryBase geometryBase)
{
// 0: get pre-created layer from cache in layer baker
int layerIndex = _layerBaker.GetLayerIndex(path, baseLayerName);
// 1: create object attributes for baking
ObjectAttributes atts = obj.GetAttributes();
atts.LayerIndex = layerIndex;
// 2: convert
var result = _converter.Convert(obj);
// 3: bake
var conversionIds = new List<string>();
if (result is GeometryBase geometryBase)
var guid = BakeObject(geometryBase, obj, null, atts);
conversionIds.Add(guid.ToString());
}
else if (result is List<GeometryBase> geometryBases) // one to many raw encoding case
{
// NOTE: I'm unhappy about this case (dim). It's needed as the raw encoder approach can hypothetically return
// multiple "geometry bases" - but this is not a fallback conversion.
// EXTRA NOTE: Oguzhan says i shouldn't be unhappy about this - it's a legitimate case
// EXTRA EXTRA NOTE: TY Ogu, i am no longer than unhappy about it. It's legit "mess".
foreach (var gb in geometryBases)
{
var guid = BakeObject(geometryBase, obj, null, atts);
var guid = BakeObject(gb, obj, null, atts);
conversionIds.Add(guid.ToString());
}
else if (result is List<GeometryBase> geometryBases) // one to many raw encoding case
{
// NOTE: I'm unhappy about this case (dim). It's needed as the raw encoder approach can hypothetically return
// multiple "geometry bases" - but this is not a fallback conversion.
// EXTRA NOTE: Oguzhan says i shouldn't be unhappy about this - it's a legitimate case
// EXTRA EXTRA NOTE: TY Ogu, i am no longer than unhappy about it. It's legit "mess".
foreach (var gb in geometryBases)
{
var guid = BakeObject(gb, obj, null, atts);
conversionIds.Add(guid.ToString());
}
}
else if (result is List<(GeometryBase, Base)> fallbackConversionResult) // one to many fallback conversion
{
var guids = BakeObjectsAsFallbackGroup(fallbackConversionResult, obj, atts, baseLayerName);
conversionIds.AddRange(guids.Select(id => id.ToString()));
}
if (conversionIds.Count == 0)
{
// TODO: add this condition to report object - same as in autocad
throw new SpeckleException("Object did not convert to any native geometry");
}
// 4: log
var id = conversionIds[0]; // this is group id if it is a one to many conversion, otherwise id of object itself
conversionResults.Add(new(Status.SUCCESS, obj, id, result.GetType().ToString()));
if (conversionIds.Count == 1)
{
bakedObjectIds.Add(id);
}
else
{
// first item always a group id if it is a one-to-many,
// we do not want to deal with later groups and its sub elements. It causes a huge issue on performance.
bakedObjectIds.AddRange(conversionIds.Skip(1));
}
// 5: populate app id map
applicationIdMap[obj.applicationId ?? obj.id.NotNull()] = conversionIds;
convertActivity?.SetStatus(SdkActivityStatusCode.Ok);
}
catch (Exception ex) when (!ex.IsFatal())
else if (result is List<(GeometryBase, Base)> fallbackConversionResult) // one to many fallback conversion
{
conversionResults.Add(new(Status.ERROR, obj, null, null, ex));
convertActivity?.SetStatus(SdkActivityStatusCode.Error);
convertActivity?.RecordException(ex);
var guids = BakeObjectsAsFallbackGroup(fallbackConversionResult, obj, atts, baseLayerName);
conversionIds.AddRange(guids.Select(id => id.ToString()));
}
if (conversionIds.Count == 0)
{
// TODO: add this condition to report object - same as in autocad
throw new ConversionException("Object did not convert to any native geometry");
}
// 4: log
var id = conversionIds[0]; // this is group id if it is a one to many conversion, otherwise id of object itself
conversionResults.Add(new(Status.SUCCESS, obj, id, result.GetType().ToString()));
if (conversionIds.Count == 1)
{
bakedObjectIds.Add(id);
}
else
{
// first item always a group id if it is a one-to-many,
// we do not want to deal with later groups and its sub elements. It causes a huge issue on performance.
bakedObjectIds.AddRange(conversionIds.Skip(1));
}
// 5: populate app id map
applicationIdMap[obj.applicationId ?? obj.id.NotNull()] = conversionIds;
});
if (ex is not null)
{
conversionResults.Add(new(Status.ERROR, obj, null, null, ex));
}
}
}
@@ -3,11 +3,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Models.Card.SendFilter;
@@ -15,9 +12,7 @@ using Speckle.Connectors.DUI.Settings;
using Speckle.Connectors.TeklaShared.Operations.Send.Settings;
using Speckle.Converters.Common;
using Speckle.Converters.TeklaShared;
using Speckle.Sdk;
using Speckle.Sdk.Common;
using Speckle.Sdk.Logging;
using Tekla.Structures;
using Tekla.Structures.Model;
using Task = System.Threading.Tasks.Task;
@@ -31,18 +26,15 @@ public sealed class TeklaSendBinding : ISendBinding
public IBrowserBridge Parent { get; }
private readonly DocumentModelStore _store;
private readonly IServiceProvider _serviceProvider;
private readonly List<ISendFilter> _sendFilters;
private readonly ICancellationManager _cancellationManager;
private readonly ISendConversionCache _sendConversionCache;
private readonly IOperationProgressManager _operationProgressManager;
private readonly ILogger<TeklaSendBinding> _logger;
private readonly ITeklaConversionSettingsFactory _teklaConversionSettingsFactory;
private readonly ISpeckleApplication _speckleApplication;
private readonly ISdkActivityFactory _activityFactory;
private readonly Model _model;
private readonly ToSpeckleSettingsManager _toSpeckleSettingsManager;
private readonly Events _events;
private readonly ISendOperationManagerFactory _sendOperationManagerFactory;
private ConcurrentDictionary<string, byte> ChangedObjectIds { get; set; } = new();
@@ -50,30 +42,24 @@ public sealed class TeklaSendBinding : ISendBinding
DocumentModelStore store,
IBrowserBridge parent,
IEnumerable<ISendFilter> sendFilters,
IServiceProvider serviceProvider,
ICancellationManager cancellationManager,
ISendConversionCache sendConversionCache,
IOperationProgressManager operationProgressManager,
ILogger<TeklaSendBinding> logger,
ITeklaConversionSettingsFactory teklaConversionSettingsFactory,
ISpeckleApplication speckleApplication,
ISdkActivityFactory activityFactory,
ToSpeckleSettingsManager toSpeckleSettingsManager
ToSpeckleSettingsManager toSpeckleSettingsManager,
ISendOperationManagerFactory sendOperationManagerFactory
)
{
_store = store;
_serviceProvider = serviceProvider;
_sendFilters = sendFilters.ToList();
_cancellationManager = cancellationManager;
_sendConversionCache = sendConversionCache;
_operationProgressManager = operationProgressManager;
_logger = logger;
_teklaConversionSettingsFactory = teklaConversionSettingsFactory;
_speckleApplication = speckleApplication;
Parent = parent;
Commands = new SendBindingUICommands(parent);
_activityFactory = activityFactory;
_toSpeckleSettingsManager = toSpeckleSettingsManager;
_sendOperationManagerFactory = sendOperationManagerFactory;
_model = new Model();
_events = new Events();
@@ -111,55 +97,22 @@ public sealed class TeklaSendBinding : ISendBinding
public async Task Send(string modelCardId)
{
using var activity = _activityFactory.Start();
try
{
if (_store.GetModelById(modelCardId) is not SenderModelCard modelCard)
{
throw new InvalidOperationException("No publish model card was found.");
}
using var scope = _serviceProvider.CreateScope();
scope
.ServiceProvider.GetRequiredService<IConverterSettingsStore<TeklaConversionSettings>>()
.Initialize(
_teklaConversionSettingsFactory.Create(_model, _toSpeckleSettingsManager.GetSendRebarsAsSolid(modelCard))
);
using var cancellationItem = _cancellationManager.GetCancellationItem(modelCardId);
List<ModelObject> teklaObjects = modelCard
.SendFilter.NotNull()
.RefreshObjectIds()
.Select(id => _model.SelectModelObject(new Identifier(new Guid(id))))
.Where(obj => obj != null)
.ToList();
if (teklaObjects.Count == 0)
{
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
}
var sendResult = await scope
.ServiceProvider.GetRequiredService<SendOperation<ModelObject>>()
.Execute(
teklaObjects,
modelCard.GetSendInfo(_speckleApplication.ApplicationAndVersion),
_operationProgressManager.CreateOperationProgressEventHandler(Parent, modelCardId, cancellationItem.Token),
cancellationItem.Token
);
await Commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
return;
}
catch (Exception ex) when (!ex.IsFatal())
{
_logger.LogModelCardHandledError(ex);
await Commands.SetModelError(modelCardId, ex);
}
using var manager = _sendOperationManagerFactory.Create();
await manager.Process(
Commands,
modelCardId,
(sp, card) =>
sp.GetRequiredService<IConverterSettingsStore<TeklaConversionSettings>>()
.Initialize(
_teklaConversionSettingsFactory.Create(_model, _toSpeckleSettingsManager.GetSendRebarsAsSolid(card))
),
card =>
card.SendFilter.NotNull()
.RefreshObjectIds()
.Select(id => _model.SelectModelObject(new Identifier(new Guid(id))))
.Where(obj => obj != null)
.ToList()
);
}
public void CancelSend(string modelCardId) => _cancellationManager.CancelOperation(modelCardId);
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="556" height="556">
<path d="M0 0 C2.68178515 -0.10788793 5.36158701 -0.18284062 8.04485559 -0.24056935 C9.13956854 -0.28712245 9.13956854 -0.28712245 10.25639689 -0.33461601 C15.42392248 -0.37873316 18.03983188 1.19615808 21.85079432 4.57655406 C23.53030286 6.41909656 25.19721393 8.27320741 26.85079432 10.13905406 C28.63325965 11.65427932 30.44628583 13.13430061 32.28829432 14.57655406 C36.82315593 18.2341167 41.10615614 22.08522433 45.36788416 26.05067515 C49.46710401 29.84242039 53.74818294 33.36317239 58.10079432 36.86171031 C62.07939558 40.15648948 65.85342999 43.65369956 69.63595057 47.17030406 C71.68758552 49.16577194 71.68758552 49.16577194 73.85079432 50.13905406 C73.85079432 165.96905406 73.85079432 281.79905406 73.85079432 401.13905406 C70.07853158 401.89350661 66.80914803 402.33988018 63.00995684 402.54321456 C61.24651833 402.64025281 61.24651833 402.64025281 59.44745481 402.73925143 C58.15983877 402.80637566 56.87222273 402.87349989 55.54558802 402.94265819 C54.16061467 403.01745884 52.77565846 403.09257745 51.3907181 403.16798657 C47.58513638 403.37425655 43.77932388 403.5759523 39.97345757 403.7768935 C35.86802697 403.9944394 31.76282287 404.21618416 27.65758753 404.43737864 C19.61152388 404.87020667 11.56525149 405.29902855 3.51889466 405.72636826 C-3.02789393 406.07411696 -9.57461056 406.42319096 -16.12127829 406.77320743 C-17.0531872 406.82302844 -17.98509611 406.87284945 -18.94524469 406.92418019 C-20.83859421 407.02540322 -22.73194364 407.12662769 -24.625293 407.22785359 C-42.39377824 408.17763753 -60.16251155 409.12271444 -77.93132506 410.066334 C-94.15587247 410.9280848 -110.3801104 411.79551235 -126.60420801 412.66568691 C-143.27984604 413.56003135 -159.95568115 414.45061259 -176.63173711 415.3371312 C-185.98692688 415.8345264 -195.34203459 416.3333562 -204.69693899 416.83609271 C-212.66963311 417.26450336 -220.6425097 417.6893096 -228.61563493 418.1096235 C-232.67679838 418.32380773 -236.73786231 418.53954137 -240.79870367 418.7597549 C-250.24696362 419.27120809 -259.69521079 419.7441256 -269.14920568 420.13905406 C-270.7080625 420.20788582 -270.7080625 420.20788582 -272.29841137 420.27810812 C-274.98019652 420.38599605 -277.65999838 420.46094874 -280.34326696 420.51867747 C-281.07307559 420.54971287 -281.80288422 420.58074826 -282.55480826 420.61272413 C-287.72233385 420.65684128 -290.33824324 419.08195004 -294.14920568 415.70155406 C-295.82871423 413.85901156 -297.4956253 412.00490071 -299.14920568 410.13905406 C-300.93167102 408.6238288 -302.7446972 407.14380751 -304.58670568 405.70155406 C-309.1215673 402.04399142 -313.40456751 398.19288379 -317.66629553 394.22743297 C-321.76551538 390.43568773 -326.04659431 386.91493573 -330.39920568 383.41639781 C-334.37780695 380.12161864 -338.15184135 376.62440856 -341.93436193 373.10780406 C-343.98599689 371.11233618 -343.98599689 371.11233618 -346.14920568 370.13905406 C-346.14920568 254.30905406 -346.14920568 138.47905406 -346.14920568 19.13905406 C-342.37694295 18.38460151 -339.1075594 17.93822794 -335.30836821 17.73489356 C-334.13274254 17.67020139 -332.95711687 17.60550922 -331.74586618 17.53885669 C-329.81444212 17.43817034 -329.81444212 17.43817034 -327.84399939 17.33544993 C-326.45902604 17.26064928 -325.07406983 17.18553067 -323.68912947 17.11012155 C-319.88354775 16.90385157 -316.07773525 16.70215582 -312.27186894 16.50121462 C-308.16643834 16.28366872 -304.06123424 16.06192396 -299.9559989 15.84072948 C-291.90993525 15.40790145 -283.86366286 14.97907957 -275.81730603 14.55173986 C-269.27051744 14.20399116 -262.72380081 13.85491716 -256.17713308 13.50490069 C-255.24522417 13.45507968 -254.31331526 13.40525867 -253.35316668 13.35392793 C-251.45981716 13.2527049 -249.56646773 13.15148043 -247.67311837 13.05025453 C-229.90463313 12.10047059 -212.13589982 11.15539368 -194.36708631 10.21177412 C-178.1425389 9.35002332 -161.91830097 8.48259577 -145.69420336 7.61242121 C-129.01856533 6.71807677 -112.34273022 5.82749553 -95.66667426 4.94097692 C-86.31148449 4.44358172 -76.95637678 3.94475192 -67.60147238 3.44201541 C-59.62877826 3.01360476 -51.65590166 2.58879852 -43.68277644 2.16848462 C-39.62161299 1.95430039 -35.56054906 1.73856675 -31.4997077 1.51835322 C-21.00190037 0.95008593 -10.50295108 0.46376075 0 0 Z " fill="#136CFE" transform="translate(414.14920568466187,67.8609459400177)"/>
<path d="M0 0 C1.09513583 0.93797189 2.19016717 1.87606579 3.28515625 2.81420898 C3.89496338 3.33659653 4.50477051 3.85898407 5.13305664 4.39720154 C8.09747131 6.94219534 11.04894894 9.50203507 14 12.0625 C17.98281965 15.51764481 21.96614048 18.97214625 25.95703125 22.41796875 C31.43224298 27.14850209 36.89787448 31.87981943 42.25 36.75 C46.61972427 40.71647791 51.15446071 44.45110685 55.75 48.15234375 C59.9610745 51.61039624 59.9610745 51.61039624 60.24839699 54.48619521 C60.24763755 55.54561493 60.24687811 56.60503465 60.24609566 57.696558 C60.25007775 58.91624515 60.25405985 60.1359323 60.25816262 61.39257967 C60.25245581 62.75835343 60.2465646 64.12412643 60.24050903 65.48989868 C60.24138044 66.93118089 60.24313023 68.37246279 60.24568737 69.813743 C60.25017763 73.78841375 60.2421343 77.76297754 60.23213124 81.73763466 C60.2235231 86.01848482 60.22641503 90.29932856 60.22793579 94.58018494 C60.22898632 102.00175032 60.22269224 109.42328063 60.21146011 116.84483719 C60.19523073 127.57525958 60.18999974 138.30566495 60.18748413 149.03609829 C60.18310299 166.44399702 60.16978256 183.85187705 60.15087891 201.25976562 C60.13253092 218.17350165 60.11836913 235.0872326 60.10986328 252.00097656 C60.10933783 253.04291257 60.10881239 254.08484858 60.10827102 255.15835841 C60.10566101 260.38525798 60.10313358 265.61215758 60.10064721 270.83905721 C60.07990168 314.2260511 60.04466478 357.61302459 60 401 C57.30327256 399.68867252 55.10766831 398.40366098 52.85546875 396.41796875 C52.26894531 395.90492188 51.68242188 395.391875 51.078125 394.86328125 C50.45421875 394.31027344 49.8303125 393.75726563 49.1875 393.1875 C47.83733684 392.00379531 46.48707365 390.8202047 45.13671875 389.63671875 C44.44884277 389.03134277 43.7609668 388.4259668 43.05224609 387.80224609 C39.8823133 385.01846738 36.69091235 382.25967383 33.5 379.5 C29.6984591 376.20845227 25.89959274 372.91395923 22.109375 369.609375 C21.46291016 369.04669922 20.81644531 368.48402344 20.15039062 367.90429688 C18.94481233 366.85483663 17.74026011 365.80419556 16.53710938 364.75195312 C15.69116211 364.0162207 15.69116211 364.0162207 14.828125 363.265625 C14.27790359 362.77459114 13.72768219 362.28355729 13.1607874 361.77764362 C10.97078576 359.90911162 10.97078576 359.90911162 8.26641434 358.21885878 C4.00976108 355.2735885 0.62018696 352.91735932 -1.01264703 347.86931789 C-1.38547379 344.08674205 -1.41617836 340.38421509 -1.32279968 336.59239197 C-1.32760236 335.13679651 -1.3372446 333.6812104 -1.35128051 332.22567469 C-1.37579056 328.24282556 -1.33201566 324.26325185 -1.27672184 320.28082001 C-1.22909811 315.98032903 -1.2453021 311.68001409 -1.25364685 307.3793335 C-1.25940739 299.93399925 -1.22497563 292.48972754 -1.16303062 285.04466057 C-1.07352922 274.2806138 -1.0449745 263.5170794 -1.03116272 252.75270087 C-1.00710372 235.28739818 -0.93394357 217.82266149 -0.82983398 200.35766602 C-0.72882295 183.39480415 -0.65098106 166.43209615 -0.60424805 149.46899414 C-0.60135809 148.4229232 -0.59846813 147.37685227 -0.5954906 146.29908221 C-0.5811349 141.05110988 -0.56723418 135.80313646 -0.55355966 130.55516231 C-0.43957542 87.03638289 -0.24587484 43.51822069 0 0 Z " fill="#0057E5" transform="translate(68,87)"/>
<path d="M0 0 C2.6818859 -0.10759252 5.36182449 -0.18242274 8.04518056 -0.24024439 C8.77492937 -0.2713396 9.50467818 -0.30243481 10.2565406 -0.3344723 C15.42395295 -0.37924171 18.03925991 1.1955654 21.85012746 4.5758872 C23.529636 6.4184297 25.19654707 8.27254056 26.85012746 10.1383872 C28.6325928 11.65361247 30.44561897 13.13363375 32.28762746 14.5758872 C36.82248907 18.23344984 41.10548928 22.08455748 45.3672173 26.0500083 C49.46643716 29.84175353 53.74751608 33.36250553 58.10012746 36.86104345 C62.07872872 40.15582262 65.85276313 43.6530327 69.63528371 47.1696372 C71.68691867 49.16510509 71.68691867 49.16510509 73.85012746 50.1383872 C73.85012746 50.7983872 73.85012746 51.4583872 73.85012746 52.1383872 C72.31364552 52.21355566 72.31364552 52.21355566 70.74612355 52.29024267 C66.77577585 52.48520284 62.80560995 52.68369449 58.83547902 52.88301611 C57.14900009 52.96724542 55.46247906 53.05063777 53.77590871 53.13301611 C42.70404546 53.67457464 31.64717795 54.34682706 20.58840871 55.11104345 C4.290098 56.2281303 -12.01772636 56.98018462 -28.33737254 57.7008872 C-33.26995253 57.91944329 -38.20242004 58.14027289 -43.1347301 58.36484098 C-45.06149156 58.45169004 -46.98839373 58.53539987 -48.91529918 58.61899328 C-54.15985425 58.85617839 -59.38218004 59.12938191 -64.60812449 59.63618994 C-71.33944597 60.28701668 -78.08261426 60.56125525 -84.83737254 60.8571372 C-86.23020788 60.92028529 -87.62302994 60.98372711 -89.01583934 61.04744482 C-94.13299295 61.28090696 -99.25038119 61.50904394 -104.36776805 61.73732519 C-108.71025034 61.93124804 -113.05262941 62.12725401 -117.39489818 62.32590246 C-119.40582428 62.41707343 -121.41688536 62.50525168 -123.42794871 62.59334326 C-128.84844125 62.84046272 -134.24847476 63.11451162 -139.64987254 63.6383872 C-146.36709836 64.28988349 -153.09658537 64.56186724 -159.83737254 64.8571372 C-161.23020788 64.92028529 -162.62302994 64.98372711 -164.01583934 65.04744482 C-169.13299295 65.28090696 -174.25038119 65.50904394 -179.36776805 65.73732519 C-183.71025034 65.93124804 -188.05262941 66.12725401 -192.39489818 66.32590246 C-194.40582428 66.41707343 -196.41688536 66.50525168 -198.42794871 66.59334326 C-204.83608978 66.88548947 -211.20441906 67.29010649 -217.58892894 67.90974951 C-221.81811977 68.28732613 -226.05276882 68.4632477 -230.29440379 68.6383872 C-231.22548457 68.67899267 -232.15656535 68.71959814 -233.1158607 68.76143408 C-236.06459902 68.88951894 -239.01347324 69.01406967 -241.96237254 69.1383872 C-244.85907035 69.26298682 -247.75573373 69.38831918 -250.65235972 69.51457739 C-252.57704723 69.5969742 -254.50186644 69.67635098 -256.4268043 69.75267553 C-261.39230545 69.9532462 -266.34559181 70.20952188 -271.30294871 70.55977392 C-272.29965083 70.62366308 -273.29635295 70.68755224 -274.32325816 70.75337744 C-276.21907318 70.87652335 -278.11393023 71.01588667 -280.00712657 71.17427588 C-284.32986731 71.43954 -286.56782723 71.44754138 -290.47677684 69.37129736 C-292.98299272 67.13335467 -295.01524754 64.72959562 -297.14987254 62.1383872 C-298.90870169 60.64061366 -300.70204078 59.18257357 -302.52487254 57.7633872 C-307.08008392 54.08072335 -311.3889981 50.20812418 -315.67331004 46.22041845 C-318.86275765 43.2693574 -322.13334047 40.47860203 -325.52487254 37.7633872 C-332.39147291 32.24396758 -338.7492495 26.18393919 -345.14987254 20.1383872 C-341.86273931 18.20319503 -339.22077902 17.81245823 -335.43208289 17.61117887 C-334.25844827 17.54449566 -333.08481365 17.47781244 -331.87561435 17.40910852 C-330.58508546 17.34489713 -329.29455658 17.28068575 -327.96492076 17.21452856 C-326.5807858 17.13931362 -325.19669302 17.06331908 -323.81264001 16.98661101 C-320.00502534 16.77786985 -316.1969007 16.58027847 -312.38860142 16.38448215 C-308.28226766 16.17142965 -304.17649007 15.94812329 -300.07063365 15.72609472 C-292.02130807 15.2924658 -283.97150591 14.86839178 -275.92150312 14.44754277 C-266.53650998 13.95656711 -257.15201499 13.45637364 -247.76752729 12.95584561 C-231.00628324 12.06220958 -214.24459083 11.17727653 -197.48263621 10.29707861 C-181.24562027 9.4444409 -165.00896619 8.58528942 -148.77267528 7.71895361 C-128.25369125 6.62411653 -107.73440764 5.5350757 -87.2148626 4.45080443 C-80.68739152 4.10571968 -74.16003056 3.75859894 -67.6327045 3.41078329 C-59.65633417 2.98587052 -51.67977202 2.56477877 -43.70295649 2.14830457 C-39.63977879 1.93608996 -35.57669696 1.72237032 -31.51383281 1.50422812 C-21.01126976 0.94136469 -10.5074945 0.46163861 0 0 Z " fill="#5FA4F9" transform="translate(414.1498725414276,67.86161279678345)"/>
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="24">
<path d="M0 0 C1.70736328 -0.02126953 1.70736328 -0.02126953 3.44921875 -0.04296875 C6.3125 0.1875 6.3125 0.1875 8.3125 2.1875 C8.45767744 5.0968558 8.49880796 7.907446 8.4375 10.8125 C8.42847656 11.61429688 8.41945313 12.41609375 8.41015625 13.2421875 C8.38656223 15.22408523 8.35069065 17.20582981 8.3125 19.1875 C4.37369868 20.11123389 0.66726634 20.35195401 -3.375 20.375 C-5.08236328 20.39626953 -5.08236328 20.39626953 -6.82421875 20.41796875 C-9.6875 20.1875 -9.6875 20.1875 -11.6875 18.1875 C-11.83267744 15.2781442 -11.87380796 12.467554 -11.8125 9.5625 C-11.80347656 8.76070312 -11.79445313 7.95890625 -11.78515625 7.1328125 C-11.76156223 5.15091477 -11.72569065 3.16917019 -11.6875 1.1875 C-7.74869868 0.26376611 -4.04226634 0.02304599 0 0 Z " fill="#136CFE" transform="translate(13.6875,1.8125)"/>
<path d="M0 0 C1.14726562 -0.02578125 2.29453125 -0.0515625 3.4765625 -0.078125 C4.43304688 0.03015625 5.38953125 0.1384375 6.375 0.25 C7.035 1.24 7.695 2.23 8.375 3.25 C5.34069419 4.7671529 2.20094035 4.47513316 -1.125 4.5 C-1.81464844 4.520625 -2.50429687 4.54125 -3.21484375 4.5625 C-5.21875 4.578125 -5.21875 4.578125 -8.625 4.25 C-9.285 3.26 -9.945 2.27 -10.625 1.25 C-7.07243456 0.16498001 -3.70293281 0.05015259 0 0 Z " fill="#539AF9" transform="translate(13.625,1.75)"/>
<path d="M0 0 C1.32 0.99 2.64 1.98 4 3 C4.390625 6.13671875 4.390625 6.13671875 4.25 9.6875 C4.21390625 10.86699219 4.1778125 12.04648438 4.140625 13.26171875 C4.09421875 14.16535156 4.0478125 15.06898437 4 16 C3.34 16.33 2.68 16.66 2 17 C1.34 16.67 0.68 16.34 0 16 C0 10.72 0 5.44 0 0 Z " fill="#035AE9" transform="translate(2,3)"/>
</svg>

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

@@ -58,16 +58,16 @@ public class Civil3dRootToSpeckleConverter : IRootToSpeckleConverter
{
var result = objectConverter.Convert(target);
// NOTE: we can not test acad objects props, so commented out.
// // we need to capture properties on autocad entities
// if (target is ADB.Entity autocadEntity)
// {
// var properties = _propertiesExtractor.GetProperties(autocadEntity);
// if (properties.Count > 0)
// {
// result["properties"] = properties;
// }
// }
// This is needed to retrieve property sets on solids
// Civil entity properties are retrieved in the CivilEntityToSpeckleTopLevelConverter
if (target is not CDB.Entity && target is ADB.Entity autocadEntity)
{
var properties = _propertiesExtractor.GetProperties(autocadEntity);
if (properties.Count > 0)
{
result["properties"] = properties;
}
}
tr.Commit();
return result;
@@ -43,7 +43,7 @@ public class ClassPropertiesExtractor
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public Dictionary<string, object?> GetClassProperties(CDB.Entity entity)
public Dictionary<string, object?> GetClassProperties(ADB.Entity entity)
{
switch (entity)
{
@@ -19,7 +19,7 @@ public class ExtensionDictionaryExtractor
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public Dictionary<string, object?>? GetExtensionDictionary(CDB.Entity entity)
public Dictionary<string, object?>? GetExtensionDictionary(ADB.Entity entity)
{
if (entity is null || entity.ExtensionDictionary == ADB.ObjectId.Null)
{
@@ -14,7 +14,7 @@ public class PartDataExtractor
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
public Dictionary<string, object?>? GetPartData(CDB.Entity entity)
public Dictionary<string, object?>? GetPartData(ADB.Entity entity)
{
return entity switch
{
@@ -23,7 +23,7 @@ public class PropertiesExtractor
_extensionDictionaryExtractor = extensionDictionaryExtractor;
}
public Dictionary<string, object?> GetProperties(CDB.Entity entity)
public Dictionary<string, object?> GetProperties(ADB.Entity entity)
{
// first get all class properties, which will be at the root level of props dictionary
Dictionary<string, object?> properties = _classPropertiesExtractor.GetClassProperties(entity);
@@ -0,0 +1,204 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Sdk;
using Speckle.Testing;
namespace Speckle.Connectors.DUI.Tests;
[TestFixture]
public class ReceiveOperationManagerTests : MoqTest
{
private Mock<IServiceScope> _serviceScopeMock;
private Mock<ICancellationManager> _cancellationManagerMock;
private Mock<IDocumentModelStore> _storeMock;
private Mock<ISpeckleApplication> _speckleAppMock;
private Mock<IOperationProgressManager> _progressManagerMock;
private Mock<ILogger<ReceiveOperationManager>> _loggerMock;
private ReceiveOperationManager _manager;
[SetUp]
public void SetUp()
{
_serviceScopeMock = Create<IServiceScope>();
_cancellationManagerMock = Create<ICancellationManager>();
_storeMock = Create<IDocumentModelStore>();
_speckleAppMock = Create<ISpeckleApplication>();
_progressManagerMock = Create<IOperationProgressManager>();
_loggerMock = Create<ILogger<ReceiveOperationManager>>(MockBehavior.Loose);
_manager = new ReceiveOperationManager(
_serviceScopeMock.Object,
_cancellationManagerMock.Object,
_storeMock.Object,
_speckleAppMock.Object,
_progressManagerMock.Object,
_loggerMock.Object
);
_serviceScopeMock.Setup(x => x.Dispose());
}
[TearDown]
public void TearDown()
{
_manager.Dispose();
}
[Test]
public void Process_ShouldThrow_WhenModelCardNotFound()
{
_storeMock.Setup(x => x.GetModelById("id1")).Returns((ModelCard?)null);
var commands = Create<IReceiveBindingUICommands>();
Assert.ThrowsAsync<InvalidOperationException>(
async () =>
await _manager.Process(
commands.Object,
"id1",
_ => { },
(s, f) => Task.FromResult<HostObjectBuilderResult?>(null)
)
);
}
[Test]
public async Task Process_ShouldHandleOperationCanceledException()
{
var modelCard = new ReceiverModelCard { ModelCardId = "id2", ModelName = "Test" };
_storeMock.Setup(x => x.GetModelById("id2")).Returns(modelCard);
var cancellationItem = Create<ICancellationItem>();
cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None);
cancellationItem.Setup(x => x.Dispose());
_cancellationManagerMock.Setup(x => x.GetCancellationItem("id2")).Returns(cancellationItem.Object);
_cancellationManagerMock.Setup(x => x.CancelOperation("id2"));
var receiveOp = Create<IReceiveOperation>();
var serviceProvider = Create<IServiceProvider>();
serviceProvider.Setup(x => x.GetService(typeof(IReceiveOperation))).Returns(receiveOp.Object);
_serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object);
var exception = new OperationCanceledException();
var commands = Create<IReceiveBindingUICommands>();
commands.Setup(x => x.Bridge).Returns(Create<IBrowserBridge>().Object);
var progressHandler = Create<IProgress<CardProgress>>();
_progressManagerMock
.Setup(x =>
x.CreateOperationProgressEventHandler(It.IsAny<IBrowserBridge>(), "id2", It.IsAny<CancellationToken>())
)
.Returns(progressHandler.Object);
var processor = new Func<string?, Func<Task<HostObjectBuilderResult>>, Task<HostObjectBuilderResult?>>(
(s, f) => throw exception
);
await _manager.Process(commands.Object, "id2", _ => { }, processor);
_cancellationManagerMock.Verify(x => x.CancelOperation("id2"), Times.Once);
}
[Test]
public async Task Process_ShouldHandleGeneralException_AndSetModelError()
{
var modelCard = new ReceiverModelCard { ModelCardId = "id3", ModelName = "Test" };
_storeMock.Setup(x => x.GetModelById("id3")).Returns(modelCard);
var cancellationItem = Create<ICancellationItem>();
cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None);
cancellationItem.Setup(x => x.Dispose());
_cancellationManagerMock.Setup(x => x.GetCancellationItem("id3")).Returns(cancellationItem.Object);
_cancellationManagerMock.Setup(x => x.CancelOperation("id3"));
var commands = Create<IReceiveBindingUICommands>();
var exception = new InvalidOperationException("fail");
commands.Setup(x => x.SetModelError("id3", exception)).Returns(Task.CompletedTask);
var bridge = Create<IBrowserBridge>();
commands.Setup(x => x.Bridge).Returns(bridge.Object);
var progressHandler = Create<IProgress<CardProgress>>();
_progressManagerMock
.Setup(x => x.CreateOperationProgressEventHandler(bridge.Object, "id3", It.IsAny<CancellationToken>()))
.Returns(progressHandler.Object);
var receiveOp = Create<IReceiveOperation>();
var serviceProvider = Create<IServiceProvider>();
serviceProvider.Setup(x => x.GetService(typeof(IReceiveOperation))).Returns(receiveOp.Object);
_serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object);
var processor = new Func<string?, Func<Task<HostObjectBuilderResult>>, Task<HostObjectBuilderResult?>>(
(s, f) => throw exception
);
await _manager.Process(commands.Object, "id3", _ => { }, processor);
commands.Verify(x => x.SetModelError("id3", It.IsAny<Exception>()), Times.Once);
_cancellationManagerMock.Verify(x => x.CancelOperation("id3"), Times.Once);
}
[Test]
public async Task Process_ShouldSetModelReceiveResult_OnSuccess()
{
var modelCard = new ReceiverModelCard
{
ModelCardId = "id4",
ModelName = "Test",
AccountId = "AccountId",
ServerUrl = "http://localhost",
ProjectId = "ProjectId",
ProjectName = "ProjectName",
ModelId = "ModelId",
SelectedVersionId = "SelectedVersionId",
};
_storeMock.Setup(x => x.GetModelById("id4")).Returns(modelCard);
var cancellationItem = Create<ICancellationItem>();
cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None);
cancellationItem.Setup(x => x.Dispose());
_cancellationManagerMock.Setup(x => x.CancelOperation("id4"));
_cancellationManagerMock.Setup(x => x.GetCancellationItem("id4")).Returns(cancellationItem.Object);
var commands = Create<IReceiveBindingUICommands>();
commands.Setup(x => x.Bridge).Returns(Create<IBrowserBridge>().Object);
commands
.Setup(x =>
x.SetModelReceiveResult("id4", It.IsAny<IEnumerable<string>>(), It.IsAny<IEnumerable<ConversionResult>>())
)
.Returns(Task.CompletedTask);
var progressHandler = Create<IProgress<CardProgress>>();
_progressManagerMock
.Setup(x =>
x.CreateOperationProgressEventHandler(It.IsAny<IBrowserBridge>(), "id4", It.IsAny<CancellationToken>())
)
.Returns(progressHandler.Object);
var receiveOp = Create<IReceiveOperation>();
var bakedIds = new List<string> { "obj1", "obj2" };
var hostResult = new HostObjectBuilderResult(bakedIds, []);
var serviceProvider = Create<IServiceProvider>();
serviceProvider.Setup(x => x.GetService(typeof(IReceiveOperation))).Returns(receiveOp.Object);
_serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProvider.Object);
receiveOp
.Setup(x => x.Execute(It.IsAny<ReceiveInfo>(), progressHandler.Object, CancellationToken.None))
.ReturnsAsync(hostResult);
_speckleAppMock.Setup(x => x.Slug).Returns("slug");
var processor = new Func<string?, Func<Task<HostObjectBuilderResult>>, Task<HostObjectBuilderResult?>>(
async (s, f) => await f()
);
await _manager.Process(commands.Object, "id4", _ => { }, processor);
commands.Verify(
x => x.SetModelReceiveResult("id4", bakedIds, It.IsAny<IEnumerable<ConversionResult>>()),
Times.Once
);
_cancellationManagerMock.Verify(x => x.CancelOperation("id4"), Times.Once);
}
}
@@ -0,0 +1,116 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Moq;
using NUnit.Framework;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Connectors.DUI.Bridge;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Utils;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
using Speckle.Sdk.Models;
using Speckle.Sdk.Serialisation;
using Speckle.Testing;
namespace Speckle.Connectors.DUI.Tests;
public class SendOperationManagerTests : MoqTest
{
[Test]
public async Task TestHappyProcess()
{
// Arrange
var serviceScopeMock = Create<IServiceScope>();
var serviceProviderMock = Create<IServiceProvider>();
serviceScopeMock.Setup(x => x.ServiceProvider).Returns(serviceProviderMock.Object);
serviceScopeMock.Setup(x => x.Dispose());
var operationProgressManager = Create<IOperationProgressManager>();
var progressHandler = Create<IProgress<CardProgress>>();
var modelCard = new SenderModelCard
{
ModelCardId = "model1",
AccountId = "acc",
ServerUrl = "http://localhost",
ProjectId = "proj",
ModelId = "mod"
};
var bridge = Create<IBrowserBridge>();
operationProgressManager
.Setup(x =>
x.CreateOperationProgressEventHandler(bridge.Object, modelCard.ModelCardId, It.IsAny<CancellationToken>())
)
.Returns(progressHandler.Object);
var store = new TestDocumentModelStore(
Create<ILogger<DocumentModelStore>>(MockBehavior.Loose).Object,
Create<IJsonSerializer>(MockBehavior.Loose).Object
);
store.AddModel(modelCard);
var cancellationManager = Create<ICancellationManager>();
var cancellationItem = Create<ICancellationItem>();
cancellationItem.Setup(x => x.Token).Returns(CancellationToken.None);
cancellationItem.Setup(x => x.Dispose());
cancellationManager.Setup(x => x.GetCancellationItem(modelCard.ModelCardId)).Returns(cancellationItem.Object);
var speckleApplication = Create<ISpeckleApplication>();
speckleApplication.SetupGet(x => x.ApplicationAndVersion).Returns("TestApp 1.0");
var activityFactory = Create<ISdkActivityFactory>();
var activity = Create<ISdkActivity>();
activityFactory.Setup(x => x.Start(null, It.IsAny<string>())).Returns(activity.Object);
activity.Setup(x => x.Dispose());
var logger = Create<ILogger<SendOperationManager>>(MockBehavior.Loose);
var sendResults = new List<SendConversionResult>();
var versionId = "v1";
var objects = new List<string> { "obj1", "obj2" };
var sendOperationMock = Create<ISendOperation<string>>();
sendOperationMock
.Setup(x => x.Execute(objects, It.IsAny<SendInfo>(), progressHandler.Object, It.IsAny<CancellationToken>()))
.ReturnsAsync(
new SendOperationResult("rootObjId", versionId, new Dictionary<Id, ObjectReference>(), sendResults)
);
serviceProviderMock.Setup(x => x.GetService(typeof(ISendOperation<string>))).Returns(sendOperationMock.Object);
var commandsMock = Create<ISendBindingUICommands>();
commandsMock.Setup(x => x.Bridge).Returns(bridge.Object);
commandsMock
.Setup(x => x.SetModelSendResult(modelCard.ModelCardId, versionId, sendResults))
.Returns(Task.CompletedTask);
using var manager = new SendOperationManager(
serviceScopeMock.Object,
operationProgressManager.Object,
store,
cancellationManager.Object,
speckleApplication.Object,
activityFactory.Object,
logger.Object
);
// Act
await manager.Process(commandsMock.Object, "model1", (sp, card) => { }, card => objects);
}
// Helper for in-memory DocumentModelStore
private sealed class TestDocumentModelStore : DocumentModelStore
{
public TestDocumentModelStore(ILogger<DocumentModelStore> logger, IJsonSerializer serializer)
: base(logger, serializer) { }
protected override void HostAppSaveState(string modelCardState) { }
protected override void LoadState() => throw new NotImplementedException();
}
}
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0-windows;net8.0-windows</TargetFrameworks>
<TargetFrameworks>net48;net8.0-windows</TargetFrameworks>
<!-- we're doing it because tekla is complaning about arm dlls -->
<!-- we don't really want to support windows arm for now -->
<PlatformTarget>x64</PlatformTarget>
@@ -340,306 +340,6 @@
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
}
},
"net6.0-windows7.0": {
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"Microsoft.Web.WebView2": {
"type": "Direct",
"requested": "[1.0.1938.49, )",
"resolved": "1.0.1938.49",
"contentHash": "z8KnFnaTYzhA/ZnyRX0qGfS1NU5ZBJeClAH64F0fVDvdDJTvME7xl6zTJ0Jlfe1BtL3C0NH9xTy64shg2baKdw=="
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"GraphQL.Client": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0",
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
"System.Reactive": "5.0.0"
}
},
"GraphQL.Client.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
"dependencies": {
"GraphQL.Primitives": "6.0.0"
}
},
"GraphQL.Client.Abstractions.Websocket": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0"
}
},
"GraphQL.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.CSharp": {
"type": "Transitive",
"resolved": "4.7.0",
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
},
"Microsoft.Data.Sqlite": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "7.0.5",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "2.2.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Primitives": "2.2.0",
"System.ComponentModel.Annotations": "4.5.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==",
"dependencies": {
"System.Memory": "4.5.1",
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Speckle.Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.4"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"System.ComponentModel.Annotations": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Reactive": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Objects": "[3.4.2, )",
"Speckle.Sdk": "[3.4.2, )",
"Speckle.Sdk.Dependencies": "[3.4.2, )"
}
},
"speckle.connectors.dui": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.Logging.Abstractions": "[2.2.0, )",
"Speckle.Connectors.Common": "[1.0.0, )"
}
},
"speckle.connectors.logging": {
"type": "Project"
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "2.2.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging.Abstractions": "2.2.0",
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
},
"Speckle.DoubleNumerics": {
"type": "CentralTransitive",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==",
"dependencies": {
"Speckle.Sdk": "3.4.2"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.4.2"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
}
},
"net8.0-windows7.0": {
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
@@ -47,7 +47,7 @@ public class BasicConnectorBindingCommands
private const string SET_MODEL_ERROR_UI_COMMAND_NAME = "setModelError";
public const string SET_GLOBAL_NOTIFICATION = "setGlobalNotification";
protected IBrowserBridge Bridge { get; }
public IBrowserBridge Bridge { get; }
public BasicConnectorBindingCommands(IBrowserBridge bridge)
{
@@ -1,10 +1,20 @@
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.DUI.Bridge;
namespace Speckle.Connectors.DUI.Bindings;
public interface ISendBindingUICommands
{
public void RefreshSendFilters(string frontEndName);
Task RefreshSendFilters();
public void SetModelsExpired(string frontEndName, IEnumerable<string> expiredModelIds);
Task SetModelsExpired(IEnumerable<string> expiredModelIds);
Task SetModelError(string modelCardId, Exception exception);
public void SetModelCreatedVersionId(string frontEndName, string modelCardId, string versionId);
Task SetModelSendResult(
string modelCardId,
string versionId,
IEnumerable<SendConversionResult> sendConversionResults
);
IBrowserBridge Bridge { get; }
}
@@ -3,7 +3,20 @@ using Speckle.Connectors.DUI.Bridge;
namespace Speckle.Connectors.DUI.Bindings;
public sealed class ReceiveBindingUICommands : BasicConnectorBindingCommands
public interface IReceiveBindingUICommands
{
Task SetModelError(string modelCardId, Exception exception);
Task SetModelReceiveResult(
string modelCardId,
IEnumerable<string> bakedObjectIds,
IEnumerable<ConversionResult> conversionResults
);
IBrowserBridge Bridge { get; }
}
public sealed class ReceiveBindingUICommands : BasicConnectorBindingCommands, IReceiveBindingUICommands
{
// POC: put here events once we needed for receive specific
private const string SET_MODEL_RECEIVE_RESULT_UI_COMMAND_NAME = "setModelReceiveResult";
@@ -0,0 +1,87 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
namespace Speckle.Connectors.DUI.Bindings;
public partial interface IReceiveOperationManager : IDisposable;
[GenerateAutoInterface]
public sealed class ReceiveOperationManager(
IServiceScope serviceScope,
ICancellationManager cancellationManager,
IDocumentModelStore store,
ISpeckleApplication speckleApplication,
IOperationProgressManager operationProgressManager,
ILogger<ReceiveOperationManager> logger
) : IReceiveOperationManager
{
public async Task Process(
IReceiveBindingUICommands commands,
string modelCardId,
Action<IServiceProvider> initializeScope,
Func<string?, Func<Task<HostObjectBuilderResult>>, Task<HostObjectBuilderResult?>> processor
)
{
// Get receiver card
if (store.GetModelById(modelCardId) is not ReceiverModelCard modelCard)
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No download model card was found.");
}
try
{
using var cancellationItem = cancellationManager.GetCancellationItem(modelCardId);
initializeScope(serviceScope.ServiceProvider);
var progress = operationProgressManager.CreateOperationProgressEventHandler(
commands.Bridge,
modelCardId,
cancellationItem.Token
);
var ro = serviceScope.ServiceProvider.GetRequiredService<IReceiveOperation>();
var conversionResults = await processor(
modelCard.ModelName,
() => ro.Execute(modelCard.GetReceiveInfo(speckleApplication.Slug), progress, cancellationItem.Token)
);
if (conversionResults is null)
{
return;
}
modelCard.BakedObjectIds = conversionResults.BakedObjectIds.ToList();
await commands.SetModelReceiveResult(
modelCardId,
conversionResults.BakedObjectIds,
conversionResults.ConversionResults
);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
logger.LogModelCardHandledError(ex);
await commands.SetModelError(modelCardId, ex);
}
finally
{
// otherwise the id of the operation persists on the cancellation manager and triggers 'Operations cancelled because of document swap!' message to UI.
cancellationManager.CancelOperation(modelCardId);
}
}
[AutoInterfaceIgnore]
public void Dispose() => serviceScope.Dispose();
}
@@ -0,0 +1,31 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.DUI.Models;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
namespace Speckle.Connectors.DUI.Bindings;
[GenerateAutoInterface]
public class ReceiveOperationManagerFactory(
IServiceProvider serviceProvider,
IOperationProgressManager operationProgressManager,
DocumentModelStore store,
ICancellationManager cancellationManager,
ISpeckleApplication speckleApplication,
ILoggerFactory loggerFactory
) : IReceiveOperationManagerFactory
{
public IReceiveOperationManager Create() =>
new ReceiveOperationManager(
#pragma warning disable CA2000
serviceProvider.CreateScope(),
#pragma warning restore CA2000
cancellationManager,
store,
speckleApplication,
operationProgressManager,
loggerFactory.CreateLogger<ReceiveOperationManager>()
);
}
@@ -4,7 +4,9 @@ using Speckle.Connectors.DUI.Bridge;
namespace Speckle.Connectors.DUI.Bindings;
// POC: Send Commands share all commands from BasicBindings + some, this pattern should be revised
public class SendBindingUICommands(IBrowserBridge bridge) : BasicConnectorBindingCommands(bridge)
public class SendBindingUICommands(IBrowserBridge bridge)
: BasicConnectorBindingCommands(bridge),
ISendBindingUICommands
{
private const string REFRESH_SEND_FILTERS_UI_COMMAND_NAME = "refreshSendFilters";
private const string SET_MODELS_EXPIRED_UI_COMMAND_NAME = "setModelsExpired";
@@ -0,0 +1,106 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.Common.Operations;
using Speckle.Connectors.DUI.Exceptions;
using Speckle.Connectors.DUI.Logging;
using Speckle.Connectors.DUI.Models;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
namespace Speckle.Connectors.DUI.Bindings;
public partial interface ISendOperationManager : IDisposable;
[GenerateAutoInterface]
public sealed class SendOperationManager(
IServiceScope serviceScope,
IOperationProgressManager operationProgressManager,
DocumentModelStore store,
ICancellationManager cancellationManager,
ISpeckleApplication speckleApplication,
ISdkActivityFactory activityFactory,
ILogger<SendOperationManager> logger
) : ISendOperationManager
{
public async Task Process<T>(
ISendBindingUICommands commands,
string modelCardId,
Action<IServiceProvider, SenderModelCard> initializeScope,
Func<SenderModelCard, IReadOnlyList<T>> gatherObjects
)
{
await Process(commands, modelCardId, initializeScope, (card, _) => Task.FromResult(gatherObjects(card)));
}
public async Task Process<T>(
ISendBindingUICommands commands,
string modelCardId,
Action<IServiceProvider, SenderModelCard> initializeScope,
Func<SenderModelCard, Task<IReadOnlyList<T>>> gatherObjects
)
{
await Process(commands, modelCardId, initializeScope, async (card, _) => await gatherObjects(card));
}
public async Task Process<T>(
ISendBindingUICommands commands,
string modelCardId,
Action<IServiceProvider, SenderModelCard> initializeScope,
Func<SenderModelCard, IProgress<CardProgress>, Task<IReadOnlyList<T>>> gatherObjects
)
{
using var activity = activityFactory.Start();
try
{
if (store.GetModelById(modelCardId) is not SenderModelCard modelCard)
{
// Handle as GLOBAL ERROR at BrowserBridge
throw new InvalidOperationException("No publish model card was found.");
}
using var cancellationItem = cancellationManager.GetCancellationItem(modelCardId);
initializeScope(serviceScope.ServiceProvider, modelCard);
var progress = operationProgressManager.CreateOperationProgressEventHandler(
commands.Bridge,
modelCardId,
cancellationItem.Token
);
var objects = await gatherObjects(modelCard, progress);
if (objects.Count == 0)
{
// Handle as CARD ERROR in this function
throw new SpeckleSendFilterException("No objects were found to convert. Please update your publish filter!");
}
var sendInfo = modelCard.GetSendInfo(speckleApplication.ApplicationAndVersion);
var sendResult = await serviceScope
.ServiceProvider.GetRequiredService<ISendOperation<T>>()
.Execute(objects, sendInfo, progress, cancellationItem.Token);
await commands.SetModelSendResult(modelCardId, sendResult.VersionId, sendResult.ConversionResults);
}
catch (OperationCanceledException)
{
// SWALLOW -> UI handles it immediately, so we do not need to handle anything for now!
// Idea for later -> when cancel called, create promise from UI to solve it later with this catch block.
// So have 3 state on UI -> Cancellation clicked -> Cancelling -> Cancelled
return;
}
catch (Exception ex) when (!ex.IsFatal()) // UX reasons - we will report operation exceptions as model card error. We may change this later when we have more exception documentation
{
logger.LogModelCardHandledError(ex);
await commands.SetModelError(modelCardId, ex);
}
}
[AutoInterfaceIgnore]
public void Dispose() => serviceScope.Dispose();
}
@@ -0,0 +1,34 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.Common.Cancellation;
using Speckle.Connectors.DUI.Models;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
using Speckle.Sdk.Logging;
namespace Speckle.Connectors.DUI.Bindings;
[GenerateAutoInterface]
public class SendOperationManagerFactory(
IServiceProvider serviceProvider,
IOperationProgressManager operationProgressManager,
DocumentModelStore store,
ICancellationManager cancellationManager,
ISpeckleApplication speckleApplication,
ISdkActivityFactory activityFactory,
ILoggerFactory loggerFactory
) : ISendOperationManagerFactory
{
public ISendOperationManager Create() =>
new SendOperationManager(
#pragma warning disable CA2000
serviceProvider.CreateScope(),
#pragma warning restore CA2000
operationProgressManager,
store,
cancellationManager,
speckleApplication,
activityFactory,
loggerFactory.CreateLogger<SendOperationManager>()
);
}
@@ -20,6 +20,7 @@ public static class ContainerRegistration
// context always newed up on host app's main/ui thread
serviceCollection.AddSingleton<IThreadContext>(new TThreadContext());
serviceCollection.AddSingleton<DocumentModelStore, TDocumentStore>();
serviceCollection.AddSingleton<IDocumentModelStore>(sp => sp.GetService<DocumentModelStore>());
serviceCollection.AddTransient<IBrowserBridge, BrowserBridge>(); // POC: Each binding should have it's own bridge instance
@@ -40,10 +41,13 @@ public static class ContainerRegistration
{
try
{
serviceProvider
.GetRequiredService<ILoggerFactory>()
.CreateLogger("UnobservedTaskException")
.LogError(args.Exception, "Unobserved task exception");
foreach (var exception in args.Exception.InnerExceptions)
{
if (TestAndLogStacktrace(serviceProvider, exception))
{
args.SetObserved();
}
}
}
#pragma warning disable CA1031
catch (Exception e)
@@ -53,10 +57,25 @@ public static class ContainerRegistration
Console.WriteLine(args.Exception);
Console.WriteLine(e);
}
finally
{
args.SetObserved();
}
};
}
private static bool TestAndLogStacktrace(IServiceProvider serviceProvider, Exception exception)
{
var stackTrace = exception.ToString();
if (stackTrace.IndexOf("Speckle", StringComparison.InvariantCultureIgnoreCase) <= 0)
{
serviceProvider
.GetRequiredService<ILoggerFactory>()
.CreateLogger("UnobservedTaskException")
.LogInformation(exception, "Non-Speckle unobserved task exception");
return false;
}
serviceProvider
.GetRequiredService<ILoggerFactory>()
.CreateLogger("UnobservedTaskException")
.LogError(exception, "Unobserved task exception");
return true;
}
}
@@ -1,5 +1,4 @@
using Microsoft.Extensions.Logging;
using Speckle.Connectors.DUI.Bindings;
using Speckle.Sdk;
namespace Speckle.Connectors.DUI.Logging;
@@ -13,7 +12,6 @@ namespace Speckle.Connectors.DUI.Logging;
public static class HandledModelCardErrors
{
public static void LogModelCardHandledError<T>(this ILogger<T> logger, Exception ex)
where T : IBinding
{
LogLevel level = ex switch
{
@@ -2,6 +2,7 @@ using System.Diagnostics;
using Microsoft.Extensions.Logging;
using Speckle.Connectors.DUI.Models.Card;
using Speckle.Connectors.DUI.Utils;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
using Speckle.Sdk.Common;
@@ -10,7 +11,9 @@ namespace Speckle.Connectors.DUI.Models;
/// <summary>
/// Encapsulates the state Speckle needs to persist in the host app's document.
/// </summary>
[GenerateAutoInterface]
public abstract class DocumentModelStore(ILogger<DocumentModelStore> logger, IJsonSerializer serializer)
: IDocumentModelStore
{
private readonly List<ModelCard> _models = new();
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net48;net8.0</TargetFrameworks>
<Configurations>Debug;Release;Local</Configurations>
</PropertyGroup>
@@ -327,293 +327,6 @@
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
}
},
"net6.0": {
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"GraphQL.Client": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0",
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
"System.Reactive": "5.0.0"
}
},
"GraphQL.Client.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
"dependencies": {
"GraphQL.Primitives": "6.0.0"
}
},
"GraphQL.Client.Abstractions.Websocket": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0"
}
},
"GraphQL.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.CSharp": {
"type": "Transitive",
"resolved": "4.7.0",
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
},
"Microsoft.Data.Sqlite": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "7.0.5",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "2.2.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Primitives": "2.2.0",
"System.ComponentModel.Annotations": "4.5.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==",
"dependencies": {
"System.Memory": "4.5.1",
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Speckle.Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.4"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"System.ComponentModel.Annotations": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Reactive": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"speckle.connectors.common": {
"type": "Project",
"dependencies": {
"Microsoft.Extensions.DependencyInjection": "[2.2.0, )",
"Speckle.Connectors.Logging": "[1.0.0, )",
"Speckle.Objects": "[3.4.2, )",
"Speckle.Sdk": "[3.4.2, )",
"Speckle.Sdk.Dependencies": "[3.4.2, )"
}
},
"speckle.connectors.logging": {
"type": "Project"
},
"Microsoft.Extensions.DependencyInjection": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "2.2.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging.Abstractions": "2.2.0",
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Speckle.DoubleNumerics": {
"type": "CentralTransitive",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
},
"Speckle.Objects": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==",
"dependencies": {
"Speckle.Sdk": "3.4.2"
}
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.4.2"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
}
},
"net8.0": {
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
@@ -1,6 +1,7 @@
using Ara3D.Utils;
using Speckle.Sdk.Api;
using Speckle.Sdk.Credentials;
using Speckle.Sdk.Models.Extensions;
namespace Speckle.Importers.Ifc.Tester2;
@@ -16,7 +17,10 @@ public sealed class IfcTester(IClientFactory clientFactory, Importer importer, I
{
// Settings, Change these to suit!
// private readonly ICollection<FilePath> _filePath = [new(@"C:\Users\Jedd\Desktop\GRAPHISOFT_Archicad_Sample_Project-S-Office_v1.0_AC25.ifc")]
private readonly IEnumerable<string> _filePaths = Directory.EnumerateFiles(@"C:\Users\Jedd\Desktop\", "*.ifc");
private readonly IEnumerable<string> _filePaths = Directory.EnumerateFiles(
@"C:\Users\Jedd\Desktop\big files",
"*.ifc"
);
private readonly Uri _serverUrl = new("https://app.speckle.systems");
private const string PROJECT_ID = "f3a42bdf24";
@@ -28,7 +32,16 @@ public sealed class IfcTester(IClientFactory clientFactory, Importer importer, I
foreach (var path in _filePaths)
{
await ImportFile(speckleClient, path, cancellationToken);
try
{
await ImportFile(speckleClient, path, cancellationToken);
}
#pragma warning disable CA1031
catch (Exception ex)
#pragma warning restore CA1031
{
Console.WriteLine(ex.ToFormattedString());
}
}
}
@@ -12,11 +12,17 @@ public sealed class GraphConverter(INodeConverter nodeConverter, IRenderMaterial
{
public Base Convert(IfcModel model, IfcGraph graph)
{
Base rootCollection = nodeConverter.Convert(model, graph.GetIfcProject());
try
{
Base rootCollection = nodeConverter.Convert(model, graph.GetIfcProject());
//Grabing materials from ProxyManager
rootCollection["renderMaterialProxies"] = proxyManager.RenderMaterialProxies.Values.ToList();
return rootCollection;
//Grabing materials from ProxyManager
rootCollection["renderMaterialProxies"] = proxyManager.RenderMaterialProxies.Values.ToList();
return rootCollection;
}
finally
{
proxyManager.Clear();
}
}
}
@@ -38,13 +38,16 @@ public sealed class Importer(
CancellationToken cancellationToken
)
{
var filePath = new FilePath(args.FilePath);
var stopwatch = Stopwatch.StartNew();
var ifcModel = ifcFactory.Open(args.FilePath);
Console.WriteLine($"Starting processing file : {filePath.GetFileName()}");
var ifcModel = ifcFactory.Open(filePath);
var ms = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"Opened with WebIFC: {ms} ms");
var graph = IfcGraph.Load(new FilePath(args.FilePath));
var graph = IfcGraph.Load(filePath);
var ms2 = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"Loaded with StepParser: {ms2 - ms} ms");
@@ -90,7 +93,15 @@ public sealed class Importer(
);
ms = ms2;
ms2 = stopwatch.ElapsedMilliseconds;
Console.WriteLine($"Committed to Speckle: {ms2 - ms} ms");
Console.WriteLine($"Committed to Speckle: {ms2 - ms} ms - {GetUrl(speckleVersion, modelId)}");
Console.WriteLine();
return speckleVersion;
}
private static string GetUrl(Version version, string modelId)
{
return version.previewUrl.ToString().Replace("preview", "projects").Replace("commits/", $"models/{modelId}@");
}
}
@@ -10,6 +10,8 @@ public sealed class RenderMaterialProxyManager : IRenderMaterialProxyManager
{
public Dictionary<string, RenderMaterialProxy> RenderMaterialProxies { get; } = new();
public void Clear() => RenderMaterialProxies.Clear();
public void AddMeshMapping(RenderMaterial renderMaterial, Mesh mesh)
{
string materialId = renderMaterial.applicationId.NotNull();
+3 -3
View File
@@ -303,11 +303,11 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Performance", "Sdk\
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Testing", "Sdk\Speckle.Testing\Speckle.Testing.csproj", "{02E79865-6261-CDE0-77EA-3DD2E01DACBD}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Objects", "..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects.csproj", "{FBD58ABD-9704-C232-7CF3-D96EC5CFCBE6}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects", "..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects.csproj", "{FBD58ABD-9704-C232-7CF3-D96EC5CFCBE6}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk", "..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk.csproj", "{0201A282-BEFA-8897-C535-03EBAC94870B}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk", "..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk.csproj", "{0201A282-BEFA-8897-C535-03EBAC94870B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Speckle.Sdk.Dependencies", "..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies.csproj", "{0677CA87-027F-D526-4463-3517F75B76EC}"
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies", "..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies.csproj", "{0677CA87-027F-D526-4463-3517F75B76EC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+3 -3
View File
@@ -196,7 +196,7 @@
<Project Path="Sdk\Speckle.Performance\Speckle.Performance.csproj" />
<Project Path="Sdk\Speckle.Testing\Speckle.Testing.csproj" />
</Folder>
<Project Path="../speckle-sharp-sdk/src/Speckle.Objects/Speckle.Objects.csproj" />
<Project Path="../speckle-sharp-sdk/src/Speckle.Sdk.Dependencies/Speckle.Sdk.Dependencies.csproj" />
<Project Path="../speckle-sharp-sdk/src/Speckle.Sdk/Speckle.Sdk.csproj" />
<Project Path="..\speckle-sharp-sdk\src\Speckle.Objects\Speckle.Objects.csproj" />
<Project Path="..\speckle-sharp-sdk\src\Speckle.Sdk.Dependencies\Speckle.Sdk.Dependencies.csproj" />
<Project Path="..\speckle-sharp-sdk\src\Speckle.Sdk\Speckle.Sdk.csproj" />
</Solution>
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net48;net8.0</TargetFrameworks>
<Configurations>Debug;Release;Local</Configurations>
</PropertyGroup>
@@ -61,66 +61,6 @@
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
},
"net6.0": {
"LibTessDotNet": {
"type": "Direct",
"requested": "[1.1.15, )",
"resolved": "1.1.15",
"contentHash": "KuA7N3Nv/lIeawJdQBQJR6oqWD9KETHLbWzBqapwFs+Tby+R5I4crkKujKMm5bXcSuFZ8LNtflFQVadsWCbBjg=="
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.DoubleNumerics": {
"type": "Direct",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
},
"net8.0": {
"LibTessDotNet": {
"type": "Direct",
@@ -0,0 +1,73 @@
using FluentAssertions;
using Moq;
using NUnit.Framework;
using Speckle.Connectors.Common.Operations;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Logging;
namespace Speckle.Connectors.Common.Tests.Operations;
public class ReceiveConversionHandlerTests
{
[Test]
public void TryConvert_ReturnsNullOnSuccess()
{
var activityFactory = new Mock<ISdkActivityFactory>();
var activity = new Mock<ISdkActivity>();
activityFactory.Setup(f => f.Start(It.IsAny<string>(), It.IsAny<string>())).Returns(activity.Object);
var handler = new ReceiveConversionHandler(activityFactory.Object);
Exception? result = handler.TryConvert(
() => { /* success */
}
);
result.Should().BeNull();
activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Ok), Times.Once);
}
[Test]
public void TryConvert_ReturnsConversionException()
{
var activityFactory = new Mock<ISdkActivityFactory>();
var activity = new Mock<ISdkActivity>();
activityFactory.Setup(f => f.Start(It.IsAny<string>(), It.IsAny<string>())).Returns(activity.Object);
var handler = new ReceiveConversionHandler(activityFactory.Object);
var ex = new ConversionException("fail");
Exception? result = handler.TryConvert(() => throw ex);
result.Should().Be(ex);
activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Error), Times.Once);
}
[Test]
public void TryConvert_ThrowsOperationCanceledException()
{
var activityFactory = new Mock<ISdkActivityFactory>();
var activity = new Mock<ISdkActivity>();
activityFactory.Setup(f => f.Start(It.IsAny<string>(), It.IsAny<string>())).Returns(activity.Object);
var handler = new ReceiveConversionHandler(activityFactory.Object);
Assert.Throws<OperationCanceledException>(() => handler.TryConvert(() => throw new OperationCanceledException()));
activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Error), Times.Once);
}
[Test]
public void TryConvert_ReturnsNonFatalException()
{
var activityFactory = new Mock<ISdkActivityFactory>();
var activity = new Mock<ISdkActivity>();
activityFactory.Setup(f => f.Start(It.IsAny<string>(), It.IsAny<string>())).Returns(activity.Object);
var handler = new ReceiveConversionHandler(activityFactory.Object);
#pragma warning disable CA2201
var ex = new Exception("non-fatal");
#pragma warning restore CA2201
Exception? result = handler.TryConvert(() => throw ex);
result.Should().Be(ex);
activity.Verify(a => a.SetStatus(SdkActivityStatusCode.Error), Times.Once);
activity.Verify(a => a.RecordException(ex), Times.Once);
}
}
@@ -35,6 +35,8 @@ public class SendProgressTests : MoqTest
case ProgressEvent.FindingChildren:
sendProgressState.SetupSet(x => x.Total = args.Count);
break;
case ProgressEvent.UploadingObjects:
break;
}
displayManager.Setup(x => x.ShouldUpdate()).Returns(shouldUpdate);
@@ -44,6 +46,7 @@ public class SendProgressTests : MoqTest
{
switch (e)
{
case ProgressEvent.UploadingObjects:
case ProgressEvent.UploadBytes:
sendProgressState.Setup(x => x.PreviouslyFromCacheOrSerialized).Returns(previousFromCacheOrSerialized);
if (previousFromCacheOrSerialized)
@@ -0,0 +1,39 @@
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
using Speckle.Sdk.Common.Exceptions;
using Speckle.Sdk.Logging;
namespace Speckle.Connectors.Common.Operations;
[GenerateAutoInterface]
public class ReceiveConversionHandler(ISdkActivityFactory activityFactory) : IReceiveConversionHandler
{
public Exception? TryConvert(Action conversion)
{
using var convertActivity = activityFactory.Start("Converting object");
try
{
conversion();
convertActivity?.SetStatus(SdkActivityStatusCode.Ok);
return null;
}
catch (ConversionException ce)
{
//handle conversions but don't log to seq
convertActivity?.SetStatus(SdkActivityStatusCode.Error);
return ce;
}
catch (OperationCanceledException)
{
//handle conversions but don't log to seq and also throw
convertActivity?.SetStatus(SdkActivityStatusCode.Error);
throw;
}
catch (Exception ex) when (!ex.IsFatal())
{
convertActivity?.SetStatus(SdkActivityStatusCode.Error);
convertActivity?.RecordException(ex);
return ex;
}
}
}
@@ -1,6 +1,7 @@
using Speckle.Connectors.Common.Builders;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.Logging;
using Speckle.InterfaceGenerator;
using Speckle.Sdk;
using Speckle.Sdk.Api;
using Speckle.Sdk.Credentials;
@@ -10,6 +11,7 @@ using Speckle.Sdk.Models.Extensions;
namespace Speckle.Connectors.Common.Operations;
[GenerateAutoInterface]
public sealed class ReceiveOperation(
IHostObjectBuilder hostObjectBuilder,
IAccountService accountService,
@@ -18,7 +20,7 @@ public sealed class ReceiveOperation(
IOperations operations,
IReceiveVersionRetriever receiveVersionRetriever,
IThreadContext threadContext
)
) : IReceiveOperation
{
public async Task<HostObjectBuilderResult> Execute(
ReceiveInfo receiveInfo,
@@ -102,6 +104,12 @@ public sealed class ReceiveOperation(
conversionActivity?.SetStatus(SdkActivityStatusCode.Ok);
return res;
}
catch (OperationCanceledException)
{
//handle conversions but don't log to seq and also throw
conversionActivity?.SetStatus(SdkActivityStatusCode.Error);
throw;
}
catch (Exception ex)
{
conversionActivity?.RecordException(ex);
@@ -3,6 +3,7 @@ using Speckle.Connectors.Common.Caching;
using Speckle.Connectors.Common.Conversion;
using Speckle.Connectors.Common.Threading;
using Speckle.Connectors.Logging;
using Speckle.InterfaceGenerator;
using Speckle.Sdk.Api;
using Speckle.Sdk.Credentials;
using Speckle.Sdk.Logging;
@@ -12,6 +13,7 @@ using Speckle.Sdk.Serialisation.V2.Send;
namespace Speckle.Connectors.Common.Operations;
[GenerateAutoInterface]
public sealed class SendOperation<T>(
IRootObjectBuilder<T> rootObjectBuilder,
ISendConversionCache sendConversionCache,
@@ -21,7 +23,7 @@ public sealed class SendOperation<T>(
ISendOperationVersionRecorder sendOperationVersionRecorder,
ISdkActivityFactory activityFactory,
IThreadContext threadContext
)
) : ISendOperation<T>
{
public async Task<SendOperationResult> Execute(
IReadOnlyList<T> objects,
@@ -14,23 +14,27 @@ public class SendProgressState : ISendProgressState
public class SendProgress(IProgressDisplayManager progressDisplayManager, ISendProgressState sendProgressState)
: ISendProgress
{
private string? _previousSpeed;
private string _previousSpeed = "unknown";
private double _previousUploaded;
public void Begin() => progressDisplayManager.Begin();
public void Report(IProgress<CardProgress> onOperationProgressed, ProgressArgs args)
{
if (args.ProgressEvent == ProgressEvent.FromCacheOrSerialized)
switch (args.ProgressEvent)
{
sendProgressState.PreviouslyFromCacheOrSerialized = args.Count >= args.Total;
}
else if (args.ProgressEvent == ProgressEvent.FindingChildren)
{
sendProgressState.Total = args.Count;
}
else if (args.ProgressEvent == ProgressEvent.UploadBytes)
{
_previousSpeed = progressDisplayManager.CalculateSpeed(args);
case ProgressEvent.FromCacheOrSerialized:
sendProgressState.PreviouslyFromCacheOrSerialized = args.Count >= args.Total;
break;
case ProgressEvent.FindingChildren:
sendProgressState.Total = args.Count;
break;
case ProgressEvent.UploadBytes:
_previousSpeed = progressDisplayManager.CalculateSpeed(args);
break;
case ProgressEvent.UploadingObjects:
_previousUploaded = args.Count;
break;
}
if (!progressDisplayManager.ShouldUpdate())
{
@@ -48,12 +52,13 @@ public class SendProgress(IProgressDisplayManager progressDisplayManager, ISendP
new($"Caching... ({args.Count} objects)", progressDisplayManager.CalculatePercentage(args))
);
break;
case ProgressEvent.UploadingObjects:
case ProgressEvent.UploadBytes:
if (!sendProgressState.PreviouslyFromCacheOrSerialized)
{
return;
}
onOperationProgressed.Report(new($"Uploading... ({_previousSpeed})", null));
onOperationProgressed.Report(new($"Uploading... {_previousUploaded} ({_previousSpeed})", null));
break;
case ProgressEvent.FromCacheOrSerialized:
var message = $"Serializing... ({args.Count} / {sendProgressState.Total} found objects)";
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net48;net8.0</TargetFrameworks>
<Configurations>Debug;Release;Local</Configurations>
</PropertyGroup>
<ItemGroup>
@@ -317,283 +317,6 @@
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
}
},
"net6.0": {
"Microsoft.Extensions.DependencyInjection": {
"type": "Direct",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "MZtBIwfDFork5vfjpJdG5g8wuJFt7d/y3LOSVVtDK/76wlbtz6cjltfKHqLx2TKVqTj5/c41t77m1+h20zqtPA==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0"
}
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"Speckle.Objects": {
"type": "Direct",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==",
"dependencies": {
"Speckle.Sdk": "3.4.2"
}
},
"Speckle.Sdk": {
"type": "Direct",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.4.2"
}
},
"Speckle.Sdk.Dependencies": {
"type": "Direct",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
},
"GraphQL.Client": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0",
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
"System.Reactive": "5.0.0"
}
},
"GraphQL.Client.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
"dependencies": {
"GraphQL.Primitives": "6.0.0"
}
},
"GraphQL.Client.Abstractions.Websocket": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0"
}
},
"GraphQL.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.CSharp": {
"type": "Transitive",
"resolved": "4.7.0",
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
},
"Microsoft.Data.Sqlite": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "7.0.5",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "2.2.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Primitives": "2.2.0",
"System.ComponentModel.Annotations": "4.5.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==",
"dependencies": {
"System.Memory": "4.5.1",
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Speckle.Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.4"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"System.ComponentModel.Annotations": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Reactive": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"speckle.connectors.logging": {
"type": "Project"
},
"Microsoft.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "2.2.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging.Abstractions": "2.2.0",
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Microsoft.Extensions.Logging.Abstractions": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
},
"Speckle.DoubleNumerics": {
"type": "CentralTransitive",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
}
},
"net8.0": {
"Microsoft.Extensions.DependencyInjection": {
"type": "Direct",
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net48;net8.0</TargetFrameworks>
<Configurations>Debug;Release;Local</Configurations>
</PropertyGroup>
@@ -305,271 +305,6 @@
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
}
},
"net6.0": {
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "B2WqEox8o+4KUOpL7rZPyh6qYjik8tHi2tN8Z9jZkHzED8ElYgZa/h6K+xliB435SqUcWT290Fr2aa8BtZjn8A=="
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"Speckle.Objects": {
"type": "Direct",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "2TcYsGm+vG5mpZj+fiwPJv/4wXtstrWb9FasxsQN2JdUNDKvg1/rVFE9Pby1tPWN+4J0X0QaXutGj0yNwLRe7w==",
"dependencies": {
"Speckle.Sdk": "3.4.2"
}
},
"GraphQL.Client": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "8yPNBbuVBpTptivyAlak4GZvbwbUcjeQTL4vN1HKHRuOykZ4r7l5fcLS6vpyPyLn0x8FsL31xbOIKyxbmR9rbA==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0",
"GraphQL.Client.Abstractions.Websocket": "6.0.0",
"System.Reactive": "5.0.0"
}
},
"GraphQL.Client.Abstractions": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "h7uzWFORHZ+CCjwr/ThAyXMr0DPpzEANDa4Uo54wqCQ+j7qUKwqYTgOrb1W40sqbvNaZm9v/X7It31SUw0maHA==",
"dependencies": {
"GraphQL.Primitives": "6.0.0"
}
},
"GraphQL.Client.Abstractions.Websocket": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "Nr9bPf8gIOvLuXpqEpqr9z9jslYFJOvd0feHth3/kPqeR3uMbjF5pjiwh4jxyMcxHdr8Pb6QiXkV3hsSyt0v7A==",
"dependencies": {
"GraphQL.Client.Abstractions": "6.0.0"
}
},
"GraphQL.Primitives": {
"type": "Transitive",
"resolved": "6.0.0",
"contentHash": "yg72rrYDapfsIUrul7aF6wwNnTJBOFvuA9VdDTQpPa8AlAriHbufeXYLBcodKjfUdkCnaiggX1U/nEP08Zb5GA=="
},
"Microsoft.Bcl.AsyncInterfaces": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "W8DPQjkMScOMTtJbPwmPyj9c3zYSFGawDW3jwlBOOsnY+EzZFLgNQ/UMkK35JmkNOVPdCyPr2Tw7Vv9N+KA3ZQ=="
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.CSharp": {
"type": "Transitive",
"resolved": "4.7.0",
"contentHash": "pTj+D3uJWyN3My70i2Hqo+OXixq3Os2D1nJ2x92FFo6sk8fYS1m1WLNTs0Dc1uPaViH0YvEEwvzddQ7y4rhXmA=="
},
"Microsoft.Data.Sqlite": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "KGxbPeWsQMnmQy43DSBxAFtHz3l2JX8EWBSGUCvT3CuZ8KsuzbkqMIJMDOxWtG8eZSoCDI04aiVQjWuuV8HmSw==",
"dependencies": {
"Microsoft.Data.Sqlite.Core": "7.0.5",
"SQLitePCLRaw.bundle_e_sqlite3": "2.1.4"
}
},
"Microsoft.Data.Sqlite.Core": {
"type": "Transitive",
"resolved": "7.0.5",
"contentHash": "FTerRmQPqHrCrnoUzhBu+E+1DNGwyrAMLqHkAqOOOu5pGfyMOj8qQUBxI/gDtWtG11p49UxSfWmBzRNlwZqfUg==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"Microsoft.Extensions.Configuration": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "nOP8R1mVb/6mZtm2qgAJXn/LFm/2kMjHDAg/QJLFG6CuWYJtaD3p1BwQhufBVvRzL9ceJ/xF0SQ0qsI2GkDQAA==",
"dependencies": {
"Microsoft.Extensions.Configuration.Abstractions": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "65MrmXCziWaQFrI0UHkQbesrX5wTwf9XPjY5yFm/VkgJKFJ5gqvXRoXjIZcf2wLi5ZlwGz/oMYfyURVCWbM5iw==",
"dependencies": {
"Microsoft.Extensions.Primitives": "2.2.0"
}
},
"Microsoft.Extensions.Configuration.Binder": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "vJ9xvOZCnUAIHcGC3SU35r3HKmHTVIeHzo6u/qzlHAqD8m6xv92MLin4oJntTvkpKxVX3vI1GFFkIQtU3AdlsQ==",
"dependencies": {
"Microsoft.Extensions.Configuration": "2.2.0"
}
},
"Microsoft.Extensions.DependencyInjection.Abstractions": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "f9hstgjVmr6rmrfGSpfsVOl2irKAgr1QjrSi3FgnS7kulxband50f2brRLwySAQTADPZeTdow0mpSMcoAdadCw=="
},
"Microsoft.Extensions.Options": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "UpZLNLBpIZ0GTebShui7xXYh6DmBHjWM8NxGxZbdQh/bPZ5e6YswqI+bru6BnEL5eWiOdodsXtEz3FROcgi/qg==",
"dependencies": {
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Primitives": "2.2.0",
"System.ComponentModel.Annotations": "4.5.0"
}
},
"Microsoft.Extensions.Primitives": {
"type": "Transitive",
"resolved": "2.2.0",
"contentHash": "azyQtqbm4fSaDzZHD/J+V6oWMFaf2tWP4WEGIYePLCMw3+b2RQdj9ybgbQyjCshcitQKQ4lEDOZjmSlTTrHxUg==",
"dependencies": {
"System.Memory": "4.5.1",
"System.Runtime.CompilerServices.Unsafe": "4.5.1"
}
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
},
"Speckle.Newtonsoft.Json": {
"type": "Transitive",
"resolved": "13.0.2",
"contentHash": "g1BejUZwax5PRfL6xHgLEK23sqHWOgOj9hE7RvfRRlN00AGt8GnPYt8HedSK7UB3HiRW8zCA9Pn0iiYxCK24BA=="
},
"SQLitePCLRaw.bundle_e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "EWI1olKDjFEBMJu0+3wuxwziIAdWDVMYLhuZ3Qs84rrz+DHwD00RzWPZCa+bLnHCf3oJwuFZIRsHT5p236QXww==",
"dependencies": {
"SQLitePCLRaw.lib.e_sqlite3": "2.1.4",
"SQLitePCLRaw.provider.e_sqlite3": "2.1.4"
}
},
"SQLitePCLRaw.core": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "inBjvSHo9UDKneGNzfUfDjK08JzlcIhn1+SP5Y3m6cgXpCxXKCJDy6Mka7LpgSV+UZmKSnC8rTwB0SQ0xKu5pA==",
"dependencies": {
"System.Memory": "4.5.3"
}
},
"SQLitePCLRaw.lib.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "2C9Q9eX7CPLveJA0rIhf9RXAvu+7nWZu1A2MdG6SD/NOu26TakGgL1nsbc0JAspGijFOo3HoN79xrx8a368fBg=="
},
"SQLitePCLRaw.provider.e_sqlite3": {
"type": "Transitive",
"resolved": "2.1.4",
"contentHash": "CSlb5dUp1FMIkez9Iv5EXzpeq7rHryVNqwJMWnpq87j9zWZexaEMdisDktMsnnrzKM6ahNrsTkjqNodTBPBxtQ==",
"dependencies": {
"SQLitePCLRaw.core": "2.1.4"
}
},
"System.ComponentModel.Annotations": {
"type": "Transitive",
"resolved": "4.5.0",
"contentHash": "UxYQ3FGUOtzJ7LfSdnYSFd7+oEv6M8NgUatatIN2HxNtDdlcvFAf+VIq4Of9cDMJEJC0aSRv/x898RYhB4Yppg=="
},
"System.Memory": {
"type": "Transitive",
"resolved": "4.5.3",
"contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA=="
},
"System.Reactive": {
"type": "Transitive",
"resolved": "5.0.0",
"contentHash": "erBZjkQHWL9jpasCE/0qKAryzVBJFxGHVBAvgRN1bzM0q2s1S4oYREEEL0Vb+1kA/6BKb5FjUZMp5VXmy+gzkQ=="
},
"System.Runtime.CompilerServices.Unsafe": {
"type": "Transitive",
"resolved": "4.5.1",
"contentHash": "Zh8t8oqolRaFa9vmOZfdQm/qKejdqz0J9kr7o2Fu0vPeoH3BL1EOXipKWwkWtLT1JPzjByrF19fGuFlNbmPpiw=="
},
"Microsoft.Extensions.Logging": {
"type": "CentralTransitive",
"requested": "[2.2.0, )",
"resolved": "2.2.0",
"contentHash": "Nxqhadc9FCmFHzU+fz3oc8sFlE6IadViYg8dfUdGzJZ2JUxnCsRghBhhOWdM4B2zSZqEc+0BjliBh/oNdRZuig==",
"dependencies": {
"Microsoft.Extensions.Configuration.Binder": "2.2.0",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging.Abstractions": "2.2.0",
"Microsoft.Extensions.Options": "2.2.0"
}
},
"Speckle.DoubleNumerics": {
"type": "CentralTransitive",
"requested": "[4.1.0, )",
"resolved": "4.1.0",
"contentHash": "20DtS+FsDRsOD9+AU3TwNFZ0qrKo5f6f7B5ZR9wStsIHHHC9k7DpjbCvuNtmnSjx54MD+TJC7wV2f5iyGVPj1A=="
},
"Speckle.Sdk": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "SOjUacHaCt+w19DhSgwQijhcwYZZSgmRVBOLk/O1Lwlq66cHVy3pzyBbsNR8zM+rVAtXrpahf60TjBg2EsD5Zg==",
"dependencies": {
"GraphQL.Client": "6.0.0",
"Microsoft.Bcl.AsyncInterfaces": "5.0.0",
"Microsoft.CSharp": "4.7.0",
"Microsoft.Data.Sqlite": "7.0.5",
"Microsoft.Extensions.DependencyInjection.Abstractions": "2.2.0",
"Microsoft.Extensions.Logging": "2.2.0",
"Speckle.DoubleNumerics": "4.1.0",
"Speckle.Newtonsoft.Json": "13.0.2",
"Speckle.Sdk.Dependencies": "3.4.2"
}
},
"Speckle.Sdk.Dependencies": {
"type": "CentralTransitive",
"requested": "[3.4.2, )",
"resolved": "3.4.2",
"contentHash": "mYjR5i5zaNxkR2VXi2Ills3XG3VZ4z3wLSQBn7GldAudtxI8yS09M6w4ltFNcBmgLlnYHYiIbsWEilIGUbi0Nw=="
}
},
"net8.0": {
"Microsoft.Extensions.Logging.Abstractions": {
"type": "Direct",
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>net48;net6.0;net8.0</TargetFrameworks>
<TargetFrameworks>net48;net8.0</TargetFrameworks>
</PropertyGroup>
<ItemGroup>
@@ -80,85 +80,6 @@
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
},
"net6.0": {
"JetBrains.Profiler.SelfApi": {
"type": "Direct",
"requested": "[2.5.12, )",
"resolved": "2.5.12",
"contentHash": "m0MGIX6Eut9Z5hzqF4gNVn8oK2jeYDe7kihZTtD2/Iy9P7zE+zemO9VisiMD/1I1V8Es7lHOI49HNq9VGut96A==",
"dependencies": {
"JetBrains.HabitatDetector": "1.4.3",
"JetBrains.Profiler.Api": "1.4.8"
}
},
"Microsoft.NETFramework.ReferenceAssemblies": {
"type": "Direct",
"requested": "[1.0.3, )",
"resolved": "1.0.3",
"contentHash": "vUc9Npcs14QsyOD01tnv/m8sQUnGTGOw1BCmKcv77LBJY7OxhJ+zJF7UD/sCL3lYNFuqmQEVlkfS4Quif6FyYg==",
"dependencies": {
"Microsoft.NETFramework.ReferenceAssemblies.net461": "1.0.3"
}
},
"Microsoft.SourceLink.GitHub": {
"type": "Direct",
"requested": "[8.0.0, )",
"resolved": "8.0.0",
"contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
"dependencies": {
"Microsoft.Build.Tasks.Git": "8.0.0",
"Microsoft.SourceLink.Common": "8.0.0"
}
},
"PolySharp": {
"type": "Direct",
"requested": "[1.14.1, )",
"resolved": "1.14.1",
"contentHash": "mOOmFYwad3MIOL14VCjj02LljyF1GNw1wP0YVlxtcPvqdxjGGMNdNJJxHptlry3MOd8b40Flm8RPOM8JOlN2sQ=="
},
"Speckle.InterfaceGenerator": {
"type": "Direct",
"requested": "[0.9.6, )",
"resolved": "0.9.6",
"contentHash": "HKH7tYrYYlCK1ct483hgxERAdVdMtl7gUKW9ijWXxA1UsYR4Z+TrRHYmzZ9qmpu1NnTycSrp005NYM78GDKV1w=="
},
"JetBrains.FormatRipper": {
"type": "Transitive",
"resolved": "2.2.2",
"contentHash": "UvbPJM1ryALWSrnMX428ZxLujOrSAxdCgSwr1/7A0mFFxM8Rxku0OjN+zZENmZQ6Hirm7StkC176qy0m30UgjQ=="
},
"JetBrains.HabitatDetector": {
"type": "Transitive",
"resolved": "1.4.3",
"contentHash": "4VC4sP/T+16MwsfUjwbKVYwKEOEu9cdQxLvN9uUiIm17m2y1SlV4Aj29HKsFbFyCbTePOGQMw3ccoPuym6d+EQ==",
"dependencies": {
"JetBrains.FormatRipper": "2.2.2"
}
},
"JetBrains.Profiler.Api": {
"type": "Transitive",
"resolved": "1.4.8",
"contentHash": "hH0Hej/hjwTn14yhhzEcGaB3HJ40C/CwW2E8RrhsqCcBg5bs50LQFOx2a5dFXjWDMzspAso5xADtQmBI6lXKTw==",
"dependencies": {
"JetBrains.HabitatDetector": "1.4.3"
}
},
"Microsoft.Build.Tasks.Git": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
},
"Microsoft.NETFramework.ReferenceAssemblies.net461": {
"type": "Transitive",
"resolved": "1.0.3",
"contentHash": "AmOJZwCqnOCNp6PPcf9joyogScWLtwy0M1WkqfEQ0M9nYwyDD7EX9ZjscKS5iYnyvteX7kzSKFCKt9I9dXA6mA=="
},
"Microsoft.SourceLink.Common": {
"type": "Transitive",
"resolved": "8.0.0",
"contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
}
},
"net8.0": {
"JetBrains.Profiler.SelfApi": {
"type": "Direct",
+43
View File
@@ -0,0 +1,43 @@
<Solution>
<Configurations>
<BuildType Name="Debug" />
<BuildType Name="Local" />
<BuildType Name="Release" />
</Configurations>
<Folder Name="/Build/">
<Project Path="Build\Build.csproj" />
<File Path=".github\workflows\pr.yml" />
<File Path=".github\workflows\release.yml" />
</Folder>
<Folder Name="/Config/">
<File Path=".csharpierrc.yaml" />
<File Path=".editorconfig" />
<File Path="codecov.yml" />
<File Path="CodeMetricsConfig.txt" />
<File Path="Directory.Build.props" />
<File Path="Directory.Packages.props" />
<File Path=".config\dotnet-tools.json" />
<File Path="global.json" />
<File Path="README.md" />
</Folder>
<Folder Name="/Connectors/" />
<Folder Name="/Importers/" />
<Folder Name="/Importers/Ifc/">
<Project Path="Importers\Ifc\Speckle.Importers.Ifc.Tester2\Speckle.Importers.Ifc.Tester2.csproj" />
<Project Path="Importers\Ifc\Speckle.Importers.Ifc.Tester\Speckle.Importers.Ifc.Tester.csproj" />
<Project Path="Importers\Ifc\Speckle.Importers.Ifc\Speckle.Importers.Ifc.csproj" />
</Folder>
<Folder Name="/Sdk/">
<Project Path="DUI3\Speckle.Connectors.DUI.Tests\Speckle.Connectors.DUI.Tests.csproj" />
<Project Path="DUI3\Speckle.Connectors.DUI.WebView\Speckle.Connectors.DUI.WebView.csproj" />
<Project Path="DUI3\Speckle.Connectors.DUI\Speckle.Connectors.DUI.csproj" />
<Project Path="Sdk\Speckle.Common.MeshTriangulation\Speckle.Common.MeshTriangulation.csproj" />
<Project Path="Sdk\Speckle.Connectors.Common.Tests\Speckle.Connectors.Common.Tests.csproj" />
<Project Path="Sdk\Speckle.Connectors.Common\Speckle.Connectors.Common.csproj" />
<Project Path="Sdk\Speckle.Connectors.Logging\Speckle.Connectors.Logging.csproj" />
<Project Path="Sdk\Speckle.Converters.Common.Tests\Speckle.Converters.Common.Tests.csproj" />
<Project Path="Sdk\Speckle.Converters.Common\Speckle.Converters.Common.csproj" />
<Project Path="Sdk\Speckle.Performance\Speckle.Performance.csproj" />
<Project Path="Sdk\Speckle.Testing\Speckle.Testing.csproj" />
</Folder>
</Solution>

Some files were not shown because too many files have changed in this diff Show More