Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0eb835bed0 | |||
| 7a7ce8ff3d | |||
| 473f0890fe | |||
| a8955a435f | |||
| 80f25eb1a2 | |||
| 5716f92fbf | |||
| 63e7aaa661 | |||
| 7234a4be79 | |||
| e1cceb9bba | |||
| 30157b5ac2 | |||
| f9b1628c18 | |||
| 9429a11fa7 | |||
| af4c6d9f71 | |||
| a4f23e060c | |||
| d2099c98e0 | |||
| c21b51135a | |||
| c5c8bf6b6f | |||
| d9a92e90ec | |||
| 79ae201646 | |||
| 01b32d2558 | |||
| b3067aa346 | |||
| d1349c5df1 | |||
| d44365a6d4 | |||
| c8c94184df | |||
| 62c436131c | |||
| ac3579de46 | |||
| e7a72b25d7 | |||
| 6d155d987a | |||
| e4a78e4c6e | |||
| 35c819dab0 | |||
| 3001a4af48 | |||
| eeaa69e7b4 | |||
| 5717022293 | |||
| b5c1ad1ea3 | |||
| ea56717594 | |||
| 2ffb4219fc | |||
| 08843689ec | |||
| 299109505c | |||
| 520dccc674 |
@@ -26,6 +26,9 @@ Style/DocumentationMethod:
|
||||
|
||||
Metrics/AbcSize:
|
||||
Enabled: false
|
||||
|
||||
Metrics/BlockLength:
|
||||
Enabled: false
|
||||
|
||||
Metrics/ClassLength:
|
||||
Enabled: false
|
||||
|
||||
@@ -77,15 +77,15 @@ This should have also have set up the package installer `gem` and interactive ru
|
||||
gem -v
|
||||
irb -v
|
||||
|
||||
Let's also install our first gem `bundle` which is a package manager that will help us with development.
|
||||
Let's also install our first gem `bundler` which is a package manager that will help us with development.
|
||||
|
||||
gem install bundle
|
||||
gem install bundler
|
||||
|
||||
### Editor Setup
|
||||
|
||||
Clone this repo and run:
|
||||
|
||||
bundle install
|
||||
bundler install
|
||||
|
||||
This will install all the necessary packages for the connector.
|
||||
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
require "net/http"
|
||||
|
||||
require "json"
|
||||
|
||||
require "uri"
|
||||
|
||||
server = "https://latest.speckle.dev"
|
||||
|
||||
token = "1dc2e3330a56371dc9011e5bed406264c9e65dd355"
|
||||
|
||||
limit = 20
|
||||
streams_list = "
|
||||
query User {
|
||||
user {
|
||||
id
|
||||
email
|
||||
name
|
||||
bio
|
||||
company
|
||||
avatar
|
||||
verified
|
||||
profiles
|
||||
role
|
||||
streams(limit: #{limit}) {
|
||||
totalCount
|
||||
cursor
|
||||
items {
|
||||
id
|
||||
name
|
||||
description
|
||||
isPublic
|
||||
createdAt
|
||||
updatedAt
|
||||
collaborators {
|
||||
id
|
||||
name
|
||||
role
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"
|
||||
|
||||
endpoint = URI("#{server}/graphql")
|
||||
|
||||
res =
|
||||
::Net::HTTP.start(endpoint.host, endpoint.port, use_ssl: true) do |http|
|
||||
req = ::Net::HTTP::Post.new(endpoint)
|
||||
req["Content-Type"] = "application/json"
|
||||
req["Authorization"] = "Bearer #{token}"
|
||||
# The body needs to be a JSON string.
|
||||
req.body = ::JSON[{ query: streams_list }]
|
||||
puts(req.body)
|
||||
http.request(req)
|
||||
end
|
||||
|
||||
streams = ::JSON.parse(res.body)["data"]["user"]["streams"]["items"]
|
||||
puts(streams)
|
||||
@@ -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
|
||||
|
||||
@@ -33,22 +32,21 @@ module SpeckleSystems::SpeckleConnector
|
||||
end
|
||||
|
||||
def self._get_speckle_dir
|
||||
platform = RUBY_PLATFORM.downcase
|
||||
|
||||
speckle_dir =
|
||||
if platform =~ (/mingw/) || platform =~ (/win/)
|
||||
# win
|
||||
File.join(Dir.home, "AppData/Roaming/Speckle")
|
||||
elsif platform =~ /linux/
|
||||
# linux
|
||||
File.expand_path("~/.local/share/Speckle")
|
||||
case Sketchup.platform
|
||||
# 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
|
||||
# mac
|
||||
File.expand_path("~/.config/Speckle")
|
||||
nil
|
||||
end
|
||||
|
||||
return speckle_dir if Dir.exist?(speckle_dir)
|
||||
|
||||
raise(IOError, "No Speckle Directory exists. Please read the guide to get Speckle set up on your machine: \nhttps://speckle.guide/user/manager.html")
|
||||
raise(
|
||||
IOError,
|
||||
"No Speckle Directory exists. Please read the guide to get Speckle set up on your machine: \nhttps://speckle.guide/user/manager.html"
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -6,8 +6,10 @@ 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")
|
||||
props = obj.keys.filter_map { |key| key if key.start_with?("@") }
|
||||
%w[displayMesh displayValue data].each { |prop| props.push(prop) if obj.key?(prop) }
|
||||
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]) }
|
||||
elsif obj.is_a?(Hash)
|
||||
obj.each_value { |value| traverse_commit_object(value) }
|
||||
@@ -25,25 +27,32 @@ module SpeckleSystems::SpeckleConnector::ToNative
|
||||
"Objects.Geometry.Line",
|
||||
"Objects.Geometry.Polyline",
|
||||
"Objects.Geometry.Mesh",
|
||||
"Objects.Geometry.Brep",
|
||||
"Objects.Other.BlockInstance",
|
||||
"Objects.Other.BlockDefinition",
|
||||
"Objects.Other.RenderMaterial"
|
||||
].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)
|
||||
when "Objects.Other.BlockDefinition" then component_definition_to_native(obj)
|
||||
when "Objects.Geometry.Mesh" then mesh_to_native(obj, entities)
|
||||
when "Objects.Geometry.Brep" then mesh_to_native(obj["displayMesh"], entities)
|
||||
else
|
||||
nil
|
||||
end
|
||||
# rescue StandardError => e
|
||||
# puts("Failed to convert #{obj["speckle_type"]} (id: #{obj["id"]})")
|
||||
# puts(e)
|
||||
# nil
|
||||
# rescue StandardError => e
|
||||
# puts("Failed to convert #{obj["speckle_type"]} (id: #{obj["id"]})")
|
||||
# puts(e)
|
||||
# nil
|
||||
end
|
||||
|
||||
def length_to_native(length, units = @units)
|
||||
@@ -51,11 +60,16 @@ module SpeckleSystems::SpeckleConnector::ToNative
|
||||
end
|
||||
|
||||
def edge_to_native(line, entities)
|
||||
return unless line.key?("value")
|
||||
|
||||
values = line["value"]
|
||||
points = values.each_slice(3).to_a.map { |pt| point_to_native(pt[0], pt[1], pt[2], line["units"]) }
|
||||
entities.add_edges(*points)
|
||||
if line.key?("value")
|
||||
values = line["value"]
|
||||
points = values.each_slice(3).to_a.map { |pt| point_to_native(pt[0], pt[1], pt[2], line["units"]) }
|
||||
points.push(points[0]) if line["closed"]
|
||||
entities.add_edges(*points)
|
||||
else
|
||||
start_pt = point_to_native(line["start"]["x"], line["start"]["y"], line["start"]["z"], line["units"])
|
||||
end_pt = point_to_native(line["end"]["x"], line["end"]["y"], line["end"]["z"], line["units"])
|
||||
entities.add_edges(start_pt, end_pt)
|
||||
end
|
||||
end
|
||||
|
||||
def face_to_native
|
||||
@@ -66,31 +80,17 @@ module SpeckleSystems::SpeckleConnector::ToNative
|
||||
Geom::Point3d.new(length_to_native(x, units), length_to_native(y, units), length_to_native(z, units))
|
||||
end
|
||||
|
||||
def component_definition_to_native(block_def)
|
||||
definition = Sketchup.active_model.definitions[block_def["name"]]
|
||||
return definition if definition&.guid == block_def["applicationId"]
|
||||
|
||||
definition&.entities&.clear!
|
||||
definition ||= Sketchup.active_model.definitions.add(block_def["name"])
|
||||
block_def["geometry"].each { |obj| convert_to_native(obj, definition.entities) }
|
||||
definition
|
||||
end
|
||||
|
||||
def mesh_to_native(mesh, entities)
|
||||
native_mesh = Geom::PolygonMesh.new
|
||||
points = [] # to preserve indices - duplicate points won't be added in `point_to_native`
|
||||
native_mesh = Geom::PolygonMesh.new(mesh["vertices"].count / 3)
|
||||
points = []
|
||||
mesh["vertices"].each_slice(3) do |pt|
|
||||
points.push(point_to_native(pt[0], pt[1], pt[2], mesh["units"]))
|
||||
end
|
||||
faces = mesh["faces"]
|
||||
while faces.count.positive?
|
||||
size = faces.shift
|
||||
num_pts =
|
||||
case size
|
||||
when 0 then 3
|
||||
when 1 then 4
|
||||
else size
|
||||
end
|
||||
num_pts = faces.shift
|
||||
# 0 -> 3, 1 -> 4 to preserve backwards compatibility
|
||||
num_pts += 3 if num_pts < 3
|
||||
indices = faces.shift(num_pts)
|
||||
native_mesh.add_polygon(indices.map { |index| points[index] })
|
||||
end
|
||||
@@ -99,20 +99,36 @@ module SpeckleSystems::SpeckleConnector::ToNative
|
||||
native_mesh
|
||||
end
|
||||
|
||||
def component_definition_to_native(block_def)
|
||||
definition = Sketchup.active_model.definitions[block_def["name"]]
|
||||
return definition if definition && (definition.name == block_def["name"] || definition.guid == block_def["applicationId"])
|
||||
|
||||
definition&.entities&.clear!
|
||||
definition ||= Sketchup.active_model.definitions.add(block_def["name"])
|
||||
block_def["geometry"].each { |obj| convert_to_native(obj, definition.entities) }
|
||||
puts("definition finished: #{block_def["name"]} (#{block_def["id"]})")
|
||||
puts(" entity count: #{definition.entities.count}")
|
||||
definition
|
||||
end
|
||||
|
||||
def component_instance_to_native(block, entities)
|
||||
is_group = block.key?("is_sketchup_group") && block["is_sketchup_group"]
|
||||
# is_group = block.key?("is_sketchup_group") && block["is_sketchup_group"]
|
||||
# something about this conversion is freaking out if nested block geo is a group
|
||||
# so this is set to false always until I can figure this out
|
||||
is_group = false
|
||||
|
||||
definition = component_definition_to_native(block["blockDefinition"])
|
||||
# return unless definition.entities.count.positive?
|
||||
|
||||
transform = transform_to_native(block["transform"], block["units"])
|
||||
transform = transform_to_native(
|
||||
block["transform"].is_a?(Hash) ? block["transform"]["value"] : block["transform"],
|
||||
block["units"]
|
||||
)
|
||||
instance =
|
||||
if is_group
|
||||
entities.add_group(definition.entities.to_a)
|
||||
else
|
||||
entities.add_instance(definition, transform)
|
||||
end
|
||||
puts("Failed to create instance for speckle object #{block["id"]}") if instance.nil?
|
||||
puts("Failed to create instance for speckle block instance #{block["id"]}") if instance.nil?
|
||||
instance.transformation = transform if is_group
|
||||
instance.material = material_to_native(block["renderMaterial"])
|
||||
instance
|
||||
@@ -121,13 +137,22 @@ module SpeckleSystems::SpeckleConnector::ToNative
|
||||
def transform_to_native(t_arr, units = @units)
|
||||
Geom::Transformation.new(
|
||||
[
|
||||
t_arr[0], t_arr[4], t_arr[8], t_arr[12],
|
||||
t_arr[1], t_arr[5], t_arr[9], t_arr[13],
|
||||
t_arr[2], t_arr[6], t_arr[10], t_arr[14],
|
||||
length_to_native(t_arr[3], units),
|
||||
length_to_native(t_arr[7], units),
|
||||
length_to_native(t_arr[11], units),
|
||||
t_arr[15]
|
||||
t_arr[0],
|
||||
t_arr[4],
|
||||
t_arr[8],
|
||||
t_arr[12],
|
||||
t_arr[1],
|
||||
t_arr[5],
|
||||
t_arr[9],
|
||||
t_arr[13],
|
||||
t_arr[2],
|
||||
t_arr[6],
|
||||
t_arr[10],
|
||||
t_arr[14],
|
||||
length_to_native(t_arr[3], units),
|
||||
length_to_native(t_arr[7], units),
|
||||
length_to_native(t_arr[11], units),
|
||||
t_arr[15]
|
||||
]
|
||||
)
|
||||
end
|
||||
|
||||
@@ -40,7 +40,6 @@ module SpeckleSystems::SpeckleConnector::ToSpeckle
|
||||
|
||||
def component_instance_to_speckle(instance, is_group: false)
|
||||
transform = instance.transformation
|
||||
origin = transform.origin
|
||||
{
|
||||
speckle_type: "Objects.Other.BlockInstance",
|
||||
applicationId: instance.guid,
|
||||
@@ -50,17 +49,19 @@ module SpeckleSystems::SpeckleConnector::ToSpeckle
|
||||
name: instance.name,
|
||||
renderMaterial: instance.material.nil? ? nil : material_to_speckle(instance.material),
|
||||
transform: transform_to_speckle(transform),
|
||||
insertionPoint: speckle_point(origin[0], origin[1], origin[2]),
|
||||
"@blockDefinition" => component_definition_to_speckle(instance.definition)
|
||||
}
|
||||
end
|
||||
|
||||
def group_mesh_to_speckle(component_def)
|
||||
mat_groups = {}
|
||||
nested_blocks = []
|
||||
|
||||
component_def.entities.each do |face|
|
||||
next unless face.typename == "Face"
|
||||
component_def.entities.each do |entity|
|
||||
nested_blocks.push(component_instance_to_speckle(entity)) if entity.typename == "ComponentInstance"
|
||||
next unless entity.typename == "Face"
|
||||
|
||||
face = entity
|
||||
# convert material
|
||||
mat_id = face.material.nil? ? "none" : face.material.entityID
|
||||
mat_groups[mat_id] = initialise_group_mesh(face, component_def.bounds) unless mat_groups.key?(mat_id)
|
||||
@@ -76,17 +77,33 @@ module SpeckleSystems::SpeckleConnector::ToSpeckle
|
||||
end
|
||||
|
||||
mat_groups.values.map { |group| group.delete(:pt_count) }
|
||||
mat_groups.values
|
||||
mat_groups.values + nested_blocks
|
||||
end
|
||||
|
||||
def transform_to_speckle(transform)
|
||||
t_arr = transform.to_a
|
||||
[
|
||||
t_arr[0], t_arr[4], t_arr[8], length_to_speckle(t_arr[12]),
|
||||
t_arr[1], t_arr[5], t_arr[9], length_to_speckle(t_arr[13]),
|
||||
t_arr[2], t_arr[6], t_arr[10], length_to_speckle(t_arr[14]),
|
||||
t_arr[3], t_arr[7], t_arr[11], t_arr[15]
|
||||
]
|
||||
{
|
||||
speckle_type: "Objects.Other.Transform",
|
||||
units: @units,
|
||||
value: [
|
||||
t_arr[0],
|
||||
t_arr[4],
|
||||
t_arr[8],
|
||||
length_to_speckle(t_arr[12]),
|
||||
t_arr[1],
|
||||
t_arr[5],
|
||||
t_arr[9],
|
||||
length_to_speckle(t_arr[13]),
|
||||
t_arr[2],
|
||||
t_arr[6],
|
||||
t_arr[10],
|
||||
length_to_speckle(t_arr[14]),
|
||||
t_arr[3],
|
||||
t_arr[7],
|
||||
t_arr[11],
|
||||
t_arr[15]
|
||||
]
|
||||
}
|
||||
end
|
||||
|
||||
def initialise_group_mesh(face, bounds)
|
||||
@@ -97,7 +114,7 @@ module SpeckleSystems::SpeckleConnector::ToSpeckle
|
||||
"@(31250)vertices" => [],
|
||||
"@(62500)faces" => [],
|
||||
"@(31250)textureCoordinates" => [],
|
||||
pt_count: -1, # faces are 1 indexed
|
||||
pt_count: -1,
|
||||
renderMaterial: face.material.nil? ? nil : material_to_speckle(face.material)
|
||||
}
|
||||
end
|
||||
|
||||
@@ -81,10 +81,12 @@ module SpeckleSystems::SpeckleConnector
|
||||
end
|
||||
|
||||
def self.init_local_accounts
|
||||
puts("Initialisation of Speckle accounts requested by plugin")
|
||||
@dialog.execute_script("loadAccounts(#{Accounts.load_accounts.to_json}, #{Accounts.get_suuid.to_json})")
|
||||
end
|
||||
|
||||
def self.reload_accounts
|
||||
puts("Reload of Speckle accounts requested by plugin")
|
||||
@dialog.execute_script("loadAccounts(#{Accounts.load_accounts.to_json})")
|
||||
end
|
||||
end
|
||||
|
||||
Generated
+7498
-3226
File diff suppressed because it is too large
Load Diff
+3
-2
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
-1
@@ -85,6 +85,7 @@
|
||||
<v-container fluid>
|
||||
<router-view :stream-search-query="streamSearchQuery" />
|
||||
</v-container>
|
||||
<global-toast />
|
||||
</v-main>
|
||||
</v-app>
|
||||
</template>
|
||||
@@ -96,6 +97,7 @@ import userQuery from './graphql/user.gql'
|
||||
import { onLogin } from './vue-apollo'
|
||||
|
||||
global.loadAccounts = function (accounts, suuid) {
|
||||
console.log('>>> SpeckleSketchup: Loading accounts', accounts, `suuid: ${suuid}`)
|
||||
localStorage.setItem('localAccounts', JSON.stringify(accounts))
|
||||
if (suuid) {
|
||||
localStorage.setItem('suuid', suuid)
|
||||
@@ -117,7 +119,9 @@ global.setSelectedAccount = function (account) {
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {},
|
||||
components: {
|
||||
GlobalToast: () => import('@/components/GlobalToast')
|
||||
},
|
||||
props: {
|
||||
size: {
|
||||
type: Number,
|
||||
|
||||
@@ -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>
|
||||
+207
-170
@@ -1,164 +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 :datetime="stream.updatedAt" />
|
||||
</div>
|
||||
<v-toolbar-title>
|
||||
<v-chip v-if="stream.role" small class="mr-1">
|
||||
<v-icon small left>mdi-account-key-outline</v-icon>
|
||||
{{ stream.role.split(':')[1] }}
|
||||
</v-chip>
|
||||
|
||||
<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>
|
||||
<v-progress-linear
|
||||
v-if="(loadingSend || loadingReceive) && loadingStage"
|
||||
height="14"
|
||||
indeterminate
|
||||
>
|
||||
<div class="text-caption">{{ loadingStage }}</div>
|
||||
</v-progress-linear>
|
||||
</v-card>
|
||||
</v-hover>
|
||||
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"
|
||||
xxxclass="small-text-field"
|
||||
hide-details
|
||||
dense
|
||||
flat
|
||||
placeholder="Write your commit message here"
|
||||
></v-text-field>
|
||||
</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>
|
||||
@@ -191,11 +167,13 @@ export default {
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
hover: false,
|
||||
loadingSend: false,
|
||||
loadingReceive: false,
|
||||
loadingStage: null,
|
||||
branchName: 'main',
|
||||
commitId: 'latest'
|
||||
commitId: 'latest',
|
||||
commitMessage: null
|
||||
}
|
||||
},
|
||||
apollo: {
|
||||
@@ -278,19 +256,19 @@ export default {
|
||||
},
|
||||
mounted() {
|
||||
bus.$on(`sketchup-objects-${this.streamId}`, async (objects) => {
|
||||
console.log('received objects from sketchup', objects)
|
||||
console.log('>>> SpeckleSketchUp: Received objects from sketchup')
|
||||
|
||||
await this.createCommit(objects)
|
||||
})
|
||||
bus.$on(`sketchup-received-${this.streamId}`, () => {
|
||||
console.log('finished receiving in sketchup', this.streamId)
|
||||
console.log('>>> SpeckleSketchUp: Finished receiving in sketchup', this.streamId)
|
||||
this.loadingReceive = false
|
||||
this.loadingStage = null
|
||||
})
|
||||
bus.$on(`sketchup-fail-${this.streamId}`, () => {
|
||||
this.$matomo && this.$matomo.setCustomUrl(`http://connectors/SketchUp/stream/fail`)
|
||||
this.$matomo && this.$matomo.trackPageView(`stream/fail`)
|
||||
console.log('sketchup operation failed', this.streamId)
|
||||
console.log('>>> SpeckleSketchUp: operation failed', this.streamId)
|
||||
this.loadingReceive = this.loadingSend = false
|
||||
this.loadingStage = null
|
||||
})
|
||||
@@ -332,7 +310,24 @@ export default {
|
||||
|
||||
let rootObj = await loader.getAndConstructObject(this.updateLoadingStage)
|
||||
console.log(rootObj)
|
||||
|
||||
sketchup.receive_objects(rootObj, this.streamId)
|
||||
|
||||
await this.$apollo.mutate({
|
||||
mutation: gql`
|
||||
mutation commitReceive($input: CommitReceivedInput!) {
|
||||
commitReceive(input: $input)
|
||||
}
|
||||
`,
|
||||
variables: {
|
||||
input: {
|
||||
sourceApplication: 'sketchup',
|
||||
streamId: this.streamId,
|
||||
commitId: this.selectedCommit.id
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
this.loadingStage = 'converting'
|
||||
},
|
||||
updateLoadingStage({ stage }) {
|
||||
@@ -344,13 +339,16 @@ export default {
|
||||
this.$matomo && this.$matomo.setCustomUrl(`http://connectors/SketchUp/send`)
|
||||
this.$matomo && this.$matomo.trackPageView(`send`)
|
||||
sketchup.send_selection(this.streamId)
|
||||
console.log('request for data sent to sketchup')
|
||||
console.log('>>> SpeckleSketchUp: Objects requested from SketchUp')
|
||||
await this.sleep(2000)
|
||||
},
|
||||
async createCommit(objects) {
|
||||
if (objects.length == 0) {
|
||||
this.loadingSend = false
|
||||
this.loadingStage = null
|
||||
this.$eventHub.$emit('notification', {
|
||||
text: 'No objects selected. Nothing was sent.'
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
@@ -362,16 +360,21 @@ export default {
|
||||
this.loadingStage = 'uploading'
|
||||
this.loadingSend = true
|
||||
let batches = s.batchObjects()
|
||||
const totBatches = batches.length
|
||||
console.log(`>>> SpeckleSketchUp: ${totBatches} batches ready for sending`)
|
||||
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)}%`
|
||||
}
|
||||
|
||||
let commit = {
|
||||
streamId: this.streamId,
|
||||
branchName: this.branchName,
|
||||
objectId: hash,
|
||||
message: 'sent from sketchup',
|
||||
message: this.commitMessage ?? 'sent from sketchup',
|
||||
sourceApplication: 'sketchup',
|
||||
totalChildrenCount: s.objects[hash].totalChildrenCount
|
||||
}
|
||||
@@ -385,8 +388,10 @@ export default {
|
||||
commit: commit
|
||||
}
|
||||
})
|
||||
console.log('sent to stream: ' + this.streamId, commit)
|
||||
|
||||
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) {
|
||||
@@ -397,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',
|
||||
@@ -410,7 +415,39 @@ export default {
|
||||
}
|
||||
</script>
|
||||
|
||||
<style>
|
||||
<style scoped>
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
transition: opacity 0.2s ease-in;
|
||||
}
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.expand-enter-active {
|
||||
transition: all 0.2s ease;
|
||||
max-height: 1200px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.expand-leave-active {
|
||||
transition: all 0.3s ease;
|
||||
max-height: 1200px;
|
||||
overflow: hidden;
|
||||
}
|
||||
.expand-enter,
|
||||
.expand-leave-to {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.v-text-field >>> input {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.v-text-field >>> label {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
|
||||
.btn-fix:focus::before {
|
||||
opacity: 0 !important;
|
||||
}
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
<template>
|
||||
<v-container>
|
||||
<v-card>hello there!</v-card>
|
||||
</v-container>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {}
|
||||
</script>
|
||||
|
||||
<style></style>
|
||||
@@ -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,6 +1,6 @@
|
||||
import Vue from 'vue'
|
||||
import Vuetify from 'vuetify/lib/framework'
|
||||
|
||||
import '@/scss/styles.css'
|
||||
Vue.use(Vuetify)
|
||||
|
||||
export default new Vuetify({
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user