Compare commits

...

6 Commits

Author SHA1 Message Date
Alan Rynne 85b9e88fc1 Merge pull request #65 from specklesystems/dev
Update `dev` with changes from `main`
2024-03-14 11:40:48 +01:00
Alan Rynne 92fc894d4b fix: Throw error when multi-model URL is input (#64) 2024-02-26 18:21:23 +01:00
Alan Rynne b033cfa82b CNX-9076: first round of new web app terminology rename (#63)
* fix: first round of new web app terminology rename

* fix: Last refs to commit/branch/stream gone

* fix: Table headers

* ci: Removed unnecessary step and bumped ci ghr image

* Modified publicly visible names on resource file
2024-02-26 17:03:20 +01:00
KatKatKateryna 86cba3ce2b Update README.md (#62)
Updated install instructions as here: https://learn.microsoft.com/en-gb/power-bi/connect-data/desktop-connector-extensibility#certified-connectors
2024-02-26 10:44:10 +01:00
Alan Rynne c752487f9f fix: CNX-7606 Fixes missing Data column error (#61)
* fix: Result will now include parent commit object and no longer assume it will have children

* fix: Keep metadata in joined table
2024-01-12 13:29:42 +01:00
Alan Rynne 95f51b0d32 fix(CNX-8322): Separated completely frontend2 parsing (#59)
* fix: Separated completely frontend2 parsing

This prevents logic from Fe2 leaking into Fe1 and viceversa, which could cause `null` exceptions in some cases.

* CNX-8322 Track in Jira
2023-11-30 10:26:53 +01:00
8 changed files with 208 additions and 169 deletions
+14 -14
View File
@@ -20,18 +20,18 @@ jobs:
- run:
name: "Build Data Connector"
command: "msbuild Speckle.proj /restore /consoleloggerparameters:NoSummary /property:GenerateFullPaths=true"
- run:
name: Create Innosetup signing cert
command: |
echo $env:PFX_B64 > "tools\AEC Systems Ltd.txt"
certutil -decode "tools\AEC Systems Ltd.txt" "tools\AEC Systems Ltd.pfx"
- run:
name: Create Signed PFX file
command: .\tools\MakePQX\MakePQX.exe pack -mz bin/Speckle.mez -t bin/Speckle.pqx -c "tools\AEC Systems Ltd.pfx" -p $env:PFX_PSW
- run:
name: Build Installer
command: tools\InnoSetup\ISCC.exe tools\powerbi.iss /Sbyparam=$p
shell: cmd.exe #does not work in powershell
# - run:
# name: Create Innosetup signing cert
# command: |
# echo $env:PFX_B64 > "tools\AEC Systems Ltd.txt"
# certutil -decode "tools\AEC Systems Ltd.txt" "tools\AEC Systems Ltd.pfx"
# - run:
# name: Create Signed PFX file
# command: .\tools\MakePQX\MakePQX.exe pack -mz bin/Speckle.mez -t bin/Speckle.pqx -c "tools\AEC Systems Ltd.pfx" -p $env:PFX_PSW
# - run:
# name: Build Installer
# command: tools\InnoSetup\ISCC.exe tools\powerbi.iss /Sbyparam=$p
# shell: cmd.exe #does not work in powershell
- store_artifacts:
path: ./bin
- persist_to_workspace:
@@ -40,14 +40,14 @@ jobs:
- bin/*
deploy-connector:
docker:
- image: cibuilds/github:0.10
- image: cibuilds/github:0.13
steps:
- attach_workspace:
at: ./
- run:
name: "Publish Release on GitHub"
command: |
ghr -t ${GH_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${CIRCLE_TAG} ./bin/
ghr -t ${GH_TOKEN} -u ${CIRCLE_PROJECT_USERNAME} -r ${CIRCLE_PROJECT_REPONAME} -c ${CIRCLE_SHA1} ${CIRCLE_TAG} ./bin/Speckle.mez
workflows:
build:
jobs:
+1
View File
@@ -54,6 +54,7 @@ Go to the [Releases](https://github.com/specklesystems/speckle-powerbi/releases)
```
YOUR_USER_FOLDER\Documents\Power BI Desktop\Custom Connectors\
```
If the folder doesn't exist, create it.
### Allow custom extensions to run
+16 -24
View File
@@ -11,7 +11,7 @@ Speckle = [
// This is the custom authentication strategy for our Connector
Authentication = [
OAuth = [
Label = "Speckle.xyz",
Label = "Speckle Account",
StartLogin = (clientApplication, dataSourcePath, state, display) =>
let
server = Text.Combine(
@@ -86,10 +86,10 @@ Speckle = [
],
Key = [
KeyLabel = "Personal Access Token",
Label = "Private stream"
Label = "Private Project"
],
Implicit = [
Label = "Public stream"
Label = "Public Project"
]
],
Label = "Speckle"
@@ -103,20 +103,16 @@ shared Speckle.GetByUrl.Structured = Value.ReplaceType(
url as (
Uri.Type meta [
Documentation.FieldCaption = "Gets a Speckle Object preserving it's structure",
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"
}
Documentation.FieldDescription = "The url of a model in a Speckle server project. You can copy it directly from your browser.",
Documentation.SampleValues = {"https://app.speckle.systems/projects/23401adf/models/1234568"}
]
)
) as record meta [
Documentation.Name = "Speckle - Get Structured Object by URL",
Documentation.LongDescription = "Returns the Speckle object the URL points to, while also preserving it's structure.
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')
Supports all types of model url:#(lf)
- Model: will get the latest version of the specified model (i.e. 'https://app.speckle.systems/projects/PROJECT_ID/models/MODEL_ID')#(lf)
- Version: will get a specific version from the project (i.e. 'https://app.speckle.systems/projects/PROJECT_ID/models/MODEL_ID@VERSION_ID')
"
]
);
@@ -132,21 +128,17 @@ shared Speckle.GetByUrl = Value.ReplaceType(
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"
}
Documentation.FieldCaption = "Model URL",
Documentation.FieldDescription = "The url of a model in a Speckle server. You can copy it directly from your browser.",
Documentation.SampleValues = {"https://app.speckle.systems/projects/23401adf/models/1234568"}
]
)
) 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.Name = "Speckle - Get Model by URL",
Documentation.LongDescription = "Returns a flat list of all objects contained in a Speckle model/version of a specific a project.
Supports all types of model url:#(lf)
- Model: will get the latest version of the specified model (i.e. 'https://app.speckle.systems/projects/PROJECT_ID/models/MODEL_ID')#(lf)
- Version: will get a specific version from the project (i.e. 'https://app.speckle.systems/projects/PROJECT_ID/models/MODEL_ID@VERSION_ID')
"
]
);
+86 -81
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
<!--
Microsoft ResX Schema
Version 2.0
@@ -22,8 +22,10 @@
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing"
mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework
object]</value>
<comment>This is a comment</comment>
</data>
@@ -59,116 +61,119 @@
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace"/>
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0"/>
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string"/>
<xsd:attribute name="type" type="xsd:string"/>
<xsd:attribute name="mimetype" type="xsd:string"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string"/>
<xsd:attribute name="name" type="xsd:string"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1"/>
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3"/>
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4"/>
<xsd:attribute ref="xml:space"/>
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1"/>
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required"/>
</xsd:complexType>
</xsd:element>
</xsd:choice>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="GetByUrl.Help" xml:space="preserve">
<value>Connect to Speckle by Stream URL</value>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="GetByUrl.Help" xml:space="preserve">
<value>Connect to Speckle by Model URL</value>
</data>
<data name="GetByUrl.Label" xml:space="preserve">
<data name="GetByUrl.Label" xml:space="preserve">
<value>Speckle</value>
</data>
<data name="GetByUrl.Title" xml:space="preserve">
<value>Speckle - Get stream by URL</value>
<data name="GetByUrl.Title" xml:space="preserve">
<value>Speckle - Get Model 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 name="GetObjFromBranch.Help" xml:space="preserve">
<value>Connect to Speckle by server URL, stream ID and branch name</value>
</data>
<data name="GetObjFromBranch.Label" xml:space="preserve">
<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">
<data name="GetObjFromBranch.Title" xml:space="preserve">
<value>Speckle - Get Stream branch</value>
</data>
<data name="GetObjFromCommit.Help" xml:space="preserve">
<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">
<data name="GetObjFromCommit.Label" xml:space="preserve">
<value>A label</value>
</data>
<data name="GetObjFromCommit.Title" xml:space="preserve">
<data name="GetObjFromCommit.Title" xml:space="preserve">
<value>Speckle - Get Stream commit</value>
</data>
<data name="GetStream.Help" xml:space="preserve">
<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">
<data name="GetStream.Label" xml:space="preserve">
<value>Speckle</value>
</data>
<data name="GetStream.Title" xml:space="preserve">
<value>Speckle - Get Stream by URL [Structured]</value>
<data name="GetStream.Title" xml:space="preserve">
<value>Speckle - Get Model by URL [Structured]</value>
</data>
<data name="GetObjectAsNavTable.Title" xml:space="preserve">
<data name="GetObjectAsNavTable.Title" xml:space="preserve">
<value>Speckle - Get Object as NavTable</value>
</data>
<data name="GetObjectAsNavTable.Label" xml:space="preserve">
<data name="GetObjectAsNavTable.Label" xml:space="preserve">
<value>Speckle</value>
</data>
<data name="GetObjectAsNavTable.Help" xml:space="preserve">
<data name="GetObjectAsNavTable.Help" xml:space="preserve">
<value>Returns a navigation table for a given object</value>
</data>
<data name="Traverse.Title" xml:space="preserve">
<data name="Traverse.Title" xml:space="preserve">
<value>Traverse an object and populate refs</value>
</data>
<data name="Traverse.Label" xml:space="preserve">
<data name="Traverse.Label" xml:space="preserve">
<value>Traverse</value>
</data>
<data name="Traverse.Help" xml:space="preserve">
<data name="Traverse.Help" xml:space="preserve">
<value>Traverse help</value>
</data>
</root>
+5 -5
View File
@@ -1,5 +1,6 @@
let
Fetch = Extension.LoadFunction("Api.Fetch.pqm"),
GetObject = Extension.LoadFunction("Api.GetObject.pqm"),
GetAllObjectChildren = Extension.LoadFunction("Api.GetAllObjectChildren.pqm"),
GetObjectFromCommit = Extension.LoadFunction("GetObjectFromCommit.pqm"),
GetObjectFromBranch = Extension.LoadFunction("GetObjectFromBranch.pqm"),
@@ -34,10 +35,9 @@ in
GetObjectFromBranch(server, id, stream[branch])
else
GetObjectFromBranch(server, id, "main"),
removeEmpty = Table.RemoveLastN(commitObjectsTable, 1),
addStreamUrl = Table.AddColumn(removeEmpty, "Stream URL", each server & "/streams/" & id),
addStreamUrl = Table.AddColumn(commitObjectsTable, "Model URL", each server & "/streams/" & id),
addParentObjectId = Table.AddColumn(
addStreamUrl, "Commit Object ID", each Value.Metadata(commitObjectsTable)[objectId]
addStreamUrl, "Version Object ID", each Value.Metadata(commitObjectsTable)[objectId]
),
addUrlType = Table.AddColumn(addParentObjectId, "URL Type", each stream[urlType]),
addObjectIdCol = Table.AddColumn(addUrlType, "Object ID", each try[data][id] otherwise null),
@@ -46,9 +46,9 @@ in
),
final = Table.ReorderColumns(
addSpeckleTypeCol, {
"Stream URL",
"Model URL",
"URL Type",
"Commit Object ID",
"Version Object ID",
"Object ID",
"speckle_type",
"data"
+25 -14
View File
@@ -1,6 +1,7 @@
let
Table.GenerateByPage = Extension.LoadFunction("Table.GenerateByPage.pqm"),
Speckle.Api.GetObjectChildren = Extension.LoadFunction("Api.GetObjectChildren.pqm"),
Speckle.Api.GetObject = Extension.LoadFunction("Api.GetObject.pqm"),
Extension.LoadFunction = (fileName as text) =>
let
binary = Extension.Contents(fileName), asText = Text.FromBinary(binary)
@@ -19,17 +20,27 @@ in
// 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.
(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, 1000, nextCursor)
in
page
) meta [server = server, streamId = streamId, objectId = objectId]
let
parentObject = Speckle.Api.GetObject(server, streamId, objectId),
childrenTable = 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, 1000, nextCursor)
in
page
),
parentTable = Table.FromRecords({[data = parentObject]}),
resultTable =
if (Table.ColumnCount(childrenTable) = 0) then
parentTable
else
Table.Combine({parentTable, childrenTable})
in
resultTable meta [server = server, streamId = streamId, objectId = objectId]
+1 -1
View File
@@ -14,4 +14,4 @@
),
removed = List.Select(removeTotals, each _[data][speckle_type] <> "Speckle.Core.Models.DataChunk")
in
removed
try removed otherwise objects
+60 -30
View File
@@ -12,40 +12,70 @@ let
Message.Format = "Loading '#{0}' failed - '#{1}': '#{2}'",
Message.Parameters = {fileName, e[Reason], e[Message]},
Detail = [File = fileName, Error = e]
]
],
IsFe2Url = (segments as list) as logical => List.Count(segments) = 4 and segments{2} = "models",
GetUrlType = (branchName as nullable text, commitId as nullable text, objectId as nullable text) as text =>
if (commitId <> null) then
"Commit"
else if (objectId <> null) then
"Object"
else if (branchName <> null) then
"Branch"
else
"Stream",
ParseFe1Url = (server as text, segments as list) as record =>
let
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,
urlType = GetUrlType(branchName, commitId, objectId)
in
[
urlType = urlType,
server = server as text,
id = streamId as nullable text,
branch = branchName as nullable text,
commit = commitId as nullable text,
object = objectId as nullable text
],
ParseFe2Url = (server as text, segments as list) as record =>
let
streamId = segments{1},
modelList = segments{3},
isMultimodel = Text.Contains(modelList, ","),
firstModel = Text.Split(modelList, ","){0},
modelAndVersion = Text.Split(firstModel, "@"),
modelId = modelAndVersion{0},
versionId = if (List.Count(modelAndVersion) > 1) then modelAndVersion{1} else null,
model = if (modelId <> null) then GetModel(server, streamId, modelId) else null,
urlType = GetUrlType(model[name], versionId, null)
in
if isMultimodel then
error
Error.Record(
"NotSupported",
"Multi-model URLs are not supported.",
"Try to select just one single model in the web app and paste that in."
)
else
[
urlType = urlType,
server = server,
id = streamId,
branch = model[name],
commit = versionId,
object = null
]
in
(url as text) as record =>
let
// Get server and streamId, and branchName / commitId / objectid from the input url
server = Text.Combine({Uri.Parts(url)[Scheme], "://", Uri.Parts(url)[Host]}),
segments = Text.Split(Text.AfterDelimiter(Uri.Parts(url)[Path], "/", 0), "/"),
streamId = segments{1},
modelList = if (List.Count(segments) = 4 and segments{2} = "models") then segments{3} else null,
firstModel = Text.Split(modelList, ","){0},
modelAndVersion = Text.Split(firstModel, "@"),
modelId = modelAndVersion{0},
versionId = if (List.Count(modelAndVersion) > 1) then modelAndVersion{1} else null,
model = if (modelId <> null) then GetModel(server, streamId, modelId) else null,
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,
modelOrBranchName = if (model <> null) then model[name] else branchName,
commitOrVersion = if (versionId <> null) then versionId else commitId,
urlType =
if (commitOrVersion <> null) then
"Commit"
else if (objectId <> null) then
"Object"
else if (modelOrBranchName <> null) then
"Branch"
else
"Stream"
isFe2 = IsFe2Url(segments)
in
[
urlType = urlType,
server = server,
id = streamId,
branch = modelOrBranchName,
commit = commitOrVersion,
object = objectId
]
if (isFe2) then
ParseFe2Url(server, segments)
else
ParseFe1Url(server, segments)