├── ui ├── public │ ├── robots.txt │ ├── favicon.ico │ ├── img │ │ └── icons │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── mstile-150x150.png │ │ │ ├── apple-touch-icon.png │ │ │ ├── android-chrome-192x192.png │ │ │ ├── android-chrome-512x512.png │ │ │ ├── apple-touch-icon-120x120.png │ │ │ ├── apple-touch-icon-152x152.png │ │ │ ├── apple-touch-icon-180x180.png │ │ │ ├── apple-touch-icon-60x60.png │ │ │ ├── apple-touch-icon-76x76.png │ │ │ ├── msapplication-icon-144x144.png │ │ │ ├── android-chrome-maskable-192x192.png │ │ │ ├── android-chrome-maskable-512x512.png │ │ │ └── safari-pinned-tab.svg │ └── index.html ├── .browserslistrc ├── babel.config.js ├── src │ ├── assets │ │ ├── Sender.png │ │ ├── Receiver.png │ │ ├── SenderWhite.png │ │ ├── brick_white.png │ │ ├── ReceiverWhite.png │ │ └── logo.svg │ ├── graphql │ │ ├── serverInfo.gql │ │ ├── userById.gql │ │ ├── user.gql │ │ ├── stream.gql │ │ └── streams.gql │ ├── router │ │ └── index.js │ ├── utils │ │ └── groupBy.js │ ├── views │ │ └── Login.vue │ ├── main.js │ └── plugins │ │ └── vuetify.js ├── .env.example ├── vue.config.js ├── .gitignore ├── .prettierrc ├── README.md ├── .eslintrc.js ├── apollo.config.js └── package.json ├── .DS_Store ├── .gitmodules ├── _tools ├── jf_RubyPanel │ ├── reload.png │ ├── Delete24.png │ ├── doc_ruby.png │ ├── rubypanel.png │ └── open_folder.png ├── su_attributes │ ├── extension_info.txt │ └── su_attributes.susig ├── debugger │ └── skippy_exec_2024.rb ├── README.md └── jf_RubyPanel.rb ├── speckle_connector_3 ├── .DS_Store ├── src │ ├── .DS_Store │ ├── ext │ │ ├── sqlite3 │ │ │ ├── sqlite3_27.so │ │ │ ├── sqlite3_32.so │ │ │ ├── sqlite3_27.bundle │ │ │ └── sqlite3_32.bundle │ │ ├── immutable_ruby │ │ │ ├── undefined.rb │ │ │ ├── json.rb │ │ │ ├── core.rb │ │ │ └── LICENSE │ │ └── sqlite3.rb │ ├── constants │ │ ├── geo_constants.rb │ │ ├── observer_constants.rb │ │ ├── dict_constants.rb │ │ ├── mat_constants.rb │ │ ├── platform_constants.rb │ │ ├── path_constants.rb │ │ └── pref_constants.rb │ ├── convertors │ │ ├── units.rb │ │ ├── conversion_error.rb │ │ ├── converter.rb │ │ └── converter_v2.rb │ ├── log │ │ └── log.rb │ ├── ui_data │ │ ├── sketchup │ │ │ └── selection_info.rb │ │ └── components │ │ │ └── selections │ │ │ ├── selection.rb │ │ │ ├── list_selection_item.rb │ │ │ └── list_selection.rb │ ├── commands │ │ ├── send_selection.rb │ │ ├── activate_diffing.rb │ │ ├── save_stream.rb │ │ ├── notify_connected.rb │ │ ├── clear_mappings.rb │ │ ├── model_preferences_updated.rb │ │ ├── remove_stream.rb │ │ ├── mapper_source_updated.rb │ │ ├── user_preferences_updated.rb │ │ ├── reset_window_location.rb │ │ ├── action_command.rb │ │ ├── receive_objects.rb │ │ ├── apply_mappings.rb │ │ └── command.rb │ ├── speckle_objects │ │ ├── data │ │ │ ├── data_object.rb │ │ │ └── revit_data_object.rb │ │ ├── available_speckle_objects.rb │ │ ├── geometry │ │ │ ├── polycurve.rb │ │ │ ├── length.rb │ │ │ ├── vector.rb │ │ │ ├── plane.rb │ │ │ └── circle.rb │ │ ├── built_elements │ │ │ ├── revit │ │ │ │ ├── parameter.rb │ │ │ │ ├── family_instance.rb │ │ │ │ └── revit_element_type.rb │ │ │ ├── network.rb │ │ │ ├── default_beam.rb │ │ │ ├── default_duct.rb │ │ │ ├── default_pipe.rb │ │ │ └── default_column.rb │ │ ├── other │ │ │ ├── mapped_block_wrapper.rb │ │ │ ├── rendering_options.rb │ │ │ └── display_style.rb │ │ ├── object_reference.rb │ │ ├── gis │ │ │ └── utils.rb │ │ ├── speckle │ │ │ └── core │ │ │ │ └── models │ │ │ │ ├── gis_layer_collection.rb │ │ │ │ └── collection.rb │ │ ├── revit │ │ │ └── revit_definition.rb │ │ ├── base.rb │ │ ├── primitive │ │ │ └── interval.rb │ │ ├── color_proxy.rb │ │ └── render_material_proxy.rb │ ├── actions │ │ ├── connected.rb │ │ ├── action.rb │ │ ├── clear_queue.rb │ │ ├── events │ │ │ ├── on_document_changed.rb │ │ │ └── event_action.rb │ │ ├── config_actions │ │ │ ├── get_is_dev_mode.rb │ │ │ ├── set_user_selected_account_id.rb │ │ │ ├── get_config.rb │ │ │ ├── get_user_selected_account_id.rb │ │ │ └── update_config.rb │ │ ├── test_actions │ │ │ ├── go_away.rb │ │ │ ├── get_complex_type.rb │ │ │ ├── say_hi.rb │ │ │ └── trigger_event.rb │ │ ├── base_actions │ │ │ ├── get_source_app_name.rb │ │ │ ├── get_connector_version.rb │ │ │ ├── get_source_app_version.rb │ │ │ ├── highlight_objects.rb │ │ │ ├── get_send_filters.rb │ │ │ ├── update_send_filter.rb │ │ │ ├── get_send_settings.rb │ │ │ ├── add_model.rb │ │ │ ├── highlight_model.rb │ │ │ ├── remove_model.rb │ │ │ └── remove_models.rb │ │ ├── show_all_entities.rb │ │ ├── collect_preferences.rb │ │ ├── sketchup_config_actions │ │ │ ├── update_user_config.rb │ │ │ └── get_user_config.rb │ │ ├── load_saved_streams.rb │ │ ├── receive_actions │ │ │ ├── before_receive.rb │ │ │ └── after_receive.rb │ │ ├── collect_versions.rb │ │ ├── init_local_accounts.rb │ │ ├── account_actions │ │ │ ├── remove_account.rb │ │ │ ├── add_account.rb │ │ │ └── get_accounts.rb │ │ ├── mapped_entities_updated.rb │ │ ├── mapper_initialized.rb │ │ ├── get_document_info.rb │ │ ├── reload_accounts.rb │ │ ├── save_stream.rb │ │ ├── remove_stream.rb │ │ ├── send_from_queue.rb │ │ ├── deactivate_diffing.rb │ │ ├── send_actions │ │ │ ├── activate_send_filter.rb │ │ │ ├── activate_send_filter_tag.rb │ │ │ └── send_card_expiration_check.rb │ │ ├── queue_send.rb │ │ ├── initialize_materials.rb │ │ ├── clear_mapper_source.rb │ │ ├── selection_actions │ │ │ └── get_selection.rb │ │ ├── receive_bindings │ │ │ └── receive.rb │ │ ├── model_preference_updated.rb │ │ ├── activate_diffing.rb │ │ ├── handle_error.rb │ │ ├── on_events_action.rb │ │ └── hide_mappings_from_table.rb │ ├── filters │ │ ├── filter.rb │ │ ├── tag.rb │ │ ├── search_filter.rb │ │ ├── tag_filter.rb │ │ └── send │ │ │ ├── everything_filter.rb │ │ │ ├── layer_filter.rb │ │ │ └── selection_filter.rb │ ├── observers │ │ ├── model_observer.rb │ │ ├── entity_observer.rb │ │ ├── event_handler.rb │ │ ├── event_hash.rb │ │ ├── app_observer.rb │ │ ├── entities_observer.rb │ │ ├── factory.rb │ │ └── event_observer.rb │ ├── ui │ │ ├── bindings │ │ │ ├── selection_binding.rb │ │ │ ├── receive_binding.rb │ │ │ ├── binding.rb │ │ │ ├── accounts_binding.rb │ │ │ ├── send_binding.rb │ │ │ └── config_binding.rb │ │ ├── send_binding_old.rb │ │ ├── sketchup_config_binding.rb │ │ ├── sketchup_ui.rb │ │ ├── receive_binding.rb │ │ ├── command_data.rb │ │ ├── ui_controller.rb │ │ └── test_binding.rb │ ├── states │ │ ├── initial_state.rb │ │ ├── user_state.rb │ │ └── speckle_mapper_state.rb │ ├── cards │ │ └── send_card_multiple_filters.rb │ ├── speckle_entities │ │ └── speckle_entity_status.rb │ ├── sketchup_model │ │ ├── dictionary │ │ │ ├── speckle_model_dictionary_handler.rb │ │ │ ├── speckle_schema_dictionary_handler.rb │ │ │ └── speckle_entity_dictionary_handler.rb │ │ ├── colors │ │ │ └── color_manager.rb │ │ └── utils │ │ │ └── view_utils.rb │ ├── operations │ │ └── receive.rb │ ├── immutable │ │ └── immutable.rb │ └── mapper │ │ └── mapper_source.rb ├── img │ ├── Sender.png │ ├── s2logo.png │ ├── Receiver.png │ ├── s2logo_dui3.png │ ├── ReceiverWhite32.png │ ├── SenderWhite32.png │ ├── SenderWhite@20.png │ ├── ReceiverWhite@20.png │ ├── CreateStreamWhite@32.png │ └── CreateStreamWhite@64.png ├── debug.rb └── bootstrap.rb ├── tests ├── test_helper.rb └── src │ ├── speckle_objects │ ├── geometry │ │ ├── point_test.rb │ │ └── vector_test.rb │ └── test_base.rb │ ├── converters │ └── test_base_object_serializer.rb │ └── operations │ └── test_receive.rb ├── .solargraph.yml ├── GitVersion.yml ├── .circleci └── config.yml ├── .github ├── PULL_REQUEST_TEMPLATE │ └── PR_TEMPLATE.md ├── ISSUE_TEMPLATE │ └── ISSUE_TEMPLATE.md └── workflows │ └── deploy.yml ├── .vscode ├── launch.json └── tasks.json ├── speckle_connector_3.rb └── Gemfile /ui/public/robots.txt: -------------------------------------------------------------------------------- 1 | User-agent: * 2 | Disallow: 3 | -------------------------------------------------------------------------------- /ui/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/.DS_Store -------------------------------------------------------------------------------- /ui/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: ['@vue/cli-plugin-babel/preset'] 3 | } 4 | -------------------------------------------------------------------------------- /ui/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/favicon.ico -------------------------------------------------------------------------------- /ui/src/assets/Sender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/src/assets/Sender.png -------------------------------------------------------------------------------- /ui/src/graphql/serverInfo.gql: -------------------------------------------------------------------------------- 1 | query{ 2 | serverInfo { 3 | name 4 | canonicalUrl 5 | } 6 | } -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "_sqlite3"] 2 | path = _sqlite3 3 | url = git@github.com:specklesystems/sketchup-sqlite3.git 4 | -------------------------------------------------------------------------------- /ui/src/assets/Receiver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/src/assets/Receiver.png -------------------------------------------------------------------------------- /_tools/jf_RubyPanel/reload.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/_tools/jf_RubyPanel/reload.png -------------------------------------------------------------------------------- /speckle_connector_3/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/.DS_Store -------------------------------------------------------------------------------- /ui/.env.example: -------------------------------------------------------------------------------- 1 | VUE_APP_DEV_TOKEN= 2 | VUE_APP_SPECKLE_NAME=SpeckleSketchup 3 | VUE_APP_DEFAULT_SERVER=https://latest.speckle.dev -------------------------------------------------------------------------------- /ui/src/assets/SenderWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/src/assets/SenderWhite.png -------------------------------------------------------------------------------- /ui/src/assets/brick_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/src/assets/brick_white.png -------------------------------------------------------------------------------- /_tools/jf_RubyPanel/Delete24.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/_tools/jf_RubyPanel/Delete24.png -------------------------------------------------------------------------------- /_tools/jf_RubyPanel/doc_ruby.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/_tools/jf_RubyPanel/doc_ruby.png -------------------------------------------------------------------------------- /_tools/jf_RubyPanel/rubypanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/_tools/jf_RubyPanel/rubypanel.png -------------------------------------------------------------------------------- /speckle_connector_3/src/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/src/.DS_Store -------------------------------------------------------------------------------- /ui/src/assets/ReceiverWhite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/src/assets/ReceiverWhite.png -------------------------------------------------------------------------------- /_tools/jf_RubyPanel/open_folder.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/_tools/jf_RubyPanel/open_folder.png -------------------------------------------------------------------------------- /_tools/su_attributes/extension_info.txt: -------------------------------------------------------------------------------- 1 | ID=f4d9d053-4479-4a9a-90da-b79fa16e28c4 2 | VERSION_ID=b787af5e-8e8e-4932-92ef-a3c99681795d 3 | -------------------------------------------------------------------------------- /speckle_connector_3/img/Sender.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/Sender.png -------------------------------------------------------------------------------- /speckle_connector_3/img/s2logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/s2logo.png -------------------------------------------------------------------------------- /speckle_connector_3/img/Receiver.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/Receiver.png -------------------------------------------------------------------------------- /ui/public/img/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/favicon-16x16.png -------------------------------------------------------------------------------- /ui/public/img/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/favicon-32x32.png -------------------------------------------------------------------------------- /ui/public/img/icons/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/mstile-150x150.png -------------------------------------------------------------------------------- /_tools/su_attributes/su_attributes.susig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/_tools/su_attributes/su_attributes.susig -------------------------------------------------------------------------------- /speckle_connector_3/img/s2logo_dui3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/s2logo_dui3.png -------------------------------------------------------------------------------- /ui/public/img/icons/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/apple-touch-icon.png -------------------------------------------------------------------------------- /speckle_connector_3/img/ReceiverWhite32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/ReceiverWhite32.png -------------------------------------------------------------------------------- /speckle_connector_3/img/SenderWhite32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/SenderWhite32.png -------------------------------------------------------------------------------- /speckle_connector_3/img/SenderWhite@20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/SenderWhite@20.png -------------------------------------------------------------------------------- /speckle_connector_3/img/ReceiverWhite@20.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/ReceiverWhite@20.png -------------------------------------------------------------------------------- /speckle_connector_3/img/CreateStreamWhite@32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/CreateStreamWhite@32.png -------------------------------------------------------------------------------- /speckle_connector_3/img/CreateStreamWhite@64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/img/CreateStreamWhite@64.png -------------------------------------------------------------------------------- /ui/public/img/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /ui/public/img/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /ui/public/img/icons/apple-touch-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/apple-touch-icon-120x120.png -------------------------------------------------------------------------------- /ui/public/img/icons/apple-touch-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/apple-touch-icon-152x152.png -------------------------------------------------------------------------------- /ui/public/img/icons/apple-touch-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/apple-touch-icon-180x180.png -------------------------------------------------------------------------------- /ui/public/img/icons/apple-touch-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/apple-touch-icon-60x60.png -------------------------------------------------------------------------------- /ui/public/img/icons/apple-touch-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/apple-touch-icon-76x76.png -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/sqlite3/sqlite3_27.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/src/ext/sqlite3/sqlite3_27.so -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/sqlite3/sqlite3_32.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/src/ext/sqlite3/sqlite3_32.so -------------------------------------------------------------------------------- /ui/public/img/icons/msapplication-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/msapplication-icon-144x144.png -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/geo_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | VECTOR_Z = Geom::Vector3d.new(0, 0, 1) 5 | end 6 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/sqlite3/sqlite3_27.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/src/ext/sqlite3/sqlite3_27.bundle -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/sqlite3/sqlite3_32.bundle: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/speckle_connector_3/src/ext/sqlite3/sqlite3_32.bundle -------------------------------------------------------------------------------- /tests/test_helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Require this file in all tests 4 | require 'simplecov' 5 | SimpleCov.start 6 | 7 | require 'minitest/autorun' 8 | -------------------------------------------------------------------------------- /ui/public/img/icons/android-chrome-maskable-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/android-chrome-maskable-192x192.png -------------------------------------------------------------------------------- /ui/public/img/icons/android-chrome-maskable-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/specklesystems/speckle-sketchup/HEAD/ui/public/img/icons/android-chrome-maskable-512x512.png -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/immutable_ruby/undefined.rb: -------------------------------------------------------------------------------- 1 | module SpeckleConnector3 2 | module Immutable 3 | # @private 4 | module Undefined 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /.solargraph.yml: -------------------------------------------------------------------------------- 1 | require_paths: 2 | - "C:/Program Files/SketchUp/SketchUp 2021/Tools" 3 | - speckle_connector_3 4 | 5 | require: 6 | - sketchup-api-stubs 7 | 8 | reporters: 9 | - rubocop -------------------------------------------------------------------------------- /ui/src/graphql/userById.gql: -------------------------------------------------------------------------------- 1 | query User($id: String!) { 2 | user(id: $id) { 3 | id 4 | email 5 | name 6 | bio 7 | company 8 | avatar 9 | verified 10 | profiles 11 | role 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /GitVersion.yml: -------------------------------------------------------------------------------- 1 | workflow: GitFlow/v1 2 | next-version: 3.0.0 3 | mode: ManualDeployment 4 | branches: 5 | main: 6 | label: rc 7 | develop: 8 | regex: ^dui3/alpha$ 9 | label: beta 10 | unknown: 11 | increment: None 12 | -------------------------------------------------------------------------------- /ui/vue.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | module.exports = { 4 | publicPath: './', 5 | outputDir: path.resolve(__dirname, '../speckle_connector_3', 'vue_ui'), 6 | transpileDependencies: ['vuetify', '@speckle/objectloader'] 7 | } 8 | -------------------------------------------------------------------------------- /ui/public/img/icons/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /ui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /ui/.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "none", 3 | "tabWidth": 2, 4 | "semi": false, 5 | "endOfLine": "auto", 6 | "bracketSpacing": true, 7 | "eslintIntegration": true, 8 | "jsxBracketSameLine": true, 9 | "vueIndentScriptAndStyle": false, 10 | "htmlWhitespaceSensitivity": "ignore", 11 | "printWidth": 100, 12 | "singleQuote": true 13 | } 14 | -------------------------------------------------------------------------------- /ui/src/graphql/user.gql: -------------------------------------------------------------------------------- 1 | query { 2 | user { 3 | id 4 | email 5 | name 6 | bio 7 | company 8 | avatar 9 | verified 10 | profiles 11 | role 12 | streams { 13 | totalCount 14 | } 15 | commits(limit: 1) { 16 | totalCount 17 | items { 18 | id 19 | createdAt 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | version: 2.1 2 | 3 | # Define the jobs we want to run for this project 4 | jobs: 5 | build: 6 | docker: 7 | - image: cimg/base:2023.03 8 | steps: 9 | - run: echo "so long and thanks for all the fish" 10 | 11 | # Orchestrate our job run sequence 12 | workflows: 13 | build_and_test: 14 | when: 15 | false 16 | jobs: 17 | - build 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/convertors/units.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Converters 5 | SKETCHUP_UNITS = { 0 => 'in', 1 => 'ft', 2 => 'mm', 3 => 'cm', 4 => 'm', 5 => 'yd' }.freeze 6 | SKETCHUP_UNIT_STRINGS = { 'm' => 'm', 'mm' => 'mm', 'ft' => 'feet', 'in' => 'inch', 'yd' => 'yard', 7 | 'cm' => 'cm' }.freeze 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /speckle_connector_3/src/log/log.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | # Helper module for logging. 5 | module Log 6 | def self.write_to_file(text, file_name = 'log', path = "#{ENV['HOME']}/Desktop") 7 | file_path = path + "/#{file_name}.json" 8 | File.delete(file_path) if File.exist?(file_path) 9 | File.write(file_path, text) 10 | end 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /ui/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | 4 | Vue.use(VueRouter) 5 | 6 | const routes = [ 7 | { 8 | path: '*', 9 | name: 'Streams', 10 | component: () => import('../views/Streams.vue') 11 | }, 12 | ] 13 | 14 | const router = new VueRouter({ 15 | mode: 'history', 16 | base: process.env.BASE_URL, 17 | routes 18 | }) 19 | 20 | export default router 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/sqlite3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../constants/platform_constants' 4 | 5 | module SpeckleConnector3 6 | extension = if OPERATING_SYSTEM == OS_WIN 7 | 'so' 8 | else 9 | 'bundle' 10 | end 11 | sqlite3_file = "sqlite3_#{RUBY_VERSION_NUMBER}.#{extension}" 12 | require_relative(File.join('sqlite3', sqlite3_file)) 13 | end 14 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui_data/sketchup/selection_info.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module UiData 5 | module Sketchup 6 | class SelectionInfo < Hash 7 | def initialize(selected_object_ids, summary) 8 | super() 9 | self[:selectedObjectIds] = selected_object_ids 10 | self[:summary] = summary 11 | end 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /ui/README.md: -------------------------------------------------------------------------------- 1 | # ui 2 | 3 | ## Project setup 4 | 5 | ``` 6 | npm install 7 | ``` 8 | 9 | ### Compiles and hot-reloads for development 10 | 11 | ``` 12 | npm run serve 13 | ``` 14 | 15 | ### Compiles and minifies for production 16 | 17 | ``` 18 | npm run build 19 | ``` 20 | 21 | ### Lints and fixes files 22 | 23 | ``` 24 | npm run lint 25 | ``` 26 | 27 | ### Customize configuration 28 | 29 | See [Configuration Reference](https://cli.vuejs.org/config/). 30 | -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/observer_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | APP_OBSERVER = 'SpeckleConnector3::Observers::AppObserver' 5 | ENTITIES_OBSERVER = 'SpeckleConnector3::Observers::EntitiesObserver' 6 | ENTITY_OBSERVER = 'SpeckleConnector3::Observers::EntityObserver' 7 | MODEL_OBSERVER = 'SpeckleConnector3::Observers::ModelObserver' 8 | SELECTION_OBSERVER = 'SpeckleConnector3::Observers::SelectionObserver' 9 | end 10 | -------------------------------------------------------------------------------- /ui/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /* eslint-env node */ 2 | 3 | /** @type {import("eslint").Linter.Config} */ 4 | const config = { 5 | env: { 6 | browser: true, 7 | es2021: true, 8 | commonjs: false 9 | }, 10 | ignorePatterns: ['nginx'], 11 | extends: ['plugin:vue/recommended', 'eslint:recommended', 'prettier', 'prettier/vue'], 12 | parserOptions: { 13 | sourceType: 'module' 14 | }, 15 | plugins: ['vue'], 16 | rules: { 'no-console': 1 } 17 | } 18 | 19 | module.exports = config 20 | -------------------------------------------------------------------------------- /ui/src/utils/groupBy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Group by function definition to call it on demand. 3 | * @example 4 | * const groupByBrand = groupBy('brand') 5 | * const groupedByBrands1 = groupByBrand(array1) 6 | * const groupedByBrands2 = groupByBrand(array2) 7 | */ 8 | export const groupBy = key => array => 9 | array.reduce((objectsByKeyValue, obj) => { 10 | const value = obj[key]; 11 | objectsByKeyValue[value] = (objectsByKeyValue[value] || []).concat(obj); 12 | return objectsByKeyValue; 13 | }, {}); -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/send_selection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/send_selection' 5 | 6 | module SpeckleConnector3 7 | module Commands 8 | # Command to send selection to Speckle Server. 9 | class SendSelection < Command 10 | def _run(_resolve_id, data) 11 | stream_id = data['stream_id'] 12 | action = Actions::SendSelection.new(stream_id) 13 | app.update_state!(action) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/activate_diffing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/activate_diffing' 5 | 6 | module SpeckleConnector3 7 | module Commands 8 | # Command to activate diffing for stream. 9 | class ActivateDiffing < Command 10 | def _run(_resolve_id, data) 11 | stream_id = data['stream_id'] 12 | action = Actions::ActivateDiffing.new(stream_id) 13 | app.update_state!(action) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/data/data_object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | class DataObject < Base 9 | SPECKLE_TYPE = SPECKLE_OBJECT_DATA_OBJECT 10 | 11 | def self.to_native(state, data_object, layer, _entities, &convert_to_native) 12 | properties = data_object['properties'] 13 | return state 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/connected.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Actions 5 | # Action to update connected state of application. 6 | class Connected < Action 7 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 8 | # @return [States::State] the new updated state object 9 | def self.update_state(state) 10 | puts 'Speckle connected!' 11 | state.with(:@connected => true) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/action.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Actions 5 | # State changer object. 6 | class Action 7 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 8 | # @param parameters [Array] parameters that the action takes 9 | # @return [States::State] the new updated state object 10 | def self.update_state(_state, *_parameters) 11 | raise NotImplementedError, 'Implement in subclass.' 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/save_stream.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../accounts/accounts' 5 | require_relative '../actions/save_stream' 6 | require_relative '../actions/load_saved_streams' 7 | 8 | module SpeckleConnector3 9 | module Commands 10 | # Command to saved stream. 11 | class SaveStream < Command 12 | def _run(_resolve_id, data) 13 | stream_id = data['stream_id'] 14 | app.update_state!(Actions::SaveStream.new(stream_id)) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | 4 | module SpeckleConnector3 5 | module Filters 6 | # Base filters for sketchup connector. 7 | class Filter < Hash 8 | # @return [String] id of the filter 9 | attr_reader :id 10 | 11 | # @return [String] name of the filter 12 | attr_reader :name 13 | 14 | def initialize(id, name) 15 | super() 16 | @id = id 17 | @name = name 18 | self[:id] = id 19 | self[:name] = name 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Filters 5 | # Tag definition for filters for sketchup connector. 6 | class Tag < Hash 7 | attr_reader :id 8 | attr_reader :name 9 | attr_reader :color 10 | 11 | def initialize(id, name, color) 12 | super() 13 | @id = id 14 | @name = name 15 | @color = color 16 | self[:id] = id 17 | self[:name] = name 18 | self[:color] = color 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/model_observer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'event_observer' 4 | 5 | module SpeckleConnector3 6 | module Observers 7 | # Model related event observers. 8 | class ModelObserver < Sketchup::ModelObserver 9 | include EventObserver 10 | 11 | # rubocop:disable Naming/MethodName 12 | # @param model (Sketchup::Model) 13 | def onActivePathChanged(model) 14 | push_event(:onActivePathChanged, model) 15 | end 16 | # rubocop:enable Naming/MethodName 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/notify_connected.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/connected' 5 | require_relative '../actions/send_from_queue' 6 | 7 | module SpeckleConnector3 8 | module Commands 9 | # Command to notify connected. 10 | class NotifyConnected < Command 11 | def _run(_resolve_id, data) 12 | stream_id = data['stream_id'] 13 | app.update_state!(Actions::Connected) 14 | app.update_state!(Actions::SendFromQueue.new(stream_id)) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/search_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'filter' 4 | 5 | module SpeckleConnector3 6 | module Filters 7 | # Search filters for sketchup connector. 8 | # TODO: LATER! 9 | class SearchFilter < Filter 10 | # @return [Array] id of the filter 11 | attr_reader :tags 12 | 13 | def initialize(id, name, input, duplicable, tags, active_tags) 14 | super(id, name, input, duplicable) 15 | @tags = tags 16 | @active_tags = active_tags 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/bindings/selection_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'binding' 4 | require_relative '../../actions/selection_actions/get_selection' 5 | 6 | module SpeckleConnector3 7 | module Ui 8 | SELECTION_BINDING_NAME = 'selectionBinding' 9 | 10 | # Selection binding that provided for DUI. 11 | class SelectionBinding < Binding 12 | def commands 13 | @commands ||= { 14 | getSelection: Commands::ActionCommand.new(@app, self, Actions::GetSelection) 15 | }.freeze 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/clear_queue.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Clear queue from state. 8 | class ClearQueue < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state) 12 | new_speckle_state = state.speckle_state.with(:@message_queue => {}) 13 | state.with(:@speckle_state => new_speckle_state) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/events/on_document_changed.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Actions 5 | # Triggers whenever document has changed. 6 | class OnDocumentChanged < Action 7 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 8 | # @return [States::State] the new updated state object 9 | def self.update_state(state) 10 | js_command = "baseBinding.emit('documentChanged')" 11 | state.with_add_queue_js_command('documentChanged', js_command) 12 | end 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/entity_observer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'event_observer' 4 | 5 | module SpeckleConnector3 6 | module Observers 7 | # Entity observer. 8 | class EntityObserver < Sketchup::EntityObserver 9 | include EventObserver 10 | 11 | # rubocop:disable Naming/MethodName 12 | # @param entity (Sketchup::Entity) 13 | def onChangeEntity(entity) 14 | puts "onChangeEntity: #{entity}" 15 | push_event(:onChangeEntity, entity) 16 | end 17 | # rubocop:enable Naming/MethodName 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/clear_mappings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/clear_mappings' 5 | 6 | module SpeckleConnector3 7 | module Commands 8 | # Command to clear mapping for selected entities. 9 | class ClearMappings < Command 10 | def _run(_resolve_id, data) 11 | entities_to_map = data['entitiesToClearMap'] 12 | is_definition = data['isDefinition'] 13 | action = Actions::ClearMappings.new(entities_to_map, is_definition) 14 | app.update_state!(action) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/model_preferences_updated.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../accounts/accounts' 5 | require_relative '../actions/model_preference_updated' 6 | 7 | module SpeckleConnector3 8 | module Commands 9 | # Command to update theme. 10 | class ModelPreferencesUpdated < Command 11 | def _run(_resolve_id, data) 12 | preference = data['preference'] 13 | new_value = data['value'] 14 | app.update_state!(Actions::ModelPreferencesUpdated.new(preference, new_value)) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/remove_stream.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/remove_stream' 5 | require_relative '../actions/load_saved_streams' 6 | 7 | module SpeckleConnector3 8 | module Commands 9 | # Command to remove stream. 10 | class RemoveStream < Command 11 | def _run(_resolve_id, data) 12 | stream_id = data['stream_id'] 13 | action = Actions::RemoveStream.new(stream_id) 14 | app.update_state!(action) 15 | app.update_state!(Actions::LoadSavedStreams) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE/PR_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | Description of PR... 2 | 3 | ## Changes 4 | 5 | - Item 1 6 | - Item 2 7 | 8 | ## Checklist 9 | 10 | - [ ] Unit tests 11 | - [ ] Documentation 12 | 13 | ## References 14 | 15 | (optional) 16 | 17 | Include **important** links regarding the implementation of this PR. 18 | This usually includes and RFC or an aggregation of issues and/or individual conversations 19 | that helped put this solution together. This helps ensure there is a good aggregation 20 | of resources regarding the implementation. 21 | 22 | ```text 23 | Fixes #85, Fixes #22, Fixes username/repo#123 24 | Connects #123 25 | ``` 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/mapper_source_updated.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/mapper_source_updated' 5 | 6 | module SpeckleConnector3 7 | module Commands 8 | # Command to update mapper source. 9 | class MapperSourceUpdated < Command 10 | def _run(_resolve_id, data) 11 | base = data['base'] 12 | stream_id = data['stream_id'] 13 | commit_id = data['commit_id'] 14 | action = Actions::MapperSourceUpdated.new(base, stream_id, commit_id) 15 | app.update_state!(action) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/dict_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | SPECKLE_BASE_OBJECT = 'Speckle_Base_Object' 5 | SPECKLE_MAPPING_TOOL_SCHEMA = 'Speckle_Mapping_Tool_Schema' 6 | SPECKLE_SCHEMA = 'Speckle_Schema' 7 | 8 | SPECKLE_SEND_CARDS = 'Speckle_Send_Cards' 9 | SPECKLE_RECEIVE_CARDS = 'Speckle_Receive_Cards' 10 | 11 | SPECKLE_ID = 'speckle_id' 12 | SPECKLE_TYPE = 'speckle_type' 13 | APPLICATION_ID = 'application_id' 14 | CHILDREN = 'children' 15 | PARENT = 'parent' 16 | VALID_STREAM_IDS = 'valid_stream_ids' 17 | INVALID_STREAM_IDS = 'invalid_stream_ids' 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/config_actions/get_is_dev_mode.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to get is dev mode. 8 | class GetIsDevMode < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | js_script = "configBinding.receiveResponse('#{resolve_id}', #{DEV_MODE})" 13 | state.with_add_queue_js_command('getIsDevMode', js_script) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/test_actions/go_away.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Test purpose action. 8 | class GoAway < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | puts 'SketchUp went away :(' 13 | js_script = "testBinding.receiveResponse('#{resolve_id}')" 14 | state.with_add_queue_js_command('goAway', js_script) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/states/initial_state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module States 5 | # Initial state of the application. 6 | class InitialState 7 | # @return [UserState] the user specific part of the states 8 | attr_reader :user_state 9 | 10 | # @return [Boolean] application is connector to server or not 11 | attr_reader :is_connected 12 | 13 | def initialize(user_state) 14 | @user_state = user_state 15 | @is_connected = false 16 | freeze 17 | end 18 | 19 | def speckle_state? 20 | false 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/get_source_app_name.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Get source app name. 8 | class GetSourceAppName < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | js_command = "baseBinding.receiveResponse('#{resolve_id}', 'sketchup')" 13 | state.with_add_queue_js_command('getSourceAppName', js_command) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/cards/send_card_multiple_filters.rb: -------------------------------------------------------------------------------- 1 | # # frozen_string_literal: true 2 | # 3 | # require_relative 'card' 4 | # 5 | # module SpeckleConnector3 6 | # module Cards 7 | # # Send card for sketchup connector to communicate speckle. 8 | # class SendCardMultipleFilters < Card 9 | # # @return [Hash{String=>Filter}] filters of the card. 10 | # attr_reader :filters 11 | # 12 | # def initialize(card_id, account_id, project_id, model_id, filters) 13 | # super(card_id, account_id, project_id, model_id) 14 | # @filters = filters 15 | # self[:filters] = filters 16 | # end 17 | # end 18 | # end 19 | # end 20 | -------------------------------------------------------------------------------- /speckle_connector_3/src/convertors/conversion_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Converters 5 | class ConverterError < StandardError 6 | # @return [UiData::Report::ConversionStatus::WARNING] level of the error. 7 | attr_reader :level 8 | 9 | # @param message [String] message for error. 10 | # @param level [UiData::Report::ConversionStatus::WARNING] level of the error. 11 | def initialize(message = "An error occurred on conversion", level) 12 | @level = level 13 | super(message) # Calls the parent class's initialize method with the message 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/get_connector_version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Get connector version. 8 | class GetConnectorVersion < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | js_command = "baseBinding.receiveResponse('#{resolve_id}', '#{CONNECTOR_VERSION}')" 13 | state.with_add_queue_js_command('getConnectorVersion', js_command) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/get_source_app_version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Get source app version. 8 | class GetSourceAppVersion < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | js_command = "baseBinding.receiveResponse('#{resolve_id}', #{SKETCHUP_VERSION})" 13 | state.with_add_queue_js_command('getSourceAppVersion', js_command) 14 | end 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/show_all_entities.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Show all entities on the model. 8 | class ShowAllEntities < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, _resolve_id, _data) 12 | # Show all entities first 13 | state.sketchup_state.sketchup_model.entities.each do |ent| 14 | ent.hidden = false 15 | end 16 | state 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/user_preferences_updated.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../accounts/accounts' 5 | require_relative '../actions/user_preferences_updated' 6 | 7 | module SpeckleConnector3 8 | module Commands 9 | # Command to update preferences. 10 | class UserPreferencesUpdated < Command 11 | def _run(_resolve_id, data) 12 | preference_hash = data['preference_hash'] 13 | preference = data['preference'] 14 | new_value = data['value'] 15 | app.update_state!(Actions::UserPreferencesUpdated.new(preference_hash, preference, new_value)) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/mat_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | MAT_DICTIONARY = 'Speckle_Connector_Materials' 5 | MAT_ID = 'Speckle_Connector_Material_Id' 6 | 7 | MAT_ADD = :speckle_connector_add_material 8 | MAT_EDIT = :speckle_connector_edit_material 9 | MAT_REMOVE = :speckle_connector_remove_material 10 | 11 | DEFAULT_COLORS = { 12 | MAT_ADD => '#66FF66', 13 | MAT_EDIT => '#FFFF9F', 14 | MAT_REMOVE => '#FF6666' 15 | }.freeze 16 | 17 | DEFAULT_NAMES = { 18 | MAT_ADD => 'Speckle_Material_Add', 19 | MAT_EDIT => 'Speckle_Material_Edit', 20 | MAT_REMOVE => 'Speckle_Material_Remove' 21 | }.freeze 22 | end 23 | -------------------------------------------------------------------------------- /ui/apollo.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | 3 | // Load .env files 4 | const { loadEnv } = require('vue-cli-plugin-apollo/utils/load-env') 5 | const env = loadEnv([path.resolve(__dirname, '.env'), path.resolve(__dirname, '.env.local')]) 6 | 7 | module.exports = { 8 | client: { 9 | service: env.VUE_APP_APOLLO_ENGINE_SERVICE, 10 | includes: ['src/**/*.{js,jsx,ts,tsx,vue,gql}'] 11 | }, 12 | service: { 13 | name: env.VUE_APP_APOLLO_ENGINE_SERVICE, 14 | localSchemaFile: path.resolve(__dirname, './node_modules/.temp/graphql/schema.json') 15 | }, 16 | engine: { 17 | endpoint: process.env.APOLLO_ENGINE_API_ENDPOINT, 18 | apiKey: env.VUE_APP_APOLLO_ENGINE_KEY 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/reset_window_location.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../states/initial_state' 5 | require_relative '../actions/initialize_speckle' 6 | require_relative '../observers/factory' 7 | 8 | module SpeckleConnector3 9 | module Commands 10 | # Command to reset Speckle UI window location onto center of SketchUp window. 11 | class ResetWindowLocation < Command 12 | 13 | private 14 | 15 | def _run 16 | app = self.app 17 | app.ui_controller.user_interfaces.values.each do |interface| 18 | interface.reset_dialog_location 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/collect_preferences.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../ext/sqlite3' 5 | require_relative '../constants/path_constants' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to collect preferences from database to UI. 10 | class CollectPreferences < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, _resolve_id, _data) 14 | state.with_add_queue('collectPreferences', state.user_state.preferences.to_json, []) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/platform_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # rubocop:disable Style/Documentation 4 | module SpeckleConnector3 5 | host_os = RbConfig::CONFIG['host_os'] 6 | OS_WIN = :windows 7 | OS_MAC = :macos 8 | OPERATING_SYSTEM = case host_os 9 | when /mswin|msys|mingw|cygwin|bccwin|wince|emc/ 10 | OS_WIN 11 | when /darwin|mac os/ 12 | OS_MAC 13 | else 14 | raise "Unsupported OS: #{host_os.inspect}" 15 | end 16 | RUBY_VERSION_NUMBER = RUBY_VERSION.split('.')[0..1].join.to_i 17 | end 18 | # rubocop:enable Style/Documentation 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/event_handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'event_hash' 4 | require_relative '../actions/on_events_action' 5 | 6 | module SpeckleConnector3 7 | module Observers 8 | # Event handler class. 9 | class EventHandler 10 | # @return [SpeckleConnectorApp] an object that contains current state of speckle objects 11 | attr_reader :app 12 | 13 | def initialize(app) 14 | @app = app 15 | end 16 | 17 | def handle_events(events) 18 | run_handlers(events) 19 | end 20 | 21 | def run_handlers(events) 22 | app.update_state!(Actions::OnEventsAction, events) 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui_data/components/selections/selection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module UiData 5 | module Components 6 | module Selections 7 | # Selections data for UI. 8 | class Selection < Hash 9 | # @return [String] id of the selection. 10 | attr_reader :id 11 | 12 | # @return [String] name of the selection. 13 | attr_reader :name 14 | 15 | def initialize(id, name) 16 | super() 17 | @id = id 18 | @name = name 19 | self[:id] = id 20 | self[:name] = name 21 | end 22 | end 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/sketchup_config_actions/update_user_config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to get user config. 8 | class UpdateUserConfig < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id, new_config) 12 | puts new_config.values 13 | js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}')" 14 | state.with_add_queue_js_command('updateUserConfig', js_script) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/event_hash.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../ext/immutable_ruby/core' 4 | 5 | module SpeckleConnector3 6 | module Observers 7 | # Collection of events. 8 | class EventHash < Immutable::Hash 9 | def push_event(observer_class, event_name, data) 10 | observer_events = self[observer_class] || Immutable::EmptyHash 11 | name_events = observer_events[event_name] || Immutable::EmptyVector 12 | name_events = name_events.add(data) 13 | observer_events = observer_events.put(event_name, name_events) 14 | put(observer_class, observer_events) 15 | end 16 | end 17 | 18 | EMPTY_EVENT_HASH = EventHash.new([]) 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_entities/speckle_entity_status.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../immutable/immutable' 4 | require_relative '../convertors/units' 5 | require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler' 6 | 7 | module SpeckleConnector3 8 | module SpeckleEntities 9 | module SpeckleEntityStatus 10 | # Speckle Entity created first time with {Sketchup::Entity} before sent to server. 11 | UP_TO_DATE = 0 12 | # {Sketchup::Entity} that corresponds to Speckle Entity is edited after created by user. 13 | EDITED = 1 14 | # {Sketchup::Entity} that corresponds to Speckle Entity is removed. 15 | REMOVED = 2 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/bindings/receive_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'binding' 4 | require_relative '../../actions/receive_bindings/receive' 5 | require_relative '../../actions/receive_bindings/after_get_objects' 6 | 7 | module SpeckleConnector3 8 | module Ui 9 | RECEIVE_BINDING_NAME = 'receiveBinding' 10 | 11 | # Receive Binding that provided for DUI. 12 | class ReceiveBinding < Binding 13 | def commands 14 | @commands ||= { 15 | receive: Commands::ActionCommand.new(@app, self, Actions::Receive), 16 | afterGetObjects: Commands::ActionCommand.new(@app, self, Actions::AfterGetObjects) 17 | }.freeze 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/load_saved_streams.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to load saved streams. 8 | class LoadSavedStreams < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, _request_id, _data) 12 | (saved_streams = state.sketchup_state.sketchup_model 13 | .attribute_dictionary('Speckle', true)['saved_streams']) or [] 14 | state.with_add_queue('setSavedStreams', saved_streams, []) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Debug Local File", 9 | "type": "Ruby", 10 | "request": "launch", 11 | "cwd": "${workspaceRoot}", 12 | "program": "scratch.rb" 13 | }, 14 | { 15 | "name": "Listen for rdebug-ide", 16 | "type": "Ruby", 17 | "request": "attach", 18 | "remoteHost": "127.0.0.1", 19 | "remotePort": "7000", 20 | "cwd": "${workspaceRoot}", 21 | "remoteWorkspaceRoot": "${workspaceRoot}" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/tag_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'tag' 4 | require_relative 'filter' 5 | 6 | module SpeckleConnector3 7 | module Filters 8 | # Tag filters for sketchup connector. 9 | class TagFilter < Filter 10 | # @return [Array] id of the filter 11 | attr_reader :tags 12 | 13 | # @return [Array] id of the filter 14 | attr_reader :active_tags 15 | 16 | def initialize(id, name, input, duplicable, tags, active_tags) 17 | super(id, name, input, duplicable) 18 | @tags = tags 19 | @active_tags = active_tags 20 | self[:tags] = tags 21 | self[:activeTags] = active_tags 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/receive_actions/before_receive.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to let sketchup know receive will be started. 8 | class BeforeReceive < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id, stream_id, root_id) 12 | puts "receive started for: #{root_id}" 13 | js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')" 14 | state.with_add_queue_js_command('beforeReceive', js_script) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/receive_actions/after_receive.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to let sketchup know receive from server is finished.. 8 | class AfterReceive < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id, stream_id, root_id) 12 | puts "receive finished for: #{root_id}" 13 | js_script = "sketchupReceiveBinding.receiveResponse('#{resolve_id}')" 14 | state.with_add_queue_js_command('afterReceive', js_script) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/available_speckle_objects.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module SpeckleObjects 5 | # @return [Array] available speckle object types. 6 | AVAILABLE_SPECKLE_OBJECTS = %w[ 7 | Objects.Geometry.Point 8 | Objects.Geometry.Vector 9 | Objects.Geometry.Line 10 | Objects.Geometry.Polyline 11 | Objects.Geometry.Mesh 12 | Objects.Geometry.Brep 13 | Objects.Geometry.Box 14 | Objects.Geometry.Plane 15 | Objects.Other.BlockInstance 16 | Objects.Other.BlockDefinition 17 | Objects.Other.RenderMaterial 18 | Objects.Other.Transform 19 | Objects.Primitive.Interval 20 | Speckle.Reference 21 | ].freeze 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/geometry/polycurve.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module Geometry 9 | # Polycurve object definition for Speckle. 10 | # It basically groups the lines-curves under it's `segments` property. 11 | class Polycurve < Base 12 | SPECKLE_TYPE = OBJECTS_GEOMETRY_POLYCURVE 13 | 14 | def self.to_native(state, polycurve, layer, entities, &convert_to_native) 15 | polycurve['displayValue'] = polycurve['segments'] 16 | convert_to_native.call(state, polycurve, layer, entities) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/send_binding_old.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'bindings/binding' 4 | require_relative '../actions/send_actions/activate_send_filter' 5 | require_relative '../actions/send_actions/activate_send_filter_tag' 6 | 7 | module SpeckleConnector3 8 | module Ui 9 | SEND_BINDING_NAME = 'sendBindingOld' 10 | 11 | # Send binding that provided for DUI. 12 | class SendBindingOld < Binding 13 | def commands 14 | @commands ||= { 15 | activateSendFilter: Commands::ActionCommand.new(@app, self, Actions::ActivateSendFilter), 16 | activateSendFilterTag: Commands::ActionCommand.new(@app, self, Actions::ActivateSendFilterTag) 17 | }.freeze 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /_tools/debugger/skippy_exec_2024.rb: -------------------------------------------------------------------------------- 1 | # This is for automated pre-debugger configuration. 2 | # We run skippy first, then activate debugger. 3 | # The purpose of this file to wait till skp is live 4 | 5 | # To establish a configuration 6 | # 1. Create 'Run External Tool' before lunch step 7 | # 2. Program -> C:\Ruby32-x64\bin\ruby.exe or whatever 8 | # 3. Arguments -> C:\Users\KORAL\Documents\Git\Speckle\speckle-sketchup\_tools\debugger\bundle_exec_2024.rb or whatever 9 | # 4. Working directory -> C:\Users\KORAL\Documents\Git\Speckle\speckle-sketchup or whatever 10 | 11 | # Add a delay of 10 seconds, it is arbitrary, do not hesitate to change for what works best for you 12 | sleep(10) 13 | 14 | # Execute the original command 15 | exec('bundle exec skippy sketchup:debug 2024') 16 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/highlight_objects.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../sketchup_model/query/entity' 5 | require_relative '../../sketchup_model/utils/view_utils' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to add send card. 10 | class HighlightObjects < Action 11 | def self.update_state(state, resolve_id, object_ids) 12 | SketchupModel::Utils::ViewUtils.highlight_entities(state.sketchup_state.sketchup_model, object_ids) 13 | 14 | # Resolve promise 15 | js_script = "baseBinding.receiveResponse('#{resolve_id}')" 16 | state.with_add_queue_js_command('highlightObjects', js_script) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/test_actions/get_complex_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Test purpose action. 8 | class GetComplexType < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | complex_type = { 13 | id: 'complex_type_id', 14 | count: 3 15 | } 16 | js_script = "testBinding.receiveResponse('#{resolve_id}', #{complex_type.to_json})" 17 | state.with_add_queue_js_command('getComplexType', js_script) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/revit/parameter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../base' 4 | require_relative '../../../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module BuiltElements 9 | module Revit 10 | # Revit parameter. 11 | class Parameter < Base 12 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_PARAMETER 13 | def initialize(name:, application_id: nil) 14 | super( 15 | speckle_type: SPECKLE_TYPE, 16 | application_id: application_id, 17 | id: id 18 | ) 19 | self[:name] = name 20 | end 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/config_actions/set_user_selected_account_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../preferences/preferences' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | class SetUserSelectedAccountId < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id, account_id) 12 | Preferences.set_user_selected_account_id(account_id) 13 | js_script = "configBinding.receiveResponse('#{resolve_id}')" 14 | state.with_add_queue_js_command('setUserSelectedAccountId', js_script) 15 | end 16 | end 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/send/everything_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../ui_data/components/selections/list_selection_item' 4 | 5 | module SpeckleConnector3 6 | module Filters 7 | module Send 8 | # Everything filter for sketchup connector to send all. 9 | class EverythingFilter < UiData::Components::Selections::ListSelectionItem 10 | def initialize 11 | super('everything', 'Everything', nil, 12 | 'All supported objects in the currently opened file.') 13 | end 14 | 15 | def self.from_json(_data) 16 | EverythingFilter.new 17 | end 18 | 19 | def check_expiry(_ids) 20 | true 21 | end 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/collect_versions.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to collect versions from sketchup and connector to track user's version by mixpanel. 8 | class CollectVersions < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, _resolve_id, _data) 12 | versions = { 13 | sketchup: Sketchup.version.to_i, 14 | speckle: SpeckleConnector3::CONNECTOR_VERSION 15 | } 16 | state.with_add_queue('collectVersions', versions.to_json, []) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/network.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module BuiltElements 9 | # Network object represents scenes on Sketchup. 10 | class Network < Base 11 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_NETWORK 12 | 13 | def self.to_native(state, network, layer, entities, &convert_to_native) 14 | network['elements'].each do |element| 15 | state, _converted_entities = convert_to_native.call(state, element['elements'], layer, entities) 16 | end 17 | 18 | return state, [] 19 | end 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/bindings/binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Ui 5 | # The abstract class for binding to send data to a user interface. 6 | class Binding 7 | # @return [String] name of the binding. 8 | attr_reader :name 9 | 10 | # @return [App::SpeckleConnectorApp] the reference to the app object 11 | attr_reader :app 12 | 13 | # @param app [App::SpeckleConnectorApp] the reference to the app object 14 | # @param name [String] name of the binding. 15 | def initialize(app, name) 16 | @app = app 17 | @name = name 18 | end 19 | 20 | def commands 21 | raise NotImplementedError, 'Implement in a subclass' 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /ui/src/views/Login.vue: -------------------------------------------------------------------------------- 1 | 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: New issue 3 | about: Create a report to help us improve 4 | title: 5 | labels: 6 | assignees: 7 | --- 8 | 9 | If it's your first time here - or you forgot about them - make sure you read the [contribution guidelines](CONTRIBUTING.md), and then feel free to delete this line! 10 | 11 | ### Expected vs. Actual Behavior 12 | 13 | Describe the problem here. 14 | 15 | ### Reproduction Steps & System Config (win, osx, web, etc.) 16 | 17 | Let us know how we can reproduce this, and attach relevant files (if any). 18 | 19 | ### Proposed Solution (if any) 20 | 21 | Let us know what how you would solve this. 22 | 23 | #### Optional: Affected Projects 24 | 25 | Does this issue propagate to other dependencies or dependents? If so, list them here! 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/other/mapped_block_wrapper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | 5 | module SpeckleConnector3 6 | module SpeckleObjects 7 | module Other 8 | # MappedBlockWrapper object definition for Speckle. 9 | class MappedBlockWrapper < Base 10 | SPECKLE_TYPE = 'Objects.Other.MappedBlockWrapper' 11 | def initialize(category:, units:, instance:, application_id: nil) 12 | super( 13 | speckle_type: SPECKLE_TYPE, 14 | application_id: application_id, 15 | id: nil 16 | ) 17 | self[:category] = category 18 | self[:units] = units 19 | self[:instance] = instance 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/sketchup_config_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'bindings/binding' 4 | require_relative '../actions/sketchup_config_actions/get_user_config' 5 | require_relative '../actions/sketchup_config_actions/update_user_config' 6 | 7 | module SpeckleConnector3 8 | module Ui 9 | CONNECTOR_CONFIG_BINDING_NAME = 'connectorConfigBinding' 10 | 11 | # Config binding that provided for DUI. 12 | class SketchupConfigBinding < Binding 13 | def commands 14 | @commands ||= { 15 | getUserConfig: Commands::ActionCommand.new(@app, self, Actions::GetUserConfig), 16 | updateUserConfig: Commands::ActionCommand.new(@app, self, Actions::UpdateUserConfig) 17 | }.freeze 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /ui/src/main.js: -------------------------------------------------------------------------------- 1 | import 'regenerator-runtime/runtime' 2 | 3 | import Vue from 'vue' 4 | import App from './App.vue' 5 | import router from './router' 6 | import vuetify from './plugins/vuetify' 7 | import { createProvider } from './vue-apollo' 8 | 9 | Vue.prototype.$eventHub = new Vue() 10 | 11 | Vue.config.productionTip = false 12 | 13 | import VueTimeago from 'vue-timeago' 14 | Vue.use(VueTimeago, { locale: 'en' }) 15 | 16 | import VueTooltip from 'v-tooltip' 17 | Vue.use(VueTooltip) 18 | 19 | import SpeckleMetrics from './plugins/speckle-metrics' 20 | Vue.use(SpeckleMetrics, { token: 'acd87c5a50b56df91a795e999812a3a4' }) 21 | 22 | export const bus = new Vue() 23 | 24 | new Vue({ 25 | router, 26 | vuetify, 27 | apolloProvider: createProvider(), 28 | render: (h) => h(App) 29 | }).$mount('#app') 30 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/test_actions/say_hi.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Test purpose action. 8 | class SayHi < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id, name, count, say_hello_not_hi) 12 | said_hi = [] 13 | count.times do 14 | said_hi.append("#{say_hello_not_hi ? 'Hello' : 'Hi'} #{name}!") 15 | end 16 | js_script = "testBinding.receiveResponse('#{resolve_id}', #{said_hi})" 17 | state.with_add_queue_js_command('sayHi', js_script) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/action_command.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | 5 | module SpeckleConnector3 6 | module Commands 7 | # Command to update state of the application. 8 | class ActionCommand < Command 9 | # @param app [App::SpeckleConnectorApp] the app object to run command on 10 | # @param binding [Ui::Binding] binding object holds commands to call 11 | # @param action [#update_state] the action that knows how to change the state of the speckle app 12 | def initialize(app, binding, action) 13 | super(app, binding) 14 | @action = action 15 | end 16 | 17 | private 18 | 19 | def _run(*parameters) 20 | app.update_state!(@action, *parameters) 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/geometry/length.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../convertors/units' 4 | 5 | module SpeckleConnector3 6 | module SpeckleObjects 7 | # Geometric objects to convert speckle. 8 | module Geometry 9 | def self.length_to_speckle(length, units) 10 | length.__send__("to_#{SpeckleConnector3::Converters::SKETCHUP_UNIT_STRINGS[units]}") 11 | end 12 | 13 | def self.length_to_native(length, units) 14 | if units == 'none' 15 | units = SpeckleConnector3::Converters:: 16 | SKETCHUP_UNITS[Sketchup.active_model.options['UnitsOptions']['LengthUnit']] 17 | end 18 | length.__send__(SpeckleConnector3::Converters::SKETCHUP_UNIT_STRINGS[units]) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/states/user_state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../immutable/immutable' 4 | 5 | module SpeckleConnector3 6 | module States 7 | # User specific states. 8 | class UserState 9 | include Immutable::ImmutableUtils 10 | 11 | # @return [Immutable::Hash{Symbol => Object}] user specific preferences 12 | attr_reader :preferences 13 | 14 | def initialize(preferences) 15 | @preferences = preferences 16 | end 17 | 18 | def user_preferences 19 | @preferences[:user] 20 | end 21 | 22 | def model_preferences 23 | @preferences[:model] 24 | end 25 | 26 | def with_preferences(new_preferences) 27 | with(:@preferences => new_preferences) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/init_local_accounts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../accounts/accounts' 5 | require_relative 'load_saved_streams' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to initialize local accounts from database. 10 | class InitLocalAccounts < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, _request_id, _data) 14 | puts 'Initialisation of Speckle accounts requested by plugin' 15 | accounts_data = state.speckle_state.accounts 16 | state.with_add_queue('loadAccounts', accounts_data.to_json, []) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/get_send_filters.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../filters/send_filters' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to get send filter. 9 | class GetSendFilters < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id) 13 | default_filters = Filters::SendFilters.get_default(state.sketchup_state.sketchup_model) 14 | js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_filters.to_json})" 15 | state.with_add_queue_js_command('getSendFilter', js_script) 16 | end 17 | end 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/account_actions/remove_account.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../accounts/accounts' 5 | require_relative '../load_saved_streams' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to remove account from database. 10 | class RemoveAccount < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, resolve_id, account_id) 14 | SpeckleConnector3::Accounts.remove_account(account_id) 15 | js_script = "accountsBinding.receiveResponse('#{resolve_id}')" 16 | state.with_add_queue_js_command('removeAccount', js_script) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/account_actions/add_account.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../accounts/accounts' 5 | require_relative '../load_saved_streams' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to add account to local Account db. 10 | class AddAccount < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, resolve_id, account_id, account) 14 | SpeckleConnector3::Accounts.add_account(account_id, account) 15 | js_script = "accountsBinding.receiveResponse('#{resolve_id}')" 16 | state.with_add_queue_js_command('addAccount', js_script) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /_tools/README.md: -------------------------------------------------------------------------------- 1 | # Tools 2 | 3 | This folder stores the external tools and helper scripts to make easier life of the developer, 4 | they are not the part of the main functionality of the Speckle. 5 | 6 | Tools and scripts inside the folder will be loaded with `sketchup_connector_loader.rb` file. 7 | In order to load your own `.rb` files please add this file names into list in the loader. 8 | 9 | ````ruby 10 | ... 11 | 12 | files = %w[speckle_connector jf_RubyPanel su_attributes ] 13 | # This line placed before loading started. 14 | 15 | files.each do |ruby_file| 16 | puts "Loading #{ruby_file}" 17 | begin 18 | require ruby_file 19 | rescue LoadError 20 | puts "Could not load #{ruby_file}" 21 | end 22 | end 23 | ```` 24 | 25 | Track load status of your tools and scripts on the ruby console when SketchUp UI initializing. -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/mapped_entities_updated.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../sketchup_model/reader/mapper_reader' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Triggers when mapped entities updated. 9 | class MappedEntitiesUpdated < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, _resolve_id = nil, _data = nil) 13 | mapped_entities = SketchupModel::Reader::MapperReader 14 | .mapped_entity_details(state.speckle_state.speckle_mapper_state.mapped_entities.values.to_a) 15 | 16 | state.with_mapped_entities_queue(mapped_entities) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/receive_objects.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/receive_objects' 5 | 6 | module SpeckleConnector3 7 | module Commands 8 | # Command to receive objects from Speckle Server. 9 | class ReceiveObjects < Command 10 | def _run(_resolve_id, data) 11 | stream_id = data['stream_id'] 12 | base = data['base'] 13 | branch_name = data['branch_name'] 14 | branch_id = data['branch_id'] 15 | stream_name = data['stream_name'] 16 | source_app = data['source_app'] 17 | object_id = data['object_id'] 18 | action = Actions::ReceiveObjects.new(stream_id, base, stream_name, branch_name, branch_id, source_app, object_id) 19 | app.update_state!(action) 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/mapper_initialized.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../mapper/category/revit_category' 5 | require_relative '../mapper/category/revit_family_category' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Collects mapper selection info. 10 | class MapperInitialized < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, _data) 14 | init_parameters = { 15 | categories: Mapper::Category::RevitCategory.to_a, 16 | familyCategories: Mapper::Category::RevitFamilyCategory.to_a 17 | }.freeze 18 | state.with_mapper_init_queue(init_parameters) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/config_actions/get_config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to get config. 8 | class GetConfig < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | # Previously it was stored in user state 13 | # config = state.user_state.preferences.to_json 14 | config = { 15 | darkTheme: state.user_state.user_preferences[:dark_theme] 16 | } 17 | js_script = "configBinding.receiveResponse('#{resolve_id}', #{config.to_json})" 18 | state.with_add_queue_js_command('getConfig', js_script) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/other/rendering_options.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'color' 4 | 5 | module SpeckleConnector3 6 | module SpeckleObjects 7 | module Other 8 | # Rendering options for scenes. 9 | class RenderingOptions 10 | # @param options [Sketchup::RenderingOptions] rendering options to convert speckle object 11 | def self.to_speckle(options) 12 | options.to_h.collect do |option_prop, option_value| 13 | speckle_value = if option_value.is_a?(Sketchup::Color) 14 | Color.to_speckle(option_value) 15 | else 16 | option_value 17 | end 18 | [option_prop.to_sym, speckle_value] 19 | end.to_h 20 | end 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/bindings/accounts_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'binding' 4 | require_relative '../../actions/account_actions/get_accounts' 5 | require_relative '../../actions/account_actions/add_account' 6 | require_relative '../../actions/account_actions/remove_account' 7 | 8 | module SpeckleConnector3 9 | module Ui 10 | ACCOUNTS_BINDING_NAME = 'accountsBinding' 11 | 12 | # Binding that provided for DUI. 13 | class AccountsBinding < Binding 14 | def commands 15 | @commands ||= { 16 | getAccounts: Commands::ActionCommand.new(@app, self, Actions::GetAccounts), 17 | addAccount: Commands::ActionCommand.new(@app, self, Actions::AddAccount), 18 | removeAccount: Commands::ActionCommand.new(@app, self, Actions::RemoveAccount) 19 | }.freeze 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/update_send_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to update send filter. 9 | class UpdateSendFilter < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id, data, value) 13 | SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value) 14 | 15 | js_script = "sendBinding.receiveResponse('#{resolve_id}')" 16 | state.with_add_queue_js_command('updateSendFilter', js_script) 17 | end 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/get_document_info.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Get document info. 8 | class GetDocumentInfo < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | document_info = { 13 | location: state.sketchup_state.sketchup_model.path, 14 | name: state.sketchup_state.sketchup_model.name, 15 | id: state.sketchup_state.sketchup_model.guid 16 | } 17 | js_command = "baseBinding.receiveResponse('#{resolve_id}', #{document_info.to_json})" 18 | state.with_add_queue_js_command('getDocumentInfo', js_command) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/sketchup_ui.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Ui 5 | # An interface to Sketchup user interface. This object controls the menu `Extensions->Speckle` in Sketchup's menu, 6 | # the Speckle toolbar and sending message to the user via Sketchup. 7 | class SketchupUi 8 | MENU_TITLE = 'Speckle' 9 | BEFORE_NEVER_SHOWN = -1 10 | 11 | # @return [Sketchup::Menu] the menu of the Speckle 12 | attr_reader :speckle_menu 13 | 14 | # @return [UI::Toolbar] the Speckle toolbar 15 | attr_reader :speckle_toolbar 16 | 17 | def initialize 18 | @speckle_menu = UI.menu.add_submenu(MENU_TITLE) 19 | @speckle_toolbar = UI::Toolbar.new(MENU_TITLE) 20 | @speckle_toolbar.show if @speckle_toolbar.get_last_state == BEFORE_NEVER_SHOWN 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/receive_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'bindings/binding' 4 | require_relative '../actions/receive_actions/before_receive' 5 | require_relative '../actions/receive_actions/receive_single_object' 6 | require_relative '../actions/receive_actions/after_receive' 7 | 8 | module SpeckleConnector3 9 | module Ui 10 | RECEIVE_BINDING_NAME = 'sketchupReceiveBinding' 11 | 12 | # Binding that provided for DUI. 13 | class ReceiveBinding < Binding 14 | def commands 15 | @commands ||= { 16 | beforeReceive: Commands::ActionCommand.new(@app, self, Actions::BeforeReceive), 17 | receiveObject: Commands::ActionCommand.new(@app, self, Actions::ReceiveSingleObject), 18 | afterReceive: Commands::ActionCommand.new(@app, self, Actions::AfterReceive) 19 | }.freeze 20 | end 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/config_actions/get_user_selected_account_id.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../preferences/preferences' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | class GetUserSelectedAccountId < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | user_selected_account_id = Preferences.get_user_selected_account_id 13 | accountsConfig = { 14 | userSelectedAccountId: user_selected_account_id 15 | } 16 | js_script = "configBinding.receiveResponse('#{resolve_id}', #{accountsConfig.to_json})" 17 | state.with_add_queue_js_command('getUserSelectedAccountId', js_script) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/debug.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Speckle connector module to enable multiplayer mode ON! 4 | module SpeckleConnector3 5 | # from thomthom 6 | # https://github.com/thomthom/true-bend/blob/master/src/tt_truebend/debug.rb 7 | 8 | # @note Debug method to reload the plugin. 9 | # 10 | # @example 11 | # SpeckleConnector.reload 12 | # 13 | # @return [Integer] Number of files reloaded. 14 | # rubocop:disable SketchupSuggestions/FileEncoding 15 | def self.reload 16 | load(__FILE__) 17 | pattern = File.join(__dir__, '**/*.rb') 18 | # TODO: Here is a opportunity to improve reloading process. 19 | # We can cache last edited time of the each file later to check which file need to be reloaded. 20 | Dir.glob(pattern).each { |file| load(file) unless file.include?('bootstrap') } 21 | .size 22 | end 23 | # rubocop:enable SketchupSuggestions/FileEncoding 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/account_actions/get_accounts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../accounts/accounts' 5 | require_relative '../load_saved_streams' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to initialize local accounts from database. 10 | class GetAccounts < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, resolve_id) 14 | puts 'Initialisation of Speckle accounts requested by plugin' 15 | accounts_data = SpeckleConnector3::Accounts.load_accounts 16 | js_script = "accountsBinding.receiveResponse('#{resolve_id}', #{accounts_data.to_json})" 17 | state.with_add_queue_js_command('getAccounts', js_script) 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/src/sketchup_model/dictionary/speckle_model_dictionary_handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'base_dictionary_handler' 4 | require_relative '../../constants/dict_constants' 5 | require_relative '../../constants/type_constants' 6 | 7 | module SpeckleConnector3 8 | module SketchupModel 9 | module Dictionary 10 | # Dictionary handler of the speckle model. 11 | class SpeckleModelDictionaryHandler < BaseDictionaryHandler 12 | DICTIONARY_NAME = 'Speckle' 13 | # Writes initial data while speckle entity is creating first time. 14 | # @param sketchup_model [Sketchup::Model] Sketchup model to write data into it's attribute dictionary. 15 | def self.write_initial_model_data(sketchup_model, default_preferences) 16 | set_hash(sketchup_model, default_preferences, DICTIONARY_NAME) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/apply_mappings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'command' 4 | require_relative '../actions/apply_mappings' 5 | 6 | module SpeckleConnector3 7 | module Commands 8 | # Command to apply mapping for selected entities. 9 | class ApplyMappings < Command 10 | def _run(_resolve_id, data) 11 | entities_to_map = data['entitiesToMap'] 12 | method = data['method'] 13 | category = data['category'] 14 | family = data['family'] 15 | family_type = data['familyType'] 16 | level = data['level'] 17 | name = data['name'] 18 | is_definition = data['isDefinition'] 19 | action = Actions::ApplyMappings.new(entities_to_map, method, category, family, 20 | family_type, level, name, is_definition) 21 | app.update_state!(action) 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/object_reference.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require_relative '../immutable/immutable' 5 | require_relative 'base' 6 | 7 | module SpeckleConnector3 8 | module SpeckleObjects 9 | # Object reference to send it to Speckle server. It contains closure table to store children objects. 10 | class ObjectReference < Base 11 | 12 | attr_reader :closure, :referenced_id, :application_id 13 | 14 | def initialize(referenced_id, application_id, closure) 15 | @speckle_type = 'reference' 16 | @closure = closure 17 | @referenced_id = referenced_id 18 | @application_id = application_id 19 | super() 20 | update( 21 | { 22 | speckle_type: 'reference', 23 | referencedId: referenced_id, 24 | __closure: closure 25 | } 26 | ) 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/reload_accounts.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../accounts/accounts' 5 | require_relative 'load_saved_streams' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to reload accounts from database. 10 | class ReloadAccounts < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, _resolve_id, _data) 14 | puts 'Reload of Speckle accounts requested by plugin' 15 | new_speckle_state = state.speckle_state.with_accounts(Accounts.load_accounts) 16 | state = state.with_speckle_state(new_speckle_state) 17 | accounts_data = state.speckle_state.accounts 18 | state.with_add_queue('loadAccounts', accounts_data.to_json, []) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/save_stream.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../accounts/accounts' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Save stream. 9 | # Currently it is not a state changer. 10 | class SaveStream < Action 11 | def initialize(stream_id) 12 | super() 13 | @stream_id = stream_id 14 | end 15 | 16 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 17 | # @return [States::State] the new updated state object 18 | def update_state(state) 19 | speckle_dict = state.sketchup_state.sketchup_model.attribute_dictionary('Speckle', true) 20 | saved = speckle_dict['saved_streams'] || [] 21 | saved = saved.empty? ? [@stream_id] : saved.unshift(@stream_id) 22 | speckle_dict['saved_streams'] = saved 23 | state 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/immutable_ruby/json.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # Define the method to export immutable structures to JSON. Default exporter would only export the name of the class as 4 | # a string. In order to export it properly, we need to add `to_json` methods to the classes we want to serialize as JSON. 5 | module SpeckleConnector3 6 | module Immutable 7 | class Vector 8 | # Convert the object to JSON 9 | # @return [String] json encoded string 10 | # @param args [Array] the arguments that will be passed to JSON.to_json method 11 | def to_json(*args) 12 | to_a.to_json(*args) 13 | end 14 | end 15 | class Hash 16 | # Convert the object to JSON 17 | # @return [String] json encoded string 18 | # @param args [Array] the arguments that will be passed to JSON.to_json method 19 | def to_json(*args) 20 | to_h.to_json(*args) 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/config_actions/update_config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../user_preferences_updated' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to update config. 9 | class UpdateConfig < Action 10 | KEY_VALUES = { 11 | 'darkTheme' => 'dark_theme' 12 | }.freeze 13 | 14 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 15 | # @return [States::State] the new updated state object 16 | def self.update_state(state, resolve_id, config) 17 | config.each do |key, value| 18 | state = Actions::UserPreferencesUpdated.new('Sketchup', KEY_VALUES[key], value).update_state(state) 19 | end 20 | 21 | js_script = "configBinding.receiveResponse('#{resolve_id}')" 22 | state.with_add_queue_js_command('updateConfig', js_script) 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=733558 3 | // for the documentation about the tasks.json format 4 | // note that default shell needs to be powershell 5 | "version": "2.0.0", 6 | "tasks": [ 7 | { 8 | "label": "Debug SketchUp 2021", 9 | "type": "shell", 10 | "command": "open -a '/Applications/SketchUp 2021/SketchUp.app' --args -rdebug 'ide port=7000'", 11 | "windows": { 12 | "command": "&'C:/Program Files/SketchUp/SketchUp 2021/SketchUp.exe' -rdebug 'ide port=7000'", 13 | }, 14 | "problemMatcher": [] 15 | }, 16 | { 17 | "label": "Debug SketchUp 2022", 18 | "type": "shell", 19 | "command": "open -a '/Applications/SketchUp 2022/SketchUp.app' --args -rdebug 'ide port=7000'", 20 | "windows": { 21 | "command": "&'C:/Program Files/SketchUp/SketchUp 2022/SketchUp.exe' -rdebug 'ide port=7000'", 22 | }, 23 | "problemMatcher": [] 24 | }, 25 | ] 26 | } -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/send/layer_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../ui_data/components/selections/list_selection' 4 | 5 | module SpeckleConnector3 6 | module Filters 7 | module Send 8 | # Layer (tag) filter for sketchup connector to send all. 9 | class LayerFilter < UiData::Components::Selections::ListSelection 10 | def initialize(items, selected_items) 11 | super('tags', 'Tags', items, selected_items, true) 12 | end 13 | 14 | def self.from_json(data) 15 | items = data['items'].collect do |key, item| 16 | [key, [UiData::Components::Selections::ListSelectionItem.new(item['id'], item['name'], item['color'], '')]] 17 | end.to_h 18 | LayerFilter.new(items, data['selectedItems']) 19 | end 20 | 21 | def check_expiry(_ids) 22 | # TODO: Implement! 23 | false 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /speckle_connector_3/src/operations/receive.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../accounts/accounts' 4 | 5 | module SpeckleConnector3 6 | # Operations between server and connector. 7 | module Operations 8 | # Receive operation. (WIP) 9 | def self.receive(stream_id, object_id) 10 | default_account = Accounts.default_account 11 | url = default_account['serverInfo']['url'] 12 | token = default_account['token'] 13 | uri = URI.parse("#{url}/objects/#{stream_id}/#{object_id}/single") 14 | 15 | headers = {} 16 | headers['Authorization'] = "Bearer #{token}" 17 | headers['Accept'] = 'text/plain' 18 | content = nil 19 | 20 | @request = Sketchup::Http::Request.new(uri.to_s, Sketchup::Http::GET) 21 | @request.headers = headers 22 | 23 | # Can't catch here content as sync...! 24 | @request.start do |req, res| 25 | content = res.body 26 | end 27 | 28 | content 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/gis/utils.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../other/transform' 5 | require_relative '../other/block_definition' 6 | require_relative '../other/block_instance' 7 | require_relative '../../constants/type_constants' 8 | require_relative '../../sketchup_model/dictionary/dictionary_handler' 9 | 10 | module SpeckleConnector3 11 | module SpeckleObjects 12 | module GIS 13 | def self.get_definition_name(obj, attributes) 14 | return obj['name'] unless obj['name'].nil? 15 | 16 | return attributes['name'] unless attributes['name'].nil? 17 | 18 | return "def::#{obj['id']}" 19 | end 20 | 21 | def self.get_qgis_attributes(obj) 22 | attributes = obj['attributes'].to_h 23 | speckle_properties = %w[id speckle_type units applicationId] 24 | speckle_properties.each { |key| attributes.delete(key) } 25 | attributes 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/remove_stream.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../accounts/accounts' 5 | require_relative '../convertors/units' 6 | require_relative '../convertors/converter' 7 | 8 | module SpeckleConnector3 9 | module Actions 10 | # Action to remove stream. 11 | # Currently it is not a state changer. 12 | class RemoveStream < Action 13 | def initialize(stream_id) 14 | super() 15 | @stream_id = stream_id 16 | end 17 | 18 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 19 | # @return [States::State] the new updated state object 20 | def update_state(state) 21 | speckle_dict = state.sketchup_state.sketchup_model.attribute_dictionary('Speckle', true) 22 | saved = speckle_dict['saved_streams'] || [] 23 | saved -= [@stream_id] 24 | speckle_dict['saved_streams'] = saved 25 | state 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/command_data.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | 5 | module SpeckleConnector3 6 | module Ui 7 | # Command structure to handle it with dialog.exec_callback 8 | CommandData = Struct.new(:name, :binding_name, :resolve_id, :data) 9 | 10 | # Parser class for commands that comes from dialog to ruby engine. 11 | class CommandParser 12 | # @return [Array] parsed commands. 13 | def self.parse_commands(data) 14 | data = JSON.parse(data) if data.is_a? String 15 | return [parse(data)].compact unless data.is_a?(Array) 16 | 17 | data.collect { |command| parse(command) }.compact 18 | end 19 | 20 | def self.parse(command) 21 | return nil unless command.is_a?(Hash) 22 | 23 | name = command['name'] 24 | 25 | return nil unless name.is_a?(String) 26 | 27 | CommandData.new(name.to_sym, command['binding_name'], command['request_id'], command['data']) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /tests/src/speckle_objects/geometry/point_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require_relative '../../../test_helper' 5 | require_relative '../../../../speckle_connector_3/src/speckle_objects/geometry/point' 6 | 7 | module SpeckleConnector3 8 | module SpeckleObjects 9 | module Geometry 10 | class PointTest < Minitest::Test 11 | def setup 12 | # Do nothing 13 | end 14 | 15 | def teardown 16 | # Do nothing 17 | end 18 | 19 | def test_point_to_json 20 | point = Point.new(1.0, 1.0, 1.0, 'm') 21 | serialized_point = { 22 | speckle_type: 'Objects.Geometry.Point', 23 | units: 'm', 24 | x: 1.0, 25 | y: 1.0, 26 | z: 1.0 27 | } 28 | serialized = point.to_json 29 | hash = JSON.parse(serialized, { symbolize_names: true }) 30 | 31 | assert_equal(serialized_point, hash) 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/immutable_ruby/core.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'hash' 4 | require_relative 'set' 5 | require_relative 'vector' 6 | # Add json conversion methods 7 | require_relative 'json' 8 | 9 | module SpeckleConnector3 10 | module Immutable 11 | class Hash 12 | # Return a new {Set} containing the keys from this `Hash`. 13 | # 14 | # @example 15 | # Immutable::Hash["A" => 1, "B" => 2, "C" => 3, "D" => 2].keys 16 | # # => Immutable::Set["D", "C", "B", "A"] 17 | # 18 | # @return [Set] 19 | def keys 20 | Set.alloc(@trie) 21 | end 22 | 23 | # Return a new {Vector} populated with the values from this `Hash`. 24 | # 25 | # @example 26 | # Immutable::Hash["A" => 1, "B" => 2, "C" => 3, "D" => 2].values 27 | # # => Immutable::Vector[2, 3, 2, 1] 28 | # 29 | # @return [Vector] 30 | def values 31 | Vector.new(each_value.to_a.freeze) 32 | end 33 | end 34 | end 35 | end 36 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/ui_controller.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Ui 5 | # The class that handle communication between ruby code and different user interfaces. 6 | class UiController 7 | # @return [Immutable::Hash] the registered user interfaces that will receive notifications when Speckle states 8 | # is updated. 9 | attr_reader :user_interfaces 10 | 11 | # @return [Ui::SketchupUi] the interface to Sketchup UI features 12 | attr_reader :sketchup_ui 13 | 14 | # @param sketchup_ui [Ui::SketchupUi] the interface to Sketchup UI features 15 | def initialize(sketchup_ui) 16 | @user_interfaces = {} 17 | @sketchup_ui = sketchup_ui 18 | end 19 | 20 | # Register user interface to receive notifications about states changes 21 | def register_ui(interface_id, user_interface) 22 | # FIXME: Mutable alert! 23 | @user_interfaces[interface_id] = user_interface 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /speckle_connector_3/src/sketchup_model/dictionary/speckle_schema_dictionary_handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'delegate' 4 | require_relative 'dictionary_handler' 5 | require_relative '../../constants/dict_constants' 6 | 7 | module SpeckleConnector3 8 | module SketchupModel 9 | module Dictionary 10 | # Read and write attributes for Speckle objects' schema on SketchUp model. 11 | class SpeckleSchemaDictionaryHandler < DictionaryHandler 12 | def self.speckle_schema_to_speckle(entity) 13 | schema = {} 14 | return schema if entity.attribute_dictionaries.nil? 15 | 16 | schema_dict = entity.attribute_dictionaries.find { |dict| dict.name == dictionary_name } 17 | return schema if schema_dict.nil? 18 | 19 | schema_dict.to_h 20 | end 21 | 22 | # @return [String] the name of the dictionary to read from 23 | def self.dictionary_name 24 | SPECKLE_MAPPING_TOOL_SCHEMA 25 | end 26 | end 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/test_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'bindings/binding' 4 | require_relative '../constants/path_constants' 5 | 6 | require_relative '../actions/test_actions/say_hi' 7 | require_relative '../actions/test_actions/go_away' 8 | require_relative '../actions/test_actions/get_complex_type' 9 | require_relative '../actions/test_actions/trigger_event' 10 | 11 | 12 | module SpeckleConnector3 13 | module Ui 14 | TEST_BINDINGS_NAME = 'testBinding' 15 | 16 | # View that provided by vue.js 17 | class TestBinding < Binding 18 | def commands 19 | @commands ||= { 20 | sayHi: Commands::ActionCommand.new(@app, self, Actions::SayHi), 21 | goAway: Commands::ActionCommand.new(@app, self, Actions::GoAway), 22 | getComplexType: Commands::ActionCommand.new(@app, self, Actions::GetComplexType), 23 | triggerEvent: Commands::ActionCommand.new(@app, self, Actions::TriggerEvent) 24 | }.freeze 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /tests/src/speckle_objects/geometry/vector_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require_relative '../../../test_helper' 5 | require_relative '../../../../speckle_connector_3/src/speckle_objects/geometry/vector' 6 | 7 | module SpeckleConnector3 8 | module SpeckleObjects 9 | module Geometry 10 | class VectorTest < Minitest::Test 11 | def setup 12 | # Do nothing 13 | end 14 | 15 | def teardown 16 | # Do nothing 17 | end 18 | 19 | def test_vector_to_json 20 | point = Vector.new(1.0, 1.0, 1.0, 'm') 21 | serialized_point = { 22 | speckle_type: 'Objects.Geometry.Vector', 23 | units: 'm', 24 | x: 1.0, 25 | y: 1.0, 26 | z: 1.0 27 | } 28 | serialized = JSON.generate(point) 29 | hash = JSON.parse(serialized, { symbolize_names: true }) 30 | 31 | assert_equal(serialized_point, hash) 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/speckle/core/models/gis_layer_collection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'collection' 4 | 5 | module SpeckleConnector3 6 | module SpeckleObjects 7 | module Speckle 8 | module Core 9 | module Models 10 | # VectorLayerCollection object that collect GIS vector elements under it's elements. 11 | class GisLayerCollection < Collection 12 | # @param state [States::State] state of the Speckle application. 13 | def self.to_native(state, vector_layer_collection, layer_or_folder, entities, &convert_to_native) 14 | elements = vector_layer_collection['elements'] 15 | 16 | elements.each do |element| 17 | new_state, _converted_entities = convert_to_native.call(state, element, layer_or_folder, entities) 18 | state = new_state 19 | end 20 | 21 | return state, [] 22 | end 23 | end 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/send_from_queue.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../accounts/accounts' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Send already converted objects from queue if exist on stream. 9 | class SendFromQueue < Action 10 | def initialize(stream_id) 11 | super() 12 | @stream_id = stream_id 13 | end 14 | 15 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 16 | # @return [States::State] the new updated state object 17 | def update_state(state) 18 | to_send_stream_id = state.speckle_state.stream_queue[:stream_id] 19 | return state if to_send_stream_id == @stream_id || to_send_stream_id.nil? 20 | 21 | to_send_converted = state.speckle_state.stream_queue[:converted].to_json 22 | new_state = state.with_add_queue('convertedFromSketchup', to_send_stream_id, [to_send_converted]) 23 | new_state.with_empty_stream_queue 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/app_observer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'event_observer' 4 | 5 | module SpeckleConnector3 6 | module Observers 7 | # App observer. 8 | class AppObserver < Sketchup::AppObserver 9 | include EventObserver 10 | 11 | # rubocop:disable Naming/MethodName 12 | # SketchUp observer method triggered when new empty model is created. 13 | # 14 | # @param model (Sketchup::Model): The active model object. 15 | def onNewModel(model) 16 | push_event(:onNewModel, model) 17 | end 18 | 19 | # SketchUp observer method triggered when previously saved model is opened. 20 | # 21 | # @param model (Sketchup::Model) - The active model object. 22 | def onOpenModel(model) 23 | push_event(:onOpenModel, model) 24 | end 25 | 26 | # SketchUp observer method triggered when user exists SketchUp. 27 | def onQuit 28 | push_event(:onQuit) 29 | end 30 | # rubocop:enable Naming/MethodName 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/test_actions/trigger_event.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Test purpose action. 8 | class TriggerEvent < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id, event_name) 12 | if event_name == 'emptyTestEvent' 13 | js_script = "testBinding.emit('#{event_name}')" 14 | else 15 | args = { 16 | name: 'Oguzhan', 17 | isOk: true, 18 | count: 3 19 | } 20 | js_script = "testBinding.emit('#{event_name}', #{args.to_json})" 21 | end 22 | resolve_js_script = "testBinding.receiveResponse('#{resolve_id}')" 23 | state = state.with_add_queue_js_command('triggerEventResolve', resolve_js_script) 24 | state.with_add_queue_js_command('triggerEvent', js_script) 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /ui/src/graphql/stream.gql: -------------------------------------------------------------------------------- 1 | query Stream($id: String!, $limit: Int!) { 2 | stream(id: $id) { 3 | id 4 | name 5 | description 6 | role 7 | isPublic 8 | createdAt 9 | updatedAt 10 | collaborators { 11 | id 12 | name 13 | company 14 | avatar 15 | role 16 | } 17 | commits(limit: 1) { 18 | totalCount 19 | items { 20 | id 21 | createdAt 22 | message 23 | authorId 24 | branchName 25 | authorName 26 | authorAvatar 27 | referencedObject 28 | } 29 | } 30 | branches (limit: $limit) { 31 | totalCount 32 | items { 33 | id 34 | name 35 | commits(limit: 10) { 36 | totalCount 37 | items { 38 | id 39 | createdAt 40 | message 41 | authorId 42 | branchName 43 | authorName 44 | authorAvatar 45 | sourceApplication 46 | referencedObject 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/get_send_settings.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../settings/card_settings' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to get send settings. 9 | class GetSendSettings < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id) 13 | # NOTE: below code is tested and works! 14 | # default_settings = [ 15 | # Settings::CardSetting.new(id: "includeAttributes", title: "Include Attributes", type: "boolean", value: true), 16 | # Settings::CardSetting.new(id: "test", title: "Test", type: "string", value: "a", enum: %w[a b c]) 17 | # ] 18 | default_settings = [] 19 | js_script = "sendBinding.receiveResponse('#{resolve_id}', #{default_settings.to_json})" 20 | state.with_add_queue_js_command('getSendSettings', js_script) 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/entities_observer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'event_observer' 4 | 5 | module SpeckleConnector3 6 | module Observers 7 | # Entities observer. 8 | class EntitiesObserver < Sketchup::EntitiesObserver 9 | include EventObserver 10 | 11 | # rubocop:disable Naming/MethodName 12 | # @param entities (Sketchup::Entities) 13 | # @param entity (Sketchup::Entity) 14 | def onElementAdded(entities, entity) 15 | push_event(:onElementAdded, entities, entity) 16 | end 17 | 18 | # @param entities (Sketchup::Entities) 19 | # @param entity (Sketchup::Entity) 20 | def onElementModified(entities, entity) 21 | push_event(:onElementModified, entities, entity) 22 | end 23 | 24 | # @param entities (Sketchup::Entities) 25 | # @param entity_id (Integer) id of the removed entity. 26 | def onElementRemoved(entities, entity_id) 27 | push_event(:onElementRemoved, entities, entity_id) 28 | end 29 | # rubocop:enable Naming/MethodName 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/other/display_style.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'color' 4 | require_relative '../base' 5 | require_relative '../../constants/type_constants' 6 | 7 | module SpeckleConnector3 8 | module SpeckleObjects 9 | module Other 10 | # DisplayStyle object for layer. 11 | class DisplayStyle < Base 12 | def initialize(name:, color:, line_type:) 13 | super( 14 | speckle_type: OBJECTS_OTHER_DISPLAYSTYLE, 15 | application_id: nil, 16 | id: nil 17 | ) 18 | self[:name] = name 19 | self[:color] = color 20 | self[:linetype] = line_type unless line_type.nil? 21 | end 22 | 23 | # @param layer [Sketchup::Layer] layer to get display style. 24 | def self.from_layer(layer) 25 | DisplayStyle.new( 26 | name: '', 27 | color: Color.to_int(layer.color), 28 | line_type: layer.line_style.nil? ? nil : layer.line_style.name 29 | ) 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/deactivate_diffing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Deactivate diffing. 8 | class DeactivateDiffing < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, _resolve_id, _data) 12 | puts 'Diffing deactivated!' 13 | speckle_entities = state.speckle_state.speckle_entities 14 | diffing_activated_speckle_entities = speckle_entities.reject do |_id, entity| 15 | entity.active_diffing_stream_id.nil? 16 | end 17 | diffing_activated_speckle_entities.each do |id, entity| 18 | new_entity = entity.deactivate_diffing 19 | speckle_entities = speckle_entities.put(id, new_entity) 20 | end 21 | new_speckle_state = state.speckle_state.with_speckle_entities(speckle_entities) 22 | state.with_speckle_state(new_speckle_state) 23 | end 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/send_actions/activate_send_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to activate send filter. 9 | class ActivateSendFilter < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id, data, value) 13 | SketchupModel::Dictionary::ModelCardDictionaryHandler.update_filter(state.sketchup_state.sketchup_model, data, value) 14 | card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}" 15 | send_card = state.speckle_state.send_cards[card_id] 16 | puts "Send card filter updated -> #{card_id} -> #{send_card}" 17 | js_script = "sendBindingOld.receiveResponse('#{resolve_id}')" 18 | state.with_add_queue_js_command('activateSendFilter', js_script) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/data/revit_data_object.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../../constants/type_constants' 5 | require_relative '../other/display_value' 6 | require_relative '../../sketchup_model/dictionary/base_dictionary_handler' 7 | 8 | module SpeckleConnector3 9 | module SpeckleObjects 10 | class RevitDataObject < Base 11 | SPECKLE_TYPE = SPECKLE_OBJECT_DATA_OBJECT_REVIT 12 | 13 | def self.to_native(state, revit_data_object, layer, entities, &convert_to_native) 14 | properties = revit_data_object['properties'] 15 | 16 | new_state, instance_and_definition = SpeckleObjects::Other::DisplayValue.to_native(state, revit_data_object, layer, entities, &convert_to_native) 17 | instance, _definition = instance_and_definition 18 | attr = instance.attribute_dictionary('Speckle', true) 19 | 20 | SketchupModel::Dictionary::BaseDictionaryHandler.hash_to_dict('Revit Parameters', properties, attr) if properties 21 | return new_state, instance_and_definition 22 | end 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/send_actions/activate_send_filter_tag.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to activate send filter tag. 9 | class ActivateSendFilterTag < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id, data, value) 13 | SketchupModel::Dictionary::ModelCardDictionaryHandler.update_tag_filter(state.sketchup_state.sketchup_model, data, value) 14 | card_id = "#{data['accountId']}-#{data['projectId']}-#{data['modelId']}" 15 | send_card = state.speckle_state.send_cards[card_id] 16 | puts "Send card filter updated -> #{card_id} -> #{send_card}" 17 | js_script = "sendBindingOld.receiveResponse('#{resolve_id}')" 18 | state.with_add_queue_js_command('activateSendFilterTag', js_script) 19 | end 20 | end 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/factory.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'app_observer' 4 | require_relative 'entity_observer' 5 | require_relative 'entities_observer' 6 | require_relative 'observer_handler' 7 | require_relative 'model_observer' 8 | require_relative 'event_handler' 9 | require_relative 'selection_observer' 10 | require_relative '../constants/observer_constants' 11 | 12 | module SpeckleConnector3 13 | module Observers 14 | # Factory class to create observers and it's handler 15 | module Factory 16 | module_function 17 | 18 | def create_handler(app) 19 | event_handler = EventHandler.new(app) 20 | ObserverHandler.new(event_handler) 21 | end 22 | 23 | def create_observers(handler) 24 | { 25 | APP_OBSERVER => AppObserver.new(handler), 26 | ENTITIES_OBSERVER => EntitiesObserver.new(handler), 27 | ENTITY_OBSERVER => EntityObserver.new(handler), 28 | MODEL_OBSERVER => ModelObserver.new(handler), 29 | SELECTION_OBSERVER => SelectionObserver.new(handler) 30 | }.freeze 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui_data/components/selections/list_selection_item.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module UiData 5 | module Components 6 | module Selections 7 | # Item of the list selection data for UI. 8 | class ListSelectionItem < Hash 9 | # @return [String] id of the selection item. 10 | attr_reader :id 11 | 12 | # @return [String] name of the selection item. 13 | attr_reader :name 14 | 15 | # @return [String, NilClass] color of the selection item. 16 | attr_reader :color 17 | 18 | # @return [String] summary of the selection item. 19 | attr_reader :summary 20 | 21 | def initialize(id, name, color, summary) 22 | super() 23 | @id = id 24 | @name = name 25 | @color = color 26 | @summary = summary 27 | self[:id] = id 28 | self[:name] = name 29 | self[:color] = color unless color.nil? 30 | self[:summary] = summary 31 | end 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/revit/family_instance.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../base' 4 | require_relative '../../../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module BuiltElements 9 | module Revit 10 | # Family instance for Revit mappings. 11 | class FamilyInstance < Base 12 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_FAMILY_INSTANCE 13 | 14 | # rubocop:disable Metrics/ParameterLists 15 | def initialize(family:, type:, level:, units:, base_point:, rotation:, application_id: nil) 16 | super( 17 | speckle_type: SPECKLE_TYPE, 18 | application_id: application_id, 19 | id: nil 20 | ) 21 | self[:family] = family 22 | self[:type] = type 23 | self[:level] = level 24 | self[:units] = units 25 | self[:basePoint] = base_point 26 | self[:rotation] = rotation 27 | end 28 | # rubocop:enable Metrics/ParameterLists 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/queue_send.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../states/state' 5 | require_relative '../states/speckle_state' 6 | require_relative '../actions/send_from_queue' 7 | 8 | module SpeckleConnector3 9 | module Actions 10 | # Send queue from state. 11 | class QueueSend < Action 12 | def initialize(stream_id, converted) 13 | super() 14 | @stream_id = stream_id 15 | @converted = converted 16 | end 17 | 18 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 19 | # @return [States::State] the new updated state object 20 | def update_state(state) 21 | to_send = { stream_id: @stream_id, converted: @converted } 22 | new_speckle_state = state.speckle_state.with(:@stream_queue => to_send) 23 | new_state = state.with(:@speckle_state => new_speckle_state) 24 | if new_state.is_connected 25 | action = Actions::SendFromQueue.new(@stream_id) 26 | new_state = action.update_state(new_state) 27 | end 28 | new_state 29 | end 30 | end 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /ui/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 13 | 17 | 21 | 22 | 23 | 24 | 30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/add_model.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'add_send_model_card' 4 | require_relative 'add_receive_model_card' 5 | require_relative '../action' 6 | require_relative '../../cards/send_card' 7 | require_relative '../../cards/receive_card' 8 | require_relative '../../filters/send/everything_filter' 9 | require_relative '../../filters/send/selection_filter' 10 | require_relative '../../filters/send_filters' 11 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 12 | 13 | module SpeckleConnector3 14 | module Actions 15 | # Action to add send card. 16 | class AddModel < Action 17 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 18 | # @return [States::State] the new updated state object 19 | def self.update_state(state, resolve_id, data) 20 | if data['typeDiscriminator'] == 'SenderModelCard' 21 | Actions::AddSendModelCard.update_state(state, resolve_id, data) 22 | else 23 | Actions::AddReceiveModelCard.update_state(state, resolve_id, data) 24 | end 25 | end 26 | end 27 | end 28 | end 29 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/bindings/send_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'binding' 4 | require_relative '../../actions/send_actions/send' 5 | require_relative '../../actions/send_actions/after_send_objects' 6 | require_relative '../../actions/base_actions/get_send_filters' 7 | require_relative '../../actions/base_actions/get_send_settings' 8 | require_relative '../../actions/base_actions/update_send_filter' 9 | 10 | module SpeckleConnector3 11 | module Ui 12 | SEND_BINDING_NAME = 'sendBinding' 13 | 14 | # Send Binding that provided for DUI. 15 | class SendBinding < Binding 16 | def commands 17 | @commands ||= { 18 | send: Commands::ActionCommand.new(@app, self, Actions::Send), 19 | getSendFilters: Commands::ActionCommand.new(@app, self, Actions::GetSendFilters), 20 | getSendSettings: Commands::ActionCommand.new(@app, self, Actions::GetSendSettings), 21 | updateSendFilter: Commands::ActionCommand.new(@app, self, Actions::UpdateSendFilter), 22 | afterSendObjects: Commands::ActionCommand.new(@app, self, Actions::AfterSendObjects) 23 | }.freeze 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /ui/src/graphql/streams.gql: -------------------------------------------------------------------------------- 1 | query Streams($cursor: String) { 2 | streams(cursor: $cursor) { 3 | totalCount 4 | cursor 5 | items { 6 | id 7 | name 8 | description 9 | role 10 | isPublic 11 | createdAt 12 | updatedAt 13 | collaborators { 14 | id 15 | name 16 | company 17 | avatar 18 | role 19 | } 20 | commits(limit: 1) { 21 | totalCount 22 | items { 23 | id 24 | createdAt 25 | message 26 | authorId 27 | branchName 28 | authorName 29 | authorAvatar 30 | referencedObject 31 | } 32 | } 33 | branches { 34 | totalCount 35 | items { 36 | id 37 | name 38 | commits(limit: 10) { 39 | totalCount 40 | items { 41 | id 42 | createdAt 43 | message 44 | authorId 45 | branchName 46 | authorName 47 | authorAvatar 48 | referencedObject 49 | } 50 | } 51 | } 52 | } 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ext/immutable_ruby/LICENSE: -------------------------------------------------------------------------------- 1 | Licensing 2 | ========= 3 | 4 | Copyright (c) 2009-2014 Simon Harris 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining 7 | a copy of this software and associated documentation files (the 8 | "Software"), to deal in the Software without restriction, including 9 | without limitation the rights to use, copy, modify, merge, publish, 10 | distribute, sublicense, and/or sell copies of the Software, and to 11 | permit persons to whom the Software is furnished to do so, subject to 12 | the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be 15 | included in all copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/path_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'pathname' 4 | require_relative 'platform_constants' 5 | 6 | # Speckle connector module to enable multiplayer mode ON! 7 | module SpeckleConnector3 8 | dir = __dir__.dup 9 | dir.force_encoding('UTF-8') if dir.respond_to?(:force_encoding) 10 | HOME_PATH = (ENV['HOME']).to_s 11 | SPECKLE_SRC_PATH = Pathname.new(File.expand_path('..', dir)).cleanpath.to_s 12 | SPECKLE_APPDATA_PATH = case OPERATING_SYSTEM 13 | when OS_WIN 14 | path = ENV.fetch('APPDATA') 15 | Pathname.new(File.join(path, 'Speckle')).cleanpath.to_s 16 | when OS_MAC 17 | File.join(Dir.home, 'Library/Application Support/Speckle') 18 | else 19 | raise 'Speckle could not determine your Appdata path' 20 | end 21 | SPECKLE_ACCOUNTS_DB_PATH = File.join(SPECKLE_APPDATA_PATH, 'Accounts.db') 22 | SPECKLE_CONFIG_DB_PATH = File.join(SPECKLE_APPDATA_PATH, 'DUI3Config.db') 23 | SPECKLE_TEST_DB_PATH = File.join(SPECKLE_APPDATA_PATH, 'sketchup_test.db') 24 | end 25 | -------------------------------------------------------------------------------- /tests/src/speckle_objects/test_base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../test_helper' 4 | require_relative '../../../speckle_connector_3/src/speckle_objects/base' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | class BaseTest < Minitest::Test 9 | def setup 10 | # Do nothing 11 | end 12 | 13 | def teardown 14 | # Do nothing 15 | end 16 | 17 | def test_base_init 18 | base = Base.new 19 | json = base.to_json 20 | 21 | base_obj = {"speckle_type":"Base","applicationId":nil,"id":nil} 22 | serialized = JSON.generate(base_obj) 23 | 24 | assert_equal(json, serialized) 25 | end 26 | 27 | def test_base_set_property 28 | base = Base.new 29 | base[:sketchup_attributes] = {soften_edge: true} 30 | base[:id] = 'idididididid' 31 | 32 | base_obj = {"speckle_type":"Base","applicationId":nil,"id":'idididididid', "sketchup_attributes": {"soften_edge": true }} 33 | serialized = JSON.generate(base_obj) 34 | hash = JSON.parse(serialized, { symbolize_names: true }) 35 | 36 | assert_equal(base, hash) 37 | end 38 | end 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui_data/components/selections/list_selection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'selection' 4 | 5 | module SpeckleConnector3 6 | module UiData 7 | module Components 8 | module Selections 9 | # Selections data for UI. 10 | class ListSelection < Selection 11 | # @return [Hash{Symbol=>ListSelectionItem}, Hash{Symbol=>ListSelection}] items of the selection. 12 | attr_reader :options 13 | 14 | # @return [Array] selected items of the selection. 15 | attr_reader :selected_options 16 | 17 | # @return [Boolean] whether is multiple selection or not. 18 | attr_reader :multiple_selection 19 | 20 | def initialize(id, name, options, selected_options, multiple_selection) 21 | super(id, name) 22 | @options = options 23 | @selected_options = selected_options 24 | @multiple_selection = multiple_selection 25 | self[:options] = options 26 | self[:selectedOptions] = selected_options 27 | self[:multipleSelection] = multiple_selection 28 | end 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/initialize_materials.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative 'add_material' 5 | require_relative '../constants/mat_constants' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Action to initialize materials (legacy for diff colors) 10 | class InitializeMaterials < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state) 14 | new_state = recreate_material(state, DEFAULT_NAMES[MAT_ADD], DEFAULT_COLORS[MAT_ADD], MAT_ADD) 15 | new_state = recreate_material(new_state, DEFAULT_NAMES[MAT_EDIT], DEFAULT_COLORS[MAT_EDIT], MAT_EDIT) 16 | recreate_material(new_state, DEFAULT_NAMES[MAT_REMOVE], DEFAULT_COLORS[MAT_REMOVE], MAT_REMOVE) 17 | end 18 | 19 | def self.recreate_material(state, name, color, id, alpha: nil) 20 | Actions::AddMaterial.update_state( 21 | state, 22 | material_name: name, 23 | color: color, 24 | material_id: id, 25 | alpha: alpha 26 | ) 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/send_actions/send_card_expiration_check.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to check send card expirations. 9 | class SendCardExpirationCheck < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state) 13 | return state unless state.speckle_state.changed_entity_persistent_ids.any? || state.speckle_state.changed_entity_ids.any? 14 | 15 | expired_send_cards_ids = state.speckle_state.send_cards.select do |_id, send_card| 16 | send_card.send_filter.check_expiry(state.speckle_state.changed_entity_persistent_ids) || 17 | send_card.send_filter.check_expiry(state.speckle_state.changed_entity_ids) 18 | end.keys.to_a 19 | js_script = "sendBinding.emit('setModelsExpired', #{expired_send_cards_ids.to_json})" 20 | state.with_add_queue_js_command('setModelsExpired', js_script) 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/geometry/vector.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'length' 4 | require_relative '../base' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module Geometry 9 | # Vector object definition for Speckle. 10 | class Vector < Base 11 | SPECKLE_TYPE = 'Objects.Geometry.Vector' 12 | 13 | # @param x [Numeric] x coordinate of the vector. 14 | # @param y [Numeric] y coordinate of the vector. 15 | # @param z [Numeric] z coordinate of the vector. 16 | # @param units [String] unit of the vector. 17 | def initialize(x, y, z, units) 18 | super( 19 | speckle_type: SPECKLE_TYPE, 20 | application_id: nil, 21 | id: nil 22 | ) 23 | self[:x] = x 24 | self[:y] = y 25 | self[:z] = z 26 | self[:units] = units 27 | end 28 | 29 | def self.to_native(x, y, z, units) 30 | Geom::Vector3d.new( 31 | Geometry.length_to_native(x, units), 32 | Geometry.length_to_native(y, units), 33 | Geometry.length_to_native(z, units) 34 | ) 35 | end 36 | end 37 | end 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /speckle_connector_3/src/ui/bindings/config_binding.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'binding' 4 | require_relative '../../actions/config_actions/get_is_dev_mode' 5 | require_relative '../../actions/config_actions/get_config' 6 | require_relative '../../actions/config_actions/update_config' 7 | require_relative '../../actions/config_actions/get_user_selected_account_id' 8 | require_relative '../../actions/config_actions/set_user_selected_account_id' 9 | 10 | module SpeckleConnector3 11 | module Ui 12 | CONFIG_BINDING_NAME = 'configBinding' 13 | 14 | # Config binding that provided for DUI. 15 | class ConfigBinding < Binding 16 | def commands 17 | @commands ||= { 18 | getIsDevMode: Commands::ActionCommand.new(@app, self, Actions::GetIsDevMode), 19 | getConfig: Commands::ActionCommand.new(@app, self, Actions::GetConfig), 20 | updateConfig: Commands::ActionCommand.new(@app, self, Actions::UpdateConfig), 21 | getUserSelectedAccountId: Commands::ActionCommand.new(@app, self, Actions::GetUserSelectedAccountId), 22 | setUserSelectedAccountId: Commands::ActionCommand.new(@app, self, Actions::SetUserSelectedAccountId) 23 | }.freeze 24 | end 25 | end 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/clear_mapper_source.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../sketchup_model/dictionary/speckle_entity_dictionary_handler' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Clear mapper source. 9 | class ClearMapperSource < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, _resolve_id, _data) 13 | new_speckle_state = state.speckle_state.with_removed_mapper_source 14 | erase_levels(state) 15 | state.with_speckle_state(new_speckle_state) 16 | end 17 | 18 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 19 | def self.erase_levels(state) 20 | levels = state.sketchup_state.sketchup_model.definitions.select do |definition| 21 | SketchupModel::Dictionary::SpeckleEntityDictionaryHandler.get_attribute(definition, :speckle_type) == 22 | OBJECTS_BUILTELEMENTS_REVIT_LEVEL 23 | end 24 | levels.each do |level| 25 | level.entities.clear! 26 | level.instances.each(&:erase!) 27 | end 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /speckle_connector_3/src/immutable/immutable.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Immutable 5 | # Mixin module with utilities for immutable objects 6 | module ImmutableUtils 7 | # Create a copy of the object with some of its instance variables changed 8 | # @param kw_args [{Symbol=>Object}] names and values for the instance variables that need to be changed 9 | # @return [Object] the same kind of object with some of the instance variables changed 10 | def with(**kw_args) 11 | return self if instance_variables_equal(**kw_args) 12 | 13 | new_object = dup 14 | kw_args.each do |var_name, value| 15 | new_object.instance_variable_set(var_name, value) 16 | end 17 | new_object 18 | end 19 | 20 | # Check if the given arguments are the same objects as the corresponding instance variables 21 | # @param kw_args [{Symbol=>Object}] names and values for the instance variables to be compared 22 | # @return [Boolean] true if all the objects are equal (using {eql?}) operator 23 | def instance_variables_equal(**kw_args) 24 | kw_args.all? do |var_name, value| 25 | value.eql?(instance_variable_get(var_name)) 26 | end 27 | end 28 | end 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/revit/revit_definition.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../other/block_definition' 4 | require_relative '../base' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module Revit 9 | module Other 10 | # RevitDefinition for Speckle. 11 | class RevitDefinition < Base 12 | SPECKLE_TYPE = OBJECTS_OTHER_REVIT_REVITINSTANCE 13 | 14 | def self.get_definition_name(def_obj) 15 | family = def_obj['family'] 16 | type = def_obj['type'] 17 | category = def_obj['category'] 18 | element_id = def_obj['elementId'] 19 | id = def_obj['id'] 20 | 21 | return "#{family}-#{type}-#{category}-#{element_id}-#{id}" 22 | end 23 | 24 | def self.to_native(state, definition, layer, entities, &convert_to_native) 25 | definition_name = get_definition_name(definition) 26 | definition['name'] = definition_name 27 | definition['displayValue'] += definition['elements'] unless definition['elements'].nil? 28 | SpeckleObjects::Other::BlockDefinition.to_native(state, definition, layer, entities, &convert_to_native) 29 | end 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /speckle_connector_3/src/convertors/converter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Converters 5 | # Helper class to convert geometries between server and Sketchup. 6 | class Converter 7 | # @return [States::State] the current state of the {SpeckleConnector3::App} 8 | attr_reader :state 9 | 10 | # @return [States::SpeckleState] the current speckle state of the {States::State} 11 | attr_reader :speckle_state 12 | 13 | # @return [Sketchup::Model] active sketchup model. 14 | attr_reader :sketchup_model 15 | 16 | # @return [String] stream id that conversion happening with it 17 | attr_reader :stream_id 18 | 19 | # @return [String] speckle units 20 | attr_reader :units 21 | 22 | attr_accessor :definitions 23 | 24 | # @param state [States::State] the current state of the {SpeckleConnector3::App} 25 | def initialize(state, stream_id) 26 | @state = state 27 | @speckle_state = state.speckle_state 28 | @sketchup_model = state.sketchup_state.sketchup_model 29 | @stream_id = stream_id 30 | su_unit = state.sketchup_state.length_units 31 | @units = Converters::SKETCHUP_UNITS[su_unit] 32 | @definitions = {} 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/base.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'json' 4 | require_relative '../immutable/immutable' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | # Dynamic Base object to send it to Speckle server. 9 | class Base < Hash 10 | include Immutable::ImmutableUtils 11 | 12 | attr_reader :speckle_type, :application_id, :id 13 | 14 | def initialize(speckle_type: 'Base', application_id: nil, id: '') 15 | @speckle_type = speckle_type 16 | @application_id = application_id 17 | @id = id 18 | super() 19 | update( 20 | { 21 | speckle_type: speckle_type, 22 | applicationId: application_id, 23 | id: id 24 | } 25 | ) 26 | end 27 | 28 | def self.with_detached_layers(detached_layers) 29 | Base.new.merge(detached_layers) 30 | end 31 | 32 | def []=(key, val) 33 | # Clear if setting string or symbol 34 | if ((key.is_a? String) || (key.is_a? Symbol)) && include?(key) 35 | delete key.to_sym 36 | delete key.to_s 37 | end 38 | # TODO: Control here if we have conditions to add dynamic property to 39 | merge!({ key => val }) 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /speckle_connector_3.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'sketchup' 4 | require 'extensions' 5 | 6 | # Speckle connector module to enable multiplayer mode ON! 7 | module SpeckleConnector3 8 | # Version - patched by CI 9 | CONNECTOR_VERSION = '0.0.0' 10 | 11 | file = __FILE__.dup 12 | 13 | # Account for Ruby encoding bug under Windows. 14 | file.force_encoding('UTF-8') if file.respond_to?(:force_encoding) 15 | 16 | # Support folder should be named the same as the root .rb file. 17 | folder_name = File.basename(file, '.*') 18 | 19 | # Path to the root .rb file (this file). 20 | PATH_ROOT = File.dirname(file).freeze 21 | 22 | # Path to the support folder. 23 | PATH = File.join(PATH_ROOT, folder_name).freeze 24 | 25 | # Run from localhost or from build files 26 | DEV_MODE = true 27 | puts("Loading Speckle Connector v#{CONNECTOR_VERSION} from #{DEV_MODE ? 'dev' : 'build'}") 28 | 29 | unless file_loaded?(__FILE__) 30 | ex = SketchupExtension.new('Speckle SketchUp v3', File.join(PATH, 'bootstrap')) 31 | ex.description = 'Speckle Connector for SketchUp' 32 | ex.version = CONNECTOR_VERSION 33 | ex.copyright = 'AEC Systems Ltd.' 34 | ex.creator = 'Speckle Systems' 35 | Sketchup.register_extension(ex, true) 36 | 37 | file_loaded(__FILE__) 38 | end 39 | end 40 | -------------------------------------------------------------------------------- /speckle_connector_3/src/sketchup_model/colors/color_manager.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../speckle_objects/other/color' 4 | require_relative '../../speckle_objects/color_proxy' 5 | 6 | module SpeckleConnector3 7 | # Operations related to {SketchupModel}. 8 | module SketchupModel 9 | # Color related utilities. 10 | module Colors 11 | # Handle colors for layers. 12 | class ColorManager 13 | # @return [Hash{String=>SpeckleObjects::ColorProxy}] render material proxies. 14 | attr_reader :color_proxies 15 | 16 | def initialize 17 | @color_proxies = {} 18 | end 19 | 20 | # @param sketchup_model [Sketchup::Model] sketchup model to get colors from layers 21 | def unpack_colors(sketchup_model) 22 | sketchup_model.layers.each do |layer| 23 | value = SpeckleObjects::Other::Color.to_int(layer.color) 24 | if color_proxies[value.to_s].nil? 25 | color_proxies[value.to_s] = SpeckleObjects::ColorProxy.new(layer.color, value, [layer.persistent_id.to_s]) 26 | else 27 | color_proxies[value.to_s].add_object_id(layer.persistent_id.to_s) 28 | end 29 | end 30 | 31 | color_proxies.values 32 | end 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/selection_actions/get_selection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../ui_data/sketchup/selection_info' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to get selection. 9 | class GetSelection < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id) 13 | # POC: Not happy with it. We log also entity.entityID property since 14 | # onElementRemoved observer only return them! :/ Reconsider this in BETA! 15 | selected_object_ids = state.sketchup_state.sketchup_model.selection.collect(&:persistent_id).collect(&:to_s) + 16 | state.sketchup_state.sketchup_model.selection.collect(&:entityID).collect(&:to_s) # That's bad 17 | summary = "Selected #{selected_object_ids.length / 2} objects." # POC: OFFF. I'll fix it 18 | selection_info = UiData::Sketchup::SelectionInfo.new(selected_object_ids, summary) 19 | js_script = "selectionBinding.receiveResponse('#{resolve_id}', #{selection_info.to_json})" 20 | state.with_add_queue_js_command('getSelection', js_script) 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/default_beam.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../geometry/line' 5 | require_relative '../../constants/type_constants' 6 | require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler' 7 | 8 | module SpeckleConnector3 9 | module SpeckleObjects 10 | module BuiltElements 11 | # Default Beam object. 12 | class DefaultBeam < Base 13 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_BEAM 14 | 15 | def initialize(base_line:, units:, application_id: nil) 16 | super( 17 | speckle_type: SPECKLE_TYPE, 18 | application_id: application_id, 19 | id: nil 20 | ) 21 | self[:baseLine] = base_line 22 | self[:units] = units 23 | end 24 | 25 | # @param edge [Sketchup::Edge] edge to get speckle schema for beam. 26 | def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil) 27 | base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units) 28 | 29 | DefaultBeam.new( 30 | base_line: base_line, 31 | units: units, 32 | application_id: edge.persistent_id.to_s 33 | ) 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/default_duct.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../geometry/line' 5 | require_relative '../../constants/type_constants' 6 | require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler' 7 | 8 | module SpeckleConnector3 9 | module SpeckleObjects 10 | module BuiltElements 11 | # Default Duct object. 12 | class DefaultDuct < Base 13 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_DUCT 14 | 15 | def initialize(base_line:, units:, application_id: nil) 16 | super( 17 | speckle_type: SPECKLE_TYPE, 18 | application_id: application_id, 19 | id: nil 20 | ) 21 | self[:baseLine] = base_line 22 | self[:units] = units 23 | end 24 | 25 | # @param edge [Sketchup::Edge] edge to get speckle schema for duct. 26 | def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil) 27 | base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units) 28 | 29 | DefaultDuct.new( 30 | base_line: base_line, 31 | units: units, 32 | application_id: edge.persistent_id.to_s 33 | ) 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/default_pipe.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../geometry/line' 5 | require_relative '../../constants/type_constants' 6 | require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler' 7 | 8 | module SpeckleConnector3 9 | module SpeckleObjects 10 | module BuiltElements 11 | # Default Pipe object. 12 | class DefaultPipe < Base 13 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_PIPE 14 | 15 | def initialize(base_line:, units:, application_id: nil) 16 | super( 17 | speckle_type: SPECKLE_TYPE, 18 | application_id: application_id, 19 | id: nil 20 | ) 21 | self[:baseLine] = base_line 22 | self[:units] = units 23 | end 24 | 25 | # @param edge [Sketchup::Edge] edge to get speckle schema for pipe. 26 | def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil) 27 | base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units) 28 | 29 | DefaultPipe.new( 30 | base_line: base_line, 31 | units: units, 32 | application_id: edge.persistent_id.to_s 33 | ) 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/receive_bindings/receive.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../accounts/accounts' 5 | require_relative '../../convertors/units' 6 | require_relative '../../convertors/to_speckle' 7 | require_relative '../../operations/send' 8 | 9 | module SpeckleConnector3 10 | module Actions 11 | # Receive from server. 12 | class Receive < Action 13 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 14 | # @return [States::State] the new updated state object 15 | def self.update_state(state, resolve_id, model_card_id) 16 | model_card = state.speckle_state.receive_cards[model_card_id] 17 | resolve_js_script = "receiveBinding.receiveResponse('#{resolve_id}')" 18 | state = state.with_add_queue_js_command('receive', resolve_js_script) 19 | args = { 20 | modelCardId: model_card_id, 21 | projectId: model_card.project_id, 22 | accountId: model_card.account_id, 23 | modelId: model_card.model_id, 24 | selectedVersionId: model_card.selected_version_id 25 | } 26 | js_script = "receiveBinding.emit('receiveViaBrowser', #{args.to_json})" 27 | state.with_add_queue_js_command('receiveViaBrowser', js_script) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/default_column.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../geometry/line' 5 | require_relative '../../constants/type_constants' 6 | require_relative '../../sketchup_model/dictionary/speckle_schema_dictionary_handler' 7 | 8 | module SpeckleConnector3 9 | module SpeckleObjects 10 | module BuiltElements 11 | # Default Column object. 12 | class DefaultColumn < Base 13 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_DEFAULT_COLUMN 14 | 15 | def initialize(base_line:, units:, application_id: nil) 16 | super( 17 | speckle_type: SPECKLE_TYPE, 18 | application_id: application_id, 19 | id: nil 20 | ) 21 | self[:baseLine] = base_line 22 | self[:units] = units 23 | end 24 | 25 | # @param edge [Sketchup::Edge] edge to get speckle schema for column. 26 | def self.to_speckle_schema(_speckle_state, edge, units, global_transformation: nil) 27 | base_line = Geometry::Line.to_speckle_schema(edge: edge, units: units) 28 | 29 | DefaultColumn.new( 30 | base_line: base_line, 31 | units: units, 32 | application_id: edge.persistent_id.to_s 33 | ) 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /ui/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /ui/src/plugins/vuetify.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuetify from 'vuetify/lib/framework' 3 | import '@/scss/styles.css' 4 | Vue.use(Vuetify) 5 | 6 | export default new Vuetify({ 7 | theme: { 8 | dark: false, 9 | themes: { 10 | light: { 11 | primary: '#0480FB', //speckle blue 12 | secondary: '#01D1FD', //spark blue 13 | accent: '#46B958', //data yellow 14 | mappingEntity: '#B9d8b5', 15 | error: '#FF5555', //red 16 | warning: '#D8BF16', //lightning yellow 17 | info: '#2D2ADA', //majestic blue 18 | success: '#22966C', //mantis green 19 | environment: '#AF02CB', //environment purple 20 | background: '#eeeeee', 21 | background2: '#ffffff', 22 | text: '#FFFFFF' 23 | }, 24 | dark: { 25 | primary: '#0480FB', //speckle blue 26 | secondary: '#01D1FD', //spark blue 27 | accent: '#46B958', //data yellow 28 | mappingEntity: '#46B958', 29 | error: '#FF5555', //red 30 | warning: '#D8BF16', //lightning yellow 31 | info: '#2D2ADA', //majestic blue 32 | success: '#22966C', //mantis green 33 | environment: '#AF02CB', //environment purple 34 | background: '#3a3b3c', 35 | background2: '#303132' 36 | } 37 | } 38 | }, 39 | icons: { 40 | iconfont: 'mdi' 41 | } 42 | }) 43 | -------------------------------------------------------------------------------- /speckle_connector_3/src/mapper/mapper_source.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../immutable/immutable' 4 | require_relative '../speckle_objects/built_elements/level' 5 | require_relative '../speckle_objects/built_elements/revit/revit_element_type' 6 | 7 | module SpeckleConnector3 8 | # Mapper is a tool to convert SketchUp entities to other applications' native objects. 9 | module Mapper 10 | # Mapper source object that collects information about stream id and commit id to identify source in the branch, 11 | # also contains levels and family types to be able to map objects with them. 12 | class MapperSource 13 | # @return [String] stream id of the mapper source. 14 | attr_reader :stream_id 15 | 16 | # @return [String] commit id of the mapper source. 17 | attr_reader :commit_id 18 | 19 | # @return [Array] levels in the source branch. 20 | attr_reader :levels 21 | 22 | # @return [Immutable::Hash{String=>Array}] revit element 23 | # types. 24 | attr_reader :types 25 | 26 | def initialize(stream_id, commit_id, levels, types) 27 | @stream_id = stream_id 28 | @commit_id = commit_id 29 | @levels = levels 30 | @types = types 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /tests/src/converters/test_base_object_serializer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../test_helper' 4 | require_relative '../../../speckle_connector_3/src/states/speckle_state' 5 | require_relative '../../../speckle_connector_3/src/speckle_objects/geometry/point' 6 | require_relative '../../../speckle_connector_3/src/speckle_objects/geometry/line' 7 | require_relative '../../../speckle_connector_3/src/convertors/base_object_serializer' 8 | require_relative '../../../speckle_connector_3/src/convertors/base_object_serializer_v2' 9 | 10 | module SpeckleConnector3 11 | module Converters 12 | class BaseObjectSerializerTest < Minitest::Test 13 | def setup 14 | # Do nothing 15 | end 16 | 17 | def teardown 18 | # Do nothing 19 | end 20 | 21 | def test_base_initialize 22 | speckle_state = States::SpeckleState.new({}, {}, {}, {}) 23 | start_point = SpeckleObjects::Geometry::Point.new(0.0, 0.0, 0.0, 'm') 24 | end_point = SpeckleObjects::Geometry::Point.new(10.0, 10.0, 0.0, 'm') 25 | line = SpeckleObjects::Geometry::Line.test_line(start_point, end_point, 'm') 26 | serializer = Converters::BaseObjectSerializerV2.new 27 | 28 | id, traversed = serializer.serialize(line) 29 | assert_equal(id, "a53c02860be04238514f1a5b00883fe2") 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/model_preference_updated.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative '../ext/sqlite3' 5 | require_relative '../accounts/accounts' 6 | require_relative '../constants/path_constants' 7 | require_relative '../sketchup_model/dictionary/speckle_model_dictionary_handler' 8 | 9 | module SpeckleConnector3 10 | module Actions 11 | # When preference updated by UI. 12 | class ModelPreferencesUpdated < Action 13 | def initialize(pref, value) 14 | super() 15 | @preference = pref 16 | @value = value 17 | end 18 | 19 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 20 | # @return [States::State] the new updated state object 21 | def update_state(state) 22 | model = state.user_state.preferences[:model].dup 23 | model[@preference.to_sym] = @value 24 | new_preferences = state.user_state.preferences.put(:model, model) 25 | SketchupModel::Dictionary::SpeckleModelDictionaryHandler.set_attribute( 26 | state.sketchup_state.sketchup_model, 27 | @preference.to_sym, 28 | @value, 29 | 'Speckle' 30 | ) 31 | new_user_state = state.user_state.with_preferences(new_preferences) 32 | state.with_user_state(new_user_state) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/events/event_action.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Actions 5 | # This module contains actions that are performed to handle events triggered by observers in Sketchup. 6 | module Events 7 | # Base action for Handling events 8 | class EventAction 9 | def self.actions 10 | raise NoMethodError, 'Implement in a subclass' 11 | end 12 | 13 | # Handle the events that were collected by the observer. In case of the selection observer, 14 | # we only need to handle the events once if any of the events actually happened. 15 | # @param state [States::State] the current state of the SpeckleConnector Application 16 | # @param events [Hash{Symbol=>Array}] the event data grouped by the event name 17 | # @return [States::State] the transformed state 18 | def self.update_state(state, events) 19 | # Don't do anything if there are no events for this action 20 | return state unless events 21 | 22 | actions = self.actions 23 | actions.each do |event_name, action| 24 | next unless events.key?(event_name) 25 | 26 | event_data = events[event_name] 27 | state = action.update_state(state, event_data) 28 | end 29 | state 30 | end 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | group :development do 6 | # mini tests for ruby classes 7 | gem 'minitest' 8 | # Git hooks manager 9 | gem 'overcommit', require: false 10 | # Pry is a runtime developer console and IRB alternative with powerful introspection capabilities. 11 | # Pry aims to be more than an IRB replacement. It is an attempt to bring REPL driven programming to the Ruby language. 12 | gem 'pry' 13 | # Make-like program implemented in Ruby. Tasks and dependencies are specified in standard Ruby syntax. 14 | gem 'rake' 15 | # RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter. 16 | gem 'rubocop' 17 | # A RuboCop extension focused on enforcing Minitest best practices and coding conventions. 18 | gem 'rubocop-minitest' 19 | # A RuboCop plugin for Rake. 20 | gem 'rubocop-rake' 21 | # Code analysis for SketchUp extensions using the SketchUp Ruby API. 22 | gem 'rubocop-sketchup' 23 | # wraps around static analysis gems such as Reek, Flay and Flog to provide a quality report of your Ruby code. 24 | gem 'rubycritic', '~> 4.3', '>= 4.3.3', require: false 25 | # Auto completions for SketchUp API. 26 | gem 'sketchup-api-stubs' 27 | # Runtime dependency of skippy for Ruby 3.2. Have it! 28 | gem 'sorted_set', '~> 1.0' 29 | # Aid with common SketchUp extension tasks. 30 | gem 'skippy', '~> 0.5.2.a' 31 | end 32 | -------------------------------------------------------------------------------- /tests/src/operations/test_receive.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'net/http' 4 | 5 | require_relative '../../test_helper' 6 | require_relative '../../../speckle_connector_3/src/accounts/accounts' 7 | 8 | module SpeckleConnector3 9 | module Converters 10 | class ReceiveTest < Minitest::Test 11 | 12 | # Replace here test stream id on your local server account 13 | TEST_STREAM_ID = 'f0b4392dc8' 14 | 15 | # Replace here test object id 16 | TEST_OBJECT_ID = '76de2dc989ccab95c3c5ee2d977587b4' 17 | 18 | def setup 19 | # Do nothing 20 | end 21 | 22 | def teardown 23 | # Do nothing 24 | end 25 | 26 | def test_receive 27 | local_server_account = Accounts.try_get_local_server_account 28 | uri = URI.parse("https://speckle.xyz/objects/1ce562e99a/745ea505d154c09e2317121bd263a2b2/single") 29 | # uri = URI.parse("#{local_server_account['serverInfo']['url']}/objects/#{TEST_STREAM_ID}/#{TEST_OBJECT_ID}/single") 30 | http = Net::HTTP.new(uri.host, uri.port) 31 | req = Net::HTTP::Get.new(uri) 32 | req["Authorization"] = "Bearer #{local_server_account['token']}" 33 | res = http.request(req) 34 | object_id = JSON.parse(res.body)["id"] 35 | assert_equal(TEST_OBJECT_ID, object_id) 36 | rescue => e 37 | puts "failed #{e}" 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /speckle_connector_3/src/constants/pref_constants.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../speckle_objects/geometry/length' 4 | 5 | module SpeckleConnector3 6 | COMBINE_FACES_BY_MATERIAL = :combine_faces_by_material 7 | INCLUDE_ENTITY_ATTRIBUTES = :include_entity_attributes 8 | INCLUDE_FACE_ENTITY_ATTRIBUTES = :include_face_entity_attributes 9 | INCLUDE_EDGE_ENTITY_ATTRIBUTES = :include_edge_entity_attributes 10 | INCLUDE_GROUP_ENTITY_ATTRIBUTES = :include_group_entity_attributes 11 | INCLUDE_COMPONENT_ENTITY_ATTRIBUTES = :include_component_entity_attributes 12 | MERGE_COPLANAR_FACES = :merge_coplanar_faces 13 | 14 | ENTITY_KEYS_FOR_INCLUDING_ATTRIBUTES = { 15 | Sketchup::ComponentInstance => INCLUDE_COMPONENT_ENTITY_ATTRIBUTES, 16 | Sketchup::Group => INCLUDE_GROUP_ENTITY_ATTRIBUTES, 17 | Sketchup::Face => INCLUDE_FACE_ENTITY_ATTRIBUTES, 18 | Sketchup::Edge => INCLUDE_EDGE_ENTITY_ATTRIBUTES 19 | }.freeze 20 | 21 | LEVEL_SHIFT_VALUE = SpeckleObjects::Geometry.length_to_native(1.5, 'm') 22 | 23 | DEFAULT_MODEL_PREFERENCES = { 24 | COMBINE_FACES_BY_MATERIAL => true, 25 | INCLUDE_ENTITY_ATTRIBUTES => true, 26 | INCLUDE_FACE_ENTITY_ATTRIBUTES => true, 27 | INCLUDE_EDGE_ENTITY_ATTRIBUTES => true, 28 | INCLUDE_GROUP_ENTITY_ATTRIBUTES => true, 29 | INCLUDE_COMPONENT_ENTITY_ATTRIBUTES => true, 30 | MERGE_COPLANAR_FACES => true 31 | }.freeze 32 | end 33 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/activate_diffing.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative 'deactivate_diffing' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Deactivate diffing for stream. 9 | class ActivateDiffing < Action 10 | def initialize(stream_id) 11 | super() 12 | @stream_id = stream_id 13 | end 14 | 15 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 16 | # @return [States::State] the new updated state object 17 | def update_state(state) 18 | state = DeactivateDiffing.update_state(state, nil, {}) 19 | puts "Diffing activated for #{@stream_id}" 20 | speckle_entities = state.speckle_state.speckle_entities 21 | invalid_speckle_entities = speckle_entities.select do |_id, entity| 22 | entity.invalid_stream_ids.include?(@stream_id) && entity.sketchup_entity.is_a?(Sketchup::Face) 23 | end 24 | invalid_speckle_entities.each do |id, entity| 25 | new_entity = entity.activate_diffing(@stream_id, state.sketchup_state.materials.by_id(MAT_EDIT)) 26 | speckle_entities = speckle_entities.put(id, new_entity) 27 | end 28 | new_speckle_state = state.speckle_state.with_speckle_entities(speckle_entities) 29 | state.with_speckle_state(new_speckle_state) 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/handle_error.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Actions 5 | # Action to return error message to UI. 6 | # It is "TopLevelExceptionHandler" equivalent of C#. 7 | class HandleError < Action 8 | # @return [StandardError] error 9 | attr_reader :error 10 | 11 | # @param error [StandardError] error 12 | # @param view_name [String] name of the view (binding) 13 | # @param action [Action] action that error happened 14 | # @param parameters [Array] arguments 15 | def initialize(error, view_name, action, parameters) 16 | super() 17 | @error = error 18 | @view_name = view_name 19 | @action = action 20 | @args = parameters 21 | end 22 | 23 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 24 | # @return [States::State] the new updated state object 25 | def update_state(state) 26 | # TODO: Log here when it is ready!!! 27 | host_app_error = { 28 | message: error.message, 29 | error: error, 30 | stackTrace: error.backtrace 31 | } 32 | js_error_script = "#{@view_name}.receiveResponse('#{@args.first}', #{host_app_error.to_json})" 33 | state.with_add_queue_js_command("error_#{@view_name}", js_error_script) 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/on_events_action.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative 'events/app_event_action' 5 | require_relative 'events/entities_event_action' 6 | require_relative 'events/entity_event_action' 7 | require_relative 'events/model_event_action' 8 | require_relative 'events/selection_event_action' 9 | require_relative '../constants/observer_constants' 10 | 11 | module SpeckleConnector3 12 | module Actions 13 | # Handle events that were collected by observers 14 | class OnEventsAction < Action 15 | RUN_ORDER = { 16 | APP_OBSERVER => Events::AppEventAction, 17 | ENTITY_OBSERVER => Events::EntityEventAction, 18 | ENTITIES_OBSERVER => Events::EntitiesEventAction, 19 | MODEL_OBSERVER => Events::ModelEventAction, 20 | # MATERIALS_OBSERVER => Events::MaterialsEventAction, 21 | # LAYERS_OBSERVER => Events::LayerEventAction, 22 | # PAGES_OBSERVER => Events::PagesEventAction, 23 | SELECTION_OBSERVER => Events::SelectionEventAction 24 | }.freeze 25 | 26 | def self.update_state(state, events) 27 | RUN_ORDER.each do |observer_name, action| 28 | next unless events.key?(observer_name) 29 | 30 | parameters = events[observer_name] 31 | state = action.update_state(state, parameters) 32 | end 33 | state 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/highlight_model.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../sketchup_model/query/entity' 5 | 6 | module SpeckleConnector3 7 | module Actions 8 | # Action to add send card. 9 | class HighlightModel < Action 10 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 11 | # @return [States::State] the new updated state object 12 | def self.update_state(state, resolve_id, model_card_id) 13 | receiver_card = state.speckle_state.receive_cards[model_card_id] 14 | sender_card = state.speckle_state.send_cards[model_card_id] 15 | card = receiver_card || sender_card 16 | 17 | objects_to_highlight = if card.type_discriminator == 'ReceiverModelCard' 18 | state.speckle_state.receive_cards[model_card_id].baked_object_ids 19 | else 20 | state.speckle_state.send_cards[model_card_id].send_filter.selected_object_ids 21 | end 22 | 23 | SketchupModel::Utils::ViewUtils.highlight_entities(state.sketchup_state.sketchup_model, objects_to_highlight) 24 | 25 | # Resolve promise 26 | js_script = "baseBinding.receiveResponse('#{resolve_id}')" 27 | state.with_add_queue_js_command('highlightModel', js_script) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/geometry/plane.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'point' 4 | require_relative 'vector' 5 | require_relative '../base' 6 | 7 | module SpeckleConnector3 8 | module SpeckleObjects 9 | module Geometry 10 | # Plane object definition for Speckle. 11 | class Plane < Base 12 | SPECKLE_TYPE = 'Objects.Geometry.Plane' 13 | 14 | # @param x_dir [Geometry::Vector] vector on the x direction 15 | # @param y_dir [Geometry::Vector] vector on the y direction 16 | # @param normal [Geometry::Vector] normal vector 17 | # @param origin [Geometry::Point] origin point 18 | # @param units [String] units of the Sketchup model 19 | def initialize(x_dir, y_dir, normal, origin, units) 20 | super( 21 | speckle_type: SPECKLE_TYPE, 22 | application_id: nil, 23 | id: nil 24 | ) 25 | self[:xdir] = x_dir 26 | self[:ydir] = y_dir 27 | self[:normal] = normal 28 | self[:origin] = origin 29 | self[:units] = units 30 | end 31 | 32 | def self.origin(units) 33 | Plane.new( 34 | Vector.new(1, 0, 0, units), 35 | Vector.new(0, 1, 0, units), 36 | Vector.new(0, 0, 1, units), 37 | Point.new(0, 0, 0, units), 38 | units 39 | ) 40 | end 41 | end 42 | end 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /speckle_connector_3/src/sketchup_model/utils/view_utils.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../sketchup_model/query/entity' 4 | 5 | module SpeckleConnector3 6 | # Operations related to {SketchupModel}. 7 | module SketchupModel 8 | # Works directly with/on SketchUp Entities of different kinds (Groups, Faces, Edges, ...). 9 | module Utils 10 | # View related utils 11 | class ViewUtils 12 | def self.highlight_entities(sketchup_model, entity_ids) 13 | sketchup_model.selection.clear 14 | 15 | # below code causing huge performance bottleneck since iterate nestedly, I was initially considering to cover all cases, 16 | # but not worth to have highlighting sub elements since we already highlight the parent. This can be only an issue when user sends 17 | # only the sub elements 18 | # Flat entities to select entities on card 19 | # flat_entities = SketchupModel::Query::Entity.flat_entities(sketchup_model.entities) 20 | 21 | sketchup_model.entities.each do |entity| 22 | next unless entity_ids.include?(entity.persistent_id.to_s) 23 | 24 | sketchup_model.selection.add(entity.instances) if entity.is_a?(Sketchup::ComponentDefinition) 25 | sketchup_model.selection.add(entity) 26 | end 27 | 28 | sketchup_model.active_view.zoom(sketchup_model.selection) 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/geometry/circle.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'point' 4 | require_relative 'vector' 5 | require_relative 'length' 6 | require_relative '../base' 7 | require_relative '../../constants/type_constants' 8 | 9 | module SpeckleConnector3 10 | module SpeckleObjects 11 | module Geometry 12 | # Circle object definition for Speckle. 13 | class Circle < Base 14 | SPECKLE_TYPE = OBJECTS_GEOMETRY_CIRCLE 15 | 16 | # @param [States::State] state of the current application. 17 | # @param circle [Object] object represents Speckle Circle. 18 | # @param layer [Sketchup::Layer] layer to add {Sketchup::Edge} into it. 19 | # @param entities [Sketchup::Entities] entities collection to add {Sketchup::Edge} into it. 20 | def self.to_native(state, circle, layer, entities, &_convert_to_native) 21 | plane = circle['plane'] 22 | units = circle['units'] 23 | origin = Point.to_native(plane['origin']['x'], plane['origin']['y'], plane['origin']['z'], units) 24 | normal = Vector.to_native(plane['normal']['x'], plane['normal']['y'], plane['normal']['z'], units) 25 | radius = Geometry.length_to_native(circle['radius'], units) 26 | edges = entities.add_circle(origin, normal, radius) 27 | edges.each { |edge| edge.layer = layer } 28 | return state, edges 29 | end 30 | end 31 | end 32 | end 33 | end 34 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/built_elements/revit/revit_element_type.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../base' 4 | 5 | module SpeckleConnector3 6 | module SpeckleObjects 7 | module BuiltElements 8 | module Revit 9 | # Revit element type. 10 | class RevitElementType < Base 11 | SPECKLE_TYPE = OBJECTS_BUILTELEMENTS_REVIT_REVITELEMENTTYPE 12 | 13 | # rubocop:disable Metrics/ParameterLists 14 | def initialize(category:, family:, type:, element_id:, application_id: nil, id: nil) 15 | super( 16 | speckle_type: SPECKLE_TYPE, 17 | application_id: application_id, 18 | id: id 19 | ) 20 | self[:category] = category 21 | self[:family] = family 22 | self[:type] = type 23 | self[:elementId] = element_id 24 | end 25 | # rubocop:enable Metrics/ParameterLists 26 | 27 | def self.to_native(revit_element_type) 28 | RevitElementType.new( 29 | category: revit_element_type['category'], 30 | family: revit_element_type['family'], 31 | type: revit_element_type['type'], 32 | element_id: revit_element_type['elementId'], 33 | application_id: revit_element_type['applicationId'], 34 | id: revit_element_type['id'] 35 | ) 36 | end 37 | end 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/primitive/interval.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../base' 4 | require_relative '../../speckle_objects/geometry/length' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module Primitive 9 | # Interval object definition for Speckle. 10 | class Interval < Base 11 | SPECKLE_TYPE = 'Objects.Primitive.Interval' 12 | 13 | # @param units [String] units of the interval. 14 | # @param start_value [Numeric] start value of the transform. 15 | # @param end_value [Numeric] end value of the transform. 16 | def initialize(units:, start_value:, end_value:) 17 | super( 18 | speckle_type: SPECKLE_TYPE, 19 | application_id: nil, 20 | id: nil 21 | ) 22 | self[:units] = units 23 | self[:start] = start_value 24 | self[:end] = end_value 25 | end 26 | 27 | def self.from_numeric(start_value, end_value, units) 28 | Interval.new( 29 | units: units, 30 | start_value: start_value, 31 | end_value: end_value 32 | ) 33 | end 34 | 35 | def self.from_lengths(length_1, length_2, units) 36 | start_value = Geometry.length_to_speckle(length_1, units) 37 | end_value = Geometry.length_to_speckle(length_2, units) 38 | from_numeric(start_value, end_value, units) 39 | end 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /speckle_connector_3/bootstrap.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require 'sketchup' 4 | require 'pathname' 5 | require 'speckle_connector_3/debug' 6 | require_relative 'src/log/log' 7 | require_relative 'src/ui/sketchup_ui' 8 | require_relative 'src/ui/ui_controller' 9 | require_relative 'src/commands/menu_command_handler' 10 | require_relative 'src/app/speckle_connector_app' 11 | require_relative 'src/states/user_state' 12 | require_relative 'src/states/initial_state' 13 | require_relative 'src/commands/speckle_menu_commands' 14 | 15 | # Speckle Connector on SketchUp to enable Multiplayer mode ON! 16 | module SpeckleConnector3 17 | SKETCHUP_VERSION = Sketchup.version.to_i 18 | 19 | dir = __dir__.dup 20 | dir.force_encoding('UTF-8') if dir.respond_to?(:force_encoding) 21 | SPECKLE_CONNECTOR_SRC_PATH = Pathname.new(File.expand_path(dir)).cleanpath.to_s 22 | 23 | def self.initialize_app 24 | sketchup_ui = Ui::SketchupUi.new 25 | ui_controller = Ui::UiController.new(sketchup_ui) 26 | menu_commands = Commands::MenuCommandHandler.new 27 | user_state = SpeckleConnector3::States::UserState.new({}) 28 | initial_state = SpeckleConnector3::States::InitialState.new(user_state) 29 | app = SpeckleConnector3::App::SpeckleConnectorApp.new(menu_commands, initial_state, ui_controller) 30 | # Add menu commands to SketchUp and Speckle application 31 | Commands::SpeckleMenuCommands.add_initial_commands!(app) 32 | app 33 | end 34 | 35 | app = initialize_app 36 | SPECKLE_APP = app 37 | end 38 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/remove_model.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../cards/send_card' 5 | require_relative '../../cards/receive_card' 6 | require_relative '../../filters/send/everything_filter' 7 | require_relative '../../filters/send/selection_filter' 8 | require_relative '../../filters/send_filters' 9 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 10 | 11 | module SpeckleConnector3 12 | module Actions 13 | # Action to remove send card. 14 | class RemoveModel < Action 15 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 16 | # @return [States::State] the new updated state object 17 | def self.update_state(state, resolve_id, data) 18 | SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, data) 19 | new_speckle_state = if data['typeDiscriminator'] == 'ReceiverModelCard' 20 | state.speckle_state.without_receive_card(data['id']) 21 | else 22 | state.speckle_state.without_send_card(data['id']) 23 | end 24 | state = state.with_speckle_state(new_speckle_state) 25 | # Resolve promise 26 | js_script = "baseBinding.receiveResponse('#{resolve_id}')" 27 | state.with_add_queue_js_command('removeModel', js_script) 28 | end 29 | end 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/hide_mappings_from_table.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'action' 4 | require_relative 'events/selection_event_action' 5 | require_relative '../sketchup_model/dictionary/speckle_schema_dictionary_handler' 6 | 7 | module SpeckleConnector3 8 | module Actions 9 | # Hide entities that selected from mapped elements table. 10 | class HideMappingsFromTable < Action 11 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 12 | # @return [States::State] the new updated state object 13 | def self.update_state(state, _resolve_id, data) 14 | # Flat entities to clear mappings 15 | flat_entities = SketchupModel::Query::Entity.flat_entities(state.sketchup_state.sketchup_model.entities) 16 | 17 | # Collect entity ids to clear mappings 18 | entity_ids = data.collect { |_, entities| entities['selectedElements'].collect { |e| e['entityId'] } }.flatten 19 | 20 | # Store speckle state to update with mapped entities. 21 | flat_entities.each do |entity| 22 | next unless entity_ids.include?(entity.persistent_id.to_s) 23 | 24 | if entity.is_a?(Sketchup::ComponentDefinition) 25 | entity.instances.each do |instance| 26 | instance.hidden = true 27 | end 28 | end 29 | entity.hidden = true 30 | end 31 | 32 | Events::SelectionEventAction.update_state(state, { clear: true }) 33 | end 34 | end 35 | end 36 | end 37 | -------------------------------------------------------------------------------- /_tools/jf_RubyPanel.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # #------------------------------------------------------------------------------------------------- 4 | # ************************************************************************************************* 5 | # RubyPanel Toolbar (C) 2007 jim.foltz@gmail.com 6 | # 7 | # With special thanks to Chris Phillips (Sketchy Physics) 8 | # for the Win32API code examples. 9 | # 10 | # 2011-01-05 11 | # * Changed Toolbar name from "Ruby COnsole" to "Ruby Toolbar" (TT) 12 | # http://forums.sketchucation.com/viewtopic.php?f=323&t=1542&p=298587#p298587 13 | # * Wrapped in addition module RubyToolbar 14 | # * Use $suString.GetSting to get proper "Ruby Console" name string. 15 | # * Better check if TB was previously visible 16 | # * Use UI.start_timer to restore Toolbar 17 | # ICONS: located in the subfolder "rubytoolbar" 18 | # MODIFICATION: by Fredo6 for compliance with SU 2014 (and no dependency on Win32API) - 18 Sep 2013 19 | # ************************************************************************************************* 20 | #------------------------------------------------------------------------------------------------- 21 | 22 | require 'sketchup' 23 | require 'extensions' 24 | 25 | ext = SketchupExtension.new('Ruby Toolbar', 'jf_RubyPanel/rubytoolbar.rb') 26 | ext.creator = 'Jim Foltz ' 27 | ext.description = 'Toolbar for manipulating the Ruby Console. Compatible with SketchUp 2014' 28 | ext.version = '2014' 29 | Sketchup.register_extension(ext, true) 30 | -------------------------------------------------------------------------------- /speckle_connector_3/src/observers/event_observer.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'event_hash' 4 | require_relative '../actions/on_events_action' 5 | 6 | module SpeckleConnector3 7 | module Observers 8 | # Observer classes includes it to check common operations for all observer classes. 9 | module EventObserver 10 | # @return [ObserverHandler] handler for observer events 11 | attr_reader :observer_handler 12 | 13 | def initialize(observer_handler) 14 | super() 15 | @observer_handler = observer_handler 16 | end 17 | 18 | def push_event(event_name, *event_data) 19 | return if observers_disabled? 20 | 21 | @observer_handler.handle_event!(self.class.name, event_name, event_data) 22 | end 23 | 24 | def observers_disabled? 25 | @observer_handler.observers_disabled? 26 | end 27 | 28 | # Push event only once. If the event is already registered, don't push it again 29 | # @param event_name [Symbol] the name of the event 30 | # @param event_data [Array] the optional data that comes with the event 31 | def push_once(event_name, *event_data) 32 | return if observers_disabled? 33 | 34 | # Don't push anything if the selection event was already registered 35 | class_events = @observer_handler.events[self.class] 36 | events = class_events && class_events[event_name] 37 | return if events&.any? 38 | 39 | push_event(event_name, *event_data) 40 | end 41 | end 42 | end 43 | end 44 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/speckle/core/models/collection.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../../base' 4 | require_relative '../../../../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | module Speckle 9 | module Core 10 | module Models 11 | # Collection object that collect other speckle objects under it's elements. 12 | class Collection < Base 13 | # @param name [String] name of the collection. 14 | # @param collection_type [String] type of the collection like, layers, categories etc.. 15 | # @param elements [Array] elements of the collection. 16 | # @param application_id [String, nil] id of the collection on the model. 17 | def initialize(name:, collection_type:, elements: [], application_id: nil) 18 | super( 19 | speckle_type: SPECKLE_CORE_MODELS_COLLECTION, 20 | application_id: application_id, 21 | id: nil 22 | ) 23 | self[:name] = name 24 | self[:collectionType] = collection_type 25 | self['@elements'] = elements 26 | end 27 | 28 | def self.to_native(state, collection, layer, entities, &convert_to_native) 29 | # Always iterate as layer collection with V3 30 | LayerCollection.to_native(state, collection, layer, entities, &convert_to_native) 31 | end 32 | end 33 | end 34 | end 35 | end 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /speckle_connector_3/src/sketchup_model/dictionary/speckle_entity_dictionary_handler.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'base_dictionary_handler' 4 | require_relative '../../constants/dict_constants' 5 | require_relative '../../constants/type_constants' 6 | 7 | module SpeckleConnector3 8 | module SketchupModel 9 | module Dictionary 10 | # Dictionary handler of the speckle entity. 11 | class SpeckleEntityDictionaryHandler < DictionaryHandler 12 | DICTIONARY_NAME = SPECKLE_BASE_OBJECT 13 | 14 | # Writes initial data while speckle entity is creating first time. 15 | # @param sketchup_entity [Sketchup::Entity] Sketchup entity to write data into it's attribute dictionary. 16 | # rubocop:disable Metrics/ParameterLists 17 | def self.write_initial_base_data(sketchup_entity, application_id, id, speckle_type, children, stream_id) 18 | initial_dict_data = { 19 | # Add here more if you want to write here initial data 20 | SPECKLE_ID => id, 21 | APPLICATION_ID => application_id, 22 | SPECKLE_TYPE => speckle_type, 23 | CHILDREN => children, 24 | VALID_STREAM_IDS => [stream_id], 25 | INVALID_STREAM_IDS => [] 26 | } 27 | set_hash(sketchup_entity, initial_dict_data) 28 | end 29 | # rubocop:enable Metrics/ParameterLists 30 | 31 | # @return [String] the name of the dictionary to read from 32 | def self.dictionary_name 33 | DICTIONARY_NAME 34 | end 35 | end 36 | end 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/sketchup_config_actions/get_user_config.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | 5 | module SpeckleConnector3 6 | module Actions 7 | # Action to get user config. 8 | class GetUserConfig < Action 9 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 10 | # @return [States::State] the new updated state object 11 | def self.update_state(state, resolve_id) 12 | # Previously it was stored in user state 13 | # config = state.user_state.preferences.to_json 14 | config = [ 15 | { 16 | key: 'darkTheme', 17 | title: 'Theme', 18 | type: 'toggle', 19 | config: { 20 | value: state.user_state.user_preferences[:dark_theme] 21 | } 22 | }, 23 | { 24 | key: 'diffing', 25 | title: 'Diffing', 26 | type: 'toggle', 27 | config: { 28 | value: state.user_state.user_preferences[:diffing] 29 | } 30 | }, 31 | { 32 | key: 'referencePoint', 33 | title: 'Reference Point', 34 | type: 'dropdown', 35 | config: { 36 | value: 'test', 37 | items: ['test', 'test1', 'test2'] 38 | } 39 | } 40 | ] 41 | js_script = "connectorConfigBinding.receiveResponse('#{resolve_id}', #{config.to_json})" 42 | state.with_add_queue_js_command('getUserConfig', js_script) 43 | end 44 | end 45 | end 46 | end 47 | -------------------------------------------------------------------------------- /speckle_connector_3/src/states/speckle_mapper_state.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../immutable/immutable' 4 | require_relative '../callbacks/callback_message' 5 | require_relative '../speckle_entities/speckle_entity' 6 | require_relative '../mapper/mapper_source' 7 | 8 | module SpeckleConnector3 9 | module States 10 | # State of the speckle on ruby. 11 | class SpeckleMapperState 12 | include Immutable::ImmutableUtils 13 | 14 | # @return [Immutable::Hash{Integer=>Sketchup::Entity}] persistent_id of the sketchup entity and itself 15 | attr_reader :mapped_entities 16 | 17 | # @return [Mapper::MapperSource] source of the mapper. 18 | attr_reader :mapper_source 19 | 20 | def initialize 21 | @mapped_entities = Immutable::EmptyHash 22 | @mapper_source = nil 23 | end 24 | 25 | def with_mapped_entity(entity) 26 | new_mapped_entities = mapped_entities.put(entity.persistent_id.to_s, entity) 27 | with_mapped_entities(new_mapped_entities) 28 | end 29 | 30 | def with_removed_mapped_entity(entity) 31 | new_mapped_entities = mapped_entities.delete(entity.persistent_id.to_s) 32 | with_mapped_entities(new_mapped_entities) 33 | end 34 | 35 | def with_mapped_entities(new_mapped_entities) 36 | with(:@mapped_entities => new_mapped_entities) 37 | end 38 | 39 | def with_mapper_source(mapper_source) 40 | # TODO: Check/Sync here parameters of the mapped entities. 41 | with(:@mapper_source => mapper_source) 42 | end 43 | end 44 | end 45 | end 46 | -------------------------------------------------------------------------------- /speckle_connector_3/src/convertors/converter_v2.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module SpeckleConnector3 4 | module Converters 5 | # Helper class to convert geometries between server and Sketchup. 6 | class ConverterV2 7 | # @return [States::State] the current state of the {SpeckleConnector3::App} 8 | attr_reader :state 9 | 10 | # @return [States::SpeckleState] the current speckle state of the {States::State} 11 | attr_reader :speckle_state 12 | 13 | # @return [Sketchup::Model] active sketchup model. 14 | attr_reader :sketchup_model 15 | 16 | # @return [Cards::Card] card that conversion happening with it 17 | attr_reader :model_card 18 | 19 | # @return [String] speckle units 20 | attr_reader :units 21 | 22 | # @return [String] prefix that structured from Project and Model name 23 | attr_reader :model_prefix 24 | 25 | attr_accessor :definitions 26 | 27 | # @param state [States::State] the current state of the {SpeckleConnector3::App} 28 | # @param model_card [Cards::Card] model card that holds info for operation 29 | def initialize(state, model_card) 30 | @state = state 31 | @model_card = model_card 32 | @model_prefix = "Project: #{model_card.project_name} Model: #{model_card.model_name}" 33 | @speckle_state = state.speckle_state 34 | @sketchup_model = state.sketchup_state.sketchup_model 35 | su_unit = state.sketchup_state.length_units 36 | @units = Converters::SKETCHUP_UNITS[su_unit] 37 | @definitions = {} 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/color_proxy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'base' 4 | require_relative '../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | # A proxy class for an colors. 9 | class ColorProxy < Base 10 | SPECKLE_TYPE = SPECKLE_CORE_OTHER_COLOR_PROXY 11 | 12 | # @return [Sketchup::Color] 13 | attr_reader :sketchup_color 14 | 15 | # @return [Integer, Float] 16 | attr_reader :value 17 | 18 | # @return [String] 19 | attr_reader :name 20 | 21 | # @return [Array] The original ids of the objects that has render material 22 | attr_reader :object_ids 23 | 24 | # @param sketchup_color [Sketchup::Color] 25 | # @param object_ids [Array] 26 | # @param application_id [String | NilClass] 27 | def initialize(sketchup_color, value, object_ids, application_id: nil) 28 | super( 29 | speckle_type: SPECKLE_TYPE, 30 | application_id: application_id, 31 | id: nil 32 | ) 33 | @sketchup_color = sketchup_color 34 | @object_ids = object_ids 35 | @value = value 36 | self[:value] = value 37 | self[:name] = value.to_s 38 | self[:application_id] = value.to_s 39 | self[:objects] = object_ids 40 | end 41 | 42 | # @param object_id [String] application id of the object to add into proxy list 43 | def add_object_id(object_id) 44 | object_ids.append(object_id) 45 | self[:objects] = object_ids 46 | end 47 | end 48 | end 49 | end 50 | -------------------------------------------------------------------------------- /ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve --port 8081", 7 | "build": "vue-cli-service build", 8 | "watch-build": "vue-cli-service build --watch --mode production", 9 | "lint": "eslint . --ext .js,.ts,.vue", 10 | "prettier:check": "prettier --check .", 11 | "prettier:fix": "prettier --write ." 12 | }, 13 | "dependencies": { 14 | "@speckle/objectloader": "^2.11.4", 15 | "aws-sdk": "^2.981.0", 16 | "debounce": "^1.2.1", 17 | "mixpanel-browser": "^2.45.0", 18 | "regenerator-runtime": "^0.13.9", 19 | "register-service-worker": "^1.7.1", 20 | "sketchup-bridge": "^3.0.7", 21 | "sqlite3": "^5.1.5", 22 | "v-tooltip": "^2.1.3", 23 | "vue": "^2.6.11", 24 | "vue-apollo": "^3.0.0-beta.11", 25 | "vue-router": "^3.2.0", 26 | "vue-timeago": "^5.1.3", 27 | "vuetify": "2.6.10" 28 | }, 29 | "devDependencies": { 30 | "@vue/cli-plugin-babel": "~4.5.0", 31 | "@vue/cli-plugin-router": "~4.5.0", 32 | "@vue/cli-service": "~4.5.0", 33 | "babel-eslint": "^10.1.0", 34 | "eslint": "^7.15.0", 35 | "eslint-config-prettier": "^6.15.0", 36 | "eslint-loader": "^4.0.2", 37 | "eslint-plugin-prettier": "^3.2.0", 38 | "eslint-plugin-vue": "^7.2.0", 39 | "graphql-tag": "^2.9.0", 40 | "prettier": "^2.2.1", 41 | "sass": "~1.32.0", 42 | "sass-loader": "^10.0.0", 43 | "vue-cli-plugin-apollo": "~0.22.2", 44 | "vue-cli-plugin-vuetify": "~2.4.2", 45 | "vue-template-compiler": "^2.6.11", 46 | "vuetify-loader": "^1.7.0" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | # This workflow will install Python dependencies, run tests and lint with a single version of Python 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python 3 | 4 | name: Build and deploy 5 | 6 | on: 7 | push: 8 | branches: ["main", "installer-test/**"] 9 | tags: ["v3.*.*"] # Manual delivery on every 3.x tag 10 | 11 | jobs: 12 | build: 13 | uses: ./.github/workflows/build.yml 14 | 15 | deploy-installers: 16 | runs-on: ubuntu-latest 17 | needs: build 18 | env: 19 | IS_PUBLIC_RELEASE: ${{ github.ref_type == 'tag' }} 20 | steps: 21 | - name: 🔫 Trigger Build Installer(s) 22 | uses: the-actions-org/workflow-dispatch@v4.0.0 23 | with: 24 | workflow: Build Installers 25 | repo: specklesystems/connector-installers 26 | token: ${{ secrets.CONNECTORS_GH_TOKEN }} 27 | inputs: '{ 28 | "run_id": "${{ github.run_id }}", 29 | "semver": "${{ needs.build.outputs.semver }}", 30 | "file_version": "${{ needs.build.outputs.file_version }}", 31 | "repo": "${{ github.repository }}", 32 | "is_public_release": ${{ env.IS_PUBLIC_RELEASE }} 33 | }' 34 | ref: main 35 | wait-for-completion: true 36 | wait-for-completion-interval: 10s 37 | wait-for-completion-timeout: 10m 38 | display-workflow-run-url: true 39 | display-workflow-run-url-interval: 10s 40 | - uses: geekyeggo/delete-artifact@v5 41 | with: 42 | name: output-* 43 | -------------------------------------------------------------------------------- /speckle_connector_3/src/actions/base_actions/remove_models.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../action' 4 | require_relative '../../cards/send_card' 5 | require_relative '../../cards/receive_card' 6 | require_relative '../../filters/send/everything_filter' 7 | require_relative '../../filters/send/selection_filter' 8 | require_relative '../../filters/send_filters' 9 | require_relative '../../sketchup_model/dictionary/model_card_dictionary_handler' 10 | 11 | module SpeckleConnector3 12 | module Actions 13 | # Action to remove cards. 14 | class RemoveModels < Action 15 | # @param state [States::State] the current state of the {App::SpeckleConnectorApp} 16 | # @return [States::State] the new updated state object 17 | def self.update_state(state, resolve_id, data) 18 | data.each do |model_card| 19 | SketchupModel::Dictionary::ModelCardDictionaryHandler.remove_card_dict(state.sketchup_state.sketchup_model, model_card) 20 | new_speckle_state = if model_card['typeDiscriminator'] == 'ReceiverModelCard' 21 | state.speckle_state.without_receive_card(model_card['id']) 22 | else 23 | state.speckle_state.without_send_card(model_card['id']) 24 | end 25 | state = state.with_speckle_state(new_speckle_state) 26 | end 27 | 28 | # Resolve promise 29 | js_script = "baseBinding.receiveResponse('#{resolve_id}')" 30 | state.with_add_queue_js_command('removeModels', js_script) 31 | end 32 | end 33 | end 34 | end 35 | -------------------------------------------------------------------------------- /speckle_connector_3/src/commands/command.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../actions/handle_error' 4 | 5 | module SpeckleConnector3 6 | module Commands 7 | # Base command schema to wrap common operations for all commands. 8 | class Command 9 | # @return [App::SpeckleConnectorApp] the main app object 10 | attr_reader :app 11 | 12 | # @return [Ui::Binding] binding object holds dialog and it's state 13 | attr_reader :binding 14 | 15 | # @param app [App::SpeckleConnectorApp] the main app object 16 | # @param binding [Ui::Binding] binding object holds commands to call 17 | def initialize(app, binding) 18 | @app = app 19 | @binding = binding 20 | end 21 | 22 | def run(*parameters) 23 | begin 24 | # Run here common operations that same for each command. 25 | with_observers_disabled do 26 | _run(*parameters) 27 | end 28 | rescue StandardError => e 29 | action = Actions::HandleError.new(e, @binding.nil? ? "unknown binding" : @binding.name, @action, parameters) 30 | app.update_state!(action) 31 | end 32 | end 33 | 34 | private 35 | 36 | def with_observers_disabled(&block) 37 | observer_handler = @app.observer_handler 38 | if observer_handler 39 | observer_handler.with_observers_disabled(&block) 40 | else 41 | block.call 42 | end 43 | end 44 | 45 | def _run(*_parameters) 46 | raise NotImplementedError, 'Implement in subclass' 47 | end 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /speckle_connector_3/src/filters/send/selection_filter.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative '../../ui_data/components/selections/list_selection_item' 4 | 5 | module SpeckleConnector3 6 | module Filters 7 | module Send 8 | # Selection filter for sketchup connector to send all. 9 | class SelectionFilter < UiData::Components::Selections::ListSelectionItem 10 | DEFAULT_SUMMARY = 'User based selection filter. UI should replace this summary with the selection info summary!' 11 | 12 | # @return [Array] object ids that logged into selection filter. 13 | attr_reader :selected_object_ids 14 | 15 | def initialize(selected_object_ids, summary = DEFAULT_SUMMARY) 16 | super('selection', 'Selection', nil, summary) 17 | @selected_object_ids = selected_object_ids 18 | self[:selectedObjectIds] = selected_object_ids 19 | self[:isDefault] = true # hard coded default value, that's fair 20 | end 21 | 22 | def check_expiry(ids) 23 | selected_object_ids.intersection(ids.to_a).any? 24 | end 25 | 26 | def self.from_json(_data) 27 | SelectionFilter.new([]) 28 | end 29 | 30 | def self.read_from_document(data) 31 | SelectionFilter.new(data['selectedObjectIds'], data['summary']) 32 | end 33 | 34 | def self.from_ui_data(data) 35 | # FIXME: Solve inconsistency! UI send data as hash which should be array 36 | SelectionFilter.new(data['selectedObjectIds'].values, data['summary']) 37 | end 38 | end 39 | end 40 | end 41 | end 42 | -------------------------------------------------------------------------------- /speckle_connector_3/src/speckle_objects/render_material_proxy.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'base' 4 | require_relative '../constants/type_constants' 5 | 6 | module SpeckleConnector3 7 | module SpeckleObjects 8 | # A proxy class for an render materials. 9 | class RenderMaterialProxy < Base 10 | SPECKLE_TYPE = SPECKLE_CORE_OTHER_RENDER_MATERIAL_PROXY 11 | 12 | # @return [Sketchup::Material] 13 | attr_reader :sketchup_material 14 | 15 | # @return [SpeckleObjects::Other::RenderMaterial] 16 | attr_reader :value 17 | 18 | # @return [Array] The original ids of the objects that has render material 19 | attr_reader :object_ids 20 | 21 | # @param sketchup_material [Sketchup::Material] 22 | # @param object_ids [Array] 23 | # @param application_id [String | NilClass] 24 | def initialize(sketchup_material, value, object_ids, application_id: nil) 25 | super( 26 | speckle_type: SPECKLE_TYPE, 27 | application_id: application_id, 28 | id: nil 29 | ) 30 | @sketchup_material = sketchup_material 31 | @object_ids = object_ids 32 | @value = value 33 | self[:value] = value 34 | self[:objects] = object_ids 35 | end 36 | 37 | # @param object_id [String] application id of the object to add into proxy list 38 | def try_add_object_id(object_id) 39 | unless object_ids.include?(object_id) 40 | object_ids.append(object_id) 41 | self[:objects] = object_ids 42 | end 43 | end 44 | end 45 | end 46 | end 47 | --------------------------------------------------------------------------------