Compare commits

...

22 Commits

Author SHA1 Message Date
Oğuzhan Koral 6053d3eac1 Fix (Attributes): Rescue from problematic dictionaries 2023-01-20 11:50:18 +03:00
oguzhankoral 529830f36b Rescue from problematic dictionaries 2023-01-20 11:47:34 +03:00
Oğuzhan Koral 505cf6265c Feat (Scene): Send and receive scenes 2023-01-19 20:09:19 +03:00
oguzhankoral 8cd9673eec Send scenes to speckle 2023-01-19 20:05:44 +03:00
oguzhankoral ac9cb28558 Receive named views as scene 2023-01-19 16:38:32 +03:00
Oğuzhan Koral 6eefe0698c Fix (Branch): Activate created branch 2023-01-19 12:17:58 +03:00
oguzhankoral d0113532b6 Activate created branch 2023-01-19 11:09:23 +03:00
Oğuzhan Koral 5a1d2ad5f4 Feat (Branch): Create branch button
Thanks Fabians for helps
2023-01-18 17:02:20 +03:00
oguzhankoral dfe02f4c74 Rename CreateBranchDialog 2023-01-18 16:58:05 +03:00
oguzhankoral 5349d556b9 Group dialogs to folder 2023-01-18 16:21:43 +03:00
oguzhankoral 7f7d8a501b Add notes about refresh 2023-01-18 15:58:43 +03:00
oguzhankoral cbee0e465b Remove unused combineFacesByMaterialHandler method 2023-01-18 15:44:20 +03:00
oguzhankoral faf00f0b0d Refetch stream on StreamCard whenever branch created 2023-01-18 15:42:33 +03:00
oguzhankoral fa97da5781 Track create stream and branch via mixpanel 2023-01-18 15:03:14 +03:00
oguzhankoral e7bab546db Remove loggings 2023-01-18 14:16:52 +03:00
oguzhankoral e2f4a30b5b Fix updating problem on created branch
- Thanks to Fabians
2023-01-18 11:53:50 +03:00
oguzhankoral ccff1df041 Add tooltip to create branch method 2023-01-18 11:53:11 +03:00
oguzhankoral 2037cfc25a Import and use CreateBranchDialog per stream card 2023-01-17 19:24:53 +03:00
oguzhankoral 268a091d8a Add dialog for branch creation 2023-01-17 19:23:44 +03:00
Oğuzhan Koral 6b52dfab3e Chore (Theming): Store light mode setting separately 2023-01-17 16:16:39 +03:00
oguzhankoral 839999851f Correct preference hash for theming 2023-01-17 16:12:21 +03:00
oguzhankoral a87470b7b5 Split Sketchup settings 2023-01-17 16:11:56 +03:00
11 changed files with 290 additions and 18 deletions
+20 -1
View File
@@ -48,7 +48,9 @@ module SpeckleConnector
# @param obj [Object] speckle commit object.
def receive_commit_object(obj, model_preferences)
# First create layers on the sketchup before starting traversing
create_layers(obj.keys.filter_map { |key| key if key.start_with?('@') }, sketchup_model.layers)
filtered_layer_containers = obj.keys.filter_map { |key| key if key.start_with?('@') && key != '@Named Views' }
create_layers(filtered_layer_containers, sketchup_model.layers)
create_views(obj.filter_map { |key, value| value if key == '@Named Views' }, sketchup_model)
# Define default commit layer which is the fallback
default_commit_layer = sketchup_model.layers.layers.find { |layer| layer.display_name == '@Untagged' }
traverse_commit_object(obj, sketchup_model.layers, default_commit_layer, model_preferences)
@@ -70,6 +72,23 @@ module SpeckleConnector
create_folder_layers(folder_layer_arrays, folder)
end
# @param views [Array] views.
# @param sketchup_model [Sketchup::Model] active sketchup model.
def create_views(views, sketchup_model)
return if views.empty?
views.first.each do |view|
origin = view['origin']
target = view['target']
origin = SpeckleObjects::Geometry::Point.to_native(origin['x'], origin['y'], origin['z'], origin['units'])
target = SpeckleObjects::Geometry::Point.to_native(target['x'], target['y'], target['z'], target['units'])
# Set camera position before creating scene on it.
my_camera = Sketchup::Camera.new(origin, target, [0, 0, 1], !view['isOrthogonal'], view['lens'])
sketchup_model.active_view.camera = my_camera
sketchup_model.pages.add(view['name'])
end
end
# @param headless_layers [Array<String>] headless layer names.
# @param folder [Sketchup::Layers, Sketchup::LayerFolder] layer folder to create commit layers under it.
def create_headless_layers(headless_layers, folder)
@@ -4,9 +4,11 @@ require_relative 'converter'
require_relative 'base_object_serializer'
require_relative '../speckle_objects/base'
require_relative '../speckle_objects/geometry/line'
require_relative '../speckle_objects/geometry/length'
require_relative '../speckle_objects/geometry/mesh'
require_relative '../speckle_objects/other/block_instance'
require_relative '../speckle_objects/other/block_definition'
require_relative '../speckle_objects/built_elements/view3d'
module SpeckleConnector
module Converters
@@ -30,9 +32,48 @@ module SpeckleConnector
end
# send only layers that have any object
base_object_properties = layers.reject { |_layer_name, objects| objects.empty? }
add_views(base_object_properties) if sketchup_model.pages.any?
SpeckleObjects::Base.with_detached_layers(base_object_properties)
end
# Add views from pages.
# @param base_object_properties [Hash] dynamically attached base object properties.
# rubocop:disable Metrics/AbcSize
# rubocop:disable Metrics/MethodLength
def add_views(base_object_properties)
views = []
sketchup_model.pages.each do |page|
cam = page.camera
origin = SpeckleObjects::Geometry::Point.new(
SpeckleObjects::Geometry.length_to_speckle(cam.eye[0], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.eye[1], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.eye[2], @units),
@units
)
target = SpeckleObjects::Geometry::Point.new(
SpeckleObjects::Geometry.length_to_speckle(cam.target[0], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.target[1], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.target[2], @units),
@units
)
direction = SpeckleObjects::Geometry::Vector.new(
SpeckleObjects::Geometry.length_to_speckle(cam.direction[0], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.direction[1], @units),
SpeckleObjects::Geometry.length_to_speckle(cam.direction[2], @units),
@units
)
view = SpeckleObjects::BuiltElements::View3d.new(
page.name,
origin, target, direction, SpeckleObjects::Geometry::Vector.new(0, 0, 1, @units),
cam.perspective?, cam.fov, @units, page.name
)
views.append(view)
end
base_object_properties['@Named Views'] = views
end
# rubocop:enable Metrics/AbcSize
# rubocop:enable Metrics/MethodLength
# Serialized and traversed information to send batches.
# @param base [SpeckleObjects::Base] base object to serialize.
# @return [String, Integer, Array<Object>] base id, total_children_count of base and batches
@@ -10,6 +10,7 @@ module SpeckleConnector
module Preferences
include Immutable::ImmutableUtils
DICT_HANDLER = SketchupModel::Dictionary::SpeckleModelDictionaryHandler
DEFAULT_PREFERENCES = "('configSketchup', '{\"DarkTheme\":false}');"
# @param sketchup_model [Sketchup::Model] active model.
# rubocop:disable Metrics/MethodLength
@@ -17,8 +18,13 @@ module SpeckleConnector
# Init sqlite database
db = Sqlite3::Database.new(SPECKLE_CONFIG_DB_PATH)
# Check configSketchup key is valid or not, otherwise init with default settings
if db.exec("SELECT content FROM 'objects' WHERE hash = 'configSketchup'").empty?
db.exec("INSERT INTO 'objects' VALUES #{DEFAULT_PREFERENCES}")
end
# Select data
data = db.exec("SELECT content FROM 'objects' WHERE hash = 'configDUI'").first.first
data = db.exec("SELECT content FROM 'objects' WHERE hash = 'configSketchup'").first.first
# Parse string to hash
data_hash = JSON.parse(data).to_h
@@ -28,7 +28,10 @@ module SpeckleConnector
dictionaries.each do |dict_name, entries|
dict_name = dict_name == 'empty_dictionary_name' ? '' : dict_name
JSON.parse(entries).each do |key, value|
entity.set_attribute(dict_name, key, value)
set_attribute(entity, key, value, dict_name)
rescue StandardError => e
puts("Failed to write key: #{key} value: #{value} to dictionary #{dict_name}")
puts(e)
end
end
end
@@ -0,0 +1,45 @@
# frozen_string_literal: true
require_relative '../base'
require_relative '../../speckle_objects/geometry/point'
require_relative '../../speckle_objects/geometry/vector'
module SpeckleConnector
module SpeckleObjects
module BuiltElements
# View3d object represents scenes on Sketchup.
class View3d < Base
SPECKLE_TYPE = 'Objects.BuiltElements.View:Objects.BuiltElements.View3D'
# @param name [String] name of the scene
# @param origin [SpeckleObjects::Geometry::Point] origin (eye) of the view.
# @param target [SpeckleObjects::Geometry::Point] target of the view.
# @param direction [SpeckleObjects::Geometry::Vector] direction of the view from eye to target.
# @param up_direction [SpeckleObjects::Geometry::Vector] up direction of the view.
# @param is_perspective [Boolean] whether view is perspective or not.
# @param lens [Boolean] fov value of the view camera.
# @param units [String] units of the camera.
# @param application_id [String] application_id of the view.
# rubocop:disable Metrics/ParameterLists
def initialize(name, origin, target, direction, up_direction,
is_perspective, lens, units, application_id)
super(
speckle_type: SPECKLE_TYPE,
total_children_count: 0,
application_id: application_id,
id: nil
)
self[:name] = name
self[:origin] = origin
self[:target] = target
self[:forwardDirection] = direction
self[:upDirection] = up_direction
self[:isOrthogonal] = !is_perspective
self[:lens] = lens
self[:units] = units
end
# rubocop:enable Metrics/ParameterLists
end
end
end
end
+3 -3
View File
@@ -80,7 +80,7 @@
</v-menu>
</v-app-bar>
<create-stream v-if="accounts().length !== 0"/>
<create-stream-dialog v-if="accounts().length !== 0"/>
<v-container v-if="accounts().length !== 0" fluid>
<router-view :stream-search-query="streamSearchQuery" />
@@ -129,8 +129,8 @@ export default {
name: 'App',
components: {
Login,
CreateStream: () => import('@/components/CreateStream'),
SettingsDialog: () => import('@/components/SettingsDialog'),
CreateStreamDialog: () => import('@/components/dialogs/CreateStreamDialog'),
SettingsDialog: () => import('@/components/dialogs/SettingsDialog'),
GlobalToast: () => import('@/components/GlobalToast')
},
props: {
+28 -7
View File
@@ -60,11 +60,17 @@
<v-card-text class="d-flex align-center pb-5 mb-5 -mt-2" style="height: 50px">
<v-menu offset-y>
<template #activator="{ on, attrs }">
<v-slide-x-transition>
<div v-show="hover">
<create-branch-dialog :stream-name="stream.name" :stream-id="streamId"/>
</div>
</v-slide-x-transition>
<v-chip v-if="stream.branches" small v-bind="attrs" class="mr-1" v-on="on">
<v-icon small class="mr-1 float-left">mdi-source-branch</v-icon>
{{ branchName }}
</v-chip>
</template>
<!-- Branch list -->
<v-list dense>
<v-list-item
v-for="(branch, index) in stream.branches.items"
@@ -73,7 +79,7 @@
@click="switchBranch(branch.name)"
>
<v-list-item-title class="text-caption font-weight-regular">
<v-icon v-if="branch.name == branchName" small class="mr-1 float-left">
<v-icon v-if="branch.name === branchName" small class="mr-1 float-left">
mdi-check
</v-icon>
<v-icon v-else small class="mr-1 float-left">mdi-source-branch</v-icon>
@@ -171,6 +177,9 @@ global.oneClickSend = function (streamId) {
export default {
name: 'StreamCard',
components: {
CreateBranchDialog: () => import('@/components/dialogs/CreateBranchDialog'),
},
props: {
streamId: {
type: String,
@@ -261,16 +270,28 @@ export default {
},
computed: {
selectedBranch() {
if (this.$apollo.loading) return
return this.stream.branches.items.find((branch) => branch.name == this.branchName)
if (!this.stream) return
return this.stream.branches.items.find((branch) => branch.name === this.branchName)
},
selectedCommit() {
if (this.$apollo.loading) return
if (this.commitId == 'latest') return this.selectedBranch.commits.items[0]
return this.selectedBranch.commits.items.find((commit) => commit.id == this.commitId)
if (!this.selectedBranch) return
if (this.commitId === 'latest') return this.selectedBranch.commits.items[0]
return this.selectedBranch.commits.items.find((commit) => commit.id === this.commitId)
}
},
mounted() {
bus.$on(`refresh-stream-${this.streamId}`, () => {
let oldBranchName = this.branchName
let oldCommitId = this.commitId
this.$apollo.queries.stream.refetch()
this.branchName = oldBranchName
this.commitId = oldCommitId
})
bus.$on(`create-branch-${this.streamId}`, (branchName) => {
this.$apollo.queries.stream.refetch()
this.branchName = branchName
this.commitId = 'latest'
})
bus.$on(`sketchup-objects-${this.streamId}`, async (batches, commitId, totalChildrenCount) => {
console.log('>>> SpeckleSketchUp: Received objects from sketchup')
@@ -376,7 +397,7 @@ export default {
await this.sleep(2000)
},
async createCommit(batches, commitId, totalChildrenCount) {
if (batches.length == 0) {
if (batches.length === 0) {
this.loadingSend = false
this.loadingStage = null
this.$eventHub.$emit('notification', {
@@ -0,0 +1,137 @@
<template>
<!-- DIALOG: Create Branch -->
<v-dialog v-model="showCreateBranch">
<template #activator="{ on: dialog, attrs }">
<v-btn
v-tooltip="'Create Branch'"
icon x-small class="ml-0 mr-1"
v-bind="attrs"
v-on="{...dialog}"
>
<v-icon>
mdi-plus-circle
</v-icon>
</v-btn>
</template>
<v-card>
<v-card-title class="text-h5 mb-1">
Create a New Branch
</v-card-title>
<v-card-subtitle class="py-0 my-0 font-italic">
under {{ streamName }} stream
</v-card-subtitle>
<v-container class="px-6" pb-0>
<v-text-field
v-model="branchName"
xxxclass="small-text-field"
hide-details
dense
flat
placeholder="Branch Name"
/>
<v-text-field
v-model="description"
xxxclass="small-text-field"
hide-details
dense
flat
placeholder="Description (Optional)"
/>
</v-container>
<v-card-actions>
<v-spacer></v-spacer>
<v-btn
color="blue darken-1"
text
@click="showCreateBranch = false"
>
Cancel
</v-btn>
<v-btn
:disabled="branchName === ''"
color="blue darken-1"
text
@click="createBranch"
>
Create
</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script>
import gql from "graphql-tag";
import {bus} from "@/main";
export default {
name: "CreateBranchDialog",
props: {
streamId: {
type: String,
default: null
},
streamName: {
type: String,
default: null
}
},
data() {
return {
showCreateBranch: false,
branchName: "",
description: "",
defaultDescription: "Stream created from SketchUp",
accountToCreateStream: null
}
},
computed: {
loggedIn() {
return localStorage.getItem('SpeckleSketchup.AuthToken') !== null
},
accounts() {
return JSON.parse(localStorage.getItem('localAccounts'))
},
},
methods: {
async createBranch(){
let res = await this.$apollo.mutate({
mutation: gql`
mutation branchCreate($branch: BranchCreateInput!) {
branchCreate(branch: $branch)
}
`,
variables: {
branch: {
streamId: this.streamId,
name: this.branchName,
description: this.description === '' ? this.defaultDescription : this.description,
}
}
})
bus.$emit(`create-branch-${this.streamId}`, this.branchName)
this.showCreateBranch = false
this.branchName = ""
this.description = ""
this.$mixpanel.track('Connector Action', { name: 'Create Branch' })
return res
}
}
}
</script>
<style>
.v-dialog {
max-width: 390px
}
.v-text-field >>> input {
font-size: 0.9em;
}
.v-text-field >>> label {
font-size: 0.9em;
}
</style>
@@ -161,7 +161,7 @@ import {bus} from "@/main";
import userQuery from "@/graphql/user.gql";
export default {
name: "CreateStream",
name: "CreateStreamDialog",
data() {
return {
showCreateNewStream: false,
@@ -216,6 +216,7 @@ export default {
this.showCreateNewStream = false
this.streamName = ""
this.description = ""
this.$mixpanel.track('Connector Action', { name: 'Create Stream' })
sketchup.exec({name: "save_stream", data: {stream_id: res["data"]["streamCreate"]}})
this.refresh()
return res
@@ -122,14 +122,11 @@ export default {
}
},
methods: {
combineFacesByMaterialHandler() {
},
switchTheme() {
this.$vuetify.theme.dark = !this.$vuetify.theme.dark
sketchup.exec({
name: "user_preferences_updated",
data: {preference_hash: "configDUI", preference: "DarkTheme", value: this.$vuetify.theme.dark}
data: {preference_hash: "configSketchup", preference: "DarkTheme", value: this.$vuetify.theme.dark}
})
this.$mixpanel.track('Connector Action', { name: 'Toggle Theme' })
},
+2
View File
@@ -73,7 +73,9 @@ export default {
},
mounted() {
bus.$on('refresh-streams', () => {
// TODO: We should remember selected branches and commits before refetch
this.$apollo.queries.streams.refetch()
// TODO: We should set previously selected branches and commits after refetch
})
bus.$on('set-saved-streams', (streamIds) => {