Compare commits

...

29 Commits

Author SHA1 Message Date
Alan Rynne 15ac7c041e Merge pull request #10 from specklesystems/hotfix/url-parsing
fix: Fixes wrong implementation assignment and optional input removal
2021-12-02 12:17:03 +01:00
Alan Rynne 770d45f981 fix: Fixes wrong implementation assignment and optional input removal 2021-12-02 12:15:58 +01:00
Alan Rynne 50b59a88c3 Merge pull request #9 from specklesystems/alan/error-reporting
Stable release final touches 🪄
2021-11-29 12:41:06 +01:00
Alan Rynne 0bad9914c8 fix: Removed shared tag from API function 2021-11-29 12:40:54 +01:00
Alan Rynne aee00f3f21 fix: Removed __closure and totalChildrenCount fields. 2021-11-29 12:31:45 +01:00
Alan Rynne 2abdd4b645 fix: Removed duplicated icons and fixed folder path 2021-11-29 12:31:19 +01:00
Alan Rynne 71ef1acd8b feat: Final polish!! 2021-11-29 11:39:39 +01:00
Alan Rynne 23114a2912 chore: Pending file deletion 2021-11-25 10:02:42 +01:00
Alan Rynne ee989f927d feat: Better error handling and initial function documentation 2021-11-25 10:01:09 +01:00
Alan Rynne 1ff15c7b44 chore: Moved logos into subfolder 2021-11-25 10:00:45 +01:00
Alan Rynne 6e9fb590a0 chore: Removed duplicated api call 2021-11-24 18:58:53 +01:00
Alan Rynne 9700865934 Merge pull request #7 from specklesystems/alan/table-pagination
Adds pagination to object queries
2021-11-24 10:58:48 +01:00
Alan Rynne cf9e5a70b6 chore: Reordering of methods for clarity 2021-11-24 09:52:04 +01:00
Alan Rynne 50c360ae79 feat: Pagination works!! Plus query formating 2021-11-24 09:31:39 +01:00
Alan Rynne b671945fa7 feat: More re-structuring + pagination boilerplate 2021-11-24 09:05:52 +01:00
Alan Rynne eb4787ddfa fix: Removed redundant implementation 2021-11-23 16:40:31 +01:00
Alan Rynne 3ffd6c63e0 feat: Fetch refactoring 2021-11-23 16:33:08 +01:00
Alan Rynne a5a8316ee0 Merge pull request #6 from specklesystems/alan/receive-receipts
feat: Added receive receipts to PowerBI and branch URL support
2021-11-19 15:21:13 +01:00
Alan Rynne 17083c9474 feat: Branch url support! + minor mismatch in auth 2021-11-19 12:07:12 +01:00
Alan Rynne 3e6f9988d6 feat: Added receive receipts to PowerBI 2021-11-18 13:51:10 +01:00
Alan Rynne fe1504d1a9 Merge pull request #4 from specklesystems/claire/remove-chunks-etc
PowerBI Improvements
2021-10-08 18:44:47 +02:00
Alan Rynne c753e13859 LogToMatomo() cleanup 2021-10-08 12:46:58 +02:00
Alan Rynne fc2ffa75ba metrics: Added explanation of how logToMatomo works 2021-10-07 19:43:09 +02:00
Alan Rynne de43e34c11 metrics: third's the charm 🪄 2021-10-07 19:41:53 +02:00
Alan Rynne 70eb1059d2 metrics: second attempt 2021-10-07 19:29:14 +02:00
Alan Rynne 9e5c204c8f metrics: First attempt 2021-10-07 18:51:26 +02:00
Claire Kuang e0f2782c8b removes closures and datachunks 2021-10-07 12:01:26 +01:00
Matteo Cominetti baf2132d1b Create close-issue.yml 2021-10-02 17:10:13 +01:00
Matteo Cominetti eef502f42f Create open-issue.yml 2021-10-02 17:09:59 +01:00
15 changed files with 563 additions and 217 deletions
+78
View File
@@ -0,0 +1,78 @@
name: Update issue Status
on:
issues:
types: [closed]
jobs:
update_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
echo "$PROJECT_ID"
echo "$STATUS_FIELD_ID"
echo 'DONE_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .settings | fromjson | .options[] | select(.name== "Done") | .id' project_data.json) >> $GITHUB_ENV
echo "$DONE_ID"
- name: Add Issue to project #it's already in the project, but we do this to get its node id!
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
- name: Update Status
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $status:ID!, $id:ID!, $value:String!) {
set_status: updateProjectNextItemField(
input: {
projectId: $project
itemId: $id
fieldId: $status
value: $value
}
) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f status=$STATUS_FIELD_ID -f id=$ITEM_ID -f value=${{ env.DONE_ID }}
+50
View File
@@ -0,0 +1,50 @@
name: Move new issues into Project
on:
issues:
types: [opened]
jobs:
track_issue:
runs-on: ubuntu-latest
steps:
- name: Get project data
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ORGANIZATION: specklesystems
PROJECT_NUMBER: 9
run: |
gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectNext(number: $number) {
id
fields(first:20) {
nodes {
id
name
settings
}
}
}
}
}' -f org=$ORGANIZATION -F number=$PROJECT_NUMBER > project_data.json
echo 'PROJECT_ID='$(jq '.data.organization.projectNext.id' project_data.json) >> $GITHUB_ENV
echo 'STATUS_FIELD_ID='$(jq '.data.organization.projectNext.fields.nodes[] | select(.name== "Status") | .id' project_data.json) >> $GITHUB_ENV
- name: Add Issue to project
env:
GITHUB_TOKEN: ${{secrets.GHPROJECT_TOKEN}}
ISSUE_ID: ${{ github.event.issue.node_id }}
run: |
item_id="$( gh api graphql --header 'GraphQL-Features: projects_next_graphql' -f query='
mutation($project:ID!, $id:ID!) {
addProjectNextItem(input: {projectId: $project, contentId: $id}) {
projectNextItem {
id
}
}
}' -f project=$PROJECT_ID -f id=$ISSUE_ID --jq '.data.addProjectNextItem.projectNextItem.id')"
echo 'ITEM_ID='$item_id >> $GITHUB_ENV
+5 -5
View File
@@ -3,7 +3,7 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{4DF76451-A46A-4C0B-BE03-459FAAFA07E6}") = "Speckle", "Speckle\Speckle.mproj", "{D61F9470-E614-45C7-8047-E354FF219408}"
Project("{4DF76451-A46A-4C0B-BE03-459FAAFA07E6}") = "Speckle", "Speckle\Speckle.mproj", "{0B5FE03D-AAD9-4BC4-9EDF-B543D5E50D29}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -11,10 +11,10 @@ Global
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D61F9470-E614-45C7-8047-E354FF219408}.Debug|x86.ActiveCfg = Debug|x86
{D61F9470-E614-45C7-8047-E354FF219408}.Debug|x86.Build.0 = Debug|x86
{D61F9470-E614-45C7-8047-E354FF219408}.Release|x86.ActiveCfg = Release|x86
{D61F9470-E614-45C7-8047-E354FF219408}.Release|x86.Build.0 = Release|x86
{0B5FE03D-AAD9-4BC4-9EDF-B543D5E50D29}.Debug|x86.ActiveCfg = Debug|x86
{0B5FE03D-AAD9-4BC4-9EDF-B543D5E50D29}.Debug|x86.Build.0 = Debug|x86
{0B5FE03D-AAD9-4BC4-9EDF-B543D5E50D29}.Release|x86.ActiveCfg = Release|x86
{0B5FE03D-AAD9-4BC4-9EDF-B543D5E50D29}.Release|x86.Build.0 = Release|x86
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
+32 -28
View File
@@ -10,15 +10,16 @@
<AllowNativeQuery>False</AllowNativeQuery>
<AsAction>False</AsAction>
<FastCombine>False</FastCombine>
<ClearLog>False</ClearLog>
<ClearLog>True</ClearLog>
<ShowEngineTraces>False</ShowEngineTraces>
<ShowUserTraces>False</ShowUserTraces>
<ShowUserTraces>True</ShowUserTraces>
<LegacyRedirects>False</LegacyRedirects>
<SuppressRowErrors>False</SuppressRowErrors>
<SuppressCellErrors>False</SuppressCellErrors>
<MaxRows>1000</MaxRows>
<MaxRows>100</MaxRows>
<ExtensionProject>Yes</ExtensionProject>
<Name>Speckle</Name>
<ThrowOnFoldingFailure>False</ThrowOnFoldingFailure>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)' == 'Debug' ">
<DebugSymbols>false</DebugSymbols>
@@ -39,36 +40,39 @@
<Compile Include="Speckle.pq">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo16.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo20.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo24.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo32.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo40.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo48.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo64.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="SpeckleLogo80.png">
<SubType>Code</SubType>
</Compile>
<Compile Include="resources.resx">
<SubType>Code</SubType>
</Compile>
<Content Include="Speckle.query.pq">
<SubType>Code</SubType>
<SubType>Content</SubType>
</Content>
<Compile Include="assets/SpeckleLogo16.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo20.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo24.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo32.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo40.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo48.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo64.png">
<SubType>Content</SubType>
</Compile>
<Compile Include="assets/SpeckleLogo80.png">
<SubType>Content</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<Folder Include="assets\" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<UsingTask TaskName="BuildExtension" TaskFactory="CodeTaskFactory" AssemblyFile="$(MSBuildToolsPath)\Microsoft.Build.Tasks.v12.0.dll">
+365 -178
View File
@@ -1,153 +1,30 @@
section Speckle;
/* This is an additional nav bar that can display branches of a stream: not using this for now
[DataSource.Kind="Speckle", Publish="Speckle.Publish"]
shared Speckle.Contents = Value.ReplaceType(NavigationTable.Simple, type function (url as Uri.Type) as any);
Beta = true;
Category = "Other";
Icons = [
Icon16 = { Extension.Contents("SpeckleLogo16.png"), Extension.Contents("SpeckleLogo20.png"), Extension.Contents("SpeckleLogo24.png"), Extension.Contents("SpeckleLogo32.png") },
Icon32 = { Extension.Contents("SpeckleLogo32.png"), Extension.Contents("SpeckleLogo40.png"), Extension.Contents("SpeckleLogo48.png"), Extension.Contents("SpeckleLogo64.png") }
];
Authentication = [
Key = [
KeyLabel="Personal Access Token",
Label = "Private stream"
],
Implicit = [
Label = "Public stream"
]
];
// set up nav table
shared NavigationTable.Simple = (url) as table =>
let
baseUrl = Uri.Parts(url)[Host] as text,
streamId = Text.Split(Uri.Parts(url)[Path], "/"){2},
objects = Speckle.GetBranches(baseUrl, streamId),
table = #table(
{"Name", "Key", "Data", "ItemKind", "ItemName", "IsLeaf"},
List.InsertRange(objects, List.Count(objects), {{"GetCommit", "GetCommit", Speckle.GetObjectFromObject(baseUrl, streamId), "Function", "Function", true}})
),
NavTable = Table.ToNavigationTable(table, {"Key"}, "Name", "Data", "ItemKind", "ItemName", "IsLeaf")
in
NavTable;
GetPublish = (key as text) as record => [
Beta = Beta,
Category = Category,
ButtonText = { Extension.LoadString(Text.Format("#{0}.Title", {key})), Extension.LoadString(Text.Format("#{0}.Label",{key})) },
LearnMoreUrl = "https://speckle.guide",
SourceImage = Icons,
SourceTypeImage = Icons
];
Speckle.GetBranches = (url, id) =>
let
Source = Web.Contents(
Text.Combine({"https:/", url, "graphql"}, "/"),
[
Headers=[
#"Method"="POST",
#"Content-Type"="application/json"
],
Content=Text.ToBinary("{""query"": ""query { stream( id: \"""&id&"\"" ) { branches { items { name commits { items { id message sourceApplication authorName createdAt } } } } } }""}")
]
),
#"JSON" = Json.Document(Source),
branches = #"JSON"[data][stream][branches][items],
branchList = List.Generate(
() => [x = 0, y = Speckle.GetBranchAsList(branches{x})],
each [x] < List.Count(branches),
each [x = [x] + 1, y = Speckle.GetBranchAsList(branches{x})],
each [y]
)
in
branchList;
Speckle.GetBranchAsList = (branchRecord) =>
let
commits = Table.FromRecords(branchRecord[commits][items]),
list = {branchRecord[name], branchRecord[name], commits, "Table", "Table", true}
in
list;
*/
[DataSource.Kind="Speckle", Publish="Speckle.Publish"]
shared Speckle.Contents = Value.ReplaceType(CommitTable, type function (StreamUrl as Uri.Type) as any);
shared CommitTable = (url) as table =>
let
// Get server and streamId, and branchName / commitId / objectid from the input url
server = Text.Combine({"https://", Uri.Parts(url)[Host]}),
segments = Text.Split(Text.AfterDelimiter(Uri.Parts(url)[Path], "/", 0), "/"),
streamId = segments{1},
branchName = if( List.Count(segments) = 4 and segments{2} = "branches" ) then segments{3} else null,
commitId = if (List.Count(segments) = 4 and segments{2} = "commits" ) then segments{3} else null,
objectId = if (List.Count(segments) = 4 and segments{2} = "objects" ) then segments{3} else null,
commitTable = if (commitId <> null) then Speckle.GetObjectFromCommit(server, streamId, commitId)
else if (objectId <> null) then Speckle.GetObjectFromObject(server, streamId, objectId, false)
else if (branchName <> null) then #table( { "Error" }, { { "Invalid URL, use a stream or commit or object url" } } ) // currently not implemented, see reason below
else Speckle.GetObjectFromStream(server, streamId)
in
commitTable;
Speckle.GetObjectFromStream = (server, streamId) =>
let
branchName = "main",
Source = Web.Contents(
Text.Combine({server, "graphql"}, "/"),
[
Headers=[
#"Method"="POST",
#"Content-Type"="application/json"
],
Content=Text.ToBinary("{""query"": ""query { stream( id: \"""&streamId&"\"" ) { branch (name: \"""&branchName&"\""){ commits (limit: 1) { items { referencedObject } } } } }""}")
]
),
#"JSON" = Json.Document(Source),
objectId = #"JSON"[data][stream][branch][commits][items]{0}[referencedObject],
objectsTable = Speckle.GetObjectFromObject(server, streamId, objectId, true)
in
objectsTable;
/* Not implemented since power query M uri does not have a decode method...def not manually writing a method to handle special chars and emojis
Speckle.GetObjectFromBranch = (server, streamId, branchName) =>
let
Source = Web.Contents(
Text.Combine({server, "graphql"}, "/"),
[
Headers=[
#"Method"="POST",
#"Content-Type"="application/json"
],
Content=Text.ToBinary("{""query"": ""query { stream( id: \"""&streamId&"\"" ) { branch (name: \"""&branchName&"\""){ commits (limit: 1) { items { referencedObject } } } } }""}")
]
),
#"JSON" = Json.Document(Source),
objectId = #"JSON"[data][stream][branch][commits][items]{0}[referencedObject],
objectsTable = Speckle.GetObjectFromObject(server, streamId, objectId)
in
objectsTable;
*/
shared Speckle.GetObjectFromCommit = (server, streamId, commitId) =>
let
Source = Web.Contents(
Text.Combine({server, "graphql"}, "/"),
[
Headers=[
#"Method"="POST",
#"Content-Type"="application/json"
],
Content=Text.ToBinary("{""query"": ""query { stream( id: \"""&streamId&"\"" ) { commit (id: \"""&commitId&"\""){ referencedObject } } }""}")
]
),
#"JSON" = Json.Document(Source),
objectId = #"JSON"[data][stream][commit][referencedObject],
objectsTable = Speckle.GetObjectFromObject(server, streamId, objectId, true)
in
objectsTable;
Speckle.GetObjectFromObject = (server, streamId, objectId, IsCommitObject) =>
let
query = if (IsCommitObject) then "{""query"": ""query { stream( id: \"""&streamId&"\"" ) { object (id: \"""&objectId&"\"") { children { objects { data } } } } }""}"
else "{""query"": ""query { stream( id: \"""&streamId&"\"" ) { object (id: \"""&objectId&"\"") { data } } }""}",
Source = Web.Contents(
Text.Combine({server, "graphql"}, "/"),
[
Headers=[
#"Method"="POST",
#"Content-Type"="application/json"
],
Content=Text.ToBinary(query)
]
),
#"JSON" = Json.Document(Source),
objects = if (IsCommitObject) then #"JSON"[data][stream][object][children][objects]
else {#"JSON"[data][stream][object][data]},
objectsTable = Table.FromRecords(objects)
in
objectsTable;
// Data Source Kind description
Speckle = [
Authentication = [
Key = [
@@ -157,45 +34,355 @@ Speckle = [
Implicit = [
Label = "Public stream"
]
],
Label = Extension.LoadString("Speckle Connector")
]
];
// Data Source UI publishing description
Speckle.Publish = [
[DataSource.Kind="Speckle", Publish="GetByUrl.Publish"]
shared Speckle.GetByUrl = Value.ReplaceType(GetByUrl.Impl, GetByUrl.Type);
GetByUrl.Publish = GetPublish("GetByUrl");
GetByUrl.Type = type function (
url as (Uri.Type meta [
Documentation.FieldCaption = "Stream URL",
Documentation.FieldDescription = "The url of a stream in a Speckle server. You can copy it directly from your browser.",
Documentation.SampleValues = {"https://speckle.xyz/streams/23401adf", "https://speckle.xyz/streams/23401adf/branches/main"}
]))
as table meta [
Documentation.Name = "Speckle - Get stream by URL",
Documentation.LongDescription = "Returns a flat list of all objects contained in a specific Speckle stream/branch/commit/object.
Supports all types of stream url:#(lf)
- Stream: will get the latest commit on the 'main' branch (i.e. 'https://speckle.xyz/streams/STREAM_ID')#(lf)
- Branch: will get the latest commit on the specified branch (i.e. 'https://speckle.xyz/streams/STREAM_ID/branches/BRANCH_NAME')#(lf)
- Commit: will get a specific commit from the stream (i.e. 'https://speckle.xyz/streams/STREAM_ID/commits/COMMIT_ID')
",
Documentation.Examples = {[
Description = "Returns a table with 'Hello world' repeated 2 times",
Code = "HelloWorldWithDocs.Contents(""Hello world"", 2)"
]}
];
GetByUrl.Impl = (url as text) as table =>
let
// Get server and streamId, and branchName / commitId / objectid from the input url
s = Text.Combine({"https://", Uri.Parts(url)[Host]}),
server = Speckle.LogToMatomo(s),
segments = Text.Split(Text.AfterDelimiter(Uri.Parts(url)[Path], "/", 0), "/"),
streamId = segments{1},
branchName = if( List.Count(segments) = 4 and segments{2} = "branches" ) then segments{3} else null,
commitId = if (List.Count(segments) = 4 and segments{2} = "commits" ) then segments{3} else null,
objectId = if (List.Count(segments) = 4 and segments{2} = "objects" ) then segments{3} else null,
commitTable =
if (commitId <> null)
then Speckle.GetObjectFromCommit(server, streamId, commitId)
else if (objectId <> null)
then Speckle.GetObjectFromObject(server, streamId, objectId)
else if (branchName <> null)
then Speckle.GetObjectFromBranch(server,streamId,branchName)
else
Speckle.GetObjectFromStream(server, streamId)
in
commitTable;
Speckle.GetObjectFromStream = Value.ReplaceType(GetObjFromStream.Impl, GetObjFromStream.Type);
GetObjFromStreamKind = [
Authentication = [
Key = [
KeyLabel="Personal Access Token",
Label = "Private stream"
],
Implicit = [
Label = "Public stream"
]
]
];
GetObjFromStream.Publish = [
Beta = true,
Category = "Other",
ButtonText = { Extension.LoadString("ButtonTitle"), Extension.LoadString("ButtonHelp") },
ButtonText = { Extension.LoadString("GetStream.Title"), Extension.LoadString("GetStream.Label") },
LearnMoreUrl = "https://speckle.guide",
SourceImage = Speckle.Icons,
SourceTypeImage = Speckle.Icons
SourceImage = Icons,
SourceTypeImage = Icons
];
Speckle.Icons = [
Icon16 = { Extension.Contents("SpeckleLogo16.png"), Extension.Contents("SpeckleLogo20.png"), Extension.Contents("SpeckleLogo24.png"), Extension.Contents("SpeckleLogo32.png") },
Icon32 = { Extension.Contents("SpeckleLogo32.png"), Extension.Contents("SpeckleLogo40.png"), Extension.Contents("SpeckleLogo48.png"), Extension.Contents("SpeckleLogo64.png") }
];
GetObjFromStream.Type = type function (
server as (Text.Type meta [
Documentation.FieldCaption = "Speckle Server",
Documentation.FieldDescription = "The Speckle Server to fetch data from",
Documentation.SampleValues = {"https://speckle.xyz"}
]),
streamId as (Text.Type meta [
Documentation.FieldCaption = "Stream ID",
Documentation.FieldDescription = "The unique ID of the Stream to fetch data from.",
Documentation.SampleValues = {"8325294b8f"}
]))
as table meta [
Documentation.Name = "Speckle - Get stream objects",
Documentation.LongDescription = "Returns a table of objects contained in the Stream's main branch latest commit.",
Documentation.Examples = {[
Description = "Returns all objects in the latest commit of stream https://speckle.xyz",
Code = "Speckle.GetObjectFromStream(""https://speckle.xyz"", ""8325294b8f"")"
]}
];
// copy and pasted function from microsoft docs since it's not included yet in M standard lib
Table.ToNavigationTable = (
table as table,
keyColumns as list,
nameColumn as text,
dataColumn as text,
itemKindColumn as text,
itemNameColumn as text,
isLeafColumn as text
) as table =>
GetObjFromStream.Impl = (server as text, streamId as text) as table => Speckle.GetObjectFromBranch(server, streamId, "main");
Speckle.GetObjectFromBranch = Value.ReplaceType(GetObjFromBranch.Impl, GetObjFromBranch.Type);
GetObjFromBranch.Publish = GetPublish("GetObjFromBranch");
GetObjFromBranch.Type = type function (
server as (Text.Type meta [
Documentation.FieldCaption = "Speckle Server",
Documentation.FieldDescription = "The Speckle Server to fetch data from",
Documentation.SampleValues = {"https://speckle.xyz"}
]),
streamId as (Text.Type meta [
Documentation.FieldCaption = "Stream ID",
Documentation.FieldDescription = "The unique ID of the Stream to fetch data from.",
Documentation.SampleValues = {"8325294b8f"}
]),
branchName as (Text.Type meta [
Documentation.FieldCaption = "Branch name",
Documentation.FieldDescription = "The name of the branch inside that stream.",
Documentation.SampleValues = {"main", "some other branch", "branch/with/emoji🚀"}
]))
as table meta [
Documentation.Name = "Speckle - Get stream branch objects",
Documentation.LongDescription = "Returns a table of objects contained in the Stream's specified branch latest commit.",
Documentation.Examples = {[
Description = "Returns all objects in the latest commit of the specified branch in stream https://speckle.xyz",
Code = "Speckle.GetObjectFromStream(""https://speckle.xyz"", ""8325294b8f"")"
]}
];
GetObjFromBranch.Impl = (server as text, streamId as text, branchName as text) as table =>
let
tableType = Value.Type(table),
newTableType = Type.AddTableKey(tableType, keyColumns, true) meta
[
NavigationTable.NameColumn = nameColumn,
NavigationTable.DataColumn = dataColumn,
NavigationTable.ItemKindColumn = itemKindColumn,
Preview.DelayColumn = itemNameColumn,
NavigationTable.IsLeafColumn = isLeafColumn
],
navigationTable = Value.ReplaceType(table, newTableType)
decodedBranchName = Record.Field(Record.Field(Uri.Parts("http://www.dummy.com?A=" & branchName),"Query"),"A"), // Hacky way to decode base64 strings: Put them in a url query param and parse the URL
apiKey = try Extension.CurrentCredential()[Key] otherwise null,
query = "query($streamId: String!, $branchName: String!) {
stream( id: $streamId ) {
branch (name: $branchName ){
commits (limit: 1) {
items {
id
referencedObject
}
}
}
}
}",
res = Speckle.Api.Fetch(server, query, [streamId=streamId, branchName=decodedBranchName]),
branch=res[stream][branch],
commit = branch[commits][items]{0},
objectsTable = Speckle.Api.GetAllObjectChildren(server, streamId, commit[referencedObject]),
rr = Speckle.CommitReceived( server, streamId, commit[id] )
in
navigationTable;
if branch = null then error Text.Format("The branch '#{0}' does not exist in stream '#{1}'",{decodedBranchName, streamId})
else
// Force evaluation of read receipt (ideally it should happen after fetching, but can't find a way)
if rr then objectsTable else objectsTable;
Speckle.GetObjectFromCommit = Value.ReplaceType(GetObjFromCommit.Impl, GetObjFromCommit.Type);
GetObjFromCommit.Publish = GetPublish("GetObjFromCommit");
GetObjFromCommit.Type = type function (
server as (Text.Type meta [
Documentation.FieldCaption = "Speckle Server",
Documentation.FieldDescription = "The Speckle Server to fetch data from",
Documentation.SampleValues = {"https://speckle.xyz"}
]),
streamId as (Text.Type meta [
Documentation.FieldCaption = "Stream ID",
Documentation.FieldDescription = "The unique ID of the Stream to fetch data from.",
Documentation.SampleValues = {"8325294b8f"}
]),
commitId as (Text.Type meta [
Documentation.FieldCaption = "Commit ID",
Documentation.FieldDescription = "The unique ID of the commit to fetch.",
Documentation.SampleValues = {"main", "some other branch", "branch/with/emoji🚀"}
]))
as table meta [
Documentation.Name = "Speckle - Get stream commit objects",
Documentation.LongDescription = "Returns a table of objects contained in the Stream's specified commit.",
Documentation.Examples = {[
Description = "Returns all objects in the specified commit in stream https://speckle.xyz",
Code = "Speckle.GetObjectFromCommit(""https://speckle.xyz"", ""8325294b8f"", ""asdfw456a"")"
]}
];
GetObjFromCommit.Impl = (server as text, streamId as text, commitId as text) as table =>
let
apiKey = try Extension.CurrentCredential()[Key] otherwise null,
query = "query($streamId: String!, $commitId: String!) {
stream( id: $streamId ) {
commit (id: $commitId) {
referencedObject
}
}
}",
variables = [streamId=streamId, commitId=commitId],
#"JSON" = Speckle.Api.Fetch(server, query, variables),
commit = #"JSON"[stream][commit],
objectsTable = Speckle.Api.GetAllObjectChildren(server, streamId, commit[referencedObject]),
rr = Speckle.CommitReceived(server, streamId, commitId)
in
if commit = null then error "The commit did not exist on this stream"
else
if rr then objectsTable else objectsTable;
Speckle.GetObjectFromObject = (server as text, streamId as text, objectId as text, optional limit as number, optional cursor as text) =>
Speckle.Api.GetAllObjectChildren(server, streamId, objectId, cursor);
Speckle.CleanUpObjects = (objects as list) as list =>
let
// remove closures from records, and remove DataChunk records
removeClosureField = List.Transform(objects, each [data=Record.RemoveFields(_[data],"__closure", MissingField.Ignore)]),
removeTotals = List.Transform(removeClosureField, each [data=try Record.RemoveFields(_[data], "totalChildrenCount", MissingField.Ignore) otherwise _[data]]),
removeDatachunkRecords = List.RemoveItems(removeTotals, List.FindText(removeTotals, "Speckle.Core.Models.DataChunk"))
in
removeDatachunkRecords;
Speckle.Api.Fetch = (server as text, query as text, optional variables as record) as record =>
let
apiKey = try Extension.CurrentCredential()[Key] otherwise null,
Source = Web.Contents(
Text.Combine({server, "graphql"}, "/"),
[
Headers=[
#"Method"="POST",
#"Content-Type"="application/json",
#"Authorization"= if apiKey = null then "" else Text.Format("Bearer #{0}",{apiKey})
],
ManualStatusHandling = {400},
Content=Json.FromValue([query=Text.From(query),variables=variables])
]),
#"JSON" = Json.Document(Source)
in
// Check if response contains errors, if so, return first error.
if Record.HasFields(#"JSON", {"errors"})
then error #"JSON"[errors]{0}[message]
else #"JSON"[data];
// Read all pages of data.
// After every page, we check the "nextCursor" record on the metadata of the previous request.
// Table.GenerateByPage will keep asking for more pages until we return null.
Speckle.Api.GetAllObjectChildren = (server as text, streamId as text, objectId as text, optional cursor as text) as table =>
Table.GenerateByPage((previous) =>
let
// if previous is null, then this is our first page of data
nextCursor = if (previous = null) then cursor else Value.Metadata(previous)[Cursor]?,
// if the cursor is null but the prevous page is not, we've reached the end
page = if (previous <> null and nextCursor = null) then null else Speckle.Api.GetObjectChildren(server, streamId, objectId, 50, nextCursor)
in
page
) meta [server=server, streamId=streamId, objectId=objectId];
Speckle.Api.GetObjectChildren = (server as text, streamId as text, objectId as text, optional limit as number, optional cursor as text) =>
let
query = "query($streamId: String!, $objectId: String!, $limit: Int, $cursor: String) {
stream( id: $streamId ) {
object (id: $objectId) {
children(limit: $limit, cursor: $cursor) {
cursor
objects {
data
}
}
}
}
}",
#"JSON" = Speckle.Api.Fetch(server, query, [streamId=streamId, objectId=objectId, limit=limit, cursor=cursor]),
children = #"JSON"[stream][object][children],
nextCursor=children[cursor],
clean=Speckle.CleanUpObjects(children[objects])
in
Table.FromRecords(clean) meta [Cursor=nextCursor];
Speckle.CommitReceived = (server, streamId, commitId) =>
let
query = "mutation($input: CommitReceivedInput!) {
commitReceive(input: $input)
}",
variables = [
input = [
streamId=streamId,
commitId=commitId,
sourceApplication="PowerBI"
]
]
in
// Read receipts should fail gracefully no matter what
try Speckle.Api.Fetch(server, query, variables)[commitReceive] otherwise false;
/* Since everything is lazily evaluated, we must join and split the result of the matomo call with the server, and spit back the server url for PowerBI to actually log the calls to Matomo */
Speckle.LogToMatomo = (server) =>
let
matomoUrl = "https://speckle.matomo.cloud/matomo.php",
action = "receive/manual",
appName = "Power BI",
userId = "powerBIuser",
params = [
idsite = "2",
rec = "1",
apiv = "1",
uid = userId,
action_name = action,
url = Text.Combine({"http://connectors/PowerBI/", action}),
urlref = Text.Combine({"http://connectors/PowerBI/", action}),
_cvar = Text.FromBinary(Json.FromValue([hostApplication = appName]))
],
visitQuery = Uri.BuildQueryString(params),
visitRes = Web.Contents(Text.Combine({matomoUrl, "?", visitQuery}),
[
Headers=[
#"Method"="POST"
],
Content=Text.ToBinary(server)
]),
eventParams = [
idsite = "2",
rec = "1",
apiv = "1",
uid = userId,
_cvar = Text.FromBinary(Json.FromValue([hostApplication = appName])),
e_c = appName,
e_a = action
],
eventQuery = Uri.BuildQueryString(eventParams),
eventRes = Web.Contents(Text.Combine({ matomoUrl, "?", eventQuery}),
[
Headers=[
#"Method"="POST"
],
Content=Text.ToBinary(server)
]),
Result = Text.FromBinary(visitRes) & Text.FromBinary(eventRes),
Combined = Text.Combine({server,Result},"___"),
Split = Text.Split(Combined,"___"){0}
in
Split;
// The getNextPage function takes a single argument and is expected to return a nullable table
Table.GenerateByPage = (getNextPage as function) as table =>
let
listOfPages = List.Generate(
() => getNextPage(null), // get the first page of data
(lastPage) => lastPage <> null, // stop when the function returns null
(lastPage) => getNextPage(lastPage) // pass the previous page to the next function call
),
// concatenate the pages together
tableOfPages = Table.FromList(listOfPages, Splitter.SplitByNothing(), {"Column1"}),
firstRow = tableOfPages{0}?
in
// if we didn't get back any pages of data, return an empty table
// otherwise set the table type based on the columns of the first page
if (firstRow = null) then
Table.FromRows({})
else
Value.ReplaceType(
Table.ExpandTableColumn(tableOfPages, "Column1", Table.ColumnNames(firstRow[Column1])),
Value.Type(firstRow[Column1])
);
+2 -2
View File
@@ -1,5 +1,5 @@
// Use this file to write queries to test your data connector
let
result = Speckle.Contents("https://speckle.xyz/streams/5dfbeb49c9/objects/ed4748572b27cfe008f2592a44ab85f1")
result = Speckle.GetByUrl("https://speckle.xyz/streams/6ead215ec5/branches/main"){0}
in
result
result[data]

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Before

Width:  |  Height:  |  Size: 2.3 KiB

After

Width:  |  Height:  |  Size: 2.3 KiB

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

+31 -4
View File
@@ -117,13 +117,40 @@
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ButtonHelp" xml:space="preserve">
<value>Connect to Speckle</value>
<data name="GetByUrl.Help" xml:space="preserve">
<value>Connect to Speckle by Stream URL</value>
</data>
<data name="ButtonTitle" xml:space="preserve">
<data name="GetByUrl.Label" xml:space="preserve">
<value>Speckle</value>
</data>
<data name="DataSourceLabel" xml:space="preserve">
<data name="GetByUrl.Title" xml:space="preserve">
<value>Speckle - Get stream by URL</value>
</data>
<data name="GetObjFromBranch.Help" xml:space="preserve">
<value>Connect to Speckle by serer URL, stream ID and branch name</value>
</data>
<data name="GetObjFromBranch.Label" xml:space="preserve">
<value>Get the latest commit from a stream's branch</value>
</data>
<data name="GetObjFromBranch.Title" xml:space="preserve">
<value>Speckle - Get Stream branch</value>
</data>
<data name="GetObjFromCommit.Help" xml:space="preserve">
<value>Connect to Speckle by server URL, stream ID and commit ID</value>
</data>
<data name="GetObjFromCommit.Label" xml:space="preserve">
<value>A label</value>
</data>
<data name="GetObjFromCommit.Title" xml:space="preserve">
<value>Speckle - Get Stream commit</value>
</data>
<data name="GetStream.Help" xml:space="preserve">
<value>Connect to Speckle by server URL and stream ID</value>
</data>
<data name="GetStream.Label" xml:space="preserve">
<value>Speckle</value>
</data>
<data name="GetStream.Title" xml:space="preserve">
<value>Speckle - Get Stream</value>
</data>
</root>