Skip to content

Feat: visual revamp #156

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 58 commits into from
May 30, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
ab266fa
delete debugger
oguzhankoral May 21, 2025
9e76f62
No need tooltip data as part of interactivity
oguzhankoral May 23, 2025
a21a960
Fix coloring
oguzhankoral May 23, 2025
eecde37
delete logging
oguzhankoral May 23, 2025
8fbb5a3
Fix messaging on interactivity for tooltip data
oguzhankoral May 23, 2025
76febcf
Delete unused code
oguzhankoral May 23, 2025
41c4e64
Navbar and cursors
oguzhankoral May 23, 2025
87b64b7
Revamp viewer actions
oguzhankoral May 24, 2025
ca0765c
Hide viewer actions
oguzhankoral May 24, 2025
da774b6
not a css master commit
oguzhankoral May 24, 2025
7bdb80f
Toggle projection/orthi
oguzhankoral May 24, 2025
e1e6d4e
Remove console log
oguzhankoral May 24, 2025
7b22e92
Fix saved objects
oguzhankoral May 24, 2025
c44b546
Remove console log
oguzhankoral May 24, 2025
222a6f8
Sort performance logging
oguzhankoral May 24, 2025
e4401da
fix view mode cache
oguzhankoral May 24, 2025
83cfa39
Fix initial isolate issue
oguzhankoral May 24, 2025
843174f
Update README.md (#147)
jsdbroughton Apr 8, 2025
3ecae7f
fix typo on conditions
oguzhankoral May 24, 2025
439bf56
capabilities for object ids
oguzhankoral May 25, 2025
57c0f19
Revert isolating every setDataInput
oguzhankoral May 25, 2025
72b4b9b
Fix selection issues
oguzhankoral May 25, 2025
fe483b7
Fix tooltip fckp
oguzhankoral May 25, 2025
28ce6b6
Reset filters
oguzhankoral May 25, 2025
f3f5edd
Fix reset filter
oguzhankoral May 25, 2025
e277ce6
Ghost hidden on filter
oguzhankoral May 26, 2025
0bd1218
Bring conditional formatting back
oguzhankoral May 27, 2025
abc4bf1
Remove ghost hidden context from color card
oguzhankoral May 27, 2025
74ade84
Disable shadow catcher
oguzhankoral May 27, 2025
e65bf83
Disable camera position persistence for performance reasons
oguzhankoral May 27, 2025
e70aa8a
feat (data): sending version and branding info (#157)
dogukankaratas May 27, 2025
95294c6
Enrich receive info from desktop service
oguzhankoral May 28, 2025
2691902
test
oguzhankoral May 28, 2025
fbe9672
fix path
oguzhankoral May 28, 2025
f2ab186
fix path again
oguzhankoral May 28, 2025
4502a48
file version
oguzhankoral May 28, 2025
30c2a20
correct the version with assembly for file version
oguzhankoral May 28, 2025
b9ff8ee
sanitize tag
oguzhankoral May 28, 2025
b775a2d
Merge branch 'installer-test/versioning' into oguzhan/visual-revamp
oguzhankoral May 28, 2025
b968955
Use version from receive info
oguzhankoral May 28, 2025
6c4d668
Fix clipped zoom extend
oguzhankoral May 28, 2025
094b79f
Workspace name logo
oguzhankoral May 28, 2025
9e9bfa0
Add can hide branding logic
oguzhankoral May 28, 2025
291e33b
Fix tooltip for toggle
oguzhankoral May 28, 2025
440edcc
Fix capabilities for storing branding
oguzhankoral May 28, 2025
4dff516
Tooltips
oguzhankoral May 28, 2025
32e8b2e
Store is ortho in file
oguzhankoral May 28, 2025
e63dd8a
Store camera position and target into file according to selected view
oguzhankoral May 28, 2025
715f11f
Fix loading bar reactivity
oguzhankoral May 28, 2025
31c0c1e
Update connector flow
oguzhankoral May 29, 2025
3871bf6
Fix ghost state
oguzhankoral May 29, 2025
431d293
Store is ghost in file
oguzhankoral May 29, 2025
33b079a
Consider ghost value on reset filter
oguzhankoral May 29, 2025
6b03188
More
oguzhankoral May 29, 2025
4692af7
excludes rawencoding (#159)
dogukankaratas May 29, 2025
2690b90
adds null check for personal (#158)
dogukankaratas May 29, 2025
270d463
Progress update and error handling
oguzhankoral May 30, 2025
1a73cf6
Call pre get before
oguzhankoral May 30, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .github/workflows/build_powerbi.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ jobs:
with:
fetch-depth: 0

- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"

- name: Install GitVersion
uses: gittools/actions/gitversion/[email protected]
with:
Expand All @@ -26,6 +31,10 @@ jobs:
id: gitversion
uses: gittools/actions/gitversion/[email protected]

- name: Set connector version
run: |
python patch_version.py ${{steps.gitversion.outputs.AssemblySemVer}}

- name: Setup MSBuild
uses: microsoft/setup-msbuild@v2

Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ This repo is home to our Power BI connector. The Speckle Server provides all the

# Installation

Speckle connector can be installed directly from [Manager for Speckle](https://speckle.systems/download/). Full instructions for [installation](https://speckle.guide/user/powerbi/installation.html) and [configuration](https://speckle.guide/user/powerbi/configuration.html) can be found on our docs.
Speckle connector can be installed directly from the [connectors portal](https://app.speckle.systems/connectors/). Full instructions for [installation](https://speckle.guide/user/powerbi/installation.html) and [configuration](https://speckle.guide/user/powerbi/configuration.html) can be found on our docs.

# Using 3D Visual

Expand Down
42 changes: 42 additions & 0 deletions patch_version.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import re
import sys
import os


def sanitize_version(tag):
"""Extracts the first three numeric segments from a tag string, because PowerBI is..."""
parts = re.findall(r"\d+", tag)
return ".".join(parts[:3]) if len(parts) >= 3 else tag

def patch_connector(tag):
"""Patches the connector version within the data connector file"""
sanitized_tag = sanitize_version(tag)
pq_file = os.path.join(os.path.dirname(__file__), "src", "powerbi-data-connector", "Speckle.pq")

with open(pq_file, "r") as file:
lines = file.readlines()

for (index, line) in enumerate(lines):
if '[Version = "3.0.0"]' in line:
lines[index] = f'[Version = "{sanitized_tag}"]\n'
print(f"Patched connector version number in {pq_file}")
break

with open(pq_file, "w") as file:
file.writelines(lines)


def main():
if len(sys.argv) < 2:
return

tag = sys.argv[1]
if not re.match(r"([0-9]+)\.([0-9]+)\.([0-9]+)", tag):
raise ValueError(f"Invalid tag provided: {tag}")

print(f"Patching version: {tag}")
patch_connector(tag)


if __name__ == "__main__":
main()
11 changes: 11 additions & 0 deletions src/powerbi-data-connector/Speckle.pq
Original file line number Diff line number Diff line change
Expand Up @@ -58,12 +58,23 @@ shared Speckle.GetStructuredData = Value.ReplaceType(
type function (url as Uri.Type) as table
);

shared Speckle.GetVersion = Value.ReplaceType(
Speckle.LoadFunction("GetVersion.pqm"),
type function () as text
);

[DataSource.Kind = "Speckle"]
shared Speckle.SendToServer = Value.ReplaceType(
Speckle.LoadFunction("SendToServer.pqm"),
type function (url as Uri.Type) as table
);

[DataSource.Kind = "Speckle"]
shared Speckle.GetWorkspace = Value.ReplaceType(
Speckle.LoadFunction("GetWorkspace.pqm"),
type function (url as Uri.Type) as record
);

[DataSource.Kind = "Speckle", Publish="GetByUrl.Publish"]
shared Speckle.GetByUrl = Value.ReplaceType(
Speckle.LoadFunction("GetByUrl.pqm"),
Expand Down
2 changes: 1 addition & 1 deletion src/powerbi-data-connector/Speckle.query.pq
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// NOTE! for tests, be make sure you put here a model that in private project to make sure all good.
let
result = Speckle.GetByUrl(
"https://latest.speckle.systems/projects/126cd4b7bb/models/85c44d39c6"
"https://app.speckle.systems/projects/b61ab234b0/models/a8166255b5"
)
in
result
26 changes: 21 additions & 5 deletions src/powerbi-data-connector/speckle/api/GetStructuredData.pqm
Original file line number Diff line number Diff line change
Expand Up @@ -59,16 +59,32 @@
)
),

// Function to check if a row should be excluded based on speckle type
ShouldExcludeRow = (row as record) as logical =>
let
speckleType = Record.FieldOrDefault(row[data], "speckle_type", "")
in
speckleType = "Speckle.Core.Models.DataChunk" or
Text.Contains(speckleType, "Objects.Other.RawEncoding"),

// Filtering logic here
// If, model data contains any DataObject -> fetch only data objects
// If there are no data objects in the data -> fetch everything but DataChunks
// If model data contains any DataObject -> fetch only data objects (excluding unwanted types)
// If there are no data objects in the data -> fetch everything but exclude DataChunks and RawEncoding
HasDataObjects = Table.RowCount(
Table.SelectRows(FinalTable, each Text.Contains(Record.FieldOrDefault([data], "speckle_type", ""), "DataObject"))
Table.SelectRows(
FinalTable,
each Text.Contains(Record.FieldOrDefault([data], "speckle_type", ""), "DataObject")
and not ShouldExcludeRow(_)
)
) > 0,

FilteredTable = if HasDataObjects then
Table.SelectRows(FinalTable, each Text.Contains(Record.FieldOrDefault([data], "speckle_type", ""), "DataObject"))
Table.SelectRows(
FinalTable,
each Text.Contains(Record.FieldOrDefault([data], "speckle_type", ""), "DataObject")
and not ShouldExcludeRow(_)
)
else
Table.SelectRows(FinalTable, each Record.FieldOrDefault([data], "speckle_type", "") <> "Speckle.Core.Models.DataChunk")
Table.SelectRows(FinalTable, each not ShouldExcludeRow(_))
in
FilteredTable
46 changes: 46 additions & 0 deletions src/powerbi-data-connector/speckle/api/GetVersion.pqm
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
() as text =>
let
// read the Speckle.pq file
specklePqContent = try
Text.FromBinary(Extension.Contents("Speckle.pq"))
otherwise
error "Could not read Speckle.pq file",

lines = Text.Split(specklePqContent, "#(lf)"),

versionLine = List.First(
List.Select(
lines,
each Text.Contains(_, "[Version = ")
),
null
),

version = if versionLine <> null then
let
// find the start and end positions of the version string
startPos = Text.PositionOf(versionLine, """") + 1,
tempText = Text.Middle(versionLine, startPos),
endPos = Text.PositionOf(tempText, """"),
versionText = Text.Middle(tempText, 0, endPos)
in
versionText
else
// fallback version if parsing fails
"3.0.0",

// validate version format
isValidVersion =
let
parts = Text.Split(version, "."),
isValid = List.Count(parts) = 3 and
List.AllTrue(List.Transform(parts, each try Number.From(_) >= 0 otherwise false))
in
isValid,

result = if isValidVersion then
version
else
error "Invalid version format found: " & version
in
result
76 changes: 76 additions & 0 deletions src/powerbi-data-connector/speckle/api/GetWorkspace.pqm
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// function for getting workspace information
(url as text) as record =>
let
ApiFetch = Extension.LoadFunction("Api.Fetch.pqm"),
Parser = Extension.LoadFunction("Parser.pqm"),

// the logic for importing functions from other files
Extension.LoadFunction = (fileName as text) =>
let
binary = Extension.Contents(fileName),
asText = Text.FromBinary(binary)
in
try
Expression.Evaluate(asText, #shared)
catch (e) =>
error
[
Reason = "Extension.LoadFunction Failure",
Message.Format = "Loading '#{0}' failed - '#{1}': '#{2}'",
Message.Parameters = {fileName, e[Reason], e[Message]},
Detail = [File = fileName, Error = e]
],

parsedUrl = Parser(url),
server = parsedUrl[baseUrl],
projectId = parsedUrl[projectId],

// query to get workspace ID from project
projectQuery = "query Project($projectId: String!) {
data:project(id: $projectId) {
workspaceId
}
}",

projectVariables = [
projectId = projectId
],

projectResult = ApiFetch(server, projectQuery, projectVariables),
workspaceId = projectResult[data][workspaceId],

// check if workspaceId is null (personal project)
workspaceInfo = if workspaceId = null then
[
workspaceId = null,
workspaceLogo = null,
workspaceName = null,
canHideBranding = false
]
else
// query workspace only if workspaceId exists
let
workspaceQuery = "query Workspace($workspaceId: String!, $featureName: WorkspaceFeatureName!) {
data:workspace(id: $workspaceId) {
logo
name
hasAccessToFeature(featureName: $featureName)
}
}",

workspaceVariables = [
workspaceId = workspaceId,
featureName = "hideSpeckleBranding"
],

workspaceResult = ApiFetch(server, workspaceQuery, workspaceVariables),
workspace = workspaceResult[data]
in
[
workspaceId = workspaceId,
workspaceLogo = workspace[logo],
workspaceName = workspace[name],
canHideBranding = workspace[hasAccessToFeature]
]
in
workspaceInfo
24 changes: 17 additions & 7 deletions src/powerbi-data-connector/speckle/api/SendToServer.pqm
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
GetModel = Extension.LoadFunction("GetModel.pqm"),
Parser = Extension.LoadFunction("Parser.pqm"),
GetUser = Extension.LoadFunction("GetUser.pqm"),
GetVersion = Extension.LoadFunction("GetVersion.pqm"),
GetWorkspace = Extension.LoadFunction("GetWorkspace.pqm"),

// the logic for importing functions from other files
Extension.LoadFunction = (fileName as text) =>
let
Expand All @@ -20,18 +23,20 @@
Message.Parameters = {fileName, e[Reason], e[Message]},
Detail = [File = fileName, Error = e]
],

// Get model info and parsed URL

modelInfo = GetModel(url),
parsedUrl = Parser(url),
userInfo = GetUser(url),

// Get API key if available

apiKey = userInfo[Token],

// Get user email from credentials
userEmail = userInfo[UserEmail],


// get version from Speckle.pq - look GetVersion.pqm
connectorVersion = GetVersion(),

workspaceInfo = GetWorkspace(url),

// Prepare request data
requestData = Json.FromValue([
Url = url,
Expand All @@ -40,7 +45,12 @@
ProjectId = parsedUrl[projectId],
ObjectId = modelInfo[rootObjectId],
SourceApplication = modelInfo[sourceApplication],
Token = apiKey
Token = apiKey,
Version = connectorVersion,
WorkspaceId = workspaceInfo[workspaceId],
WorkspaceName = workspaceInfo[workspaceName],
WorkspaceLogo = workspaceInfo[workspaceLogo],
CanHideBranding = workspaceInfo[canHideBranding]
]),

// Send request to local server
Expand Down
Loading