Compare commits
29 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 15ac7c041e | |||
| 770d45f981 | |||
| 50b59a88c3 | |||
| 0bad9914c8 | |||
| aee00f3f21 | |||
| 2abdd4b645 | |||
| 71ef1acd8b | |||
| 23114a2912 | |||
| ee989f927d | |||
| 1ff15c7b44 | |||
| 6e9fb590a0 | |||
| 9700865934 | |||
| cf9e5a70b6 | |||
| 50c360ae79 | |||
| b671945fa7 | |||
| eb4787ddfa | |||
| 3ffd6c63e0 | |||
| a5a8316ee0 | |||
| 17083c9474 | |||
| 3e6f9988d6 | |||
| fe1504d1a9 | |||
| c753e13859 | |||
| fc2ffa75ba | |||
| de43e34c11 | |||
| 70eb1059d2 | |||
| 9e5c204c8f | |||
| e0f2782c8b | |||
| baf2132d1b | |||
| eef502f42f |
@@ -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 }}
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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])
|
||||
);
|
||||
|
||||
|
||||
@@ -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 |
@@ -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>
|
||||