Compare commits

..

6 Commits

Author SHA1 Message Date
izzy lyseggen 0eb835bed0 fix(convert): add "cm" to unit strings and skip revit params (#34)
* feat(convert): skip revit params

cant do anything w them so skipping for now for efficiency

* fix(convert): add "cm" to unit strings
2022-02-23 10:11:48 +00:00
Dimitrie Stefanescu 7a7ce8ff3d feat(ui): css-ing around + notifications on actions (#33) 2022-02-14 21:05:03 +00:00
izzy lyseggen 473f0890fe fix(accounts): manually grab user dir (#30)
issue with i assume company managed computers where the "current user"
is pointing to somewhere else (maybe the admin who installed sketchup?)

to solve, I'm manually grabbing the user dir from the pwd

closes Auth error and no streams found #27
2022-01-19 12:01:23 +00:00
izzy lyseggen a8955a435f chore(deps): objectloader 2.3.0 and update others (#29)
closes 📨 Receiving fails if objects have nulls #28
2022-01-13 07:21:33 -08:00
izzylys 80f25eb1a2 fix(batching): simplify slightly
also fix a transition vs transition-group warning
2022-01-12 12:26:37 -08:00
izzylys 5716f92fbf fix(accts): sqlite gem loading 2022-01-06 09:13:45 -08:00
14 changed files with 7828 additions and 3420 deletions
+2 -2
View File
@@ -5,7 +5,6 @@ begin
rescue LoadError
# ty msp-greg! https://github.com/MSP-Greg/SUMisc/releases/tag/sqlite3-mingw-1
Gem.install(File.join(File.dirname(File.expand_path(__FILE__)), "utils/sqlite3-1.4.2.mspgreg-x64-mingw32.gem"))
else
require("sqlite3")
end
@@ -35,7 +34,8 @@ module SpeckleSystems::SpeckleConnector
def self._get_speckle_dir
speckle_dir =
case Sketchup.platform
when :platform_win then File.join(Dir.home, "AppData/Roaming/Speckle")
# sometimes Dir.home on windows points somewhere else bc I guess it's picking up a higher level user?
when :platform_win then File.join(Dir.pwd[%r{^((?:[^/]*/){3})}], "AppData/Roaming/Speckle")
when :platform_osx then File.join(Dir.home, ".config", "Speckle")
else
nil
@@ -3,7 +3,7 @@ require "speckle_connector/converter/to_speckle"
require "speckle_connector/converter/to_native"
module SpeckleSystems::SpeckleConnector
SKETCHUP_UNIT_STRINGS = { "m" => "m", "mm" => "mm", "ft" => "feet", "in" => "inch", "yd" => "yard" }.freeze
SKETCHUP_UNIT_STRINGS = { "m" => "m", "mm" => "mm", "ft" => "feet", "in" => "inch", "yd" => "yard", "cm" => "cm" }.freeze
public_constant :SKETCHUP_UNIT_STRINGS
class ConverterSketchup
include ToNative
+7
View File
@@ -6,6 +6,8 @@ module SpeckleSystems::SpeckleConnector::ToNative
if can_convert_to_native(obj)
convert_to_native(obj, Sketchup.active_model.entities)
elsif obj.is_a?(Hash) && obj.key?("speckle_type")
return if is_ignored_speckle_type(obj)
puts(">>> Found #{obj["speckle_type"]}: #{obj["id"]}")
props = obj.keys.filter_map { |key| key unless key.start_with?("_") }
props.each { |prop| traverse_commit_object(obj[prop]) }
@@ -32,7 +34,12 @@ module SpeckleSystems::SpeckleConnector::ToNative
].include?(obj["speckle_type"])
end
def is_ignored_speckle_type(obj)
["Objects.BuiltElements.Revit.Parameter"].include?(obj["speckle_type"])
end
def convert_to_native(obj, entities = SketchUp.active_model.entities)
puts(">>> Converting #{obj["speckle_type"]}: #{obj["id"]}")
case obj["speckle_type"]
when "Objects.Geometry.Line", "Objects.Geometry.Polyline" then edge_to_native(obj, entities)
when "Objects.Other.BlockInstance" then component_instance_to_native(obj, entities)
+7497 -3226
View File
File diff suppressed because it is too large Load Diff
+3 -2
View File
@@ -9,12 +9,13 @@
"lint": "vue-cli-service lint"
},
"dependencies": {
"@speckle/objectloader": "^2.1.1",
"@speckle/objectloader": "^2.3.0",
"aws-sdk": "^2.981.0",
"core-js": "^3.6.5",
"debounce": "^1.2.1",
"register-service-worker": "^1.7.1",
"sqlite3": "^5.0.2",
"v-tooltip": "^2.1.3",
"vue": "^2.6.11",
"vue-apollo": "^3.0.0-beta.11",
"vue-matomo": "^4.1.0",
@@ -41,4 +42,4 @@
"vue-template-compiler": "^2.6.11",
"vuetify-loader": "^1.7.0"
}
}
}
+4 -1
View File
@@ -85,6 +85,7 @@
<v-container fluid>
<router-view :stream-search-query="streamSearchQuery" />
</v-container>
<global-toast />
</v-main>
</v-app>
</template>
@@ -118,7 +119,9 @@ global.setSelectedAccount = function (account) {
export default {
name: 'App',
components: {},
components: {
GlobalToast: () => import('@/components/GlobalToast')
},
props: {
size: {
type: Number,
+42
View File
@@ -0,0 +1,42 @@
<template>
<v-snackbar v-model="snack" app bottom color="primary">
{{ text }}
<template #action="{}">
<v-btn v-if="actionName" :to="to" @click.append="snack = false">
{{ actionName }}
</v-btn>
<v-btn small icon @click="snack = false">
<v-icon small>mdi-close</v-icon>
</v-btn>
</template>
</v-snackbar>
</template>
<script>
export default {
data() {
return {
snack: false,
text: null,
actionName: null,
to: null
}
},
watch: {
snack(newVal) {
if (!newVal) {
this.text = null
this.actionName = null
this.to = null
}
}
},
mounted() {
this.$eventHub.$on('notification', (args) => {
this.snack = true
this.text = args.text
this.actionName = args.action ? args.action.name : null
this.to = args.action ? args.action.to : null
})
}
}
</script>
+137 -168
View File
@@ -1,177 +1,140 @@
<template>
<v-hover v-slot="{ hover }">
<v-card color="" class="mt-5 mb-5" style="transition: all 0.2s ease-in-out">
<v-row>
<v-col v-if="$apollo.loading">
<v-row>
<v-col><v-skeleton-loader type="article" /></v-col>
</v-row>
</v-col>
<v-col v-else>
<v-toolbar class="transparent elevation-0" dense>
<v-toolbar-title>{{ stream.name }}</v-toolbar-title>
<v-spacer />
</v-toolbar>
<v-card-text class="transparent elevation-0 mt-0 pt-0" dense>
<div class="text-caption">
Updated
<timeago class="mr-1" :datetime="stream.updatedAt" />
|
<v-icon class="ml-1" small>mdi-account-key-outline</v-icon>
{{ stream.role.split(':')[1] }}
</div>
<v-toolbar-title>
<v-menu offset-y>
<template #activator="{ on, attrs }">
<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>
<v-list dense>
<v-list-item
v-for="(branch, index) in stream.branches.items"
:key="index"
link
@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">
mdi-check
</v-icon>
<v-icon v-else small class="mr-1 float-left">mdi-source-branch</v-icon>
{{ branch.name }} ({{ branch.commits.totalCount }})
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-menu offset-y>
<template #activator="{ on, attrs }">
<v-chip v-if="stream.commits" small v-bind="attrs" v-on="on">
<v-icon small class="mr-1 float-left">mdi-source-commit</v-icon>
{{ selectedBranch.commits.items.length ? commitId : 'no commits' }}
</v-chip>
</template>
<v-list dense>
<v-list-item
v-for="(commit, index) in selectedBranch.commits.items"
:key="index"
link
@click="switchCommit(commit.id)"
>
<v-list-item-title class="text-caption font-weight-regular">
<v-icon
v-if="(commitId == 'latest' && index == 0) || commit.id == commitId"
small
class="mr-1 float-left"
>
mdi-check
</v-icon>
<v-icon v-else small class="mr-1 float-left">mdi-source-commit</v-icon>
{{ commit.id }} |
<span class="font-weight-regular">{{ commit.message }} |</span>
<span class="font-weight-light ml-1">
<timeago :datetime="commit.createdAt" />
</span>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
</v-toolbar-title>
</v-card-text>
</v-col>
<v-col v-if="hover && !$apollo.loading" align="end" justify="center">
<v-tooltip bottom>
<template #activator="{ on, attrs }">
<v-btn icon class="mr-4 btn-fix" v-bind="attrs" v-on="on" @click="openInWeb">
<v-icon>mdi-open-in-new</v-icon>
</v-btn>
</template>
<span>Open in web</span>
</v-tooltip>
<v-tooltip bottom>
<template #activator="{ on, attrs }">
<v-btn
fab
:loading="loadingSend"
class="mr-4 elevation-1 btn-fix"
hint="Send"
v-bind="attrs"
v-on="on"
@click="send"
<v-card
v-if="stream"
:class="`mb-3 rounded-lg grey ${$vuetify.theme.dark ? 'darken-4' : 'lighten-4'}`"
@mouseenter="hover = true"
@mouseleave="hover = false"
>
<v-toolbar flat height="70">
<v-toolbar-title class="ml-0">
<!-- Uncomment when pinning is in place and add style="position: relative; left: -10px" to the element above :) -->
<!-- <v-btn v-tooltip="'Pin this stream - it will be saved to this file.'" icon x-small>
<v-icon x-small>mdi-pin</v-icon>
</v-btn> -->
{{ stream.name }}
</v-toolbar-title>
<v-spacer />
<v-slide-x-transition>
<div v-show="hover" style="white-space: nowrap">
<v-btn v-tooltip="'View online'" icon small class="mr-3" @click="openInWeb">
<v-icon small>mdi-open-in-new</v-icon>
</v-btn>
<v-btn
v-tooltip="'Send'"
icon
class="mr-3 elevation-2"
:loading="loadingSend"
@click="send"
>
<!-- <v-icon>mdi-upload</v-icon> -->
<v-img v-if="$vuetify.theme.dark" src="@/assets/SenderWhite.png" max-width="30" />
<v-img v-else src="@/assets/Sender.png" max-width="30" />
</v-btn>
<v-btn
v-tooltip="'Receive'"
icon
class="elevation-2"
:loading="loadingReceive"
@click="receive"
>
<!-- <v-icon>mdi-download</v-icon> -->
<v-img v-if="$vuetify.theme.dark" src="@/assets/ReceiverWhite.png" max-width="30" />
<v-img v-else src="@/assets/Receiver.png" max-width="30" />
</v-btn>
</div>
</v-slide-x-transition>
</v-toolbar>
<v-card-text class="caption pt-1 text-truncate" style="white-space: nowrap">
Updated
<timeago class="mr-1" :datetime="stream.updatedAt" />
|
<v-icon class="ml-1" small>mdi-account-key-outline</v-icon>
{{ stream.role.split(':')[1] }}
</v-card-text>
<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-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>
<v-list dense>
<v-list-item
v-for="(branch, index) in stream.branches.items"
:key="index"
link
@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">
mdi-check
</v-icon>
<v-icon v-else small class="mr-1 float-left">mdi-source-branch</v-icon>
{{ branch.name }} ({{ branch.commits.totalCount }})
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<v-menu offset-y>
<template #activator="{ on, attrs }">
<v-chip v-if="stream.commits" small v-bind="attrs" v-on="on">
<v-icon small class="mr-1 float-left">mdi-source-commit</v-icon>
{{ selectedBranch.commits.items.length ? commitId : 'no commits' }}
</v-chip>
</template>
<v-list dense>
<v-list-item
v-for="(commit, index) in selectedBranch.commits.items"
:key="index"
link
@click="switchCommit(commit.id)"
>
<v-list-item-title class="text-caption font-weight-regular">
<v-icon
v-if="(commitId == 'latest' && index == 0) || commit.id == commitId"
small
class="mr-1 float-left"
>
<v-img
v-if="$vuetify.theme.dark"
src="@/assets/SenderWhite.png"
max-width="40"
style="display: inline-block"
/>
<v-img
v-else
src="@/assets/Sender.png"
max-width="40"
style="display: inline-block"
/>
</v-btn>
</template>
<span>Send</span>
</v-tooltip>
<v-tooltip bottom>
<template #activator="{ on, attrs }">
<v-btn
fab
:loading="loadingReceive"
class="mr-4 elevation-1 btn-fix"
hint="Receive"
v-bind="attrs"
v-on="on"
@click="receive"
>
<v-img
v-if="$vuetify.theme.dark"
src="@/assets/ReceiverWhite.png"
max-width="40"
style="display: inline-block"
/>
<v-img
v-else
src="@/assets/Receiver.png"
max-width="40"
style="display: inline-block"
/>
</v-btn>
</template>
<span>Receive</span>
</v-tooltip>
</v-col>
</v-row>
<transition name="expand">
<v-card-text v-if="hover && !$apollo.loading" class="mt-0 pt-0">
<transition name="fade">
mdi-check
</v-icon>
<v-icon v-else small class="mr-1 float-left">mdi-source-commit</v-icon>
{{ commit.id }} |
<span class="font-weight-regular">{{ commit.message }} |</span>
<span class="font-weight-light ml-1">
<timeago :datetime="commit.createdAt" />
</span>
</v-list-item-title>
</v-list-item>
</v-list>
</v-menu>
<div class="flex-grow-1 px-4">
<v-slide-y-transition>
<div v-show="hover">
<v-text-field
v-model="commitMessage"
class="small-text-field"
xxxclass="small-text-field"
hide-details
dense
flat
label="Commit Message"
placeholder="Write your commit message here"
></v-text-field>
</transition>
</v-card-text>
<v-progress-linear
v-if="(loadingSend || loadingReceive) && loadingStage"
height="14"
indeterminate
>
<div class="text-caption">{{ loadingStage }}</div>
</v-progress-linear>
</transition>
</v-card>
</v-hover>
</div>
</v-slide-y-transition>
</div>
</v-card-text>
<v-progress-linear
v-if="(loadingSend || loadingReceive) && loadingStage"
key="progress-bar"
height="14"
indeterminate
>
<div class="text-caption">{{ loadingStage }}</div>
</v-progress-linear>
</v-card>
<v-card v-else class="my-2">
<v-skeleton-loader type="article" />
</v-card>
</template>
<script>
@@ -204,6 +167,7 @@ export default {
},
data() {
return {
hover: false,
loadingSend: false,
loadingReceive: false,
loadingStage: null,
@@ -382,6 +346,9 @@ export default {
if (objects.length == 0) {
this.loadingSend = false
this.loadingStage = null
this.$eventHub.$emit('notification', {
text: 'No objects selected. Nothing was sent.'
})
return
}
@@ -398,7 +365,7 @@ export default {
let batchesSent = 0
for (const batch of batches) {
let res = await this.sendBatch(batch)
if (res.status !== 201) throw `Upload request failed: ${res}`
if (res.status !== 201) throw `Upload request failed: ${res.status}`
batchesSent++
this.loadingStage = `uploading: ${Math.round((batchesSent / totBatches) * 100)}%`
}
@@ -422,7 +389,9 @@ export default {
}
})
console.log('>>> SpeckleSketchUp: Sent to stream: ' + this.streamId, commit)
this.$eventHub.$emit('notification', {
text: 'Model selection sent!'
})
this.loadingSend = false
this.loadingStage = null
} catch (err) {
@@ -433,7 +402,7 @@ export default {
},
async sendBatch(batch) {
let formData = new FormData()
formData.append(`batch-1`, new Blob([JSON.stringify(batch)], { type: 'application/json' }))
formData.append(`batch-1`, new Blob([batch], { type: 'application/json' }))
let token = localStorage.getItem('SpeckleSketchup.AuthToken')
let res = await fetch(`${localStorage.getItem('serverUrl')}/objects/${this.streamId}`, {
method: 'POST',
-11
View File
@@ -1,11 +0,0 @@
<template>
<v-container>
<v-card>hello there!</v-card>
</v-container>
</template>
<script>
export default {}
</script>
<style></style>
+5
View File
@@ -4,11 +4,16 @@ import router from './router'
import vuetify from './plugins/vuetify'
import { createProvider } from './vue-apollo'
Vue.prototype.$eventHub = new Vue()
Vue.config.productionTip = false
import VueTimeago from 'vue-timeago'
Vue.use(VueTimeago, { locale: 'en' })
import VueTooltip from 'v-tooltip'
Vue.use(VueTooltip)
import VueMatomo from 'vue-matomo'
Vue.use(VueMatomo, {
+1 -1
View File
@@ -1,6 +1,6 @@
import Vue from 'vue'
import Vuetify from 'vuetify/lib/framework'
import '@/scss/styles.css'
Vue.use(Vuetify)
export default new Vuetify({
+121
View File
@@ -0,0 +1,121 @@
.background-light {
background: #8e9eab;
background: -webkit-linear-gradient(to top right, #eeeeee, #c8e8ff) !important;
background: linear-gradient(to top right, #ffffff, #c8e8ff) !important;
}
.background-dark {
background: #141e30;
background: -webkit-linear-gradient(to top left, #243b55, #141e30) !important;
background: linear-gradient(to top left, #243b55, #141e30) !important;
}
/* TOOLTIPs */
.tooltip {
display: block !important;
z-index: 10000;
font-family: 'Roboto', sans-serif !important;
font-size: 0.75rem !important;
}
.tooltip .tooltip-inner {
background: rgba(0, 0, 0, 1);
color: white;
border-radius: 16px;
padding: 5px 10px 4px;
}
.tooltip .tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
border-color: rgba(0, 0, 0, 0.5);
z-index: 1;
}
.tooltip[x-placement^='top'] {
margin-bottom: 5px;
}
.tooltip[x-placement^='top'] .tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
.tooltip[x-placement^='bottom'] {
margin-top: 5px;
}
.tooltip[x-placement^='bottom'] .tooltip-arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
.tooltip[x-placement^='right'] {
margin-left: 5px;
}
.tooltip[x-placement^='right'] .tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
.tooltip[x-placement^='left'] {
margin-right: 5px;
}
.tooltip[x-placement^='left'] .tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
.tooltip.popover .popover-inner {
background: #f9f9f9;
color: black;
padding: 24px;
border-radius: 5px;
box-shadow: 0 5px 30px rgba(black, 0.1);
}
.tooltip.popover .popover-arrow {
border-color: #f9f9f9;
}
.tooltip[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
transition: opacity 0.15s, visibility 0.15s;
}
.tooltip[aria-hidden='false'] {
visibility: visible;
opacity: 1;
transition: opacity 0.15s;
}
+5 -5
View File
@@ -170,21 +170,21 @@ export class BaseObjectSerializer {
batchObjects(maxBatchSizeMb = 1) {
const maxSize = maxBatchSizeMb * 1000 * 1000
let batches = []
let batch = []
let batch = '['
let batchSize = 0
let objects = Object.values(this.objects)
objects.forEach((obj) => {
let objString = JSON.stringify(obj)
if (batchSize + objString.length < maxSize) {
batch.push(obj)
batch += objString + ','
batchSize += objString.length
} else {
batches.push(batch)
batch = [obj]
batches.push(batch.slice(0, -1) + ']')
batch = '[' + objString + ','
batchSize = objString.length
}
})
batches.push(batch)
batches.push(batch.slice(0, -1) + ']')
return batches
}
+3 -3
View File
@@ -1,5 +1,5 @@
<template>
<v-container>
<div>
<v-row>
<v-col v-if="$apollo.loading && !streams">
<v-row>
@@ -10,7 +10,7 @@
</v-col>
</v-row>
<div v-if="!streamsFound" class="text-subtitle-1 text-center mt-8">No streams found... 👀</div>
<div v-if="streams">
<div v-if="streams" class="mt-5">
<div v-for="stream in streams.items" :key="stream.id">
<stream-card :stream-id="stream.id" />
</div>
@@ -26,7 +26,7 @@
</v-btn>
</div>
</div>
</v-container>
</div>
</template>
<script>