Compare commits

..

1 Commits

Author SHA1 Message Date
msftbot[bot]
60af36b736 Add .github/fabricbot.json 2022-06-27 20:49:42 +00:00
120 changed files with 1185 additions and 3018 deletions

30
.github/fabricbot.json vendored Normal file
View File

@@ -0,0 +1,30 @@
{
"version": "1.0",
"tasks": [
{
"taskType": "trigger",
"capabilityId": "AutoMerge",
"subCapability": "AutoMerge",
"version": "1.0",
"id": "LUEPwPETV",
"config": {
"taskName": "Auto Merge",
"label": "automerge",
"minMinutesOpen": "5",
"mergeType": "squash",
"deleteBranches": true,
"requireAllStatuses": true,
"requireSpecificCheckRuns": false,
"usePrDescriptionAsCommitMessage": true,
"requireAllStatuses_exemptList": [
"Azure Pipelines",
"Dependabot",
"GitHub Pages",
"Check Enforcer"
],
"silentMode": true
}
}
],
"userGroups": []
}

View File

@@ -182,7 +182,7 @@ jobs:
with: with:
name: dist name: dist
- run: cp ./configs/prod.json config.json - run: cp ./configs/prod.json config.json
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "vimeng@microsoft.com" -Password "$AZURE_DEVOPS_PAT" - run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}" - run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
- run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg - run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2
@@ -207,7 +207,7 @@ jobs:
name: dist name: dist
- run: cp ./configs/mpac.json config.json - run: cp ./configs/mpac.json config.json
- run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.MPAC/g' DataExplorer.nuspec - run: sed -i 's/Azure.Cosmos.DB.Data.Explorer/Azure.Cosmos.DB.Data.Explorer.MPAC/g' DataExplorer.nuspec
- run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "vimeng@microsoft.com" -Password "$AZURE_DEVOPS_PAT" - run: nuget sources add -Name "ADO" -Source "$NUGET_SOURCE" -UserName "GitHub" -Password "$AZURE_DEVOPS_PAT"
- run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}" - run: nuget pack -Version "2.0.0-github-${GITHUB_SHA}"
- run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg - run: nuget push -SkipDuplicate -Source "$NUGET_SOURCE" -ApiKey Az *.nupkg
- uses: actions/upload-artifact@v2 - uses: actions/upload-artifact@v2

View File

@@ -1,6 +1,5 @@
<!doctype html> <!doctype html>
<html class="default no-js"> <html class="default no-js">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
@@ -10,292 +9,256 @@
<link rel="stylesheet" href="../assets/css/main.css"> <link rel="stylesheet" href="../assets/css/main.css">
<script async src="../assets/js/search.js" id="search-script"></script> <script async src="../assets/js/search.js" id="search-script"></script>
</head> </head>
<body> <body>
<header> <header>
<div class="tsd-page-toolbar"> <div class="tsd-page-toolbar">
<div class="container"> <div class="container">
<div class="table-wrap"> <div class="table-wrap">
<div class="table-cell" id="tsd-search" data-index="../assets/js/search.json" data-base=".."> <div class="table-cell" id="tsd-search" data-index="../assets/js/search.json" data-base="..">
<div class="field"> <div class="field">
<label for="tsd-search-field" class="tsd-widget search no-caption">Search</label> <label for="tsd-search-field" class="tsd-widget search no-caption">Search</label>
<input id="tsd-search-field" type="text" /> <input id="tsd-search-field" type="text" />
</div>
<ul class="results">
<li class="state loading">Preparing search index...</li>
<li class="state failure">The search index is not available</li>
</ul>
<a href="../index.html" class="title">cosmos-explorer</a>
</div> </div>
<div class="table-cell" id="tsd-widgets"> <ul class="results">
<div id="tsd-filter"> <li class="state loading">Preparing search index...</li>
<a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a> <li class="state failure">The search index is not available</li>
<div class="tsd-filter-group"> </ul>
<div class="tsd-select" id="tsd-filter-visibility"> <a href="../index.html" class="title">cosmos-explorer</a>
<span class="tsd-select-label">All</span> </div>
<ul class="tsd-select-list"> <div class="table-cell" id="tsd-widgets">
<li data-value="public">Public</li> <div id="tsd-filter">
<li data-value="protected">Public/Protected</li> <a href="#" class="tsd-widget options no-caption" data-toggle="options">Options</a>
<li data-value="private" class="selected">All</li> <div class="tsd-filter-group">
</ul> <div class="tsd-select" id="tsd-filter-visibility">
</div> <span class="tsd-select-label">All</span>
<input type="checkbox" id="tsd-filter-inherited" checked /> <ul class="tsd-select-list">
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label> <li data-value="public">Public</li>
<input type="checkbox" id="tsd-filter-externals" checked /> <li data-value="protected">Public/Protected</li>
<label class="tsd-widget" for="tsd-filter-externals">Externals</label> <li data-value="private" class="selected">All</li>
</ul>
</div> </div>
<input type="checkbox" id="tsd-filter-inherited" checked />
<label class="tsd-widget" for="tsd-filter-inherited">Inherited</label>
<input type="checkbox" id="tsd-filter-externals" checked />
<label class="tsd-widget" for="tsd-filter-externals">Externals</label>
</div> </div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div> </div>
<a href="#" class="tsd-widget menu no-caption" data-toggle="menu">Menu</a>
</div> </div>
</div> </div>
</div> </div>
<div class="tsd-page-title"> </div>
<div class="container"> <div class="tsd-page-title">
<ul class="tsd-breadcrumb"> <div class="container">
<li> <ul class="tsd-breadcrumb">
<a href="../modules.html">cosmos-explorer</a> <li>
</li> <a href="../modules.html">cosmos-explorer</a>
<li> </li>
<a href="../modules/selfserve_selfserveutils.html">SelfServe/SelfServeUtils</a> <li>
</li> <a href="../modules/selfserve_selfserveutils.html">SelfServe/SelfServeUtils</a>
<li> </li>
<a href="selfserve_selfserveutils.bladetype.html">BladeType</a> <li>
</li> <a href="selfserve_selfserveutils.bladetype.html">BladeType</a>
</ul> </li>
<h1>Enumeration BladeType</h1> </ul>
</div> <h1>Enumeration BladeType</h1>
</div> </div>
</header> </div>
<div class="container container-main"> </header>
<div class="row"> <div class="container container-main">
<div class="col-8 col-content"> <div class="row">
<section class="tsd-panel tsd-comment"> <div class="col-8 col-content">
<section class="tsd-panel tsd-comment">
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Portal Blade types</p>
</div>
</div>
</section>
<section class="tsd-panel-group tsd-index-group">
<h2>Index</h2>
<section class="tsd-panel tsd-index-panel">
<div class="tsd-index-content">
<section class="tsd-index-section ">
<h3>Enumeration members</h3>
<ul class="tsd-index-list">
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="selfserve_selfserveutils.bladetype.html#cassandrakeys" class="tsd-kind-icon">Cassandra<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="selfserve_selfserveutils.bladetype.html#gremlinkeys" class="tsd-kind-icon">Gremlin<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="selfserve_selfserveutils.bladetype.html#metrics" class="tsd-kind-icon">Metrics</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="selfserve_selfserveutils.bladetype.html#mongokeys" class="tsd-kind-icon">Mongo<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="selfserve_selfserveutils.bladetype.html#sqlkeys" class="tsd-kind-icon">Sql<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a href="selfserve_selfserveutils.bladetype.html#tablekeys" class="tsd-kind-icon">Table<wbr>Keys</a></li>
</ul>
</section>
</div>
</section>
</section>
<section class="tsd-panel-group tsd-member-group ">
<h2>Enumeration members</h2>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<a name="cassandrakeys" class="tsd-anchor"></a>
<h3>Cassandra<wbr>Keys</h3>
<div class="tsd-signature tsd-kind-icon">Cassandra<wbr>Keys<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = &quot;cassandraDbKeys&quot;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography"> <div class="tsd-comment tsd-typography">
<div class="lead"> <div class="lead">
<p>Portal Blade types</p> <p>Keys blade of a Cassandra API account.</p>
</div> </div>
</div> </div>
</section> </section>
<section class="tsd-panel-group tsd-index-group"> <section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<h2>Index</h2> <a name="gremlinkeys" class="tsd-anchor"></a>
<section class="tsd-panel tsd-index-panel"> <h3>Gremlin<wbr>Keys</h3>
<div class="tsd-index-content"> <div class="tsd-signature tsd-kind-icon">Gremlin<wbr>Keys<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = &quot;keys&quot;</span></div>
<section class="tsd-index-section "> <aside class="tsd-sources">
<h3>Enumeration members</h3> </aside>
<ul class="tsd-index-list"> <div class="tsd-comment tsd-typography">
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a <div class="lead">
href="selfserve_selfserveutils.bladetype.html#cassandrakeys" <p>Keys blade of a Gremlin API account.</p>
class="tsd-kind-icon">Cassandra<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a
href="selfserve_selfserveutils.bladetype.html#gremlinkeys"
class="tsd-kind-icon">Gremlin<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a
href="selfserve_selfserveutils.bladetype.html#metrics"
class="tsd-kind-icon">Metrics</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a
href="selfserve_selfserveutils.bladetype.html#mongokeys"
class="tsd-kind-icon">Mongo<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a
href="selfserve_selfserveutils.bladetype.html#sqlkeys"
class="tsd-kind-icon">Sql<wbr>Keys</a></li>
<li class="tsd-kind-enum-member tsd-parent-kind-enum"><a
href="selfserve_selfserveutils.bladetype.html#tablekeys"
class="tsd-kind-icon">Table<wbr>Keys</a></li>
</ul>
</section>
</div> </div>
</section> </div>
</section> </section>
<section class="tsd-panel-group tsd-member-group "> <section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<h2>Enumeration members</h2> <a name="metrics" class="tsd-anchor"></a>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum"> <h3>Metrics</h3>
<a name="cassandrakeys" class="tsd-anchor"></a> <div class="tsd-signature tsd-kind-icon">Metrics<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = &quot;metrics&quot;</span></div>
<h3>Cassandra<wbr>Keys</h3> <aside class="tsd-sources">
<div class="tsd-signature tsd-kind-icon">Cassandra<wbr>Keys<span </aside>
class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = <div class="tsd-comment tsd-typography">
&quot;cassandraDbKeys&quot;</span></div> <div class="lead">
<aside class="tsd-sources"> <p>Metrics blade of an Azure Cosmos DB account.</p>
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Keys blade of a Azure Cosmos DB for Apache Cassandra account.</p>
</div>
</div> </div>
</section> </div>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<a name="gremlinkeys" class="tsd-anchor"></a>
<h3>Gremlin<wbr>Keys</h3>
<div class="tsd-signature tsd-kind-icon">Gremlin<wbr>Keys<span
class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> =
&quot;keys&quot;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Keys blade of a Azure Cosmos DB for Apache Gremlin account.</p>
</div>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<a name="metrics" class="tsd-anchor"></a>
<h3>Metrics</h3>
<div class="tsd-signature tsd-kind-icon">Metrics<span class="tsd-signature-symbol">:</span>
<span class="tsd-signature-symbol"> = &quot;metrics&quot;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Metrics blade of an Azure Cosmos DB account.</p>
</div>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<a name="mongokeys" class="tsd-anchor"></a>
<h3>Mongo<wbr>Keys</h3>
<div class="tsd-signature tsd-kind-icon">Mongo<wbr>Keys<span
class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> =
&quot;mongoDbKeys&quot;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Keys blade of a Azure Cosmos DB for MongoDB account.</p>
</div>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<a name="sqlkeys" class="tsd-anchor"></a>
<h3>Sql<wbr>Keys</h3>
<div class="tsd-signature tsd-kind-icon">Sql<wbr>Keys<span class="tsd-signature-symbol">:</span>
<span class="tsd-signature-symbol"> = &quot;keys&quot;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Keys blade of a Azure Cosmos DB for NoSQL account.</p>
</div>
</div>
</section>
<section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<a name="tablekeys" class="tsd-anchor"></a>
<h3>Table<wbr>Keys</h3>
<div class="tsd-signature tsd-kind-icon">Table<wbr>Keys<span
class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> =
&quot;tableKeys&quot;</span></div>
<aside class="tsd-sources">
</aside>
<div class="tsd-comment tsd-typography">
<div class="lead">
<p>Keys blade of a Azure Cosmos DB for Table account.</p>
</div>
</div>
</section>
</section> </section>
</div> <section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<div class="col-4 col-menu menu-sticky-wrap menu-highlight"> <a name="mongokeys" class="tsd-anchor"></a>
<nav class="tsd-navigation primary"> <h3>Mongo<wbr>Keys</h3>
<ul> <div class="tsd-signature tsd-kind-icon">Mongo<wbr>Keys<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = &quot;mongoDbKeys&quot;</span></div>
<li class=" "> <aside class="tsd-sources">
<a href="../modules.html">Modules</a> </aside>
</li> <div class="tsd-comment tsd-typography">
<li class=" tsd-kind-module"> <div class="lead">
<a href="../modules/selfserve.html">Self<wbr>Serve</a> <p>Keys blade of a Mongo API account.</p>
</li> </div>
<li class=" tsd-kind-module"> </div>
<a href="../modules/selfserve___what_is_currently_supported_.html">Self<wbr>Serve -<wbr> </section>
<wbr>What is currently supported?</a> <section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
</li> <a name="sqlkeys" class="tsd-anchor"></a>
<li class=" tsd-kind-module"> <h3>Sql<wbr>Keys</h3>
<a href="../modules/selfserve_decorators.html">Self<wbr>Serve/<wbr>Decorators</a> <div class="tsd-signature tsd-kind-icon">Sql<wbr>Keys<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = &quot;keys&quot;</span></div>
</li> <aside class="tsd-sources">
<li class=" tsd-kind-module"> </aside>
<a <div class="tsd-comment tsd-typography">
href="../modules/selfserve_selfservetelemetryprocessor.html">Self<wbr>Serve/<wbr>Self<wbr>Serve<wbr>Telemetry<wbr>Processor</a> <div class="lead">
</li> <p>Keys blade of a SQL API account.</p>
<li class=" tsd-kind-module"> </div>
<a </div>
href="../modules/selfserve_selfservetypes.html">Self<wbr>Serve/<wbr>Self<wbr>Serve<wbr>Types</a> </section>
</li> <section class="tsd-panel tsd-member tsd-kind-enum-member tsd-parent-kind-enum">
<li class="current tsd-kind-module"> <a name="tablekeys" class="tsd-anchor"></a>
<a <h3>Table<wbr>Keys</h3>
href="../modules/selfserve_selfserveutils.html">Self<wbr>Serve/<wbr>Self<wbr>Serve<wbr>Utils</a> <div class="tsd-signature tsd-kind-icon">Table<wbr>Keys<span class="tsd-signature-symbol">:</span> <span class="tsd-signature-symbol"> = &quot;tableKeys&quot;</span></div>
</li> <aside class="tsd-sources">
</ul> </aside>
</nav> <div class="tsd-comment tsd-typography">
<nav class="tsd-navigation secondary menu-sticky"> <div class="lead">
<ul class="before-current"> <p>Keys blade of a Table API account.</p>
</ul> </div>
<ul class="current"> </div>
<li class="current tsd-kind-enum tsd-parent-kind-module"> </section>
<a href="selfserve_selfserveutils.bladetype.html" class="tsd-kind-icon">Blade<wbr>Type</a> </section>
<ul> </div>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum"> <div class="col-4 col-menu menu-sticky-wrap menu-highlight">
<a href="selfserve_selfserveutils.bladetype.html#cassandrakeys" <nav class="tsd-navigation primary">
class="tsd-kind-icon">Cassandra<wbr>Keys</a> <ul>
</li> <li class=" ">
<li class=" tsd-kind-enum-member tsd-parent-kind-enum"> <a href="../modules.html">Modules</a>
<a href="selfserve_selfserveutils.bladetype.html#gremlinkeys" </li>
class="tsd-kind-icon">Gremlin<wbr>Keys</a> <li class=" tsd-kind-module">
</li> <a href="../modules/selfserve.html">Self<wbr>Serve</a>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum"> </li>
<a href="selfserve_selfserveutils.bladetype.html#metrics" <li class=" tsd-kind-module">
class="tsd-kind-icon">Metrics</a> <a href="../modules/selfserve___what_is_currently_supported_.html">Self<wbr>Serve -<wbr> <wbr>What is currently supported?</a>
</li> </li>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum"> <li class=" tsd-kind-module">
<a href="selfserve_selfserveutils.bladetype.html#mongokeys" <a href="../modules/selfserve_decorators.html">Self<wbr>Serve/<wbr>Decorators</a>
class="tsd-kind-icon">Mongo<wbr>Keys</a> </li>
</li> <li class=" tsd-kind-module">
<li class=" tsd-kind-enum-member tsd-parent-kind-enum"> <a href="../modules/selfserve_selfservetelemetryprocessor.html">Self<wbr>Serve/<wbr>Self<wbr>Serve<wbr>Telemetry<wbr>Processor</a>
<a href="selfserve_selfserveutils.bladetype.html#sqlkeys" </li>
class="tsd-kind-icon">Sql<wbr>Keys</a> <li class=" tsd-kind-module">
</li> <a href="../modules/selfserve_selfservetypes.html">Self<wbr>Serve/<wbr>Self<wbr>Serve<wbr>Types</a>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum"> </li>
<a href="selfserve_selfserveutils.bladetype.html#tablekeys" <li class="current tsd-kind-module">
class="tsd-kind-icon">Table<wbr>Keys</a> <a href="../modules/selfserve_selfserveutils.html">Self<wbr>Serve/<wbr>Self<wbr>Serve<wbr>Utils</a>
</li> </li>
</ul> </ul>
</li> </nav>
</ul> <nav class="tsd-navigation secondary menu-sticky">
<ul class="after-current"> <ul class="before-current">
<li class=" tsd-kind-enum tsd-parent-kind-module"> </ul>
<a href="selfserve_selfserveutils.selfservetype.html" <ul class="current">
class="tsd-kind-icon">Self<wbr>Serve<wbr>Type</a> <li class="current tsd-kind-enum tsd-parent-kind-module">
</li> <a href="selfserve_selfserveutils.bladetype.html" class="tsd-kind-icon">Blade<wbr>Type</a>
<li class=" tsd-kind-function tsd-parent-kind-module"> <ul>
<a href="../modules/selfserve_selfserveutils.html#generatebladelink" <li class=" tsd-kind-enum-member tsd-parent-kind-enum">
class="tsd-kind-icon">generate<wbr>Blade<wbr>Link</a> <a href="selfserve_selfserveutils.bladetype.html#cassandrakeys" class="tsd-kind-icon">Cassandra<wbr>Keys</a>
</li> </li>
</ul> <li class=" tsd-kind-enum-member tsd-parent-kind-enum">
</nav> <a href="selfserve_selfserveutils.bladetype.html#gremlinkeys" class="tsd-kind-icon">Gremlin<wbr>Keys</a>
</div> </li>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
<a href="selfserve_selfserveutils.bladetype.html#metrics" class="tsd-kind-icon">Metrics</a>
</li>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
<a href="selfserve_selfserveutils.bladetype.html#mongokeys" class="tsd-kind-icon">Mongo<wbr>Keys</a>
</li>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
<a href="selfserve_selfserveutils.bladetype.html#sqlkeys" class="tsd-kind-icon">Sql<wbr>Keys</a>
</li>
<li class=" tsd-kind-enum-member tsd-parent-kind-enum">
<a href="selfserve_selfserveutils.bladetype.html#tablekeys" class="tsd-kind-icon">Table<wbr>Keys</a>
</li>
</ul>
</li>
</ul>
<ul class="after-current">
<li class=" tsd-kind-enum tsd-parent-kind-module">
<a href="selfserve_selfserveutils.selfservetype.html" class="tsd-kind-icon">Self<wbr>Serve<wbr>Type</a>
</li>
<li class=" tsd-kind-function tsd-parent-kind-module">
<a href="../modules/selfserve_selfserveutils.html#generatebladelink" class="tsd-kind-icon">generate<wbr>Blade<wbr>Link</a>
</li>
</ul>
</nav>
</div> </div>
</div> </div>
<footer class="with-border-bottom"> </div>
<div class="container"> <footer class="with-border-bottom">
<h2>Legend</h2> <div class="container">
<div class="tsd-legend-group"> <h2>Legend</h2>
<ul class="tsd-legend"> <div class="tsd-legend-group">
<li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li> <ul class="tsd-legend">
<li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li> <li class="tsd-kind-function"><span class="tsd-kind-icon">Function</span></li>
</ul> <li class="tsd-kind-type-alias"><span class="tsd-kind-icon">Type alias</span></li>
<ul class="tsd-legend"> </ul>
<li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li> <ul class="tsd-legend">
</ul> <li class="tsd-kind-enum"><span class="tsd-kind-icon">Enumeration</span></li>
<ul class="tsd-legend"> </ul>
<li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li> <ul class="tsd-legend">
</ul> <li class="tsd-kind-interface"><span class="tsd-kind-icon">Interface</span></li>
<ul class="tsd-legend"> </ul>
<li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li> <ul class="tsd-legend">
</ul> <li class="tsd-kind-class"><span class="tsd-kind-icon">Class</span></li>
</div> </ul>
</div> </div>
</footer>
<div class="container tsd-generator">
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
</div> </div>
<div class="overlay"></div> </footer>
<script src="../assets/js/main.js"></script> <div class="container tsd-generator">
<p>Generated using <a href="https://typedoc.org/" target="_blank">TypeDoc</a></p>
</div>
<div class="overlay"></div>
<script src="../assets/js/main.js"></script>
</body> </body>
</html> </html>

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="8" fill="#0078D4"/>
<path d="M9.18652 4.8418V12H7.64844V6.58008C7.5638 6.65495 7.46289 6.72656 7.3457 6.79492C7.23177 6.86003 7.1097 6.92025 6.97949 6.97559C6.84928 7.02767 6.71419 7.07324 6.57422 7.1123C6.43424 7.14811 6.2959 7.17415 6.15918 7.19043V5.8916C6.55957 5.77441 6.93717 5.62467 7.29199 5.44238C7.64681 5.26009 7.96745 5.0599 8.25391 4.8418H9.18652Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 505 B

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" stroke="#949494"/>
<path d="M7.21875 10.7207H10.1875V12H5.5293V11.4727C5.5293 11.1146 5.58952 10.7939 5.70996 10.5107C5.8304 10.2243 5.98177 9.96875 6.16406 9.74414C6.34635 9.51628 6.54492 9.31608 6.75977 9.14355C6.97786 8.96777 7.18457 8.8099 7.37988 8.66992C7.58496 8.52344 7.764 8.38346 7.91699 8.25C8.07324 8.11654 8.20345 7.9847 8.30762 7.85449C8.41504 7.72103 8.49479 7.58757 8.54688 7.4541C8.59896 7.31738 8.625 7.17253 8.625 7.01953C8.625 6.72005 8.54036 6.49382 8.37109 6.34082C8.20182 6.18783 7.94303 6.11133 7.59473 6.11133C6.99251 6.11133 6.41634 6.35059 5.86621 6.8291V5.47168C6.47493 5.0778 7.16178 4.88086 7.92676 4.88086C8.28158 4.88086 8.59896 4.92806 8.87891 5.02246C9.16211 5.11361 9.40137 5.24544 9.59668 5.41797C9.79199 5.59049 9.9401 5.80046 10.041 6.04785C10.1452 6.29199 10.1973 6.56543 10.1973 6.86816C10.1973 7.19043 10.1468 7.47689 10.0459 7.72754C9.94824 7.97819 9.81641 8.20605 9.65039 8.41113C9.48763 8.61621 9.29883 8.80501 9.08398 8.97754C8.86914 9.14681 8.64616 9.3112 8.41504 9.4707C8.25879 9.58138 8.10742 9.69206 7.96094 9.80273C7.81771 9.91016 7.69076 10.0176 7.58008 10.125C7.4694 10.2292 7.38151 10.3317 7.31641 10.4326C7.2513 10.5335 7.21875 10.6296 7.21875 10.7207Z" fill="#949494"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="8" fill="#0078D4"/>
<path d="M7.21875 10.7207H10.1875V12H5.5293V11.4727C5.5293 11.1146 5.58952 10.7939 5.70996 10.5107C5.8304 10.2243 5.98177 9.96875 6.16406 9.74414C6.34635 9.51628 6.54492 9.31608 6.75977 9.14355C6.97786 8.96777 7.18457 8.8099 7.37988 8.66992C7.58496 8.52344 7.764 8.38346 7.91699 8.25C8.07324 8.11654 8.20345 7.9847 8.30762 7.85449C8.41504 7.72103 8.49479 7.58757 8.54688 7.4541C8.59896 7.31738 8.625 7.17253 8.625 7.01953C8.625 6.72005 8.54036 6.49382 8.37109 6.34082C8.20182 6.18783 7.94303 6.11133 7.59473 6.11133C6.99251 6.11133 6.41634 6.35059 5.86621 6.8291V5.47168C6.47493 5.0778 7.16178 4.88086 7.92676 4.88086C8.28158 4.88086 8.59896 4.92806 8.87891 5.02246C9.16211 5.11361 9.40137 5.24544 9.59668 5.41797C9.79199 5.59049 9.9401 5.80046 10.041 6.04785C10.1452 6.29199 10.1973 6.56543 10.1973 6.86816C10.1973 7.19043 10.1468 7.47689 10.0459 7.72754C9.94824 7.97819 9.81641 8.20605 9.65039 8.41113C9.48763 8.61621 9.29883 8.80501 9.08398 8.97754C8.86914 9.14681 8.64616 9.3112 8.41504 9.4707C8.25879 9.58138 8.10742 9.69206 7.96094 9.80273C7.81771 9.91016 7.69076 10.0176 7.58008 10.125C7.4694 10.2292 7.38151 10.3317 7.31641 10.4326C7.2513 10.5335 7.21875 10.6296 7.21875 10.7207Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" stroke="#949494"/>
<path d="M5.69531 11.7705V10.4277C6.16406 10.7695 6.71094 10.9404 7.33594 10.9404C7.72982 10.9404 8.03581 10.8558 8.25391 10.6865C8.47526 10.5173 8.58594 10.2812 8.58594 9.97852C8.58594 9.66602 8.44922 9.42513 8.17578 9.25586C7.9056 9.08659 7.53288 9.00195 7.05762 9.00195H6.4082V7.82031H7.00879C7.92025 7.82031 8.37598 7.51758 8.37598 6.91211C8.37598 6.34245 8.02604 6.05762 7.32617 6.05762C6.85742 6.05762 6.40169 6.20898 5.95898 6.51172V5.25195C6.45052 5.00456 7.02344 4.88086 7.67773 4.88086C8.39388 4.88086 8.95052 5.04199 9.34766 5.36426C9.74805 5.68652 9.94824 6.10482 9.94824 6.61914C9.94824 7.53385 9.48438 8.10677 8.55664 8.33789V8.3623C9.05143 8.42415 9.44206 8.60482 9.72852 8.9043C10.015 9.20052 10.1582 9.5651 10.1582 9.99805C10.1582 10.6523 9.91895 11.1699 9.44043 11.5508C8.96191 11.9316 8.30111 12.1221 7.45801 12.1221C6.73535 12.1221 6.14779 12.0049 5.69531 11.7705Z" fill="#949494"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="8" fill="#0078D4"/>
<path d="M5.69531 11.7705V10.4277C6.16406 10.7695 6.71094 10.9404 7.33594 10.9404C7.72982 10.9404 8.03581 10.8558 8.25391 10.6865C8.47526 10.5173 8.58594 10.2812 8.58594 9.97852C8.58594 9.66602 8.44922 9.42513 8.17578 9.25586C7.9056 9.08659 7.53288 9.00195 7.05762 9.00195H6.4082V7.82031H7.00879C7.92025 7.82031 8.37598 7.51758 8.37598 6.91211C8.37598 6.34245 8.02604 6.05762 7.32617 6.05762C6.85742 6.05762 6.40169 6.20898 5.95898 6.51172V5.25195C6.45052 5.00456 7.02344 4.88086 7.67773 4.88086C8.39388 4.88086 8.95052 5.04199 9.34766 5.36426C9.74805 5.68652 9.94824 6.10482 9.94824 6.61914C9.94824 7.53385 9.48438 8.10677 8.55664 8.33789V8.3623C9.05143 8.42415 9.44206 8.60482 9.72852 8.9043C10.015 9.20052 10.1582 9.5651 10.1582 9.99805C10.1582 10.6523 9.91895 11.1699 9.44043 11.5508C8.96191 11.9316 8.30111 12.1221 7.45801 12.1221C6.73535 12.1221 6.14779 12.0049 5.69531 11.7705Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" stroke="#949494"/>
<path d="M9.77246 4.99805V9.41211H10.6123V10.5645H9.77246V12H8.36621V10.5645H5.31445V9.3584C5.58464 9.05566 5.86458 8.72526 6.1543 8.36719C6.44401 8.00586 6.72396 7.63477 6.99414 7.25391C7.26432 6.87305 7.51497 6.49056 7.74609 6.10645C7.98047 5.71908 8.17904 5.34961 8.3418 4.99805H9.77246ZM6.69629 9.41211H8.36621V6.96582C8.25228 7.17741 8.12858 7.39225 7.99512 7.61035C7.86165 7.8252 7.72168 8.03841 7.5752 8.25C7.42871 8.45833 7.2806 8.66178 7.13086 8.86035C6.98112 9.05566 6.83626 9.23958 6.69629 9.41211Z" fill="#949494"/>
</svg>

Before

Width:  |  Height:  |  Size: 680 B

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="8" fill="#0078D4"/>
<path d="M9.77246 4.99805V9.41211H10.6123V10.5645H9.77246V12H8.36621V10.5645H5.31445V9.3584C5.58464 9.05566 5.86458 8.72526 6.1543 8.36719C6.44401 8.00586 6.72396 7.63477 6.99414 7.25391C7.26432 6.87305 7.51497 6.49056 7.74609 6.10645C7.98047 5.71908 8.17904 5.34961 8.3418 4.99805H9.77246ZM6.69629 9.41211H8.36621V6.96582C8.25228 7.17741 8.12858 7.39225 7.99512 7.61035C7.86165 7.8252 7.72168 8.03841 7.5752 8.25C7.42871 8.45833 7.2806 8.66178 7.13086 8.86035C6.98112 9.05566 6.83626 9.23958 6.69629 9.41211Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 674 B

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="7.5" stroke="#949494"/>
<path d="M5.81738 11.8193V10.501C6.2959 10.7939 6.80534 10.9404 7.3457 10.9404C7.7526 10.9404 8.06999 10.8444 8.29785 10.6523C8.52897 10.457 8.64453 10.1934 8.64453 9.86133C8.64453 9.16797 8.15462 8.82129 7.1748 8.82129C6.81348 8.82129 6.39681 8.84896 5.9248 8.9043L6.18848 4.99805H9.89453V6.25781H7.36523L7.26758 7.65918C7.51823 7.63965 7.7347 7.62988 7.91699 7.62988C8.63639 7.62988 9.19954 7.81868 9.60645 8.19629C10.0133 8.57389 10.2168 9.08171 10.2168 9.71973C10.2168 10.4261 9.97428 11.0039 9.48926 11.4531C9.00423 11.8991 8.34668 12.1221 7.5166 12.1221C6.84277 12.1221 6.27637 12.0212 5.81738 11.8193Z" fill="#949494"/>
</svg>

Before

Width:  |  Height:  |  Size: 779 B

View File

@@ -1,4 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<circle cx="8" cy="8" r="8" fill="#0078D4"/>
<path d="M5.81738 11.8193V10.501C6.2959 10.7939 6.80534 10.9404 7.3457 10.9404C7.7526 10.9404 8.06999 10.8444 8.29785 10.6523C8.52897 10.457 8.64453 10.1934 8.64453 9.86133C8.64453 9.16797 8.15462 8.82129 7.1748 8.82129C6.81348 8.82129 6.39681 8.84896 5.9248 8.9043L6.18848 4.99805H9.89453V6.25781H7.36523L7.26758 7.65918C7.51823 7.63965 7.7347 7.62988 7.91699 7.62988C8.63639 7.62988 9.19954 7.81868 9.60645 8.19629C10.0133 8.57389 10.2168 9.08171 10.2168 9.71973C10.2168 10.4261 9.97428 11.0039 9.48926 11.4531C9.00423 11.8991 8.34668 12.1221 7.5166 12.1221C6.84277 12.1221 6.27637 12.0212 5.81738 11.8193Z" fill="white"/>
</svg>

Before

Width:  |  Height:  |  Size: 773 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.9 10.4C2.86142 9.92426 2.92976 9.44591 3.1 9C3.2722 8.57315 3.54698 8.19534 3.9 7.9L5.6 6.1L10.6 11.1L8.8 12.8C8.50466 13.153 8.12685 13.4278 7.7 13.6C7.29358 13.7932 6.84997 13.8955 6.4 13.9L5.2 13.7L4.3 13.2L1.7 15.7L1 15L3.5 12.4C3.29618 12.1222 3.12819 11.8198 3 11.5C2.92162 11.1388 2.88804 10.7694 2.9 10.4ZM6.4 12.9L7.3 12.7C7.60584 12.5584 7.87842 12.354 8.1 12.1L9.2 11.1L5.6 7.5L4.6 8.6L4 9.4C3.9125 9.72567 3.87872 10.0634 3.9 10.4C3.88428 10.7034 3.91806 11.0074 4 11.3L4.6 12.1L5.4 12.7L6.4 12.9ZM13.2 4.3C13.4038 4.5778 13.5718 4.88018 13.7 5.2C13.8153 5.59037 13.8824 5.99335 13.9 6.4C13.8955 6.84997 13.7932 7.29358 13.6 7.7C13.4278 8.12685 13.153 8.50466 12.8 8.8L11.1 10.6L6.1 5.6L7.9 3.9C8.19534 3.54698 8.57315 3.2722 9 3.1C9.44591 2.92976 9.92426 2.86142 10.4 2.9H11.5L12.4 3.4L15 1L15.7 1.7L13.2 4.3ZM12.1 8.1C12.354 7.87842 12.5584 7.60584 12.7 7.3C12.8142 7.01258 12.8818 6.70875 12.9 6.4C12.8909 6.0577 12.8232 5.71948 12.7 5.4L12.1 4.6L11.3 4.1C11.0284 3.9405 10.7136 3.87053 10.4 3.9H9.4L8.6 4.5L7.5 5.5L11.1 9.1L12.1 8.1Z" fill="#0078D4"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,15 +0,0 @@
<svg width="34" height="34" viewBox="0 0 34 34" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M0.944458 10.9331H33.0556V28.836C33.0556 29.1205 32.9425 29.3934 32.7413 29.5946C32.5401 29.7958 32.2672 29.9089 31.9827 29.9089H2.01735C1.7328 29.9089 1.45991 29.7958 1.2587 29.5946C1.05749 29.3934 0.944458 29.1205 0.944458 28.836V10.9331Z" fill="url(#paint0_linear_1497_136679)"/>
<path d="M2.02301 4.09132H31.977C32.1179 4.09132 32.2574 4.11907 32.3876 4.17299C32.5178 4.22691 32.636 4.30594 32.7357 4.40557C32.8353 4.50519 32.9143 4.62347 32.9682 4.75364C33.0222 4.8838 33.0499 5.02332 33.0499 5.16421V10.9329H0.944458V5.16421C0.944456 5.02284 0.972394 4.88286 1.02667 4.75232C1.08094 4.62178 1.16047 4.50326 1.2607 4.40356C1.36093 4.30385 1.47987 4.22494 1.6107 4.17136C1.74152 4.11778 1.88164 4.09058 2.02301 4.09132Z" fill="#0078D4"/>
<path d="M5.33553 15.0706L6.03309 14.371C6.09216 14.3118 6.17235 14.2785 6.25601 14.2783C6.33967 14.2782 6.41995 14.3113 6.47919 14.3704L11.6394 19.5161C11.6982 19.5747 11.7449 19.6444 11.7769 19.7211C11.8088 19.7979 11.8252 19.8801 11.8254 19.9632C11.8255 20.0463 11.8092 20.1286 11.7775 20.2055C11.7458 20.2823 11.6993 20.3521 11.6407 20.4109L10.9444 21.1091L5.3375 15.518C5.27826 15.4589 5.24491 15.3788 5.24479 15.2951C5.24467 15.2114 5.27779 15.1312 5.33687 15.0719L5.33553 15.0706Z" fill="#F2F2F2"/>
<path d="M6.1367 25.5068L5.43717 24.8092C5.37793 24.7501 5.34459 24.67 5.34447 24.5863C5.34435 24.5026 5.37747 24.4224 5.43654 24.3631L10.9463 18.8378L11.6445 19.534C11.7633 19.6525 11.8302 19.8133 11.8305 19.9812C11.8307 20.149 11.7643 20.31 11.6457 20.4289L6.57747 25.5115C6.5184 25.5707 6.43821 25.6041 6.35455 25.6042C6.27089 25.6043 6.19061 25.5712 6.13137 25.5121L6.1367 25.5068Z" fill="#E6E6E6"/>
<path d="M22.1019 23.8755H14.1893C13.8857 23.8755 13.6396 24.1216 13.6396 24.4252V25.2355C13.6396 25.5391 13.8857 25.7852 14.1893 25.7852H22.1019C22.4054 25.7852 22.6515 25.5391 22.6515 25.2355V24.4252C22.6515 24.1216 22.4054 23.8755 22.1019 23.8755Z" fill="#F2F2F2"/>
<defs>
<linearGradient id="paint0_linear_1497_136679" x1="17" y1="29.9089" x2="17" y2="10.9331" gradientUnits="userSpaceOnUse">
<stop stop-color="#32BEDD"/>
<stop offset="0.175" stop-color="#32CAEA"/>
<stop offset="0.41" stop-color="#32D2F2"/>
<stop offset="0.775" stop-color="#32D4F5"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -1,127 +0,0 @@
<svg width="68" height="72" viewBox="0 0 68 72" fill="none" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<circle cx="34" cy="35" r="32" fill="#BFBFBF"/>
<g style="mix-blend-mode:multiply" filter="url(#filter0_ddd_1497_137613)">
<path d="M18 21.3999C18 19.1908 19.7909 17.3999 22 17.3999H43.6L50 23.7999V48.5999C50 50.809 48.2091 52.5999 46 52.5999H22C19.7909 52.5999 18 50.809 18 48.5999V21.3999Z" fill="white"/>
</g>
<g filter="url(#filter1_b_1497_137613)">
<path d="M18 21.3999C18 19.1908 19.7909 17.3999 22 17.3999H43.6L50 23.7999V48.5999C50 50.809 48.2091 52.5999 46 52.5999H22C19.7909 52.5999 18 50.809 18 48.5999V21.3999Z" fill="url(#paint0_linear_1497_137613)"/>
</g>
<g style="mix-blend-mode:hard-light" filter="url(#filter2_ii_1497_137613)">
<path d="M18 21.3999C18 19.1908 19.7909 17.3999 22 17.3999H43.6L50 23.7999V48.5999C50 50.809 48.2091 52.5999 46 52.5999H22C19.7909 52.5999 18 50.809 18 48.5999V21.3999Z" fill="#808080"/>
<path d="M18 21.3999C18 19.1908 19.7909 17.3999 22 17.3999H43.6L50 23.7999V48.5999C50 50.809 48.2091 52.5999 46 52.5999H22C19.7909 52.5999 18 50.809 18 48.5999V21.3999Z" fill="url(#pattern0)" fill-opacity="0.02"/>
</g>
<g style="mix-blend-mode:multiply" filter="url(#filter3_ddd_1497_137613)">
<path d="M43.6006 17.3999L50.0006 23.7999H47.6006C45.3914 23.7999 43.6006 22.009 43.6006 19.7999V17.3999Z" fill="white"/>
</g>
<g filter="url(#filter4_b_1497_137613)">
<path d="M43.6006 17.3999L50.0006 23.7999H47.6006C45.3914 23.7999 43.6006 22.009 43.6006 19.7999V17.3999Z" fill="url(#paint1_linear_1497_137613)"/>
</g>
<g style="mix-blend-mode:hard-light" filter="url(#filter5_ii_1497_137613)">
<path d="M43.6006 17.3999L50.0006 23.7999H47.6006C45.3914 23.7999 43.6006 22.009 43.6006 19.7999V17.3999Z" fill="#808080"/>
<path d="M43.6006 17.3999L50.0006 23.7999H47.6006C45.3914 23.7999 43.6006 22.009 43.6006 19.7999V17.3999Z" fill="url(#pattern1)" fill-opacity="0.02"/>
</g>
<circle cx="33.9994" cy="34.9999" r="9.6" fill="#BFBFBF"/>
<path d="M30.7998 34.9998L33.3598 37.5598L37.8398 32.7598" stroke="white" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M41.6793 34.9998C41.6793 39.2414 38.2409 42.6798 33.9993 42.6798C29.7578 42.6798 26.3193 39.2414 26.3193 34.9998C26.3193 30.7583 29.7578 27.3198 33.9993 27.3198C38.2409 27.3198 41.6793 30.7583 41.6793 34.9998ZM33.9993 42.0398C37.8874 42.0398 41.0393 38.8879 41.0393 34.9998C41.0393 31.1117 37.8874 27.9598 33.9993 27.9598C30.1113 27.9598 26.9593 31.1117 26.9593 34.9998C26.9593 38.8879 30.1113 42.0398 33.9993 42.0398Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M30.3899 22.3199C30.0451 22.3769 29.7748 22.6471 29.7179 22.9919C29.661 22.6471 29.3907 22.3769 29.0459 22.3199C29.3907 22.263 29.661 21.9928 29.7179 21.6479C29.7748 21.9928 30.0451 22.263 30.3899 22.3199Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M29.5508 19.4641C30.2404 19.5779 30.781 20.1185 30.8948 20.8081C31.0086 20.1185 31.5491 19.5779 32.2388 19.4641C31.5491 19.3503 31.0086 18.8098 30.8948 18.1201C30.781 18.8098 30.2404 19.3503 29.5508 19.4641Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M7.20776 22.3199C7.55259 22.3769 7.82285 22.6471 7.87976 22.9919C7.93667 22.6471 8.20693 22.3769 8.55176 22.3199C8.20693 22.263 7.93667 21.9928 7.87976 21.6479C7.82285 21.9928 7.55259 22.263 7.20776 22.3199Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.04688 19.4641C7.35721 19.5779 6.81669 20.1185 6.70287 20.8081C6.58906 20.1185 6.04854 19.5779 5.35887 19.4641C6.04854 19.3503 6.58906 18.8098 6.70287 18.1201C6.81669 18.8098 7.35721 19.3503 8.04688 19.4641Z" fill="white"/>
<defs>
<filter id="filter0_ddd_1497_137613" x="0" y="0.399902" width="68" height="71.2002" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="3"/>
<feGaussianBlur stdDeviation="2.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0.16 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1497_137613"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feGaussianBlur stdDeviation="9"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0.12 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1497_137613" result="effect2_dropShadow_1497_137613"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="6"/>
<feGaussianBlur stdDeviation="5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0.14 0"/>
<feBlend mode="normal" in2="effect2_dropShadow_1497_137613" result="effect3_dropShadow_1497_137613"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect3_dropShadow_1497_137613" result="shape"/>
</filter>
<filter id="filter1_b_1497_137613" x="16" y="15.3999" width="36" height="39.2002" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImage" stdDeviation="1"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_1497_137613"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_1497_137613" result="shape"/>
</filter>
<filter id="filter2_ii_1497_137613" x="18" y="17.3999" width="32" height="35.2002" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1497_137613"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_innerShadow_1497_137613" result="effect2_innerShadow_1497_137613"/>
</filter>
<pattern id="pattern0" patternContentUnits="objectBoundingBox" width="1.875" height="1.70455">
<use xlink:href="#image0_1497_137613" transform="scale(0.03125 0.0284091)"/>
</pattern>
<filter id="filter3_ddd_1497_137613" x="25.6006" y="0.399902" width="42.4004" height="42.3999" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="3"/>
<feGaussianBlur stdDeviation="2.5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0.16 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1497_137613"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feGaussianBlur stdDeviation="9"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0.12 0"/>
<feBlend mode="normal" in2="effect1_dropShadow_1497_137613" result="effect2_dropShadow_1497_137613"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="6"/>
<feGaussianBlur stdDeviation="5"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0 0.25098 0 0 0 0.14 0"/>
<feBlend mode="normal" in2="effect2_dropShadow_1497_137613" result="effect3_dropShadow_1497_137613"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect3_dropShadow_1497_137613" result="shape"/>
</filter>
<filter id="filter4_b_1497_137613" x="41.6006" y="15.3999" width="10.4004" height="10.3999" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feGaussianBlur in="BackgroundImage" stdDeviation="1"/>
<feComposite in2="SourceAlpha" operator="in" result="effect1_backgroundBlur_1497_137613"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_backgroundBlur_1497_137613" result="shape"/>
</filter>
<filter id="filter5_ii_1497_137613" x="43.6006" y="17.3999" width="6.40039" height="6.3999" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dy="1"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 0.5 0"/>
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1497_137613"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset/>
<feGaussianBlur stdDeviation="3"/>
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
<feColorMatrix type="matrix" values="0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 0 0.94902 0 0 0 1 0"/>
<feBlend mode="normal" in2="effect1_innerShadow_1497_137613" result="effect2_innerShadow_1497_137613"/>
</filter>
<pattern id="pattern1" patternContentUnits="objectBoundingBox" width="9.375" height="9.375">
<use xlink:href="#image0_1497_137613" transform="scale(0.15625)"/>
</pattern>
<linearGradient id="paint0_linear_1497_137613" x1="34" y1="52.5999" x2="34" y2="17.3999" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2F2F2" stop-opacity="0.5"/>
<stop offset="1" stop-color="#F2F2F2"/>
</linearGradient>
<linearGradient id="paint1_linear_1497_137613" x1="46.8006" y1="23.7999" x2="46.8006" y2="17.3999" gradientUnits="userSpaceOnUse">
<stop stop-color="#F2F2F2" stop-opacity="0.5"/>
<stop offset="1" stop-color="#F2F2F2"/>
</linearGradient>
<image id="image0_1497_137613" width="60" height="60" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADwAAAA8CAYAAAA6/NlyAAAM9ElEQVRoQ+WbS6iO3RvG1zv/HCcbiRhR2mJESlJbjBwmGwOH0laUHAaEJLXFwCG1FROHgcPEYbRFSaJtRKQYyCltTBxi/v77rc/v+e53efic+fo/k733+z7Peta67+u+7uu+19qNlFKz2Wwmr/fv36e//vorNRqN1NbWll68eJFWrlyZDh06lG/h856enrRq1ap0//79NH78eAbIn3d1deX7+HzcuHH5uSFDhqRdu3alhQsXpkGDBqXDhw/ncXzG927cuDHfV16My707d+5MW7Zsyb9znTx5Mi1atCiPe/r06Wo8xzl48GBavXp1y3Dt7e2pwWp56NSpU3nSXEz8xo0bqbOzM23evDlNnDgxL2Tq1Km1k+3u7k7Lly9PT548SW/evEkPHz7MBtFAdQu8d+9eNsqwYcOyUb2YC9/duXOneteFCxfS3r1708WLFz8a0+eYI89gEO5//fp1unLlSlq3bl3lFNbECrPJuPH58+dpxIgRlRVnzZqVX6K19LjeZIA4MV56/fr1NGDAgDyPjo6O/LyoiBbnfZs2baq8yj19fX1pypQpGRkgQRREBOqciB4dVaKD50Rhb29vdkS1YLyJl7HO4MGD0+XLl7N3gc6RI0eqiTsJ4CECNIgTixPw/hMnTqTFixe3IMTvWKjo0fjRc7t3706zZ8/OhovjAF++8xkd5LOEAWuIKMqQjhN89+5dOn78eMZ/tKyxVOcVJwu0jTPuZyy97SQcUzRhOIwsspxLNKjvNl4/CvQPCPVzx+jv70/Dhw9vCYNGT09Pk/iM+MeaWkUIAV/gFi8GBrY8Sxz698uXL/NnkNvYsWPTnDlzsvEw1s2bN9OBAwfSjBkzEvdJSBDP7du3M19w8TtXJCU9Vs5BD4O0JUuWZNLlAs4gFT7h3aAhQxpPMAm8Ey9wD2yYjGzM9yys9KYLEmJ4yEn7TLzH+OY7Gdh3C1vev2zZsvwxxnFhn+Iax/kc1+QF/2or8z5IZ/To0Wny5MkVAliQ6UYYx3DDyDDvvHnzsievXbuWn/UyhFywiAJtR48e/ZsHOjo6mmPGjKlYkcBnEuREXs53+/fvzy/CyqQMyArvleQUYyjGP+GBxy9dupQhbAqJKOFdkhqxt3Tp0gx7UEdoyCm+M44vWfEew6TUCDq1ysPANl7fwtpYG0P9yazdaGtra0I4JaUbd8ZNhBjW4n48Rkp59OhRTl2ID7xk/kNY4LlJkyZlDnCsFst++IPxZVXfheqD5UuOQRjhfREBhPWsOX/Hjh3p1q1bmf3hAuAMshpdXV1NYgnoMLCyMnpYliXutm/f3pJCmKQpRQka0wKLZTJOKhIPKcN7CZWRI0fmBZaCg3skQaD6+PHjKi8TFuRaWRjCO3/+fItyjA7KkMZbeoeBo3pSUzPpmFejAPF+BUQUIMZsjPlSoGDcuXPn5nDwvihY8CYeYg56TSaPjMwzIMpxTGOm1oxaIU3cQVaICAYDopIMi1aUlyJe65vHhSaeNTfrXYsOoMXCIJlt27alq1evZo/UhZEe5DsLG3OzaUsGVpJqDBELKrhAUKO3t7eJGIg52LSBIGEBwK2MQVHBQMat8GSBa9asqcaMOdkcavEQ41mmLlFmLEeol4a36MCQzI3Uxe979uypNEaultrb23PxwJfKRqSecatVzZHCxXtdJN6bOXNmjnEGJq6ix/gdj1DFYCCIJ5aKpqpoABdYR3LRKHXP+CyG3bdvX34XKM0xzAIV58aXrI3VYWEKCiSaLEjiVyczKESiCHAMIAaBRJXE5Bj72LFj+Z1CG/hj3GfPnuWxuCwzZW0NGHMwnxmjhMi5c+dyWMYFi04MnmNYSieOgTE5mZTiBQxhVLwKgWApjIQ3WZD1rF7XWLEQIMYhp1isx5RXpiyeFQVMHi2P0QkVuCVmB9DBfCLrR/hjCMIshygeVpXwUpnWuDWnxs4GL4OUtCZw9mJQvGbXIzYXuA+CAmJldeQETYexaGBBFC5kEn7yN8al42HBEtWi8tQCyLAk7lsaAN9DDixUIiG+5AVhKHNKiBb4kSPwEuixzuZZ5aIGjfk8xi7jYwAFEQw9bdq0KsXqzJbi4Uf0jEACsBUhpiI8YUcjavA6whGuos1c+yNSZwXpsm78nRUNRmBx9sVMV8Z0LCa4j0ahuiFygWQnpxBm2cNfIypUW8bcv4kK4jl2PCNRxU7ljxAVymLegVGePn2aVVds8LW0eBQIsVBwgU6uLM+IMYp0Cn+L+s/lVJQT+dq2kMwd+1r+zngwMhe/K3+j+lL6RqET05akRjMRovuItMpAjypJQrADSI0aCw7jMXqfOpq45hl+37p1a0ufq+w78Tf3WQkxpjFMakJBlXmdhSAvyRpohvisi1fONvr6+ppQvbm27DQYy7wYZo1dQxaB2ICg4IC6Ij0igglHUVAaKMZfbBZGweF4zENBRNjQf47awWf46TzhgLxgJ+EEzJ0xl5aCwclBGvPnz88vfPXqVe6QELOOESsWPGdBUZaAsSNZVx6a+33euRKrvA+nvX37NlddpCdJr1SROYZLC1owx8/5HQOws/A1iJBRo6W/BxGxHPwWRDQ6OzubeMaghtUspmU7oYq36G4SQxqlbpcA6FL2xfISOFG52EK1X4bxREFdj8wQI+Toczkmc1MolbkctHBNnz49x3VUYRVLl5UJZGWngoeBBpDEILZto4Uj9TMRmvkWG/G+qKycaCwO+MzOSUvh/mFTLcZmWcbyN+Nv2LAh801s8ltdNbq7u5t4jdiQVFRHDG4slOmonAxQw6vuH1nvWgTQRsJQFBEyP0bCqLGJT3HCFcvLWChopG/e5Sy3S7+m5YkUZaEQhdqYCdmWHTp0aO5kfGp30i7nr9ydrCAdC3IW8eDBg5wv3fON8EMEGBdCRZEgOohRvEXJJnKMe4wqm4ucKGwUO3W7FzFemSc9LutquIcGg8qOe4n9s2fP/pMygTS9rP9yjUu4xFqYharWYmcEhZZZOm6GS14xNUWp6HYHrB7jKJZ9piB+ooCsnhAGqrUyLgkD5WHMwyV3MKbziUWEmoH7ESWIEeSuY4FUmhUteVg2jenhd+3UI4YsTGKDXr2u4YR42fZhDeh0LhxaScv+/v4m3YefUXtq3T+pwqo8LDt/yZYjC1iwYEE6c+bMFx9viHu7tn49+CLD1533wDvferzB8tBeeY5ztlp+V7sFlWWeBnolu4K8UkUZbsDVwy8gydZyeX/LcYdG45827Zee6/gv7BCW5zpYNBekWLG0RxrqzlEQ3x5y4UFyLIwH+7rHq6jXwpAEn61fvz5L0oEDB2b1pGwsO6XUudbOP7NTmhsAdvyiTnXikfoVEDAlKooFlydwGAtRYUfDFMGChHCZDWTYsnjwb8VPhG3U/vwuCzM2AmTUqFGV2LAnlp+J57Qc0O5ibNvieSQkXqDqiduacQEMyguoj2NnIhYIHj7hyAIqiIY+hGLlxXimn5hf7a7EZoVHl2JruGxiMJ7FUNXEQ5LZ6I6BXx4g0YJUTbH7EDfUypzIMxhvxYoVLbuEThYDwyE06Lk88KZKgpwwCoxtk93QiOInGj4WL7G533LkAauycz5hwoTKg1iYM5Juf7pgVExdM436k8nTxyIc3IJVKztBJgxSPJjiuwkFDMD35Sm/eEAtanwQw44GIeYxKreP4rZPhjQdj7iJ/L27guXpuF+1K+hxKZzgxh/OscVDSK5du/bvBf/JBbvQjMeZWEhsJrYk63BulMOuHqYDBaCvti8tW8cDYm6nxj5yPJknUaCosLCNANnUOEVdyfagQfaWiHy3pWHcW2IsOcV4jWmQgsH2EqGk17mn2vLhBMDXHu5igK/ZCuF+YyxOtG4rpDzxV9bjEiC9sXgmWiRgEC7LRQmUWCau88E0zyHHDWmMYDzQqfQsZIQPEy4bAHomniLQa/HoBN7lqEXZCCh3DWKOLnNv2QtzbrFvFhsMZKKqeNBysCaTQSXFk3PAxdMAtHacvAornmP2KIMT+JMOuVULLvdpPeMRC3D3kfAMxohNAr3IzygzSWvm0CgIyi5p3PyK7zS2eTfNBOYljyhr4wGZKHvrjlll4VHqYHIg2xj0pNC/ETplH9rOhd60Vfon7lFlp9DT+n84NmwN39LTiv0qvBoLAzwXd+Bl2zqCiN6O8pM9H686eMc+VzyHZQUHlBEP36MEqyMPTORndz3Kfx8w9n7mP3WUXY+PtlpIK7+jyHdLE8N/yz9vxCLffz3yDBhc5GG5iqXVvPG0zZe2Pr/3+DGsj+z7FcePq+KBOtcNKCxTV2zD5ljLPraiwONGQNYyEU/ZuOMnwgUpat/KDkss+n/Ff9RUaclyirxHcX/37t3ctRBeLJZ6lQXZIKh6vR/+oy32gSWzWC19TkXVFQCQFedHovS1Vx1P6cUT+BrwU+dV/gf5nFrpDQ6oIQAAAABJRU5ErkJggg=="/>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

View File

@@ -37,8 +37,8 @@ module.exports = {
global: { global: {
branches: 25, branches: 25,
functions: 25, functions: 25,
lines: 28, lines: 29,
statements: 28, statements: 29,
}, },
}, },

View File

@@ -3,337 +3,337 @@
@import "../Common/Constants"; @import "../Common/Constants";
.query-panel { .query-panel {
display: table; display: table;
display: none; display: none;
width: 100%; width: 100%;
border-top: 1px solid #dddddd; border-top: 1px solid #DDDDDD;
/*[{environment-commandbar-toolbar-separator}]*/ /*[{environment-commandbar-toolbar-separator}]*/
background-color: #ffffff; background-color: #ffffff;
/*[{plugin-background-color}]*/ /*[{plugin-background-color}]*/
padding: 2px 0px 0px 2px; padding: 2px 0px 0px 2px;
resize: vertical; resize: vertical;
} }
.query-panel .row { .query-panel .row {
display: table-row; display: table-row;
} }
.query-panel .row .cell { .query-panel .row .cell {
display: table-cell; display: table-cell;
} }
.query-panel.transition-in { .query-panel.transition-in {
display: table; display: table;
top: 0px; top: 0px;
-webkit-transition: top 2s linear; -webkit-transition: top 2s linear;
-ms-transition: top 2s linear; -ms-transition: top 2s linear;
-moz-transition: top 2s linear; -moz-transition: top 2s linear;
-khtml-transition: top 2s linear; -khtml-transition: top 2s linear;
-o-transition: top 2s linear; -o-transition: top 2s linear;
transition: top 2s linear; transition: top 2s linear;
} }
.query-builder { .query-builder {
width: 100%; width:100%;
padding-right: @DefaultSpace; padding-right: @DefaultSpace;
border-bottom: 1px solid @BaseMedium; border-bottom: 1px solid @BaseMedium;
margin-bottom: @DefaultSpace; margin-bottom: @DefaultSpace;
} }
.query-builder-toolbar { .query-builder-toolbar {
background-color: #ffffff; background-color: #ffffff;
/*[{plugin-background-color}]*/ /*[{plugin-background-color}]*/
min-width: 600px; min-width: 600px;
height: 30px; height: 30px;
border-bottom: 1px solid #dddddd; border-bottom: 1px solid #DDDDDD;
/*[1px solid {environment-commandbar-toolbar-separator}]*/ /*[1px solid {environment-commandbar-toolbar-separator}]*/
} }
.query-builder-toolbar .query-toolbar-group { .query-builder-toolbar .query-toolbar-group {
display: inline-block; display: inline-block;
height: 24px; height: 24px;
margin: 2px 0px; margin: 2px 0px;
vertical-align: middle; vertical-align: middle;
} }
.query-builder-toolbar .query-toolbar-group .query-toolbar-button { .query-builder-toolbar .query-toolbar-group .query-toolbar-button {
min-width: 0px; min-width: 0px;
padding: 0px; padding: 0px;
margin-left: 2px; margin-left: 2px;
background-color: transparent; background-color: transparent;
border: solid transparent; border: solid transparent;
} }
.query-builder-toolbar .query-toolbar-group .query-toolbar-button:active { .query-builder-toolbar .query-toolbar-group .query-toolbar-button:active {
outline: 2px solid dodgerblue; outline: 2px solid dodgerblue;
/*[2px solid {common-common-controls-button-border-hover}]*/ /*[2px solid {common-common-controls-button-border-hover}]*/
} }
.query-builder-toolbar .query-toolbar-group .query-toolbar-button:hover { .query-builder-toolbar .query-toolbar-group .query-toolbar-button:hover {
background-color: #cccedb; background-color: #CCCEDB;
/*[{common-controls-button-hover-background}]*/ /*[{common-controls-button-hover-background}]*/
} }
.query-builder-toolbar .query-toolbar-group .query-toolbar-button.active { .query-builder-toolbar .query-toolbar-group .query-toolbar-button.active {
background-color: #e6e7ed; background-color: #E6E7ED;
/*[{common-controls-inner-tab-active-background}]*/ /*[{common-controls-inner-tab-active-background}]*/
outline: none; outline: none
} }
.query-builder-toolbar .query-toolbar-group .query-toolbar-button:disabled, .query-builder-toolbar .query-toolbar-group .query-toolbar-button:disabled,
.query-builder-toolbar .query-toolbar-group .query-toolbar-button.disabled { .query-builder-toolbar .query-toolbar-group .query-toolbar-button.disabled {
background-color: #ffffff; background-color: #ffffff;
/*[{common-controls-button-disabled-background}]*/ /*[{common-controls-button-disabled-background}]*/
background: transparent; background: transparent;
border: 1px solid transparent; border: 1px solid transparent;
outline: none; outline: none;
opacity: 0.4; opacity: 0.4;
} }
.tableContainer { .tableContainer {
overflow: hidden; overflow: hidden;
.flex-display(); .flex-display();
.flex-direction(); .flex-direction();
} }
.tablesQueryTab { .tablesQueryTab{
padding-left: @MediumSpace; padding-left: @MediumSpace;
width: 100%; width: 100%;
margin-bottom: @LargeSpace; margin-bottom:@LargeSpace;
} }
.entity-error-Img { .entity-error-Img {
width: @WarningErrorIconSize; width: @WarningErrorIconSize;
height: @WarningErrorIconSize; height: @WarningErrorIconSize;
margin: @DefaultSpace 0px 0px @SmallSpace; margin: @DefaultSpace 0px 0px @SmallSpace;
} }
.query-editor-panel { .query-editor-panel {
margin-right: 16px; margin-right: 16px;
margin-left: 16px; margin-left: 16px;
margin-top: 25px; margin-top: 25px;
position: relative; position: relative;
vertical-align: middle; vertical-align: middle;
cursor: default; cursor: default;
} }
.query-editor-text { .query-editor-text {
width: 100%; width: 100%;
margin: 2px; margin: 2px;
border: solid 1px #a9acb3; border: solid 1px #A9ACB3;
/*[{plugin-textbox-disabled-color}]*/ /*[{plugin-textbox-disabled-color}]*/
resize: none; resize: none;
margin-top: -39px; margin-top: -39px;
background-color: #ddd; background-color: #ddd;
padding: 5px; padding: 5px;
} }
.error-bar { .error-bar {
padding: @LargeSpace 34px @MediumSpace 24px; padding: @LargeSpace 34px @MediumSpace 24px;
} }
.error-message { .error-message {
background-color: @BaseLow; background-color: @BaseLow;
padding: @DefaultSpace; padding: @DefaultSpace;
display: inline-flex; display: inline-flex;
} }
.error-text { .error-text {
padding-left: @MediumSpace; padding-left: @MediumSpace;
} }
.query-editor-text-invalid { .query-editor-text-invalid {
width: 100%; width: 100%;
margin: 2px; margin: 2px;
border: 1px solid #e51400; border: 1px solid #e51400;
resize: none; resize: none;
margin-top: -30px; margin-top: -30px;
} }
.query-editor-panel .warning-bar { .query-editor-panel .warning-bar {
width: 100%; width: 100%;
height: 20px; height: 20px;
background-color: #ffffff; background-color: #ffffff;
/*[{plugin-background-color}]*/ /*[{plugin-background-color}]*/
position: absolute; position: absolute;
top: -24px; top: -24px;
} }
.query-editor-panel .warning-bar .warning-message { .query-editor-panel .warning-bar .warning-message {
display: inline-flex; display: inline-flex;
padding-top: 2px; padding-top: 2px;
vertical-align: middle; vertical-align: middle;
} }
.query-editor-panel .warning-bar .warning-message .warning-text { .query-editor-panel .warning-bar .warning-message .warning-text {
margin-left: 2px; margin-left: 2px;
} }
.advanced-options-panel { .advanced-options-panel{
margin-bottom: @DefaultSpace; margin-bottom: @DefaultSpace;
} }
.advanced-options-panel .advanced-heading .advanced-title { .advanced-options-panel .advanced-heading .advanced-title {
display: inline-flex; display: inline-flex;
margin-left: 27px; margin-left: 27px;
margin-top: 10px; margin-top: 10px;
cursor: default; cursor: default;
} }
.advanced-options-panel .advanced-options { .advanced-options-panel .advanced-options {
margin-left: 32px; margin-left: 32px;
margin-top: 5px; margin-top: 5px;
border: 1px solid transparent; border: 1px solid transparent;
} }
hr { hr {
margin-top: 10px; margin-top: 10px;
margin-bottom: 12px; margin-bottom: 12px;
border: 0; border: 0;
border-top: 1px solid #ccc; border-top: 1px solid #ccc;
} }
input::-webkit-outer-spin-button, input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button { input::-webkit-inner-spin-button {
-webkit-appearance: none; -webkit-appearance: none;
} }
.advanced-options-panel .advanced-options .top .top-input { .advanced-options-panel .advanced-options .top .top-input {
width: 100px; width: 100px;
word-spacing: normal; word-spacing: normal;
color: #1e1e1e; color: #1E1E1E;
/*[{common-controls-button-foreground}]*/ /*[{common-controls-button-foreground}]*/
border: 1px solid #cccedb; border: 1px solid #CCCEDB;
/*[1px solid {plugin-textbox-border-color}]*/ /*[1px solid {plugin-textbox-border-color}]*/
height: 20px; height: 20px;
margin-left: 8px; margin-left: 8px;
} }
.advanced-options-panel .advanced-options .top .invalid-top { .advanced-options-panel .advanced-options .top .invalid-top {
color: red; color: red;
} }
.advanced-options-panel .advanced-options .select { .advanced-options-panel .advanced-options .select {
margin-top: 18px; margin-top: 18px;
display: inline-flex; display: inline-flex;
} }
.advanced-options-icon { .advanced-options-icon {
margin-left: 2px; margin-left: 2px;
vertical-align: sub; vertical-align: sub;
} }
.advanced-options-panel .advanced-options .select .select-options-text { .advanced-options-panel .advanced-options .select .select-options-text {
margin-left: 4px; margin-left: 4px;
} }
.advanced-options-panel .advanced-options .select .select-options-link { .advanced-options-panel .advanced-options .select .select-options-link {
margin-left: 4px; margin-left: 4px;
cursor: pointer; cursor: pointer;
outline: none; outline: none;
} }
.query-panel .row .column-headers .Field { .query-panel .row .column-headers .Field {
padding-left: 95px; padding-left: 95px;
padding-right: 0px; padding-right: 0px;
padding-bottom: 6px; padding-bottom: 6px;
} }
.clause-table { .clause-table {
border-spacing: 0px; border-spacing: 0px;
display: table; display: table;
width: 100%; width: 100%;
margin-top: -3px; margin-top: -3px;
} }
.clause-table-row { .clause-table-row {
display: row; display: row;
margin-bottom: 10px; margin-bottom: 10px;
} }
.clause-table-cell { .clause-table-cell {
display: table-cell; display: table-cell;
text-align: left; text-align: left;
vertical-align: middle; vertical-align: middle;
} }
.action-column > button, .action-column>button,
.group-control-header > button, .group-control-header>button,
.group-indicator-column > button { .group-indicator-column>button {
min-width: 20px; min-width: 20px;
width: 20px; width: 20px;
padding: 0px; padding: 0px;
background-color: transparent; background-color: transparent;
border-color: transparent; border-color: transparent;
cursor: pointer; cursor: pointer;
} }
.group-control-header > button:disabled { .group-control-header>button:disabled {
min-width: 20px; min-width: 20px;
width: 20px; width: 20px;
padding: 0px; padding: 0px;
background-color: transparent; background-color: transparent;
border-color: transparent; border-color: transparent;
outline: none; outline: none;
opacity: 0.4; opacity: 0.4;
cursor: default; cursor: default;
} }
.clause-table-field { .clause-table-field {
width: 100%; width: 100%;
border: 1px solid #bbbbbb; border: 1px solid #bbbbbb;
} }
.clause-table-cell button { .clause-table-cell button {
height: 20px; height: 20px;
} }
.clause-table-cell input[type="checkbox"] { .clause-table-cell input[type="checkbox"] {
padding: 0px; padding: 0px;
margin-bottom: 12px; margin-bottom: 12px;
} }
.and-or-svg { .and-or-svg {
margin-top: -8px; margin-top: -8px;
margin-right: -5px; margin-right: -5px;
} }
.scroll-box { .scroll-box {
border-bottom: 1px transparent #ddd; border-bottom: 1px transparent #DDD;
/*[1px solid {plugin-table-border-color}]*/ /*[1px solid {plugin-table-border-color}]*/
border-top: 1px transparent #ddd; border-top: 1px transparent #DDD;
/*[1px solid {plugin-table-border-color}]*/ /*[1px solid {plugin-table-border-color}]*/
max-height: 20vh; max-height: 20vh;
width: 100%; width: 100%;
} }
.scrollable { .scrollable {
overflow: auto; overflow: auto;
overflow-x: hidden; overflow-x: hidden;
} }
.and-or-column, .and-or-column,
.and-or-header { .and-or-header {
min-width: 65px; min-width: 65px;
padding-right: 10px; padding-right: 10px;
padding-left: 5px; padding-left: 5px;
} }
.operator-column, .operator-column,
.operator-header { .operator-header {
min-width: 65px; min-width: 65px;
padding-right: 10px; padding-right: 10px;
} }
.field-header, .field-header,
.field-column { .field-column {
min-width: 125px; min-width: 125px;
padding-right: 10px; padding-right: 10px;
} }
.type-header, .type-header,
.type-column { .type-column {
min-width: 85px; min-width: 85px;
} }
.and-or-column, .and-or-column,
@@ -345,41 +345,41 @@ input::-webkit-inner-spin-button {
.type-header, .type-header,
.type-column, .type-column,
.action-header { .action-header {
padding-right: 10px; padding-right: 10px;
margin-bottom: 8px; margin-bottom: 8px;
} }
.value-header, .value-header,
.value-column, .value-column,
.time-column { .time-column {
min-width: 230px; min-width: 230px;
padding: 0px 4px 0px 0px; padding: 0px 4px 0px 0px;
width: 100%; width: 100%;
margin-bottom: 8px; margin-bottom: 8px;
} }
.group-control-header, .group-control-header,
.group-control-column { .group-control-column {
min-width: 25px; min-width: 25px;
text-align: right; text-align: right;
} }
.group-indicator-table { .group-indicator-table {
border-spacing: 0px; border-spacing: 0px;
min-height: 24px; min-height: 24px
} }
.group-indicator-column { .group-indicator-column {
min-width: 21px; min-width: 21px;
padding: 0px; padding: 0px;
border-style: none; border-style: none;
height: 29px; height: 29px;
} }
.clause-table-cell.action-column, .clause-table-cell.action-column,
.clause-table-cell.action-header { .clause-table-cell.action-header {
min-width: 60px; min-width: 60px;
padding-left: @SmallSpace; padding-left: @SmallSpace;
} }
.action-header, .action-header,
@@ -388,14 +388,15 @@ input::-webkit-inner-spin-button {
.operator-header, .operator-header,
.value-header, .value-header,
.and-or-header { .and-or-header {
padding-right: 4px; padding-right: 4px;
padding-bottom: 5px; padding-bottom: 5px;
} }
.header-background { .header-background {
background-color: #ffffff; background-color: #ffffff;
} }
/*.type-header { /*.type-header {
padding-right: 4px; padding-right: 4px;
} }
@@ -409,111 +410,112 @@ input::-webkit-inner-spin-button {
}*/ }*/
.clause-table-field[readonly] { .clause-table-field[readonly] {
background-color: #eeeef2; background-color: #EEEEF2;
/*[{plugin-table-header-background-color}]*/ /*[{plugin-table-header-background-color}]*/
border: 1px solid #cccedb; border: 1px solid #CCCEDB;
/*[{plugin-table-border-color}]*/ /*[{plugin-table-border-color}]*/
} }
.addClause-title { .addClause-title {
/*[{common-common-controls-button-border-hover}]*/ /*[{common-common-controls-button-border-hover}]*/
cursor: pointer; cursor: pointer;
margin-left: -5px; margin-left: -5px;
} }
.addClause { .addClause {
width: 125px; width: 125px;
padding: 8px 0px 5px 5px; padding: 8px 0px 5px 5px;
border: 1px solid #fff; border: 1px solid #fff;
margin-left: 5px; margin-left: 5px;
} }
.addClause:hover { .addClause:hover {
.hover(); .hover();
} }
.addClause:active { .addClause:active {
.active(); .active();
border: 1px dashed @AccentMedium; border: 1px dashed @AccentMedium;
} }
.clause-table-row { .clause-table-row {
min-width: 550px; min-width: 550px;
width: 100%; width: 100%;
} }
.clause-table-field field-column { .clause-table-field field-column {
min-width: 75px; min-width: 75px;
height: 30px; height: 30px;
width: 100%; width: 100%;
} }
.clause-table-field field-input { .clause-table-field field-input {
min-width: 54px; min-width: 54px;
margin-left: -78px; margin-left: -78px;
height: 25px; height: 25px;
border: none; border: none;
} }
.query-panel .row .spacing { .query-panel .row .spacing {
padding-bottom: 6px; padding-bottom: 6px;
} }
.query-panel .divider.horizontal { .query-panel .divider.horizontal {
height: 10px; height: 10px;
width: 100%; width: 100%
} }
.inline-div { .inline-div {
display: inline; display: inline
} }
.querybuilder-addpropertyImg, .querybuilder-addpropertyImg,
.querybuilder-cancelImg { .querybuilder-cancelImg {
width: 14px; width: 14px;
height: 14px; height: 14px;
margin-left: 3px; margin-left: 3px;
margin-bottom: 8px; margin-bottom: 8px;
} }
.addclauseProperty-Img { .addclauseProperty-Img {
width: 14px; width: 14px;
height: 14px; height: 14px;
margin-bottom: 5px; margin-bottom: 5px;
margin-left: 12px; margin-left: 12px;
} }
.entity-Add-Cancel { .entity-Add-Cancel {
// padding: @DefaultSpace @SmallSpace @SmallSpace; padding: @DefaultSpace @SmallSpace @SmallSpace;
cursor: pointer; cursor: pointer;
} }
.entity-Add-Cancel:hover { .entity-Add-Cancel:hover {
.hover(); .hover();
} }
.entity-Add-Cancel:active { .entity-Add-Cancel:active {
.active(); .active();
} }
.query-builder-isDisabled { .query-builder-isDisabled {
border: 1px solid #cccedb; border: 1px solid #CCCEDB;
color: #ccc; color: #ccc;
} }
.edit-value-text { .edit-value-text {
padding-left: @DefaultSpace; padding-left: @DefaultSpace;
} }
.expand-triangle { .expand-triangle {
width: 10px; width: 10px;
height: 10px; height: 10px;
} }
.expand-triangle-right { .expand-triangle-right {
margin-bottom: 5px; margin-bottom: 5px;
} }
/* /*
@media only screen and (max-width: 1200px) { @media only screen and (max-width: 1200px) {
.clause-table { .clause-table {
@@ -522,4 +524,4 @@ input::-webkit-inner-spin-button {
width: 100%; width: 100%;
padding-top: 10px; padding-top: 10px;
} }
}*/ }*/

35
package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "1.0.0", "version": "1.0.0",
"dependencies": { "dependencies": {
"@azure/arm-cosmosdb": "9.1.0", "@azure/arm-cosmosdb": "9.1.0",
"@azure/cosmos": "3.16.2", "@azure/cosmos": "3.16.1",
"@azure/cosmos-language-service": "0.0.5", "@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "1.2.1", "@azure/identity": "1.2.1",
"@azure/ms-rest-nodeauth": "3.0.7", "@azure/ms-rest-nodeauth": "3.0.7",
@@ -396,13 +396,12 @@
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==" "integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
}, },
"node_modules/@azure/cosmos": { "node_modules/@azure/cosmos": {
"version": "3.16.2", "version": "3.16.1",
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.2.tgz", "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.1.tgz",
"integrity": "sha512-sceY5LWj0BHGj8PSyaVCfDRQLVZyoCfIY78kyIROJVEw0k+p9XFs8fhpykN8JklkCftL0WlaVY+X25SQwnhZsw==", "integrity": "sha512-9J76EMiF+ypZwO/Z7OS4PjrU/3hdRLe18dQh/Hj+jwXG2gKJ1NwgkYqcwu1HiCiX73A8+NCeA3PRDbegEnuuNQ==",
"dependencies": { "dependencies": {
"@azure/core-auth": "^1.3.0", "@azure/core-auth": "^1.3.0",
"@azure/core-rest-pipeline": "^1.2.0", "@azure/core-rest-pipeline": "^1.2.0",
"@azure/core-tracing": "^1.0.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"fast-json-stable-stringify": "^2.1.0", "fast-json-stable-stringify": "^2.1.0",
"jsbi": "^3.1.3", "jsbi": "^3.1.3",
@@ -442,17 +441,6 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/@azure/cosmos/node_modules/@azure/core-tracing": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz",
"integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==",
"dependencies": {
"tslib": "^2.2.0"
},
"engines": {
"node": ">=12.0.0"
}
},
"node_modules/@azure/cosmos/node_modules/tslib": { "node_modules/@azure/cosmos/node_modules/tslib": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
@@ -31470,13 +31458,12 @@
} }
}, },
"@azure/cosmos": { "@azure/cosmos": {
"version": "3.16.2", "version": "3.16.1",
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.2.tgz", "resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.1.tgz",
"integrity": "sha512-sceY5LWj0BHGj8PSyaVCfDRQLVZyoCfIY78kyIROJVEw0k+p9XFs8fhpykN8JklkCftL0WlaVY+X25SQwnhZsw==", "integrity": "sha512-9J76EMiF+ypZwO/Z7OS4PjrU/3hdRLe18dQh/Hj+jwXG2gKJ1NwgkYqcwu1HiCiX73A8+NCeA3PRDbegEnuuNQ==",
"requires": { "requires": {
"@azure/core-auth": "^1.3.0", "@azure/core-auth": "^1.3.0",
"@azure/core-rest-pipeline": "^1.2.0", "@azure/core-rest-pipeline": "^1.2.0",
"@azure/core-tracing": "^1.0.0",
"debug": "^4.1.1", "debug": "^4.1.1",
"fast-json-stable-stringify": "^2.1.0", "fast-json-stable-stringify": "^2.1.0",
"jsbi": "^3.1.3", "jsbi": "^3.1.3",
@@ -31488,14 +31475,6 @@
"uuid": "^8.3.0" "uuid": "^8.3.0"
}, },
"dependencies": { "dependencies": {
"@azure/core-tracing": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.0.1.tgz",
"integrity": "sha512-I5CGMoLtX+pI17ZdiFJZgxMJApsK6jjfm85hpgp3oazCdq5Wxgh4wMr7ge/TTWW1B5WBuvIOI1fMU/FrOAMKrw==",
"requires": {
"tslib": "^2.2.0"
}
},
"tslib": { "tslib": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",

View File

@@ -5,7 +5,7 @@
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@azure/arm-cosmosdb": "9.1.0", "@azure/arm-cosmosdb": "9.1.0",
"@azure/cosmos": "3.16.2", "@azure/cosmos": "3.16.1",
"@azure/cosmos-language-service": "0.0.5", "@azure/cosmos-language-service": "0.0.5",
"@azure/identity": "1.2.1", "@azure/identity": "1.2.1",
"@azure/ms-rest-nodeauth": "3.0.7", "@azure/ms-rest-nodeauth": "3.0.7",
@@ -232,4 +232,4 @@
"prettier": { "prettier": {
"printWidth": 120 "printWidth": 120
} }
} }

View File

@@ -1,6 +1,6 @@
import React, { FunctionComponent, MutableRefObject, useEffect, useRef } from "react"; import React, { FunctionComponent, MutableRefObject, useEffect, useRef } from "react";
import arrowLeftImg from "../../images/imgarrowlefticon.svg"; import arrowLeftImg from "../../images/imgarrowlefticon.svg";
import { getApiShortDisplayName } from "../Utils/APITypeUtils"; import { userContext } from "../UserContext";
import { NormalizedEventKey } from "./Constants"; import { NormalizedEventKey } from "./Constants";
export interface CollapsedResourceTreeProps { export interface CollapsedResourceTreeProps {
@@ -45,7 +45,7 @@ export const CollapsedResourceTree: FunctionComponent<CollapsedResourceTreeProps
<img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" /> <img className="arrowCollapsed" src={arrowLeftImg} alt="Expand" />
</span> </span>
<span className="collectionCollapsed"> <span className="collectionCollapsed">
<span>{getApiShortDisplayName()}</span> <span>{userContext.apiType} API</span>
</span> </span>
</li> </li>
</ul> </ul>

View File

@@ -45,8 +45,6 @@ export class ArmResourceTypes {
export class BackendDefaults { export class BackendDefaults {
public static partitionKeyKind = "Hash"; public static partitionKeyKind = "Hash";
public static partitionKeyMultiHash = "MultiHash";
public static maxNumMultiHashPartition = 2;
public static singlePartitionStorageInGb: string = "10"; public static singlePartitionStorageInGb: string = "10";
public static multiPartitionStorageInGb: string = "100"; public static multiPartitionStorageInGb: string = "100";
public static maxChangeFeedRetentionDuration: number = 10; public static maxChangeFeedRetentionDuration: number = 10;

View File

@@ -299,7 +299,7 @@ export function createMongoCollectionWithProxy(
db: params.databaseId, db: params.databaseId,
coll: params.collectionId, coll: params.collectionId,
pk: shardKey, pk: shardKey,
offerThroughput: params.autoPilotMaxThroughput || params.offerThroughput, offerThroughput: params.offerThroughput,
cd: params.createNewDatabase, cd: params.createNewDatabase,
st: params.databaseLevelThroughput, st: params.databaseLevelThroughput,
is: !!shardKey, is: !!shardKey,
@@ -309,6 +309,7 @@ export function createMongoCollectionWithProxy(
rg: userContext.resourceGroup, rg: userContext.resourceGroup,
dba: databaseAccount.name, dba: databaseAccount.name,
isAutoPilot: !!params.autoPilotMaxThroughput, isAutoPilot: !!params.autoPilotMaxThroughput,
autoPilotThroughput: params.autoPilotMaxThroughput?.toString(),
}; };
const endpoint = getFeatureEndpointOrDefault("createCollectionWithProxy"); const endpoint = getFeatureEndpointOrDefault("createCollectionWithProxy");

View File

@@ -6,7 +6,6 @@ import Explorer from "../Explorer/Explorer";
import { ResourceTokenTree } from "../Explorer/Tree/ResourceTokenTree"; import { ResourceTokenTree } from "../Explorer/Tree/ResourceTokenTree";
import { ResourceTree } from "../Explorer/Tree/ResourceTree"; import { ResourceTree } from "../Explorer/Tree/ResourceTree";
import { userContext } from "../UserContext"; import { userContext } from "../UserContext";
import { getApiShortDisplayName } from "../Utils/APITypeUtils";
import { NormalizedEventKey } from "./Constants"; import { NormalizedEventKey } from "./Constants";
export interface ResourceTreeContainerProps { export interface ResourceTreeContainerProps {
@@ -43,7 +42,7 @@ export const ResourceTreeContainer: FunctionComponent<ResourceTreeContainerProps
{/* Collections Window Title/Command Bar - Start */} {/* Collections Window Title/Command Bar - Start */}
<div className="collectiontitle"> <div className="collectiontitle">
<div className="coltitle"> <div className="coltitle">
<span className="titlepadcol">{getApiShortDisplayName()}</span> <span className="titlepadcol">{userContext.apiType} API</span>
<div className="float-right"> <div className="float-right">
<span <span
className="padimgcolrefresh" className="padimgcolrefresh"

View File

@@ -73,17 +73,6 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
const sectionStackTokens: IStackTokens = { childrenGap: 12 }; const sectionStackTokens: IStackTokens = { childrenGap: 12 };
const handleKeyPress = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter" || event.key === "Space") {
onEditEntity();
}
};
const handleKeyPressdelete = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter" || event.key === "Space") {
onDeleteEntity();
}
};
const getEntityValueType = (): string => { const getEntityValueType = (): string => {
const { Int, Smallint, Tinyint } = CassandraType; const { Int, Smallint, Tinyint } = CassandraType;
const { Double, Int32, Int64 } = TableType; const { Double, Int32, Int64 } = TableType;
@@ -137,28 +126,12 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
/> />
{!isEntityValueDisable && ( {!isEntityValueDisable && (
<TooltipHost content="Edit property" id="editTooltip"> <TooltipHost content="Edit property" id="editTooltip">
<Image <Image {...imageProps} src={EditIcon} alt="editEntity" id="editEntity" onClick={onEditEntity} />
{...imageProps}
src={EditIcon}
alt="editEntity"
id="editEntity"
onClick={onEditEntity}
tabIndex={0}
onKeyPress={handleKeyPress}
/>
</TooltipHost> </TooltipHost>
)} )}
{isDeleteOptionVisible && userContext.apiType !== "Cassandra" && ( {isDeleteOptionVisible && userContext.apiType !== "Cassandra" && (
<TooltipHost content="Delete property" id="deleteTooltip"> <TooltipHost content="Delete property" id="deleteTooltip">
<Image <Image {...imageProps} src={DeleteIcon} alt="delete entity" id="deleteEntity" onClick={onDeleteEntity} />
{...imageProps}
src={DeleteIcon}
alt="delete entity"
id="deleteEntity"
onClick={onDeleteEntity}
tabIndex={0}
onKeyPress={handleKeyPressdelete}
/>
</TooltipHost> </TooltipHost>
)} )}
</Stack> </Stack>

View File

@@ -9,7 +9,7 @@ export const InfoTooltip: React.FunctionComponent<TooltipProps> = ({ children }:
return ( return (
<span> <span>
<TooltipHost content={children}> <TooltipHost content={children}>
<Icon iconName="Info" ariaLabel={children} className="panelInfoIcon" tabIndex={0} /> <Icon iconName="Info" ariaLabel="Info" className="panelInfoIcon" tabIndex={0} />
</TooltipHost> </TooltipHost>
</span> </span>
); );

View File

@@ -24,7 +24,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
); );
try { try {
let collection: DataModels.Collection; let collection: DataModels.Collection;
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) { if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
if (params.createNewDatabase) { if (params.createNewDatabase) {
const createDatabaseParams: DataModels.CreateDatabaseParams = { const createDatabaseParams: DataModels.CreateDatabaseParams = {
autoPilotMaxThroughput: params.autoPilotMaxThroughput, autoPilotMaxThroughput: params.autoPilotMaxThroughput,

View File

@@ -25,8 +25,7 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
if (userContext.apiType === "Tables") { if (userContext.apiType === "Tables") {
throw new Error("Creating database resources is not allowed for tables accounts"); throw new Error("Creating database resources is not allowed for tables accounts");
} }
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
!userContext.features.enableSDKoperations
? createDatabaseWithARM(params) ? createDatabaseWithARM(params)
: createDatabaseWithSDK(params)); : createDatabaseWithSDK(params));

View File

@@ -20,11 +20,7 @@ export async function createStoredProcedure(
): Promise<StoredProcedureDefinition & Resource> { ): Promise<StoredProcedureDefinition & Resource> {
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`); const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
try { try {
const getResponse = await getSqlStoredProcedure( const getResponse = await getSqlStoredProcedure(
userContext.subscriptionId, userContext.subscriptionId,

View File

@@ -14,11 +14,7 @@ export async function createTrigger(
): Promise<TriggerDefinition | SqlTriggerResource> { ): Promise<TriggerDefinition | SqlTriggerResource> {
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`); const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
try { try {
const getResponse = await getSqlTrigger( const getResponse = await getSqlTrigger(
userContext.subscriptionId, userContext.subscriptionId,

View File

@@ -20,11 +20,7 @@ export async function createUserDefinedFunction(
): Promise<UserDefinedFunctionDefinition & Resource> { ): Promise<UserDefinedFunctionDefinition & Resource> {
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`); const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
try { try {
const getResponse = await getSqlUserDefinedFunction( const getResponse = await getSqlUserDefinedFunction(
userContext.subscriptionId, userContext.subscriptionId,

View File

@@ -12,7 +12,7 @@ import { handleError } from "../ErrorHandlingUtils";
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> { export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`); const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) { if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
await deleteCollectionWithARM(databaseId, collectionId); await deleteCollectionWithARM(databaseId, collectionId);
} else { } else {
await client().database(databaseId).container(collectionId).delete(); await client().database(databaseId).container(collectionId).delete();

View File

@@ -12,7 +12,10 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`); const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) { if (userContext.apiType === "Tables") {
throw new Error("Deleting database resources is not allowed for tables accounts");
}
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
await deleteDatabaseWithARM(databaseId); await deleteDatabaseWithARM(databaseId);
} else { } else {
await client().database(databaseId).delete(); await client().database(databaseId).delete();

View File

@@ -4,7 +4,6 @@ import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationCons
import { client } from "../CosmosClient"; import { client } from "../CosmosClient";
import { getEntityName } from "../DocumentUtility"; import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils"; import { handleError } from "../ErrorHandlingUtils";
import { getPartitionKeyValue } from "./getPartitionKeyValue";
export const deleteDocument = async (collection: CollectionBase, documentId: DocumentId): Promise<void> => { export const deleteDocument = async (collection: CollectionBase, documentId: DocumentId): Promise<void> => {
const entityName: string = getEntityName(); const entityName: string = getEntityName();
@@ -14,7 +13,7 @@ export const deleteDocument = async (collection: CollectionBase, documentId: Doc
await client() await client()
.database(collection.databaseId) .database(collection.databaseId)
.container(collection.id()) .container(collection.id())
.item(documentId.id(), getPartitionKeyValue(documentId)) .item(documentId.id(), documentId.partitionKeyValue?.length === 0 ? undefined : documentId.partitionKeyValue)
.delete(); .delete();
logConsoleInfo(`Successfully deleted ${entityName} ${documentId.id()}`); logConsoleInfo(`Successfully deleted ${entityName} ${documentId.id()}`);
} catch (error) { } catch (error) {

View File

@@ -12,11 +12,7 @@ export async function deleteStoredProcedure(
): Promise<void> { ): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`); const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
await deleteSqlStoredProcedure( await deleteSqlStoredProcedure(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -8,11 +8,7 @@ import { handleError } from "../ErrorHandlingUtils";
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> { export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`); const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
await deleteSqlTrigger( await deleteSqlTrigger(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -8,11 +8,7 @@ import { handleError } from "../ErrorHandlingUtils";
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> { export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`); const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
await deleteSqlUserDefinedFunction( await deleteSqlUserDefinedFunction(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -1,12 +0,0 @@
import { userContext } from "UserContext";
import DocumentId from "../../Explorer/Tree/DocumentId";
export const getPartitionKeyValue = (documentId: DocumentId) => {
if (userContext.apiType === "Tables" && documentId.partitionKeyValue?.length === 0) {
return "";
}
if (documentId.partitionKeyValue?.length === 0) {
return undefined;
}
return documentId.partitionKeyValue;
};

View File

@@ -14,11 +14,7 @@ export const readCollectionOffer = async (params: ReadCollectionOfferParams): Pr
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`); const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
return await readCollectionOfferWithARM(params.databaseId, params.collectionId); return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
} }

View File

@@ -13,11 +13,7 @@ import { handleError } from "../ErrorHandlingUtils";
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> { export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`); const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
return await readCollectionsWithARM(databaseId); return await readCollectionsWithARM(databaseId);
} }

View File

@@ -13,11 +13,7 @@ export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promis
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`); const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
return await readDatabaseOfferWithARM(params.databaseId); return await readDatabaseOfferWithARM(params.databaseId);
} }

View File

@@ -13,11 +13,7 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
let databases: DataModels.Database[]; let databases: DataModels.Database[];
const clearMessage = logConsoleProgress(`Querying databases`); const clearMessage = logConsoleProgress(`Querying databases`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
databases = await readDatabasesWithARM(); databases = await readDatabasesWithARM();
} else { } else {
const sdkResponse = await client().databases.readAll().fetchAll(); const sdkResponse = await client().databases.readAll().fetchAll();

View File

@@ -6,7 +6,6 @@ import { HttpHeaders } from "../Constants";
import { client } from "../CosmosClient"; import { client } from "../CosmosClient";
import { getEntityName } from "../DocumentUtility"; import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils"; import { handleError } from "../ErrorHandlingUtils";
import { getPartitionKeyValue } from "./getPartitionKeyValue";
export const readDocument = async (collection: CollectionBase, documentId: DocumentId): Promise<Item> => { export const readDocument = async (collection: CollectionBase, documentId: DocumentId): Promise<Item> => {
const entityName = getEntityName(); const entityName = getEntityName();
@@ -22,7 +21,8 @@ export const readDocument = async (collection: CollectionBase, documentId: Docum
const response = await client() const response = await client()
.database(collection.databaseId) .database(collection.databaseId)
.container(collection.id()) .container(collection.id())
.item(documentId.id(), getPartitionKeyValue(documentId)) // use undefined if the partitionKeyValue is empty
.item(documentId.id(), documentId.partitionKeyValue?.length === 0 ? undefined : documentId.partitionKeyValue)
.read(options); .read(options);
return response?.resource; return response?.resource;

View File

@@ -12,11 +12,7 @@ export async function readStoredProcedures(
): Promise<(StoredProcedureDefinition & Resource)[]> { ): Promise<(StoredProcedureDefinition & Resource)[]> {
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
const rpResponse = await listSqlStoredProcedures( const rpResponse = await listSqlStoredProcedures(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -13,11 +13,7 @@ export async function readTriggers(
): Promise<SqlTriggerResource[] | TriggerDefinition[]> { ): Promise<SqlTriggerResource[] | TriggerDefinition[]> {
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType === "SQL"
) {
const rpResponse = await listSqlTriggers( const rpResponse = await listSqlTriggers(
userContext.subscriptionId, userContext.subscriptionId,
userContext.resourceGroup, userContext.resourceGroup,

View File

@@ -11,9 +11,9 @@ export async function readUserDefinedFunctions(
collectionId: string collectionId: string
): Promise<(UserDefinedFunctionDefinition & Resource)[]> { ): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`); const clearMessage = logConsoleProgress(`Querying user defined functions for container ${collectionId}`);
const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const rpResponse = await listSqlUserDefinedFunctions( const rpResponse = await listSqlUserDefinedFunctions(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -33,11 +33,7 @@ export async function updateCollection(
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`); const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
try { try {
if ( if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
userContext.authType === AuthType.AAD &&
!userContext.features.enableSDKoperations &&
userContext.apiType !== "Tables"
) {
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection); collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
} else { } else {
const sdkResponse = await client() const sdkResponse = await client()

View File

@@ -6,7 +6,6 @@ import { logConsoleInfo, logConsoleProgress } from "../../Utils/NotificationCons
import { client } from "../CosmosClient"; import { client } from "../CosmosClient";
import { getEntityName } from "../DocumentUtility"; import { getEntityName } from "../DocumentUtility";
import { handleError } from "../ErrorHandlingUtils"; import { handleError } from "../ErrorHandlingUtils";
import { getPartitionKeyValue } from "./getPartitionKeyValue";
export const updateDocument = async ( export const updateDocument = async (
collection: CollectionBase, collection: CollectionBase,
@@ -26,7 +25,7 @@ export const updateDocument = async (
const response = await client() const response = await client()
.database(collection.databaseId) .database(collection.databaseId)
.container(collection.id()) .container(collection.id())
.item(documentId.id(), getPartitionKeyValue(documentId)) .item(documentId.id(), documentId.partitionKeyValue?.length === 0 ? undefined : documentId.partitionKeyValue)
.replace(newDocument, options); .replace(newDocument, options);
logConsoleInfo(`Successfully updated ${entityName} ${documentId.id()}`); logConsoleInfo(`Successfully updated ${entityName} ${documentId.id()}`);

View File

@@ -56,7 +56,7 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
const clearMessage = logConsoleProgress(`Updating offer for ${offerResourceText}`); const clearMessage = logConsoleProgress(`Updating offer for ${offerResourceText}`);
try { try {
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) { if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
if (params.collectionId) { if (params.collectionId) {
updatedOffer = await updateCollectionOfferWithARM(params); updatedOffer = await updateCollectionOfferWithARM(params);
} else if (userContext.apiType === "Tables") { } else if (userContext.apiType === "Tables") {

View File

@@ -20,9 +20,9 @@ export async function updateStoredProcedure(
): Promise<StoredProcedureDefinition & Resource> { ): Promise<StoredProcedureDefinition & Resource> {
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`); const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
try { try {
const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const getResponse = await getSqlStoredProcedure( const getResponse = await getSqlStoredProcedure(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -13,9 +13,9 @@ export async function updateTrigger(
trigger: SqlTriggerResource trigger: SqlTriggerResource
): Promise<SqlTriggerResource | TriggerDefinition> { ): Promise<SqlTriggerResource | TriggerDefinition> {
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`); const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const getResponse = await getSqlTrigger( const getResponse = await getSqlTrigger(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -19,9 +19,9 @@ export async function updateUserDefinedFunction(
userDefinedFunction: UserDefinedFunctionDefinition userDefinedFunction: UserDefinedFunctionDefinition
): Promise<UserDefinedFunctionDefinition & Resource> { ): Promise<UserDefinedFunctionDefinition & Resource> {
const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`); const clearMessage = logConsoleProgress(`Updating user defined function ${userDefinedFunction.id}`);
const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext; const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
try { try {
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") { if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
const getResponse = await getSqlUserDefinedFunction( const getResponse = await getSqlUserDefinedFunction(
subscriptionId, subscriptionId,
resourceGroup, resourceGroup,

View File

@@ -33,8 +33,6 @@ export interface DatabaseAccountExtendedProperties {
privateEndpointConnections?: unknown[]; privateEndpointConnections?: unknown[];
capacity?: { totalThroughputLimit: number }; capacity?: { totalThroughputLimit: number };
locations?: DatabaseAccountResponseLocation[]; locations?: DatabaseAccountResponseLocation[];
postgresqlEndpoint?: string;
publicNetworkAccess?: string;
} }
export interface DatabaseAccountResponseLocation { export interface DatabaseAccountResponseLocation {
@@ -483,10 +481,6 @@ export interface IMaxUsersPerDbAccountExceeded extends IPhoenixError {
} }
export interface IPhoenixConnectionInfoResult { export interface IPhoenixConnectionInfoResult {
readonly phoenixServiceInfo?: IPhoenixServiceInfo;
}
export interface IPhoenixServiceInfo {
readonly authToken?: string; readonly authToken?: string;
readonly phoenixServiceUrl?: string; readonly phoenixServiceUrl?: string;
readonly forwardingId?: string; readonly forwardingId?: string;
@@ -568,16 +562,6 @@ export interface ContainerConnectionInfo {
//need to add ram and rom info //need to add ram and rom info
} }
export interface PostgresFirewallRule {
id: string;
name: string;
type: string;
properties: {
startIpAddress: string;
endIpAddress: string;
};
}
export enum PhoenixErrorType { export enum PhoenixErrorType {
MaxAllocationTimeExceeded = "MaxAllocationTimeExceeded", MaxAllocationTimeExceeded = "MaxAllocationTimeExceeded",
MaxDbAccountsPerUserExceeded = "MaxDbAccountsPerUserExceeded", MaxDbAccountsPerUserExceeded = "MaxDbAccountsPerUserExceeded",
@@ -587,5 +571,4 @@ export enum PhoenixErrorType {
SubscriptionNotAllowed = "SubscriptionNotAllowed", SubscriptionNotAllowed = "SubscriptionNotAllowed",
UnknownError = "UnknownError", UnknownError = "UnknownError",
PhoenixFlightFallback = "PhoenixFlightFallback", PhoenixFlightFallback = "PhoenixFlightFallback",
UserMissingPermissionsError = "UserMissingPermissionsError",
} }

View File

@@ -35,9 +35,6 @@ export enum MessageTypes {
RefreshDatabaseAccount, RefreshDatabaseAccount,
CloseTab, CloseTab,
OpenQuickstartBlade, OpenQuickstartBlade,
OpenPostgreSQLPasswordReset,
OpenPostgresNetworkingBlade,
OpenCosmosDBNetworkingBlade,
} }
export { Versions, ActionContracts, Diagnostics }; export { Versions, ActionContracts, Diagnostics };

View File

@@ -186,6 +186,7 @@ export interface Collection extends CollectionBase {
onDrop(source: Collection, event: { originalEvent: DragEvent }): void; onDrop(source: Collection, event: { originalEvent: DragEvent }): void;
uploadFiles(fileList: FileList): Promise<{ data: UploadDetailsRecord[] }>; uploadFiles(fileList: FileList): Promise<{ data: UploadDetailsRecord[] }>;
getLabel(): string;
getPendingThroughputSplitNotification(): Promise<DataModels.Notification>; getPendingThroughputSplitNotification(): Promise<DataModels.Notification>;
} }
@@ -371,7 +372,6 @@ export enum TerminalKind {
Default = 0, Default = 0,
Mongo = 1, Mongo = 1,
Cassandra = 2, Cassandra = 2,
Postgres = 3,
} }
export interface DataExplorerInputsFrame { export interface DataExplorerInputsFrame {
@@ -395,11 +395,6 @@ export interface DataExplorerInputsFrame {
sharedThroughputDefault?: number; sharedThroughputDefault?: number;
dataExplorerVersion?: string; dataExplorerVersion?: string;
defaultCollectionThroughput?: CollectionCreationDefaults; defaultCollectionThroughput?: CollectionCreationDefaults;
isPostgresAccount?: boolean;
isReplica?: boolean;
clientIpAddress?: string;
// TODO: Update this param in the OSS extension to remove isFreeTier, isMarlinServerGroup, and make nodes a flat array instead of an nested array
connectionStringParams?: any;
flights?: readonly string[]; flights?: readonly string[];
features?: { features?: {
[key: string]: string; [key: string]: string;

View File

@@ -44,7 +44,7 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
}, },
]; ];
if (userContext.apiType !== "Tables" || userContext.features.enableSDKoperations) { if (userContext.apiType !== "Tables") {
items.push({ items.push({
iconSrc: DeleteDatabaseIcon, iconSrc: DeleteDatabaseIcon,
onClick: () => onClick: () =>

View File

@@ -2,7 +2,6 @@
* Wrapper around Notebook server terminal * Wrapper around Notebook server terminal
*/ */
import { useTerminal } from "hooks/useTerminal";
import postRobot from "post-robot"; import postRobot from "post-robot";
import * as React from "react"; import * as React from "react";
import * as DataModels from "../../../Contracts/DataModels"; import * as DataModels from "../../../Contracts/DataModels";
@@ -41,7 +40,6 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
handleFrameLoad(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void { handleFrameLoad(event: React.SyntheticEvent<HTMLIFrameElement, Event>): void {
this.terminalWindow = (event.target as HTMLIFrameElement).contentWindow; this.terminalWindow = (event.target as HTMLIFrameElement).contentWindow;
useTerminal.getState().setTerminal(this.terminalWindow);
this.sendPropsToTerminalFrame(); this.sendPropsToTerminalFrame();
} }
@@ -76,8 +74,6 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
this.props.databaseAccount?.properties.mongoEndpoint || this.props.databaseAccount?.properties.documentEndpoint; this.props.databaseAccount?.properties.mongoEndpoint || this.props.databaseAccount?.properties.documentEndpoint;
} else if (StringUtils.endsWith(notebookServerEndpoint, "cassandra")) { } else if (StringUtils.endsWith(notebookServerEndpoint, "cassandra")) {
terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint; terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint;
} else if (StringUtils.endsWith(notebookServerEndpoint, "postgresql")) {
return this.props.databaseAccount?.properties.postgresqlEndpoint;
} }
if (terminalEndpoint) { if (terminalEndpoint) {

View File

@@ -1,5 +1,5 @@
import { HoverCard, HoverCardType, Icon, Label, Link, Stack } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { Icon, Label, Stack, HoverCard, HoverCardType, Link } from "@fluentui/react";
import { CodeOfConductEndpoints } from "../../../../Common/Constants"; import { CodeOfConductEndpoints } from "../../../../Common/Constants";
import "./InfoComponent.less"; import "./InfoComponent.less";
@@ -41,7 +41,7 @@ export class InfoComponent extends React.Component<InfoComponentProps> {
public render(): JSX.Element { public render(): JSX.Element {
return ( return (
<HoverCard plainCardProps={{ onRenderPlainCard: this.onHover }} instantOpenOnClick type={HoverCardType.plain}> <HoverCard plainCardProps={{ onRenderPlainCard: this.onHover }} instantOpenOnClick type={HoverCardType.plain}>
<div className="infoPanelMain" tabIndex={0}> <div className="infoPanelMain">
<Icon className="infoIconMain" iconName="Help" styles={{ root: { verticalAlign: "middle" } }} /> <Icon className="infoIconMain" iconName="Help" styles={{ root: { verticalAlign: "middle" } }} />
<Label className="infoLabelMain">Help</Label> <Label className="infoLabelMain">Help</Label>
</div> </div>

View File

@@ -12,7 +12,6 @@ exports[`InfoComponent renders 1`] = `
> >
<div <div
className="infoPanelMain" className="infoPanelMain"
tabIndex={0}
> >
<Icon <Icon
className="infoIconMain" className="infoIconMain"

View File

@@ -310,9 +310,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
/> />
)} )}
{userContext.apiType === "SQL" && this.isLargePartitionKeyEnabled() && ( {this.isLargePartitionKeyEnabled() && <Text>Large {this.partitionKeyName.toLowerCase()} has been enabled</Text>}
<Text>Large {this.partitionKeyName.toLowerCase()} has been enabled</Text>
)}
</Stack> </Stack>
); );

View File

@@ -82,6 +82,7 @@ interface ThroughputInputAutoPilotV3State {
spendAckChecked: boolean; spendAckChecked: boolean;
exceedFreeTierThroughput: boolean; exceedFreeTierThroughput: boolean;
} }
export class ThroughputInputAutoPilotV3Component extends React.Component< export class ThroughputInputAutoPilotV3Component extends React.Component<
ThroughputInputAutoPilotV3Props, ThroughputInputAutoPilotV3Props,
ThroughputInputAutoPilotV3State ThroughputInputAutoPilotV3State
@@ -623,10 +624,7 @@ export class ThroughputInputAutoPilotV3Component extends React.Component<
return ( return (
<> <>
{warningMessage && ( {warningMessage && (
<MessageBar <MessageBar messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}>
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
role="alert"
>
{warningMessage} {warningMessage}
</MessageBar> </MessageBar>
)} )}

View File

@@ -15,7 +15,6 @@ exports[`ThroughputInputAutoPilotV3Component autopilot input visible 1`] = `
"iconName": "WarningSolid", "iconName": "WarningSolid",
} }
} }
role="alert"
> >
<Text <Text
styles={ styles={

View File

@@ -35,7 +35,6 @@ exports[`SettingsComponent renders 1`] = `
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"phoenixClient": PhoenixClient { "phoenixClient": PhoenixClient {
"armResourceId": undefined,
"retryOptions": Object { "retryOptions": Object {
"maxTimeout": 5000, "maxTimeout": 5000,
"minTimeout": 5000, "minTimeout": 5000,
@@ -112,7 +111,6 @@ exports[`SettingsComponent renders 1`] = `
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"phoenixClient": PhoenixClient { "phoenixClient": PhoenixClient {
"armResourceId": undefined,
"retryOptions": Object { "retryOptions": Object {
"maxTimeout": 5000, "maxTimeout": 5000,
"minTimeout": 5000, "minTimeout": 5000,

View File

@@ -23,12 +23,12 @@ describe("ThroughputInput Pane", () => {
}); });
it("should switch mode properly", () => { it("should switch mode properly", () => {
wrapper.find('[aria-label="Manual database throughput"]').simulate("change"); wrapper.find('[aria-label="Manual mode"]').simulate("change");
expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe( expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe(
"Container throughput (400 - unlimited RU/s)" "Container throughput (400 - unlimited RU/s)"
); );
wrapper.find('[aria-label="Autoscale database throughput"]').simulate("change"); wrapper.find('[aria-label="Autoscale mode"]').simulate("change");
expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe("Container throughput (autoscale)"); expect(wrapper.find('[aria-label="Throughput header"]').at(0).text()).toBe("Container throughput (autoscale)");
}); });
}); });

View File

@@ -28,7 +28,6 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
isSharded, isSharded,
isFreeTier, isFreeTier,
showFreeTierExceedThroughputTooltip, showFreeTierExceedThroughputTooltip,
isQuickstart,
setThroughputValue, setThroughputValue,
setIsAutoscale, setIsAutoscale,
setIsThroughputCapExceeded, setIsThroughputCapExceeded,
@@ -36,7 +35,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
}: ThroughputInputProps) => { }: ThroughputInputProps) => {
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true); const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
const [throughput, setThroughput] = useState<number>( const [throughput, setThroughput] = useState<number>(
isFreeTier || isQuickstart ? AutoPilotUtils.autoPilotThroughput1K : AutoPilotUtils.autoPilotThroughput4K isFreeTier ? AutoPilotUtils.autoPilotThroughput1K : AutoPilotUtils.autoPilotThroughput4K
); );
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false); const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
const [throughputError, setThroughputError] = useState<string>(""); const [throughputError, setThroughputError] = useState<string>("");
@@ -186,9 +185,8 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
<Stack horizontal verticalAlign="center"> <Stack horizontal verticalAlign="center">
<input <input
id="Autoscale-input"
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
aria-label="Autoscale database throughput" aria-label="Autoscale mode"
aria-required={true} aria-required={true}
checked={isAutoscaleSelected} checked={isAutoscaleSelected}
type="radio" type="radio"
@@ -196,14 +194,11 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
tabIndex={0} tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Autoscale")} onChange={(e) => handleOnChangeMode(e, "Autoscale")}
/> />
<label htmlFor="Autoscale-input" className="throughputInputRadioBtnLabel"> <span className="throughputInputRadioBtnLabel">Autoscale</span>
Autoscale
</label>
<input <input
id="Manual-input"
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
aria-label="Manual database throughput" aria-label="Manual mode"
checked={!isAutoscaleSelected} checked={!isAutoscaleSelected}
type="radio" type="radio"
aria-required={true} aria-required={true}
@@ -211,20 +206,14 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
tabIndex={0} tabIndex={0}
onChange={(e) => handleOnChangeMode(e, "Manual")} onChange={(e) => handleOnChangeMode(e, "Manual")}
/> />
<label className="throughputInputRadioBtnLabel" htmlFor="Manual-input"> <span className="throughputInputRadioBtnLabel">Manual</span>
Manual
</label>
</Stack> </Stack>
{isAutoscaleSelected && ( {isAutoscaleSelected && (
<Stack className="throughputInputSpacing"> <Stack className="throughputInputSpacing">
<Text variant="small" aria-label="capacity calculator of azure cosmos db"> <Text variant="small" aria-label="ruDescription">
Estimate your required RU/s with{" "} Estimate your required RU/s with{" "}
<Link <Link target="_blank" href="https://cosmos.azure.com/capacitycalculator/" aria-label="ruDescription">
target="_blank"
href="https://cosmos.azure.com/capacitycalculator/"
aria-label="capacity calculator of azure cosmos db"
>
capacity calculator capacity calculator
</Link> </Link>
. .

View File

@@ -344,13 +344,13 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
onMouseLeave={[Function]} onMouseLeave={[Function]}
> >
<StyledIconBase <StyledIconBase
ariaLabel="Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage." ariaLabel="Info"
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
> >
<IconBase <IconBase
ariaLabel="Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage." ariaLabel="Info"
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
styles={[Function]} styles={[Function]}
@@ -630,7 +630,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
} }
> >
<i <i
aria-label="Set the throughput — Request Units per second (RU/s) — required for the workload. A read of a 1 KB document uses 1 RU. Select manual if you plan to scale RU/s yourself. Select autoscale to allow the system to scale RU/s based on usage." aria-label="Info"
className="panelInfoIcon root-57" className="panelInfoIcon root-57"
data-icon-name="Info" data-icon-name="Info"
role="img" role="img"
@@ -655,43 +655,39 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
className="ms-Stack css-58" className="ms-Stack css-58"
> >
<input <input
aria-label="Autoscale database throughput" aria-label="Autoscale mode"
aria-required={true} aria-required={true}
checked={true} checked={true}
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
id="Autoscale-input"
key=".0:$.0" key=".0:$.0"
onChange={[Function]} onChange={[Function]}
role="radio" role="radio"
tabIndex={0} tabIndex={0}
type="radio" type="radio"
/> />
<label <span
className="throughputInputRadioBtnLabel" className="throughputInputRadioBtnLabel"
htmlFor="Autoscale-input"
key=".0:$.1" key=".0:$.1"
> >
Autoscale Autoscale
</label> </span>
<input <input
aria-label="Manual database throughput" aria-label="Manual mode"
aria-required={true} aria-required={true}
checked={false} checked={false}
className="throughputInputRadioBtn" className="throughputInputRadioBtn"
id="Manual-input"
key=".0:$.2" key=".0:$.2"
onChange={[Function]} onChange={[Function]}
role="radio" role="radio"
tabIndex={0} tabIndex={0}
type="radio" type="radio"
/> />
<label <span
className="throughputInputRadioBtnLabel" className="throughputInputRadioBtnLabel"
htmlFor="Manual-input"
key=".0:$.3" key=".0:$.3"
> >
Manual Manual
</label> </span>
</div> </div>
</Stack> </Stack>
<Stack <Stack
@@ -701,23 +697,23 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
className="ms-Stack throughputInputSpacing css-59" className="ms-Stack throughputInputSpacing css-59"
> >
<Text <Text
aria-label="capacity calculator of azure cosmos db" aria-label="ruDescription"
key=".0:$.0" key=".0:$.0"
variant="small" variant="small"
> >
<span <span
aria-label="capacity calculator of azure cosmos db" aria-label="ruDescription"
className="css-54" className="css-54"
> >
Estimate your required RU/s with Estimate your required RU/s with
<StyledLinkBase <StyledLinkBase
aria-label="capacity calculator of azure cosmos db" aria-label="ruDescription"
href="https://cosmos.azure.com/capacitycalculator/" href="https://cosmos.azure.com/capacitycalculator/"
target="_blank" target="_blank"
> >
<LinkBase <LinkBase
aria-label="capacity calculator of azure cosmos db" aria-label="ruDescription"
href="https://cosmos.azure.com/capacitycalculator/" href="https://cosmos.azure.com/capacitycalculator/"
styles={[Function]} styles={[Function]}
target="_blank" target="_blank"
@@ -996,7 +992,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
} }
> >
<a <a
aria-label="capacity calculator of azure cosmos db" aria-label="ruDescription"
className="ms-Link root-60" className="ms-Link root-60"
href="https://cosmos.azure.com/capacitycalculator/" href="https://cosmos.azure.com/capacitycalculator/"
onClick={[Function]} onClick={[Function]}
@@ -1335,13 +1331,13 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
onMouseLeave={[Function]} onMouseLeave={[Function]}
> >
<StyledIconBase <StyledIconBase
ariaLabel="Set the max RU/s to the highest RU/s you want your container to scale to. The container will scale between 10% of max RU/s to the max RU/s based on usage." ariaLabel="Info"
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
> >
<IconBase <IconBase
ariaLabel="Set the max RU/s to the highest RU/s you want your container to scale to. The container will scale between 10% of max RU/s to the max RU/s based on usage." ariaLabel="Info"
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
styles={[Function]} styles={[Function]}
@@ -1621,7 +1617,7 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
} }
> >
<i <i
aria-label="Set the max RU/s to the highest RU/s you want your container to scale to. The container will scale between 10% of max RU/s to the max RU/s based on usage." aria-label="Info"
className="panelInfoIcon root-57" className="panelInfoIcon root-57"
data-icon-name="Info" data-icon-name="Info"
role="img" role="img"

View File

@@ -133,6 +133,7 @@ describe("ContainerSampleGenerator", () => {
} as DatabaseAccount, } as DatabaseAccount,
}); });
// Rejects with error that contains experience
expect(ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub)).rejects.toMatch(experience); expect(ContainerSampleGenerator.createSampleGeneratorAsync(explorerStub)).rejects.toMatch(experience);
}); });

View File

@@ -1,6 +1,5 @@
import { createCollection } from "../../Common/dataAccess/createCollection"; import { createCollection } from "../../Common/dataAccess/createCollection";
import { createDocument } from "../../Common/dataAccess/createDocument"; import { createDocument } from "../../Common/dataAccess/createDocument";
import { createDocument as createMongoDocument } from "../../Common/MongoProxyClient";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
@@ -29,7 +28,7 @@ export class ContainerSampleGenerator {
dataFileContent = await import( dataFileContent = await import(
/* webpackChunkName: "gremlinSampleJsonData" */ "../../../sampleData/gremlinSampleData.json" /* webpackChunkName: "gremlinSampleJsonData" */ "../../../sampleData/gremlinSampleData.json"
); );
} else if (userContext.apiType === "SQL" || userContext.apiType === "Mongo") { } else if (userContext.apiType === "SQL") {
dataFileContent = await import( dataFileContent = await import(
/* webpackChunkName: "sqlSampleJsonData" */ "../../../sampleData/sqlSampleData.json" /* webpackChunkName: "sqlSampleJsonData" */ "../../../sampleData/sqlSampleData.json"
); );
@@ -69,7 +68,7 @@ export class ContainerSampleGenerator {
return database.findCollectionWithId(this.sampleDataFile.collectionId); return database.findCollectionWithId(this.sampleDataFile.collectionId);
} }
public async populateContainerAsync(collection: ViewModels.Collection, shardKey?: string): Promise<void> { public async populateContainerAsync(collection: ViewModels.Collection): Promise<void> {
if (!collection) { if (!collection) {
throw new Error("No container to populate"); throw new Error("No container to populate");
} }
@@ -100,9 +99,7 @@ export class ContainerSampleGenerator {
await Promise.all( await Promise.all(
this.sampleDataFile.data.map(async (doc) => { this.sampleDataFile.data.map(async (doc) => {
try { try {
userContext.apiType === "Mongo" await createDocument(collection, doc);
? await createMongoDocument(collection.databaseId, collection, shardKey, doc)
: await createDocument(collection, doc);
} catch (error) { } catch (error) {
NotificationConsoleUtils.logConsoleError(error); NotificationConsoleUtils.logConsoleError(error);
} }

View File

@@ -16,7 +16,12 @@ import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHand
import * as Logger from "../Common/Logger"; import * as Logger from "../Common/Logger";
import { QueriesClient } from "../Common/QueriesClient"; import { QueriesClient } from "../Common/QueriesClient";
import * as DataModels from "../Contracts/DataModels"; import * as DataModels from "../Contracts/DataModels";
import { ContainerConnectionInfo, IPhoenixServiceInfo, IProvisionData, IResponse } from "../Contracts/DataModels"; import {
ContainerConnectionInfo,
IPhoenixConnectionInfoResult,
IProvisionData,
IResponse,
} from "../Contracts/DataModels";
import * as ViewModels from "../Contracts/ViewModels"; import * as ViewModels from "../Contracts/ViewModels";
import { GitHubOAuthService } from "../GitHub/GitHubOAuthService"; import { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
import { useSidePanel } from "../hooks/useSidePanel"; import { useSidePanel } from "../hooks/useSidePanel";
@@ -93,8 +98,7 @@ export default class Explorer {
dataExplorerArea: Constants.Areas.ResourceTree, dataExplorerArea: Constants.Areas.ResourceTree,
}); });
this._isInitializingNotebooks = false; this._isInitializingNotebooks = false;
this.phoenixClient = new PhoenixClient();
this.phoenixClient = new PhoenixClient(userContext?.databaseAccount?.id);
useNotebook.subscribe( useNotebook.subscribe(
() => this.refreshCommandBarButtons(), () => this.refreshCommandBarButtons(),
(state) => state.isNotebooksEnabledForAccount (state) => state.isNotebooksEnabledForAccount
@@ -352,7 +356,7 @@ export default class Explorer {
(notebookServerInfo && notebookServerInfo.notebookServerEndpoint === undefined)) (notebookServerInfo && notebookServerInfo.notebookServerEndpoint === undefined))
) { ) {
const provisionData: IProvisionData = { const provisionData: IProvisionData = {
cosmosEndpoint: userContext?.databaseAccount?.properties?.documentEndpoint, cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
poolId: PoolIdType.DefaultPoolId, poolId: PoolIdType.DefaultPoolId,
}; };
const connectionStatus: ContainerConnectionInfo = { const connectionStatus: ContainerConnectionInfo = {
@@ -403,7 +407,7 @@ export default class Explorer {
} }
private async setNotebookInfo( private async setNotebookInfo(
connectionInfo: IResponse<IPhoenixServiceInfo>, connectionInfo: IResponse<IPhoenixConnectionInfoResult>,
connectionStatus: DataModels.ContainerConnectionInfo connectionStatus: DataModels.ContainerConnectionInfo
) { ) {
const containerData = { const containerData = {
@@ -1057,10 +1061,6 @@ export default class Explorer {
title = "Cassandra Shell"; title = "Cassandra Shell";
break; break;
case ViewModels.TerminalKind.Postgres:
title = "PSQL Shell";
break;
default: default:
throw new Error("Terminal kind: ${kind} not supported"); throw new Error("Terminal kind: ${kind} not supported");
} }
@@ -1120,7 +1120,7 @@ export default class Explorer {
account: userContext.databaseAccount, account: userContext.databaseAccount,
container: this, container: this,
junoClient: this.notebookManager?.junoClient, junoClient: this.notebookManager?.junoClient,
selectedTab: selectedTab || GalleryTabKind.OfficialSamples, selectedTab: selectedTab || GalleryTabKind.PublicGallery,
notebookUrl, notebookUrl,
galleryItem, galleryItem,
isFavorite, isFavorite,
@@ -1247,11 +1247,9 @@ export default class Explorer {
} }
public async refreshExplorer(): Promise<void> { public async refreshExplorer(): Promise<void> {
if (userContext.apiType !== "Postgres") { userContext.authType === AuthType.ResourceToken
userContext.authType === AuthType.ResourceToken ? this.refreshDatabaseForResourceToken()
? this.refreshDatabaseForResourceToken() : this.refreshAllDatabases();
: this.refreshAllDatabases();
}
await useNotebook.getState().refreshNotebooksEnabledStateForAccount(); await useNotebook.getState().refreshNotebooksEnabledStateForAccount();
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount // TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount

View File

@@ -6,9 +6,8 @@
import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react"; import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react";
import { useNotebook } from "Explorer/Notebook/useNotebook"; import { useNotebook } from "Explorer/Notebook/useNotebook";
import * as React from "react"; import * as React from "react";
import { userContext } from "UserContext";
import create, { UseStore } from "zustand"; import create, { UseStore } from "zustand";
import { ConnectionStatusType, StyleConstants } from "../../../Common/Constants"; import { StyleConstants } from "../../../Common/Constants";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent"; import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer"; import Explorer from "../../Explorer";
import { useSelectedNode } from "../../useSelectedNode"; import { useSelectedNode } from "../../useSelectedNode";
@@ -34,22 +33,6 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const buttons = useCommandBar((state) => state.contextButtons); const buttons = useCommandBar((state) => state.contextButtons);
const backgroundColor = StyleConstants.BaseLight; const backgroundColor = StyleConstants.BaseLight;
if (userContext.apiType === "Postgres") {
const buttons = CommandBarComponentButtonFactory.createPostgreButtons(container);
return (
<div className="commandBarContainer">
<FluentCommandBar
ariaLabel="Use left and right arrow keys to navigate between commands"
items={CommandBarUtil.convertButton(buttons, backgroundColor)}
styles={{
root: { backgroundColor: backgroundColor },
}}
overflowButtonProps={{ ariaLabel: "More commands" }}
/>
</div>
);
}
const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(container, selectedNodeState); const staticButtons = CommandBarComponentButtonFactory.createStaticCommandBarButtons(container, selectedNodeState);
const contextButtons = (buttons || []).concat( const contextButtons = (buttons || []).concat(
CommandBarComponentButtonFactory.createContextCommandBarButtons(container, selectedNodeState) CommandBarComponentButtonFactory.createContextCommandBarButtons(container, selectedNodeState)
@@ -70,12 +53,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor); const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true)); uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
const connectionInfo = useNotebook((state) => state.connectionInfo); if (useNotebook.getState().isPhoenixNotebooks || useNotebook.getState().isPhoenixFeatures) {
if (
(useNotebook.getState().isPhoenixNotebooks || useNotebook.getState().isPhoenixFeatures) &&
connectionInfo?.status !== ConnectionStatusType.Connect
) {
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus(container, "connectionStatus")); uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus(container, "connectionStatus"));
} }

View File

@@ -104,10 +104,6 @@ export function createStaticCommandBarButtons(
if (!useNotebook.getState().isPhoenixFeatures) { if (!useNotebook.getState().isPhoenixFeatures) {
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.mongoShellTemporarilyDownMsg); applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.mongoShellTemporarilyDownMsg);
} }
} else if (btn.commandButtonLabel.indexOf("Open Terminal") !== -1) {
if (!useNotebook.getState().isPhoenixFeatures) {
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.temporarilyDownMsg);
}
} else if (!useNotebook.getState().isPhoenixNotebooks) { } else if (!useNotebook.getState().isPhoenixNotebooks) {
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.temporarilyDownMsg); applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.temporarilyDownMsg);
} }
@@ -523,28 +519,6 @@ function createOpenCassandraTerminalButton(container: Explorer): CommandButtonCo
}; };
} }
function createOpenPsqlTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open PSQL Shell";
const disableButton =
!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled;
return {
iconSrc: HostedTerminalIcon,
iconAlt: label,
onCommandClick: () => {
if (useNotebook.getState().isNotebookEnabled) {
container.openNotebookTerminal(ViewModels.TerminalKind.Postgres);
}
},
commandButtonLabel: label,
hasPopup: false,
disabled: disableButton,
ariaLabel: label,
tooltipText: !disableButton
? ""
: "This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.",
};
}
function createNotebookWorkspaceResetButton(container: Explorer): CommandButtonComponentProps { function createNotebookWorkspaceResetButton(container: Explorer): CommandButtonComponentProps {
const label = "Reset Workspace"; const label = "Reset Workspace";
return { return {
@@ -607,9 +581,3 @@ function createStaticCommandBarButtonsForResourceToken(
return [newSqlQueryBtn, openQueryBtn]; return [newSqlQueryBtn, openQueryBtn];
} }
export function createPostgreButtons(container: Explorer): CommandButtonComponentProps[] {
const openPostgreShellBtn = createOpenPsqlTerminalButton(container);
return [openPostgreShellBtn];
}

View File

@@ -9,7 +9,7 @@ import { ConnectionStatusType, HttpHeaders, HttpStatusCodes, Notebook, PoolIdTyp
import { getErrorMessage } from "../../Common/ErrorHandlingUtils"; import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
import * as Logger from "../../Common/Logger"; import * as Logger from "../../Common/Logger";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import { IPhoenixServiceInfo, IProvisionData, IResponse } from "../../Contracts/DataModels"; import { IPhoenixConnectionInfoResult, IProvisionData, IResponse } from "../../Contracts/DataModels";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils"; import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils"; import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
@@ -23,7 +23,7 @@ export class NotebookContainerClient {
private scheduleTimerId: NodeJS.Timeout; private scheduleTimerId: NodeJS.Timeout;
constructor(private onConnectionLost: () => void) { constructor(private onConnectionLost: () => void) {
this.phoenixClient = new PhoenixClient(userContext?.databaseAccount?.id); this.phoenixClient = new PhoenixClient();
this.retryOptions = { this.retryOptions = {
retries: Notebook.retryAttempts, retries: Notebook.retryAttempts,
maxTimeout: Notebook.retryAttemptDelayMs, maxTimeout: Notebook.retryAttemptDelayMs,
@@ -129,9 +129,9 @@ export class NotebookContainerClient {
); );
} }
public async resetWorkspace(): Promise<IResponse<IPhoenixServiceInfo>> { public async resetWorkspace(): Promise<IResponse<IPhoenixConnectionInfoResult>> {
this.isResettingWorkspace = true; this.isResettingWorkspace = true;
let response: IResponse<IPhoenixServiceInfo>; let response: IResponse<IPhoenixConnectionInfoResult>;
try { try {
response = await this._resetWorkspace(); response = await this._resetWorkspace();
} catch (error) { } catch (error) {
@@ -142,7 +142,7 @@ export class NotebookContainerClient {
return response; return response;
} }
private async _resetWorkspace(): Promise<IResponse<IPhoenixServiceInfo>> { private async _resetWorkspace(): Promise<IResponse<IPhoenixConnectionInfoResult>> {
const notebookServerInfo = useNotebook.getState().notebookServerInfo; const notebookServerInfo = useNotebook.getState().notebookServerInfo;
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) { if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
const error = "No server endpoint detected"; const error = "No server endpoint detected";

View File

@@ -124,9 +124,8 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
} }
const firstWriteLocation = const firstWriteLocation =
userContext.apiType === "Postgres" databaseAccount?.properties?.writeLocations &&
? databaseAccount?.location databaseAccount?.properties?.writeLocations[0]?.locationName.toLowerCase();
: databaseAccount?.properties?.writeLocations?.[0]?.locationName.toLowerCase();
const disallowedLocationsUri = `${configContext.BACKEND_ENDPOINT}/api/disallowedLocations`; const disallowedLocationsUri = `${configContext.BACKEND_ENDPOINT}/api/disallowedLocations`;
const authorizationHeader = getAuthorizationHeader(); const authorizationHeader = getAuthorizationHeader();
try { try {
@@ -308,16 +307,13 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
let isPhoenixFeatures = false; let isPhoenixFeatures = false;
const isPublicInternetAllowed = isPublicInternetAccessAllowed(); const isPublicInternetAllowed = isPublicInternetAccessAllowed();
const phoenixClient = new PhoenixClient(userContext?.databaseAccount?.id); const phoenixClient = new PhoenixClient();
const dbAccountAllowedInfo = await phoenixClient.getDbAccountAllowedStatus(); const dbAccountAllowedInfo = await phoenixClient.getDbAccountAllowedStatus();
if (dbAccountAllowedInfo.status === HttpStatusCodes.OK) { if (dbAccountAllowedInfo.status === HttpStatusCodes.OK) {
if (dbAccountAllowedInfo?.type === PhoenixErrorType.PhoenixFlightFallback) { if (dbAccountAllowedInfo?.type === PhoenixErrorType.PhoenixFlightFallback) {
isPhoenixNotebooks = isPublicInternetAllowed && userContext.features.phoenixNotebooks === true; isPhoenixNotebooks = isPublicInternetAllowed && userContext.features.phoenixNotebooks;
isPhoenixFeatures = isPhoenixFeatures = isPublicInternetAllowed && userContext.features.phoenixFeatures;
isPublicInternetAllowed &&
// phoenix needs to be enabled for Postgres accounts since the PSQL shell requires phoenix containers
(userContext.features.phoenixFeatures === true || userContext.apiType === "Postgres");
} else { } else {
isPhoenixNotebooks = isPhoenixFeatures = isPublicInternetAllowed; isPhoenixNotebooks = isPhoenixFeatures = isPublicInternetAllowed;
} }

View File

@@ -1,9 +1,17 @@
jest.mock("../hooks/useFullScreenURLs");
import "@testing-library/jest-dom"; import "@testing-library/jest-dom";
import { render, screen } from "@testing-library/react"; import { render, screen } from "@testing-library/react";
import React from "react"; import React from "react";
import { useFullScreenURLs } from "../hooks/useFullScreenURLs";
import { OpenFullScreen } from "./OpenFullScreen"; import { OpenFullScreen } from "./OpenFullScreen";
it("renders the correct URLs", () => { it("renders the correct URLs", () => {
(useFullScreenURLs as jest.Mock).mockReturnValue({
readWrite: "read and write url",
read: "read only url",
});
render(<OpenFullScreen />); render(<OpenFullScreen />);
expect(screen.getByText("Open")).toBeDefined(); expect(screen.getByLabelText("Read and Write")).toHaveValue("https://cosmos.azure.com/?key=read and write url");
expect(screen.getByLabelText("Read Only")).toHaveValue("https://cosmos.azure.com/?key=read only url");
}); });

View File

@@ -1,26 +1,66 @@
import { PrimaryButton, Stack, Text } from "@fluentui/react"; import { DefaultButton, PrimaryButton, Spinner, Stack, Text, TextField } from "@fluentui/react";
import copyToClipboard from "clipboard-copy";
import * as React from "react"; import * as React from "react";
import { useFullScreenURLs } from "../hooks/useFullScreenURLs";
export const OpenFullScreen: React.FunctionComponent = () => { export const OpenFullScreen: React.FunctionComponent = () => {
const [isReadUrlCopy, setIsReadUrlCopy] = React.useState<boolean>(false);
const [isReadWriteUrlCopy, setIsReadWriteUrlCopy] = React.useState<boolean>(false);
const result = useFullScreenURLs();
if (!result) {
return <Spinner label="Generating URLs..." ariaLive="assertive" labelPosition="right" />;
}
const readWriteUrl = `https://cosmos.azure.com/?key=${result.readWrite}`;
const readUrl = `https://cosmos.azure.com/?key=${result.read}`;
return ( return (
<> <>
<div style={{ padding: "34px" }}> <Stack tokens={{ childrenGap: 10 }}>
<Stack tokens={{ childrenGap: 10 }}> <Text>
<Text> Open this database account in a new browser tab with Cosmos DB Explorer. Or copy the read-write or read only
Open this database account in a new browser tab with Cosmos DB Explorer. You can connect using your access urls below to share with others. For security purposes, the URLs grant time-bound access to the
Microsoft account or a connection string. account. When access expires, you can reconnect, using a valid connection string for the account.
</Text> </Text>
<Stack horizontal tokens={{ childrenGap: 10 }}> <TextField label="Read and Write" readOnly defaultValue={readWriteUrl} />
<PrimaryButton <Stack horizontal tokens={{ childrenGap: 10 }}>
onClick={() => { <DefaultButton
window.open("https://cosmos.azure.com/", "_blank"); ariaLabel={isReadWriteUrlCopy ? "Copied url" : "Copy"}
}} onClick={() => {
text="Open" copyToClipboard(readWriteUrl);
iconProps={{ iconName: "OpenInNewWindow" }} setIsReadWriteUrlCopy(true);
/> }}
</Stack> text={isReadWriteUrlCopy ? "Copied" : "Copy"}
iconProps={{ iconName: "Copy" }}
/>
<PrimaryButton
onClick={() => {
window.open(readWriteUrl, "_blank");
}}
text="Open"
iconProps={{ iconName: "OpenInNewWindow" }}
/>
</Stack> </Stack>
</div> <TextField label="Read Only" readOnly defaultValue={readUrl} />
<Stack horizontal tokens={{ childrenGap: 10 }}>
<DefaultButton
ariaLabel={isReadUrlCopy ? "Copied url" : "Copy"}
onClick={() => {
setIsReadUrlCopy(true);
copyToClipboard(readUrl);
}}
text={isReadUrlCopy ? "Copied" : "Copy"}
iconProps={{ iconName: "Copy" }}
/>
<PrimaryButton
onClick={() => {
window.open(readUrl, "_blank");
}}
text="Open"
iconProps={{ iconName: "OpenInNewWindow" }}
/>
</Stack>
</Stack>
</> </>
); );
}; };

View File

@@ -89,10 +89,9 @@ export interface AddCollectionPanelState {
enableIndexing: boolean; enableIndexing: boolean;
isSharded: boolean; isSharded: boolean;
partitionKey: string; partitionKey: string;
subPartitionKeys: string[];
enableDedicatedThroughput: boolean; enableDedicatedThroughput: boolean;
createMongoWildCardIndex: boolean; createMongoWildCardIndex: boolean;
useHashV1: boolean; useHashV2: boolean;
enableAnalyticalStore: boolean; enableAnalyticalStore: boolean;
uniqueKeys: string[]; uniqueKeys: string[];
errorMessage: string; errorMessage: string;
@@ -122,11 +121,9 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
enableIndexing: true, enableIndexing: true,
isSharded: userContext.apiType !== "Tables", isSharded: userContext.apiType !== "Tables",
partitionKey: this.getPartitionKey(), partitionKey: this.getPartitionKey(),
subPartitionKeys: [],
enableDedicatedThroughput: false, enableDedicatedThroughput: false,
createMongoWildCardIndex: createMongoWildCardIndex: isCapabilityEnabled("EnableMongo"),
isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport"), useHashV2: false,
useHashV1: false,
enableAnalyticalStore: false, enableAnalyticalStore: false,
uniqueKeys: [], uniqueKeys: [],
errorMessage: "", errorMessage: "",
@@ -262,14 +259,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
true true
).toLocaleLowerCase()}.`} ).toLocaleLowerCase()}.`}
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`A database is analogous to a namespace. It is the unit of management for a set of ${getCollectionName(
true
).toLocaleLowerCase()}.`}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -345,14 +335,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
true true
).toLocaleLowerCase()} within the database.`} ).toLocaleLowerCase()} within the database.`}
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`Throughput configured at the database level will be shared across all ${getCollectionName(
true
).toLocaleLowerCase()} within the database.`}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
)} )}
@@ -363,7 +346,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
isDatabase={true} isDatabase={true}
isSharded={this.state.isSharded} isSharded={this.state.isSharded}
isFreeTier={this.isFreeTierAccount()} isFreeTier={this.isFreeTierAccount()}
isQuickstart={this.props.isQuickstart}
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)} setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)} setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) => setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
@@ -400,12 +382,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge} directionalHint={DirectionalHint.bottomLeftEdge}
content={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`} content={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`Unique identifier for the ${getCollectionName().toLocaleLowerCase()} and used for id-based routing through REST and all SDKs.`}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -488,14 +465,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
"Sharded collections split your data across many replica sets (shards) to achieve unlimited scalability. Sharded collections require choosing a shard key (field) to evenly distribute your data." "Sharded collections split your data across many replica sets (shards) to achieve unlimited scalability. Sharded collections require choosing a shard key (field) to evenly distribute your data."
} }
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={
"Sharded collections split your data across many replica sets (shards) to achieve unlimited scalability. Sharded collections require choosing a shard key (field) to evenly distribute your data."
}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -542,12 +512,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge} directionalHint={DirectionalHint.bottomLeftEdge}
content={this.getPartitionKeyTooltipText()} content={this.getPartitionKeyTooltipText()}
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={this.getPartitionKeyTooltipText()}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -579,77 +544,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
} }
}} }}
/> />
{userContext.apiType === "SQL" &&
this.state.subPartitionKeys.map((subPartitionKey: string, index: number) => {
return (
<Stack style={{ marginBottom: 8 }} key={`uniqueKey${index}`} horizontal>
<div
style={{
width: "20px",
border: "solid",
borderWidth: "0px 0px 1px 1px",
marginRight: "5px",
}}
></div>
<input
type="text"
id="addCollection-partitionKeyValue"
key={`addCollection-partitionKeyValue_${index}`}
aria-required
required
size={40}
tabIndex={index > 0 ? 1 : 0}
className="panelTextField"
autoComplete="off"
placeholder={this.getPartitionKeyPlaceHolder(index)}
aria-label={this.getPartitionKeyName()}
pattern={".*"}
title={""}
value={subPartitionKey}
onChange={(event: React.ChangeEvent<HTMLInputElement>) => {
const subPartitionKeys = [...this.state.subPartitionKeys];
if (!this.state.subPartitionKeys[index] && !event.target.value.startsWith("/")) {
subPartitionKeys[index] = "/" + event.target.value.trim();
this.setState({ subPartitionKeys });
} else {
subPartitionKeys[index] = event.target.value.trim();
this.setState({ subPartitionKeys });
}
}}
/>
<IconButton
iconProps={{ iconName: "Delete" }}
style={{ height: 27 }}
onClick={() => {
const subPartitionKeys = this.state.subPartitionKeys.filter((uniqueKey, j) => index !== j);
this.setState({ subPartitionKeys });
}}
/>
</Stack>
);
})}
{userContext.apiType === "SQL" && (
<Stack className="panelGroupSpacing">
<DefaultButton
styles={{ root: { padding: 0, width: 250, height: 30 }, label: { fontSize: 12 } }}
hidden={this.state.useHashV1}
disabled={this.state.subPartitionKeys.length >= Constants.BackendDefaults.maxNumMultiHashPartition}
onClick={() => this.setState({ subPartitionKeys: [...this.state.subPartitionKeys, ""] })}
>
Add hierarchical partition key (preview)
</DefaultButton>
{this.state.subPartitionKeys.length > 0 && (
<Text variant="small">
<Icon iconName="InfoSolid" className="removeIcon" tabIndex={0} /> This feature allows you to
partition your data with up to three levels of keys for better data distribution. Requires preview
version of .NET V3 or Java V4 SDK.{" "}
<Link href="https://aka.ms/cosmos-hierarchical-partitioning" target="_blank">
Learn more
</Link>
</Text>
)}
</Stack>
)}
</Stack> </Stack>
)} )}
@@ -676,17 +570,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
does not count towards the throughput you provisioned for the database. This throughput amount will be does not count towards the throughput you provisioned for the database. This throughput amount will be
billed in addition to the throughput amount you provisioned at the database level.`} billed in addition to the throughput amount you provisioned at the database level.`}
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={`You can optionally provision dedicated throughput for a ${getCollectionName().toLocaleLowerCase()} within a database that has throughput
provisioned. This dedicated throughput amount will not be shared with other ${getCollectionName(
true
).toLocaleLowerCase()} in the database and
does not count towards the throughput you provisioned for the database. This throughput amount will be
billed in addition to the throughput amount you provisioned at the database level.`}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
)} )}
@@ -697,7 +581,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
isDatabase={false} isDatabase={false}
isSharded={this.state.isSharded} isSharded={this.state.isSharded}
isFreeTier={this.isFreeTierAccount()} isFreeTier={this.isFreeTierAccount()}
isQuickstart={this.props.isQuickstart}
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)} setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)} setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) => setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
@@ -717,18 +600,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
</Text> </Text>
<TooltipHost <TooltipHost
directionalHint={DirectionalHint.bottomLeftEdge} directionalHint={DirectionalHint.bottomLeftEdge}
content={ content="Unique keys provide developers with the ability to add a layer of data integrity to their database. By
"Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key." creating a unique key policy when a container is created, you ensure the uniqueness of one or more values
} per partition key."
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel={
"Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key."
}
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -791,13 +667,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge} directionalHint={DirectionalHint.bottomLeftEdge}
content={this.getAnalyticalStorageTooltipContent()} content={this.getAnalyticalStorageTooltipContent()}
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel="Enable analytical store capability to perform near real-time analytics on your operational data, without
impacting the performance of transactional workloads."
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -863,7 +733,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
}} }}
> >
<Stack className="panelGroupSpacing" id="collapsibleSectionContent"> <Stack className="panelGroupSpacing" id="collapsibleSectionContent">
{isCapabilityEnabled("EnableMongo") && !isCapabilityEnabled("EnableMongo16MBDocumentSupport") && ( {isCapabilityEnabled("EnableMongo") && (
<Stack className="panelGroupSpacing"> <Stack className="panelGroupSpacing">
<Stack horizontal> <Stack horizontal>
<span className="mandatoryStar">*&nbsp;</span> <span className="mandatoryStar">*&nbsp;</span>
@@ -874,12 +744,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
directionalHint={DirectionalHint.bottomLeftEdge} directionalHint={DirectionalHint.bottomLeftEdge}
content="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development." content="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development."
> >
<Icon <Icon iconName="Info" className="panelInfoIcon" tabIndex={0} />
iconName="Info"
className="panelInfoIcon"
tabIndex={0}
ariaLabel="The _id field is indexed by default. Creating a wildcard index for all fields will optimize queries and is recommended for development."
/>
</TooltipHost> </TooltipHost>
</Stack> </Stack>
@@ -899,29 +764,18 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
)} )}
{userContext.apiType === "SQL" && ( {userContext.apiType === "SQL" && (
<Stack className="panelGroupSpacing"> <Checkbox
<Checkbox label="My partition key is larger than 101 bytes"
label="My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)" checked={this.state.useHashV2}
checked={this.state.useHashV1} styles={{
styles={{ text: { fontSize: 12 },
text: { fontSize: 12 }, checkbox: { width: 12, height: 12 },
checkbox: { width: 12, height: 12 }, label: { padding: 0, alignItems: "center" },
label: { padding: 0, alignItems: "center", wordWrap: "break-word", whiteSpace: "break-spaces" }, }}
}} onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) =>
onChange={(ev: React.FormEvent<HTMLElement>, isChecked: boolean) => this.setState({ useHashV2: isChecked })
this.setState({ useHashV1: isChecked, subPartitionKeys: [] }) }
} />
/>
<Text variant="small">
<Icon iconName="InfoSolid" className="removeIcon" tabIndex={0} /> To ensure compatibility with
older SDKs, the created container will use a legacy partitioning scheme that supports partition
key values of size only up to 101 bytes. If this is enabled, you will not be able to use
hierarchical partition keys.{" "}
<Link href="https://aka.ms/cosmos-large-pk" target="_blank">
Learn more
</Link>
</Text>
</Stack>
)} )}
</Stack> </Stack>
</CollapsibleSectionComponent> </CollapsibleSectionComponent>
@@ -976,20 +830,12 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName; return isLowerCase ? partitionKeyName.toLocaleLowerCase() : partitionKeyName;
} }
private getPartitionKeyPlaceHolder(index?: number): string { private getPartitionKeyPlaceHolder(): string {
switch (userContext.apiType) { switch (userContext.apiType) {
case "Mongo": case "Mongo":
return "e.g., address.zipCode"; return "e.g., address.zipCode";
case "Gremlin": case "Gremlin":
return "e.g., /address"; return "e.g., /address";
case "SQL":
return `${
index === undefined
? "Required - first partition key e.g., /TenantId"
: index === 0
? "second partition key e.g., /UserId"
: "third partition key e.g., /SessionId"
}`;
default: default:
return "e.g., /address/zipCode"; return "e.g., /address/zipCode";
} }
@@ -1315,16 +1161,11 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
} }
const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys(); const uniqueKeyPolicy: DataModels.UniqueKeyPolicy = this.parseUniqueKeys();
const partitionKeyVersion = this.state.useHashV1 ? undefined : 2; const partitionKeyVersion = this.state.useHashV2 ? 2 : undefined;
const partitionKey: DataModels.PartitionKey = partitionKeyString const partitionKey: DataModels.PartitionKey = partitionKeyString
? { ? {
paths: [ paths: [partitionKeyString],
partitionKeyString, kind: "Hash",
...(userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0
? this.state.subPartitionKeys
: []),
],
kind: userContext.apiType === "SQL" && this.state.subPartitionKeys.length > 0 ? "MultiHash" : "Hash",
version: partitionKeyVersion, version: partitionKeyVersion,
} }
: undefined; : undefined;
@@ -1408,7 +1249,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
collection.isSampleCollection = true; collection.isSampleCollection = true;
useTeachingBubble.getState().setSampleCollection(collection); useTeachingBubble.getState().setSampleCollection(collection);
const sampleGenerator = await ContainerSampleGenerator.createSampleGeneratorAsync(this.props.explorer); const sampleGenerator = await ContainerSampleGenerator.createSampleGeneratorAsync(this.props.explorer);
await sampleGenerator.populateContainerAsync(collection, partitionKeyString); await sampleGenerator.populateContainerAsync(collection);
// auto-expand sample database + container and show teaching bubble // auto-expand sample database + container and show teaching bubble
await database.expandDatabase(); await database.expandDatabase();
collection.expandCollection(); collection.expandCollection();

View File

@@ -89,8 +89,8 @@ export const DeleteDatabaseConfirmationPanel: FunctionComponent<DeleteDatabaseCo
} }
} catch (error) { } catch (error) {
setLoadingFalse(); setLoadingFalse();
setFormError(error);
const errorMessage = getErrorMessage(error); const errorMessage = getErrorMessage(error);
setFormError(errorMessage);
TelemetryProcessor.traceFailure( TelemetryProcessor.traceFailure(
Action.DeleteDatabase, Action.DeleteDatabase,
{ {

View File

@@ -24,7 +24,6 @@ exports[`GitHub Repos Panel should render Default properly 1`] = `
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"phoenixClient": PhoenixClient { "phoenixClient": PhoenixClient {
"armResourceId": undefined,
"retryOptions": Object { "retryOptions": Object {
"maxTimeout": 5000, "maxTimeout": 5000,
"minTimeout": 5000, "minTimeout": 5000,

View File

@@ -48,7 +48,7 @@ export const PanelInfoErrorComponent: React.FunctionComponent<PanelInfoErrorProp
)} )}
</Text> </Text>
{showErrorDetails && ( {showErrorDetails && (
<a className="paneErrorLink" role="link" onClick={expandConsole} tabIndex={0} onKeyPress={expandConsole}> <a className="paneErrorLink" role="link" onClick={expandConsole}>
More details More details
</a> </a>
)} )}

View File

@@ -14,7 +14,6 @@ exports[`StringInput Pane should render Create new directory properly 1`] = `
"onRefreshDatabasesKeyPress": [Function], "onRefreshDatabasesKeyPress": [Function],
"onRefreshResourcesClick": [Function], "onRefreshResourcesClick": [Function],
"phoenixClient": PhoenixClient { "phoenixClient": PhoenixClient {
"armResourceId": undefined,
"retryOptions": Object { "retryOptions": Object {
"maxTimeout": 5000, "maxTimeout": 5000,
"minTimeout": 5000, "minTimeout": 5000,

View File

@@ -242,11 +242,6 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
submitButtonText: getButtonLabel(userContext.apiType), submitButtonText: getButtonLabel(userContext.apiType),
onSubmit, onSubmit,
}; };
const handlekeypressaddentity = (event: React.KeyboardEvent<HTMLElement>) => {
if (event.key === "Enter" || event.key === "Space") {
addNewEntity();
}
};
return ( return (
<RightPaneForm {...props}> <RightPaneForm {...props}>
@@ -289,13 +284,7 @@ export const AddTableEntityPanel: FunctionComponent<AddTableEntityPanelProps> =
); );
})} })}
{userContext.apiType !== "Cassandra" && ( {userContext.apiType !== "Cassandra" && (
<Stack <Stack horizontal onClick={addNewEntity} className="addButtonEntiy">
horizontal
onClick={addNewEntity}
className="addButtonEntiy"
tabIndex={0}
onKeyPress={handlekeypressaddentity}
>
<Image {...imageProps} src={AddPropertyIcon} alt="Add Entity" /> <Image {...imageProps} src={AddPropertyIcon} alt="Add Entity" />
<Text className="addNewParamStyle">{getAddButtonLabel(userContext.apiType)}</Text> <Text className="addNewParamStyle">{getAddButtonLabel(userContext.apiType)}</Text>
</Stack> </Stack>

View File

@@ -29,14 +29,10 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
className="addButtonEntiy" className="addButtonEntiy"
horizontal={true} horizontal={true}
onClick={[Function]} onClick={[Function]}
onKeyPress={[Function]}
tabIndex={0}
> >
<div <div
className="ms-Stack addButtonEntiy css-53" className="ms-Stack addButtonEntiy css-53"
onClick={[Function]} onClick={[Function]}
onKeyPress={[Function]}
tabIndex={0}
> >
<StyledImageBase <StyledImageBase
alt="Add Entity" alt="Add Entity"

View File

@@ -31,7 +31,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4} directionalHint={4}
> >
<Icon <Icon
ariaLabel="A database is analogous to a namespace. It is the unit of management for a set of containers."
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
@@ -125,7 +124,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4} directionalHint={4}
> >
<Icon <Icon
ariaLabel="Throughput configured at the database level will be shared across all containers within the database."
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
@@ -165,7 +163,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4} directionalHint={4}
> >
<Icon <Icon
ariaLabel="Unique identifier for the container and used for id-based routing through REST and all SDKs."
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
@@ -209,7 +206,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4} directionalHint={4}
> >
<Icon <Icon
ariaLabel="The partition key is used to automatically distribute data across partitions for scalability. Choose a property in your JSON document that has a wide range of values and evenly distributes request volume. For small read-heavy workloads or write-heavy workloads of any size, id is often a good choice."
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
@@ -227,36 +223,13 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
id="addCollection-partitionKeyValue" id="addCollection-partitionKeyValue"
onChange={[Function]} onChange={[Function]}
pattern=".*" pattern=".*"
placeholder="Required - first partition key e.g., /TenantId" placeholder="e.g., /address/zipCode"
required={true} required={true}
size={40} size={40}
title="" title=""
type="text" type="text"
value="" value=""
/> />
<Stack
className="panelGroupSpacing"
>
<CustomizedDefaultButton
disabled={false}
hidden={false}
onClick={[Function]}
styles={
Object {
"label": Object {
"fontSize": 12,
},
"root": Object {
"height": 30,
"padding": 0,
"width": 250,
},
}
}
>
Add hierarchical partition key (preview)
</CustomizedDefaultButton>
</Stack>
</Stack> </Stack>
<Stack> <Stack>
<Stack <Stack
@@ -273,7 +246,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4} directionalHint={4}
> >
<Icon <Icon
ariaLabel="Unique keys provide developers with the ability to add a layer of data integrity to their database. By creating a unique key policy when a container is created, you ensure the uniqueness of one or more values per partition key."
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
@@ -331,7 +303,6 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
directionalHint={4} directionalHint={4}
> >
<Icon <Icon
ariaLabel="Enable analytical store capability to perform near real-time analytics on your operational data, without impacting the performance of transactional workloads."
className="panelInfoIcon" className="panelInfoIcon"
iconName="Info" iconName="Info"
tabIndex={0} tabIndex={0}
@@ -425,49 +396,26 @@ exports[`AddCollectionPanel should render Default properly 1`] = `
className="panelGroupSpacing" className="panelGroupSpacing"
id="collapsibleSectionContent" id="collapsibleSectionContent"
> >
<Stack <StyledCheckboxBase
className="panelGroupSpacing" checked={false}
> label="My partition key is larger than 101 bytes"
<StyledCheckboxBase onChange={[Function]}
checked={false} styles={
label="My application uses an older Cosmos .NET or Java SDK version (.NET V1 or Java V2)" Object {
onChange={[Function]} "checkbox": Object {
styles={ "height": 12,
Object { "width": 12,
"checkbox": Object { },
"height": 12, "label": Object {
"width": 12, "alignItems": "center",
}, "padding": 0,
"label": Object { },
"alignItems": "center", "text": Object {
"padding": 0, "fontSize": 12,
"whiteSpace": "break-spaces", },
"wordWrap": "break-word",
},
"text": Object {
"fontSize": 12,
},
}
} }
/> }
<Text />
variant="small"
>
<Icon
className="removeIcon"
iconName="InfoSolid"
tabIndex={0}
/>
To ensure compatibility with older SDKs, the created container will use a legacy partitioning scheme that supports partition key values of size only up to 101 bytes. If this is enabled, you will not be able to use hierarchical partition keys.
<StyledLinkBase
href="https://aka.ms/cosmos-large-pk"
target="_blank"
>
Learn more
</StyledLinkBase>
</Text>
</Stack>
</Stack> </Stack>
</CollapsibleSectionComponent> </CollapsibleSectionComponent>
</div> </div>

View File

@@ -1,105 +0,0 @@
export const newTableCommand = `DROP SCHEMA IF EXISTS cosmosdb_tutorial CASCADE;
CREATE SCHEMA cosmosdb_tutorial;
SET search_path to cosmosdb_tutorial;
CREATE TABLE github_users
(
user_id bigint,
url text,
login text,
avatar_url text,
gravatar_id text,
display_login text
);
CREATE TABLE github_events
(
event_id bigint,
event_type text,
event_public boolean,
repo_id bigint,
payload jsonb,
repo jsonb,
user_id bigint,
org jsonb,
created_at timestamp
);
CREATE INDEX event_type_index ON github_events (event_type);
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops);
`;
export const newTableCommandForDisplay = `DROP SCHEMA IF EXISTS cosmosdb_tutorial CASCADE;
CREATE SCHEMA cosmosdb_tutorial;
-- Using schema created for tutorial
SET search_path to cosmosdb_tutorial;
CREATE TABLE github_users
(
user_id bigint,
url text,
login text,
avatar_url text,
gravatar_id text,
display_login text
);
CREATE TABLE github_events
(
event_id bigint,
event_type text,
event_public boolean,
repo_id bigint,
payload jsonb,
repo jsonb,
user_id bigint,
org jsonb,
created_at timestamp
);
--Create indexes on events table
CREATE INDEX event_type_index ON github_events (event_type);
CREATE INDEX payload_index ON github_events USING GIN (payload jsonb_path_ops);`;
export const distributeTableCommand = `SET search_path to cosmosdb_tutorial;
SELECT create_distributed_table('github_users', 'user_id');
SELECT create_distributed_table('github_events', 'user_id');
`;
export const distributeTableCommandForDisplay = `-- Using schema created for the tutorial
SET search_path to cosmosdb_tutorial;
SELECT create_distributed_table('github_users', 'user_id');
SELECT create_distributed_table('github_events', 'user_id');`;
export const loadDataCommand = `SET search_path to cosmosdb_tutorial;
\\COPY github_users FROM PROGRAM 'wget -q -O - "$@" "https://examples.citusdata.com/users.csv"' WITH (FORMAT CSV);
\\COPY github_events FROM PROGRAM 'wget -q -O - "$@" "https://examples.citusdata.com/events.csv"' WITH (FORMAT CSV);
`;
export const loadDataCommandForDisplay = `-- Using schema created for the tutorial
SET search_path to cosmosdb_tutorial;
-- download users and store in table
\\COPY github_users FROM PROGRAM 'wget -q -O - "$@" "https://examples.citusdata.com/users.csv"' WITH (FORMAT CSV);
\\COPY github_events FROM PROGRAM 'wget -q -O - "$@" "https://examples.citusdata.com/events.csv"' WITH (FORMAT CSV);`;
export const queryCommand = `SET search_path to cosmosdb_tutorial;
SELECT count(*) FROM github_users;
SELECT created_at, event_type, repo->>'name' AS repo_name
FROM github_events
WHERE user_id = 3861633;
SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::int) AS num_commits FROM github_events WHERE event_type = 'PushEvent' AND payload @> '{"ref":"refs/heads/master"}' GROUP BY hour ORDER BY hour;
`;
export const queryCommandForDisplay = `-- Using schema created for the tutorial
SET search_path to cosmosdb_tutorial;
-- count all rows (across shards)
SELECT count(*) FROM github_users;
-- Find all events for a single user.
SELECT created_at, event_type, repo->>'name' AS repo_name
FROM github_events
WHERE user_id = 3861633;
-- Find the number of commits on the master branch per hour
SELECT date_trunc('hour', created_at) AS hour, sum((payload->>'distinct_size')::int) AS num_commits FROM github_events WHERE event_type = 'PushEvent' AND payload @> '{"ref":"refs/heads/master"}' GROUP BY hour ORDER BY hour;`;

View File

@@ -1,22 +0,0 @@
import { Image, PrimaryButton, Stack, Text } from "@fluentui/react";
import { sendMessage } from "Common/MessageHandler";
import { MessageTypes } from "Contracts/ExplorerContracts";
import React from "react";
import FirewallRuleScreenshot from "../../../images/firewallRule.png";
export const QuickstartFirewallNotification: React.FC = (): JSX.Element => (
<Stack style={{ padding: "16px 20px" }}>
<Text block>
To use the PostgreSQL shell, you need to add a firewall rule to allow access from all IP addresses
(0.0.0.0-255.255.255).
</Text>
<Text block>We strongly recommend removing this rule once you finish using the PostgreSQL shell.</Text>
<Image style={{ margin: "20px 0" }} src={FirewallRuleScreenshot} />
<PrimaryButton
style={{ width: 150 }}
onClick={() => sendMessage({ type: MessageTypes.OpenPostgresNetworkingBlade })}
>
Add firewall rule
</PrimaryButton>
</Stack>
);

View File

@@ -1,327 +0,0 @@
import {
DefaultButton,
Icon,
IconButton,
Image,
IPivotItemProps,
Pivot,
PivotItem,
PrimaryButton,
Stack,
Text,
TextField,
} from "@fluentui/react";
import {
distributeTableCommand,
distributeTableCommandForDisplay,
loadDataCommand,
loadDataCommandForDisplay,
newTableCommand,
newTableCommandForDisplay,
queryCommand,
queryCommandForDisplay,
} from "Explorer/Quickstart/PostgreQuickstartCommands";
import { useTerminal } from "hooks/useTerminal";
import React, { useState } from "react";
import Youtube from "react-youtube";
import Pivot1SelectedIcon from "../../../images/Pivot1_selected.svg";
import Pivot2Icon from "../../../images/Pivot2.svg";
import Pivot2SelectedIcon from "../../../images/Pivot2_selected.svg";
import Pivot3Icon from "../../../images/Pivot3.svg";
import Pivot3SelectedIcon from "../../../images/Pivot3_selected.svg";
import Pivot4Icon from "../../../images/Pivot4.svg";
import Pivot4SelectedIcon from "../../../images/Pivot4_selected.svg";
import Pivot5Icon from "../../../images/Pivot5.svg";
import Pivot5SelectedIcon from "../../../images/Pivot5_selected.svg";
import CompleteIcon from "../../../images/QuickstartComplete.svg";
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
enum GuideSteps {
Login,
NewTable,
DistributeTable,
LoadData,
Query,
}
export const QuickstartGuide: React.FC = (): JSX.Element => {
const [currentStep, setCurrentStep] = useState<number>(0);
const onCopyBtnClicked = (selector: string): void => {
const textfield: HTMLInputElement = document.querySelector(selector);
textfield.select();
document.execCommand("copy");
};
const getPivotHeaderIcon = (step: number): string => {
switch (step) {
case 0:
return Pivot1SelectedIcon;
case 1:
return step === currentStep ? Pivot2SelectedIcon : Pivot2Icon;
case 2:
return step === currentStep ? Pivot3SelectedIcon : Pivot3Icon;
case 3:
return step === currentStep ? Pivot4SelectedIcon : Pivot4Icon;
case 4:
return step === currentStep ? Pivot5SelectedIcon : Pivot5Icon;
default:
return "";
}
};
const customPivotHeaderRenderer = (
link: IPivotItemProps,
defaultRenderer: (link?: IPivotItemProps) => JSX.Element | null,
step: number
): JSX.Element | null => {
if (!link || !defaultRenderer) {
return null;
}
return (
<Stack horizontal verticalAlign="center">
{currentStep > step ? (
<Icon iconName="CompletedSolid" style={{ color: "#57A300", marginRight: 8 }} />
) : (
<Image style={{ marginRight: 8 }} src={getPivotHeaderIcon(step)} />
)}
{defaultRenderer({ ...link, itemIcon: undefined })}
</Stack>
);
};
return (
<Stack style={{ paddingTop: 8, height: "100%", width: "100%" }}>
<Stack style={{ flexGrow: 1, padding: "0 20px", overflow: "auto" }}>
<Text variant="xxLarge">Quick start guide</Text>
{currentStep < 5 && (
<Pivot
style={{ marginTop: 10, width: "100%" }}
selectedKey={GuideSteps[currentStep]}
onLinkClick={(item?: PivotItem) => setCurrentStep(Object.values(GuideSteps).indexOf(item.props.itemKey))}
>
<PivotItem
headerText="Login"
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 0)}
itemKey={GuideSteps[0]}
onClick={() => {
setCurrentStep(0);
}}
>
<Stack style={{ marginTop: 20 }}>
<Text>
This tutorial guides you to create and query distributed tables using a sample dataset.
<br />
<br />
To begin, please enter the cluster&apos;s password in the PostgreSQL terminal.
<br />
<br />
Note: If you navigate out of the Quick Start tab (PostgreSQL Shell), the session will be closed and
all ongoing commands might be interrupted.
</Text>
<Youtube videoId="nT64dFSfiUo" style={{ margin: "20px 0" }} opts={{ width: "90%" }} />
</Stack>
</PivotItem>
<PivotItem
headerText="New table"
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 1)}
itemKey={GuideSteps[1]}
onClick={() => setCurrentStep(1)}
>
<Stack style={{ marginTop: 20 }}>
<Text>Let&apos;s create two tables github_users and github_events in cosmosdb_tutorial schema.</Text>
<DefaultButton
style={{ marginTop: 16, width: 150 }}
onClick={() => useTerminal.getState().sendMessage(newTableCommand)}
>
Create new table
</DefaultButton>
<Stack horizontal style={{ marginTop: 16 }}>
<TextField
id="newTableCommand"
multiline
rows={5}
readOnly
defaultValue={newTableCommandForDisplay}
styles={{
root: { width: "90%" },
field: {
backgroundColor: "#EEEEEE",
fontFamily:
"Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New",
},
}}
/>
<IconButton
iconProps={{
iconName: "Copy",
}}
onClick={() => onCopyBtnClicked("#newTableCommand")}
/>
</Stack>
<Youtube videoId="il_sA6U1WcY" style={{ margin: "20px 0" }} opts={{ width: "90%" }} />
</Stack>
</PivotItem>
<PivotItem
headerText="Distribute table"
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 2)}
itemKey={GuideSteps[2]}
onClick={() => setCurrentStep(2)}
>
<Stack style={{ marginTop: 20 }}>
<Text>
Lets distribute the two tables using the create_distributed_table() function.
<br />
<br />
We are choosing user_id as the distribution column for our sample dataset.
</Text>
<DefaultButton
style={{ marginTop: 16, width: 200 }}
onClick={() => useTerminal.getState().sendMessage(distributeTableCommand)}
>
Create distributed table
</DefaultButton>
<Stack horizontal style={{ marginTop: 16 }}>
<TextField
id="distributeTableCommand"
multiline
rows={5}
readOnly
defaultValue={distributeTableCommandForDisplay}
styles={{
root: { width: "90%" },
field: {
backgroundColor: "#EEEEEE",
fontFamily:
"Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New",
},
}}
/>
<IconButton
iconProps={{
iconName: "Copy",
}}
onClick={() => onCopyBtnClicked("#distributeTableCommand")}
/>
</Stack>
<Youtube videoId="kCCDRRrN1r0" style={{ margin: "20px 0" }} opts={{ width: "90%" }} />
</Stack>
</PivotItem>
<PivotItem
headerText="Load data"
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 3)}
itemKey={GuideSteps[3]}
onClick={() => setCurrentStep(3)}
>
<Stack style={{ marginTop: 20 }}>
<Text>Let&apos;s load the two tables with a sample dataset generated from the GitHub API.</Text>
<DefaultButton
style={{ marginTop: 16, width: 110 }}
onClick={() => useTerminal.getState().sendMessage(loadDataCommand)}
>
Load data
</DefaultButton>
<Stack horizontal style={{ marginTop: 16 }}>
<TextField
id="loadDataCommand"
multiline
rows={5}
readOnly
defaultValue={loadDataCommandForDisplay}
styles={{
root: { width: "90%" },
field: {
backgroundColor: "#EEEEEE",
fontFamily:
"Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New",
},
}}
/>
<IconButton
iconProps={{
iconName: "Copy",
}}
onClick={() => onCopyBtnClicked("#loadDataCommand")}
/>
</Stack>
<Youtube videoId="XSMEE2tujEk" style={{ margin: "20px 0" }} opts={{ width: "90%" }} />
</Stack>
</PivotItem>
<PivotItem
headerText="Query"
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 4)}
itemKey={GuideSteps[4]}
onClick={() => setCurrentStep(4)}
>
<Stack style={{ marginTop: 20 }}>
<Text>
Congratulations on creating and distributing your tables. Now, it&apos;s time to run your first query!
</Text>
<DefaultButton
style={{ marginTop: 16, width: 115 }}
onClick={() => useTerminal.getState().sendMessage(queryCommand)}
>
Try queries
</DefaultButton>
<Stack horizontal style={{ marginTop: 16 }}>
<TextField
id="queryCommand"
multiline
rows={5}
readOnly
defaultValue={queryCommandForDisplay}
styles={{
root: { width: "90%" },
field: {
backgroundColor: "#EEEEEE",
fontFamily:
"Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New",
},
}}
/>
<IconButton
iconProps={{
iconName: "Copy",
}}
onClick={() => onCopyBtnClicked("#queryCommand")}
/>
</Stack>
<Youtube videoId="k_EanjMtaPg" style={{ margin: "20px 0" }} opts={{ width: "90%" }} />
</Stack>
</PivotItem>
</Pivot>
)}
{currentStep === 5 && (
<Stack style={{ margin: "auto" }} horizontalAlign="center">
<Image src={CompleteIcon} />
<Text variant="mediumPlus" style={{ fontWeight: 900, marginTop: 7 }}>
You are all set!
</Text>
<Text variant="mediumPlus" style={{ marginTop: 8 }}>
You have completed the quick start guide.{" "}
</Text>
</Stack>
)}
</Stack>
<Stack horizontal style={{ padding: "16px 20px", boxShadow: "inset 0px 1px 0px rgba(204, 204, 204, 0.8)" }}>
<DefaultButton disabled={currentStep === 0} onClick={() => setCurrentStep(currentStep - 1)}>
Previous
</DefaultButton>
{currentStep < 5 && (
<PrimaryButton onClick={() => setCurrentStep(currentStep + 1)} style={{ marginLeft: 8 }}>
Next
</PrimaryButton>
)}
{currentStep === 5 && (
<PrimaryButton
onClick={() => useTabs.getState().closeReactTab(ReactTabKind.Quickstart)}
style={{ marginLeft: 8 }}
>
Close
</PrimaryButton>
)}
</Stack>
</Stack>
);
};

View File

@@ -1,202 +0,0 @@
import { Link, Stack, TeachingBubble, Text } from "@fluentui/react";
import { ReactTabKind, useTabs } from "hooks/useTabs";
import { useTeachingBubble } from "hooks/useTeachingBubble";
import React from "react";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceCancel, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
export const MongoQuickstartTutorial: React.FC = (): JSX.Element => {
const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble();
const onDimissTeachingBubble = (): void => {
setStep(0);
traceCancel(Action.CancelUITour, { step });
};
if (userContext.apiType !== "Mongo") {
return <></>;
}
switch (step) {
case 1:
return isSampleDBExpanded ? (
<TeachingBubble
headline="View sample data"
target={"#sampleItems"}
hasCloseButton
primaryButtonProps={{
text: "Open Items",
onClick: () => {
sampleCollection.openTab();
setStep(2);
},
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 1 of 8"
>
Start viewing and working with your data by opening Documents under Data
</TeachingBubble>
) : (
<></>
);
case 2:
return isDocumentsTabOpened ? (
<TeachingBubble
headline="View Documents"
target={".documentsGridHeaderContainer"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(3),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(1),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 2 of 8"
>
View documents here using the documents window. You can also use your favorite MongoDB tools and drivers to do
so.
</TeachingBubble>
) : (
<></>
);
case 3:
return (
<TeachingBubble
headline="Add new document"
target={"#mongoNewDocumentBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(4),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(2),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 3 of 8"
>
Add new document by copy / pasting JSON or uploading a JSON. You can also use your favorite MongoDB tools and
drivers to do so.
</TeachingBubble>
);
case 4:
return (
<TeachingBubble
headline="Run a query"
target={".querydropdown"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(5),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(3),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 4 of 8"
>
Query your data using the filter function. Azure Cosmos DB for MongoDB provides comprehensive support for
MongoDB query language constructs. You can also use your favorite MongoDB tools and drivers to do so.
</TeachingBubble>
);
case 5:
return (
<TeachingBubble
headline="Scale throughput"
target={"#sampleScaleSettings"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(6),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(4),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 5 of 8"
>
Change throughput provisioned to your collection according to your needs
</TeachingBubble>
);
case 6:
return (
<TeachingBubble
headline="Indexing Policy"
target={"#sampleSettings"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(7),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(5),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 6 of 8"
>
Use the indexing policy editor to create and edit your indexes.
</TeachingBubble>
);
case 7:
return (
<TeachingBubble
headline="Create notebook"
target={"#newNotebookBtn"}
hasCloseButton
primaryButtonProps={{
text: "Next",
onClick: () => setStep(8),
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(6),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 7 of 8"
>
Visualize your data, store queries in an interactive document
</TeachingBubble>
);
case 8:
return (
<TeachingBubble
headline="Congratulations!"
target={"#newNotebookBtn"}
hasCloseButton
primaryButtonProps={{
text: "Launch connect",
onClick: () => {
traceSuccess(Action.CompleteUITour);
useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect);
},
}}
secondaryButtonProps={{
text: "Previous",
onClick: () => setStep(7),
}}
onDismiss={() => onDimissTeachingBubble()}
footerContent="Step 8 of 8"
>
<Stack>
<Text style={{ color: "white" }}>
You have finished the tour in data explorer. For next steps, you may want to launch connect and start
connecting with your current app.
</Text>
<Link style={{ color: "white", fontWeight: 600 }} target="_blank" href="https://aka.ms/cosmosdbsurvey">
Share your feedback
</Link>
</Stack>
</TeachingBubble>
);
default:
return <></>;
}
};

View File

@@ -14,6 +14,10 @@
padding-right: 16px; padding-right: 16px;
max-width: 1168px; max-width: 1168px;
> * {
justify-content: space-between;
}
> .title { > .title {
position: relative; // To attach FeaturePanelLauncher as absolute position: relative; // To attach FeaturePanelLauncher as absolute
color: @BaseHigh; color: @BaseHigh;
@@ -36,7 +40,6 @@
text-align: center; text-align: center;
cursor: pointer; cursor: pointer;
margin: 40px auto; margin: 40px auto;
width: 84%;
> .mainButton { > .mainButton {
min-width: 124px; min-width: 124px;

View File

@@ -1,41 +1,37 @@
/** /**
* Accordion top class * Accordion top class
*/ */
import { import { Coachmark, DirectionalHint, Image, Link, Stack, TeachingBubbleContent, Text } from "@fluentui/react";
Coachmark,
DirectionalHint,
Image,
Link,
Stack,
TeachingBubble,
TeachingBubbleContent,
Text
} from "@fluentui/react";
import { sendMessage } from "Common/MessageHandler";
import { MessageTypes } from "Contracts/ExplorerContracts";
import { TerminalKind } from "Contracts/ViewModels";
import { useCarousel } from "hooks/useCarousel"; import { useCarousel } from "hooks/useCarousel";
import { usePostgres } from "hooks/usePostgres"; import { useTabs } from "hooks/useTabs";
import { ReactTabKind, useTabs } from "hooks/useTabs";
import * as React from "react"; import * as React from "react";
import { Action } from "Shared/Telemetry/TelemetryConstants"; import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor"; import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import AddDatabaseIcon from "../../../images/AddDatabase.svg";
import NewQueryIcon from "../../../images/AddSqlQuery_16x16.svg";
import NewStoredProcedureIcon from "../../../images/AddStoredProcedure.svg";
import OpenQueryIcon from "../../../images/BrowseQuery.svg";
import ConnectIcon from "../../../images/Connect_color.svg"; import ConnectIcon from "../../../images/Connect_color.svg";
import ContainersIcon from "../../../images/Containers.svg"; import ContainersIcon from "../../../images/Containers.svg";
import LinkIcon from "../../../images/Link_blue.svg"; import LinkIcon from "../../../images/Link_blue.svg";
import NotebookIcon from "../../../images/notebook/Notebook-resource.svg"; import NotebookIcon from "../../../images/notebook/Notebook-resource.svg";
import NotebookColorIcon from "../../../images/Notebooks.svg"; import NotebookColorIcon from "../../../images/Notebooks.svg";
import PowerShellIcon from "../../../images/PowerShell.svg";
import QuickStartIcon from "../../../images/Quickstart_Lightning.svg"; import QuickStartIcon from "../../../images/Quickstart_Lightning.svg";
import ScaleAndSettingsIcon from "../../../images/Scale_15x15.svg";
import CollectionIcon from "../../../images/tree-collection.svg"; import CollectionIcon from "../../../images/tree-collection.svg";
import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants"; import * as Constants from "../../Common/Constants";
import * as ViewModels from "../../Contracts/ViewModels";
import { useSidePanel } from "../../hooks/useSidePanel";
import { userContext } from "../../UserContext"; import { userContext } from "../../UserContext";
import { getCollectionName } from "../../Utils/APITypeUtils"; import { getCollectionName, getDatabaseName } from "../../Utils/APITypeUtils";
import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher"; import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher";
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil"; import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
import Explorer from "../Explorer"; import Explorer from "../Explorer";
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity"; import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
import { useNotebook } from "../Notebook/useNotebook"; import { useNotebook } from "../Notebook/useNotebook";
import { AddDatabasePanel } from "../Panes/AddDatabasePanel/AddDatabasePanel";
import { BrowseQueriesPane } from "../Panes/BrowseQueriesPane/BrowseQueriesPane";
import { useDatabases } from "../useDatabases"; import { useDatabases } from "../useDatabases";
import { useSelectedNode } from "../useSelectedNode"; import { useSelectedNode } from "../useSelectedNode";
@@ -87,18 +83,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
() => this.setState({}), () => this.setState({}),
(state) => state.showCoachMark (state) => state.showCoachMark
), ),
},
{
dispose: usePostgres.subscribe(
() => this.setState({}),
(state) => state.showPostgreTeachingBubble
),
},
{
dispose: usePostgres.subscribe(
() => this.setState({}),
(state) => state.showResetPasswordBubble
),
} }
); );
} }
@@ -117,47 +101,13 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
<div className="splashScreenContainer"> <div className="splashScreenContainer">
<div className="splashScreen"> <div className="splashScreen">
<div className="title"> <div className="title">
{userContext.apiType === "Postgres" Welcome to Cosmos DB
? "Welcome to Azure Cosmos DB for PostgreSQL"
: "Welcome to Azure Cosmos DB"}
<FeaturePanelLauncher /> <FeaturePanelLauncher />
</div> </div>
<div className="subtitle"> <div className="subtitle">Globally distributed, multi-model database service for any scale</div>
{userContext.apiType === "Postgres"
? "Get started with our sample datasets, documentation, and additional tools."
: "Globally distributed, multi-model database service for any scale"}
</div>
<div className="mainButtonsContainer"> <div className="mainButtonsContainer">
{userContext.apiType === "Postgres" &&
usePostgres.getState().showPostgreTeachingBubble &&
!usePostgres.getState().showResetPasswordBubble && (
<TeachingBubble
headline="New to Cosmos DB PGSQL?"
target={"#mainButton-quickstartDescription"}
hasCloseButton
onDismiss={() => usePostgres.getState().setShowPostgreTeachingBubble(false)}
calloutProps={{
directionalHint: DirectionalHint.rightCenter,
directionalHintFixed: true,
preventDismissOnLostFocus: true,
preventDismissOnResize: true,
preventDismissOnScroll: true,
}}
primaryButtonProps={{
text: "Get started",
onClick: () => {
useTabs.getState().openAndActivateReactTab(ReactTabKind.Quickstart);
usePostgres.getState().setShowPostgreTeachingBubble(false);
},
}}
>
Welcome! If you are new to Cosmos DB PGSQL and need help with getting started, here is where you
can find sample data, query.
</TeachingBubble>
)}
{mainItems.map((item) => ( {mainItems.map((item) => (
<Stack <Stack
id={`mainButton-${item.id}`}
horizontal horizontal
className="mainButton focusable" className="mainButton focusable"
key={`${item.title}`} key={`${item.title}`}
@@ -181,36 +131,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
</div> </div>
</Stack> </Stack>
))} ))}
{userContext.apiType === "Postgres" && usePostgres.getState().showResetPasswordBubble && (
<TeachingBubble
headline="Create your password"
target={"#mainButton-quickstartDescription"}
hasCloseButton
onDismiss={() => {
localStorage.setItem(userContext.databaseAccount.id, "true");
usePostgres.getState().setShowResetPasswordBubble(false);
}}
calloutProps={{
directionalHint: DirectionalHint.bottomRightEdge,
directionalHintFixed: true,
preventDismissOnLostFocus: true,
preventDismissOnResize: true,
preventDismissOnScroll: true,
}}
primaryButtonProps={{
text: "Create",
onClick: () => {
localStorage.setItem(userContext.databaseAccount.id, "true");
sendMessage({
type: MessageTypes.OpenPostgreSQLPasswordReset,
});
usePostgres.getState().setShowResetPasswordBubble(false);
},
}}
>
If you haven&apos;t changed your password yet, change it now.
</TeachingBubble>
)}
</div> </div>
{useCarousel.getState().showCoachMark && ( {useCarousel.getState().showCoachMark && (
<Coachmark <Coachmark
@@ -240,50 +160,20 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
</TeachingBubbleContent> </TeachingBubbleContent>
</Coachmark> </Coachmark>
)} )}
{userContext.apiType === "Postgres" ? ( <div className="moreStuffContainer">
<Stack horizontal style={{ margin: "0 auto", width: "84%" }} tokens={{ childrenGap: 32 }}> <div className="moreStuffColumn commonTasks">
<Stack style={{ width: "33%" }}> <div className="title">Recents</div>
<Text {this.getRecentItems()}
variant="large"
style={{
marginBottom: 16,
fontFamily: '"Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif',
}}
>
Next steps
</Text>
{this.getNextStepItems()}
</Stack>
<Stack style={{ width: "33%" }}>
<Text
variant="large"
style={{
marginBottom: 16,
fontFamily: '"Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif',
}}
>
Tips & learn more
</Text>
{this.getTipsAndLearnMoreItems()}
</Stack>
<Stack style={{ width: "33%" }}></Stack>
</Stack>
) : (
<div className="moreStuffContainer">
<div className="moreStuffColumn commonTasks">
<div className="title">Recents</div>
{this.getRecentItems()}
</div>
<div className="moreStuffColumn">
<div className="title">Top 3 things you need to know</div>
{this.top3Items()}
</div>
<div className="moreStuffColumn tipsContainer">
<div className="title">Learning Resources</div>
{this.getLearningResourceItems()}
</div>
</div> </div>
)} <div className="moreStuffColumn">
<div className="title">Top 3 things you need to know</div>
{this.top3Items()}
</div>
<div className="moreStuffColumn tipsContainer">
<div className="title">Learning Resources</div>
{this.getLearningResourceItems()}
</div>
</div>
</div> </div>
</div> </div>
</form> </form>
@@ -304,19 +194,16 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
public createMainItems(): SplashScreenItem[] { public createMainItems(): SplashScreenItem[] {
const heroes: SplashScreenItem[] = []; const heroes: SplashScreenItem[] = [];
if ( if (userContext.apiType === "SQL" || userContext.apiType === "Mongo") {
userContext.apiType === "SQL" ||
userContext.apiType === "Mongo" ||
(userContext.apiType === "Postgres" && !userContext.isReplica)
) {
const launchQuickstartBtn = { const launchQuickstartBtn = {
id: "quickstartDescription", id: "quickstartDescription",
iconSrc: QuickStartIcon, iconSrc: QuickStartIcon,
title: "Launch quick start", title: "Launch quick start",
description: "Launch a quick start tutorial to get started with sample data", description: "Launch a quick start tutorial to get started with sample data",
showLinkIcon: userContext.apiType === "Mongo",
onClick: () => { onClick: () => {
userContext.apiType === "Postgres" userContext.apiType === "Mongo"
? useTabs.getState().openAndActivateReactTab(ReactTabKind.Quickstart) ? window.open("http://aka.ms/mongodbquickstart", "_blank")
: this.container.onNewCollectionClicked({ isQuickstart: true }); : this.container.onNewCollectionClicked({ isQuickstart: true });
traceOpen(Action.LaunchQuickstart, { apiType: userContext.apiType }); traceOpen(Action.LaunchQuickstart, { apiType: userContext.apiType });
}, },
@@ -332,41 +219,118 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
heroes.push(newNotebookBtn); heroes.push(newNotebookBtn);
} }
if (userContext.apiType === "Postgres") { const newContainerBtn = {
const postgreShellBtn = { iconSrc: ContainersIcon,
iconSrc: PowerShellIcon, title: `New ${getCollectionName()}`,
title: "PostgreSQL Shell", description: "Create a new container for storage and throughput",
description: "Create table and interact with data using PostgreSQLs shell interface", onClick: () => {
onClick: () => this.container.openNotebookTerminal(TerminalKind.Postgres), this.container.onNewCollectionClicked();
}; traceOpen(Action.NewContainerHomepage, { apiType: userContext.apiType });
heroes.push(postgreShellBtn); },
} else { };
const newContainerBtn = { heroes.push(newContainerBtn);
iconSrc: ContainersIcon,
title: `New ${getCollectionName()}`,
description: "Create a new container for storage and throughput",
onClick: () => {
this.container.onNewCollectionClicked();
traceOpen(Action.NewContainerHomepage, { apiType: userContext.apiType });
},
};
heroes.push(newContainerBtn);
}
const connectBtn = { const connectBtn = {
iconSrc: ConnectIcon, iconSrc: ConnectIcon,
title: userContext.apiType === "Postgres" ? "Connect with pgAdmin" : "Connect", title: "Connect",
description: description: "Prefer using your own choice of tooling? Find the connection string you need to connect",
userContext.apiType === "Postgres" onClick: () => useTabs.getState().openAndActivateConnectTab(),
? "Prefer pgAdmin? Find your connection strings here"
: "Prefer using your own choice of tooling? Find the connection string you need to connect",
onClick: () => useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect),
}; };
heroes.push(connectBtn); heroes.push(connectBtn);
return heroes; return heroes;
} }
private createCommonTaskItems(): SplashScreenItem[] {
const items: SplashScreenItem[] = [];
if (userContext.authType === AuthType.ResourceToken) {
return items;
}
if (!useSelectedNode.getState().isDatabaseNodeOrNoneSelected()) {
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
items.push({
iconSrc: NewQueryIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewQueryClick(selectedCollection, undefined);
},
title: "New SQL Query",
description: undefined,
});
} else if (userContext.apiType === "Mongo") {
items.push({
iconSrc: NewQueryIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewMongoQueryClick(selectedCollection, undefined);
},
title: "New Query",
description: undefined,
});
}
if (userContext.apiType === "SQL") {
items.push({
iconSrc: OpenQueryIcon,
title: "Open Query",
description: undefined,
onClick: () =>
useSidePanel
.getState()
.openSidePanel("Open Saved Queries", <BrowseQueriesPane explorer={this.container} />),
});
}
if (userContext.apiType !== "Cassandra") {
items.push({
iconSrc: NewStoredProcedureIcon,
title: "New Stored Procedure",
description: undefined,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
},
});
}
/* Scale & Settings */
const isShared = useDatabases.getState().findSelectedDatabase()?.isDatabaseShared();
const label = isShared ? "Settings" : "Scale & Settings";
items.push({
iconSrc: ScaleAndSettingsIcon,
title: label,
description: undefined,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onSettingsClick();
},
});
} else {
items.push({
iconSrc: AddDatabaseIcon,
title: "New " + getDatabaseName(),
description: undefined,
onClick: async () => {
const throughputCap = userContext.databaseAccount?.properties.capacity?.totalThroughputLimit;
if (throughputCap && throughputCap !== -1) {
await useDatabases.getState().loadAllOffers();
}
useSidePanel
.getState()
.openSidePanel(
"New " + getDatabaseName(),
<AddDatabasePanel explorer={this.container} buttonElement={document.activeElement as HTMLElement} />
);
},
});
}
return items;
}
private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) { private decorateOpenCollectionActivity({ databaseId, collectionId }: MostRecentActivity.OpenCollectionItem) {
return { return {
iconSrc: CollectionIcon, iconSrc: CollectionIcon,
@@ -408,6 +372,29 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
}); });
} }
private createTipsItems(): SplashScreenItem[] {
return [
{
iconSrc: undefined,
title: "Data Modeling",
description: "Learn more about modeling",
onClick: () => window.open(SplashScreen.dataModelingUrl),
},
{
iconSrc: undefined,
title: "Cost & Throughput Calculation",
description: "Learn more about cost calculation",
onClick: () => window.open(SplashScreen.throughputEstimatorUrl),
},
{
iconSrc: undefined,
title: "Configure automatic failover",
description: "Learn more about Cosmos DB high-availability",
onClick: () => window.open(SplashScreen.failoverUrl),
},
];
}
private onSplashScreenItemKeyPress(event: React.KeyboardEvent, callback: () => void) { private onSplashScreenItemKeyPress(event: React.KeyboardEvent, callback: () => void) {
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) { if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
callback(); callback();
@@ -419,7 +406,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
let items: { link: string; title: string; description: string }[]; let items: { link: string; title: string; description: string }[];
switch (userContext.apiType) { switch (userContext.apiType) {
case "SQL": case "SQL":
case "Postgres":
items = [ items = [
{ {
link: "https://aka.ms/msl-modeling-partitioning-2", link: "https://aka.ms/msl-modeling-partitioning-2",
@@ -443,7 +429,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
{ {
link: "https://aka.ms/mongodbintro", link: "https://aka.ms/mongodbintro",
title: "What is the MongoDB API?", title: "What is the MongoDB API?",
description: "Understand Azure Cosmos DB for MongoDB and its features.", description: "Understand the Cosmos DB API for MongoDB and its features.",
}, },
{ {
link: "https://aka.ms/mongodbfeaturesupport", link: "https://aka.ms/mongodbfeaturesupport",
@@ -500,7 +486,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
{ {
link: "https://aka.ms/tableintro", link: "https://aka.ms/tableintro",
title: "What is the Table API?", title: "What is the Table API?",
description: "Understand Azure Cosmos DB for Table and its features", description: "Understand the Table API in Cosmos DB and its features",
}, },
{ {
link: "https://aka.ms/tableimport", link: "https://aka.ms/tableimport",
@@ -509,8 +495,8 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
}, },
{ {
link: "https://aka.ms/tablefaq", link: "https://aka.ms/tablefaq",
title: "Azure Cosmos DB for Table FAQs", title: "Table API FAQs",
description: "Common questions about Azure Cosmos DB for Table", description: "Common questions about the Table API",
}, },
]; ];
break; break;
@@ -528,7 +514,7 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
> >
{item.title} {item.title}
</Link> </Link>
<Image src={LinkIcon} alt=" " /> <Image src={LinkIcon} />
</Stack> </Stack>
<Text>{item.description}</Text> <Text>{item.description}</Text>
</Stack> </Stack>
@@ -566,7 +552,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
let items: { link: string; title: string; description: string }[]; let items: { link: string; title: string; description: string }[];
switch (userContext.apiType) { switch (userContext.apiType) {
case "SQL": case "SQL":
case "Postgres":
items = [ items = [
{ {
link: "https://aka.ms/msl-sdk-connect", link: "https://aka.ms/msl-sdk-connect",
@@ -647,17 +632,17 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
{ {
link: "https://aka.ms/tabledotnet", link: "https://aka.ms/tabledotnet",
title: "Build a .NET App", title: "Build a .NET App",
description: "How to access Azure Cosmos DB for Table from a .NET app.", description: "How to access Table API from a .NET app.",
}, },
{ {
link: "https://aka.ms/Tablejava", link: "https://aka.ms/Tablejava",
title: "Build a Java App", title: "Build a Java App",
description: "Create a Azure Cosmos DB for Table app with Java SDK ", description: "Create a Table API app with Java SDK ",
}, },
{ {
link: "https://aka.ms/tablenodejs", link: "https://aka.ms/tablenodejs",
title: "Build a Node.js App", title: "Build a Node.js App",
description: "Create a Azure Cosmos DB for Table app with Node.js SDK", description: "Create a Table API app with Node.js SDK",
}, },
]; ];
break; break;
@@ -685,76 +670,4 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
</Stack> </Stack>
); );
} }
private getNextStepItems(): JSX.Element {
const items: { link: string; title: string; description: string }[] = [
{
link: "https://go.microsoft.com/fwlink/?linkid=2208312",
title: "Data Modeling",
description: "",
},
{
link: " https://go.microsoft.com/fwlink/?linkid=2206941 ",
title: "How to choose a Distribution Column",
description: "",
},
{
link: "https://go.microsoft.com/fwlink/?linkid=2207425",
title: "Build Apps with Python/Java/Django",
description: "",
},
];
return (
<Stack style={{ minWidth: 124, maxWidth: 296 }}>
{items.map((item, i) => (
<Stack key={`nextStep${i}`} style={{ marginBottom: 26 }}>
<Stack horizontal verticalAlign="center" style={{ fontSize: 14 }}>
<Link href={item.link} target="_blank" style={{ marginRight: 5 }}>
{item.title}
</Link>
<Image src={LinkIcon} />
</Stack>
<Text>{item.description}</Text>
</Stack>
))}
</Stack>
);
}
private getTipsAndLearnMoreItems(): JSX.Element {
const items: { link: string; title: string; description: string }[] = [
{
link: "https://go.microsoft.com/fwlink/?linkid=2207226",
title: "Performance Tuning",
description: "",
},
{
link: "https://go.microsoft.com/fwlink/?linkid=2208037",
title: "Useful Diagnostic Queries",
description: "",
},
{
link: "https://go.microsoft.com/fwlink/?linkid=2205270",
title: "Distributed SQL Reference",
description: "",
},
];
return (
<Stack style={{ minWidth: 124, maxWidth: 296 }}>
{items.map((item, i) => (
<Stack key={`tips${i}`} style={{ marginBottom: 26 }}>
<Stack horizontal verticalAlign="center" style={{ fontSize: 14 }}>
<Link href={item.link} target="_blank" style={{ marginRight: 5 }}>
{item.title}
</Link>
<Image src={LinkIcon} />
</Stack>
<Text>{item.description}</Text>
</Stack>
))}
</Stack>
);
}
} }

View File

@@ -516,7 +516,7 @@ export default class QueryBuilderViewModel {
}; };
public onAddNewClauseKeyDown = (event: KeyboardEvent): boolean => { public onAddNewClauseKeyDown = (event: KeyboardEvent): boolean => {
if (event.key === "Enter" || event.key === "Space") { if (event.keyCode === KeyCodes.Enter || event.keyCode === KeyCodes.Space) {
this.addClauseIndex(this.clauseArray().length - 1); this.addClauseIndex(this.clauseArray().length - 1);
event.stopPropagation(); event.stopPropagation();
return false; return false;

View File

@@ -811,7 +811,6 @@ export default class DocumentsTab extends TabsBase {
ariaLabel: label, ariaLabel: label,
hasPopup: false, hasPopup: false,
disabled: !this.newDocumentButton.enabled(), disabled: !this.newDocumentButton.enabled(),
id: "mongoNewDocumentBtn",
}); });
} }

View File

@@ -1,145 +0,0 @@
import {
Checkbox,
Dropdown,
Icon,
IconButton,
IDropdownOption,
ITextFieldStyles,
Label,
Link,
Stack,
Text,
TextField,
TooltipHost,
} from "@fluentui/react";
import React from "react";
import { userContext } from "UserContext";
export const PostgresConnectTab: React.FC = (): JSX.Element => {
const { adminLogin, nodes, enablePublicIpAccess } = userContext.postgresConnectionStrParams;
const [usePgBouncerPort, setUsePgBouncerPort] = React.useState<boolean>(false);
const [selectedNode, setSelectedNode] = React.useState<string>(nodes?.[0]?.value);
const portNumber = usePgBouncerPort ? "6432" : "5432";
const onCopyBtnClicked = (selector: string): void => {
const textfield: HTMLInputElement = document.querySelector(selector);
textfield.select();
document.execCommand("copy");
};
const textfieldStyles: Partial<ITextFieldStyles> = {
root: { width: "100%" },
field: { backgroundColor: "rgb(230, 230, 230)" },
fieldGroup: { borderColor: "rgb(138, 136, 134)" },
subComponentStyles: { label: { fontWeight: 400 } },
description: { fontWeight: 400 },
};
const nodesDropdownOptions: IDropdownOption[] = nodes.map((node) => ({
key: node.value,
text: node.text,
}));
const postgresSQLConnectionURL = `postgres://${adminLogin}:{your_password}@${selectedNode}:${portNumber}/citus?sslmode=require`;
const psql = `psql "host=${selectedNode} port=${portNumber} dbname=citus user=${adminLogin} password={your_password} sslmode=require"`;
const jdbc = `jdbc:postgresql://${selectedNode}:${portNumber}/citus?user=${adminLogin}&password={your_password}&sslmode=require`;
const libpq = `host=${selectedNode} port=${portNumber} dbname=citus user=${adminLogin} password={your_password} sslmode=require`;
const adoDotNet = `Server=${selectedNode};Database=citus;Port=${portNumber};User Id=${adminLogin};Password={your_password};Ssl Mode=Require;`;
return (
<div style={{ width: "100%", padding: 16 }}>
<Stack horizontal verticalAlign="center" style={{ marginBottom: 8 }}>
<Label style={{ marginRight: 8 }}>Public IP addresses on worker nodes:</Label>
<TooltipHost
content="
You can enable or disable public IP addresses on the worker nodes on 'Networking' page of your server group."
>
<Icon style={{ margin: "5px 8px 0 0", cursor: "default" }} iconName="Info" />
</TooltipHost>
<TextField value={enablePublicIpAccess ? "On" : "Off"} readOnly disabled />
</Stack>
<Stack horizontal style={{ marginBottom: 8 }}>
<Label style={{ marginRight: 85 }}>Show connection strings for</Label>
<Dropdown
options={nodesDropdownOptions}
selectedKey={selectedNode}
onChange={(_, option) => {
const selectedNode = option.key as string;
setSelectedNode(selectedNode);
if (!selectedNode.startsWith("c.")) {
setUsePgBouncerPort(false);
}
}}
style={{ width: 200 }}
/>
</Stack>
<Stack horizontal style={{ marginBottom: 8 }}>
<Label style={{ marginRight: 44 }}>PgBouncer connection strings</Label>
<Checkbox
boxSide="end"
checked={usePgBouncerPort}
onChange={(_, checked: boolean) => setUsePgBouncerPort(checked)}
disabled={!selectedNode?.startsWith("c.")}
/>
</Stack>
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
<TextField
label="PostgreSQL connection URL"
id="postgresSQLConnectionURL"
readOnly
value={postgresSQLConnectionURL}
styles={textfieldStyles}
/>
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#postgresSQLConnectionURL")} />
</Stack>
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
<TextField label="psql" id="psql" readOnly value={psql} styles={textfieldStyles} />
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#psql")} />
</Stack>
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
<TextField label="JDBC" id="JDBC" readOnly value={jdbc} styles={textfieldStyles} />
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#JDBC")} />
</Stack>
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
<TextField
label="Node.js, Python, Ruby, PHP, C++ (libpq)"
id="libpq"
readOnly
value={libpq}
styles={textfieldStyles}
/>
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#libpq")} />
</Stack>
<Stack horizontal verticalAlign="end" style={{ marginBottom: 8 }}>
<TextField label="ADO.NET" id="adoDotNet" readOnly value={adoDotNet} styles={textfieldStyles} />
<IconButton iconProps={{ iconName: "Copy" }} onClick={() => onCopyBtnClicked("#adoDotNet")} />
</Stack>
<Label>Secure connections</Label>
<Text style={{ marginBottom: 8 }}>
Only secure connections are supported. For production use cases, we recommend using the &apos;verify-full&apos;
mode to enforce TLS certificate verification. You will need to download the Hyperscale (Citus) certificate, and
provide it when connecting to the database.{" "}
<Link href="https://go.microsoft.com/fwlink/?linkid=2155061" target="_blank">
Learn more
</Link>
</Text>
<Label>Connect with pgAdmin</Label>
<Text>
Refer to our{" "}
<Link
href="https://learn.microsoft.com/en-us/azure/postgresql/hyperscale/howto-connect?tabs=pgadmin"
target="_blank"
>
guide
</Link>{" "}
to help you connect via pgAdmin.
</Text>
</div>
);
};

View File

@@ -600,43 +600,56 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
metricsMap.forEach((queryMetrics) => { metricsMap.forEach((queryMetrics) => {
if (queryMetrics) { if (queryMetrics) {
aggregatedMetrics.documentLoadTime = aggregatedMetrics.documentLoadTime =
queryMetrics.documentLoadTime &&
this._normalize(queryMetrics.documentLoadTime.totalMilliseconds()) + this._normalize(queryMetrics.documentLoadTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.documentLoadTime); this._normalize(aggregatedMetrics.documentLoadTime);
aggregatedMetrics.documentWriteTime = aggregatedMetrics.documentWriteTime =
queryMetrics.documentWriteTime &&
this._normalize(queryMetrics.documentWriteTime.totalMilliseconds()) + this._normalize(queryMetrics.documentWriteTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.documentWriteTime); this._normalize(aggregatedMetrics.documentWriteTime);
aggregatedMetrics.indexHitDocumentCount = aggregatedMetrics.indexHitDocumentCount =
queryMetrics.indexHitDocumentCount &&
this._normalize(queryMetrics.indexHitDocumentCount) + this._normalize(queryMetrics.indexHitDocumentCount) +
this._normalize(aggregatedMetrics.indexHitDocumentCount); this._normalize(aggregatedMetrics.indexHitDocumentCount);
aggregatedMetrics.outputDocumentCount = aggregatedMetrics.outputDocumentCount =
queryMetrics.outputDocumentCount &&
this._normalize(queryMetrics.outputDocumentCount) + this._normalize(aggregatedMetrics.outputDocumentCount); this._normalize(queryMetrics.outputDocumentCount) + this._normalize(aggregatedMetrics.outputDocumentCount);
aggregatedMetrics.outputDocumentSize = aggregatedMetrics.outputDocumentSize =
queryMetrics.outputDocumentSize &&
this._normalize(queryMetrics.outputDocumentSize) + this._normalize(aggregatedMetrics.outputDocumentSize); this._normalize(queryMetrics.outputDocumentSize) + this._normalize(aggregatedMetrics.outputDocumentSize);
aggregatedMetrics.indexLookupTime = aggregatedMetrics.indexLookupTime =
queryMetrics.indexLookupTime &&
this._normalize(queryMetrics.indexLookupTime.totalMilliseconds()) + this._normalize(queryMetrics.indexLookupTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.indexLookupTime); this._normalize(aggregatedMetrics.indexLookupTime);
aggregatedMetrics.retrievedDocumentCount = aggregatedMetrics.retrievedDocumentCount =
queryMetrics.retrievedDocumentCount &&
this._normalize(queryMetrics.retrievedDocumentCount) + this._normalize(queryMetrics.retrievedDocumentCount) +
this._normalize(aggregatedMetrics.retrievedDocumentCount); this._normalize(aggregatedMetrics.retrievedDocumentCount);
aggregatedMetrics.retrievedDocumentSize = aggregatedMetrics.retrievedDocumentSize =
queryMetrics.retrievedDocumentSize &&
this._normalize(queryMetrics.retrievedDocumentSize) + this._normalize(queryMetrics.retrievedDocumentSize) +
this._normalize(aggregatedMetrics.retrievedDocumentSize); this._normalize(aggregatedMetrics.retrievedDocumentSize);
aggregatedMetrics.vmExecutionTime = aggregatedMetrics.vmExecutionTime =
queryMetrics.vmExecutionTime &&
this._normalize(queryMetrics.vmExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.vmExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.vmExecutionTime); this._normalize(aggregatedMetrics.vmExecutionTime);
aggregatedMetrics.totalQueryExecutionTime = aggregatedMetrics.totalQueryExecutionTime =
queryMetrics.totalQueryExecutionTime &&
this._normalize(queryMetrics.totalQueryExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.totalQueryExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.totalQueryExecutionTime); this._normalize(aggregatedMetrics.totalQueryExecutionTime);
aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime = aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime =
aggregatedMetrics.runtimeExecutionTimes &&
this._normalize(queryMetrics.runtimeExecutionTimes.queryEngineExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.runtimeExecutionTimes.queryEngineExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime); this._normalize(aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime);
aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime = aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime =
aggregatedMetrics.runtimeExecutionTimes &&
this._normalize(queryMetrics.runtimeExecutionTimes.systemFunctionExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.runtimeExecutionTimes.systemFunctionExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime); this._normalize(aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime);
aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime = aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime =
aggregatedMetrics.runtimeExecutionTimes &&
this._normalize(queryMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime.totalMilliseconds()) + this._normalize(queryMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime.totalMilliseconds()) +
this._normalize(aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime); this._normalize(aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime);
} }
}); });

View File

@@ -70,19 +70,24 @@
<tbody data-bind="template: { name: 'queryClause-template', foreach: clauseArray, as: 'clause' }"></tbody> <tbody data-bind="template: { name: 'queryClause-template', foreach: clauseArray, as: 'clause' }"></tbody>
</table> </table>
</div> </div>
<button <div
data-bind="click: addNewClause, event: { keydown: onAddNewClauseKeyDown }" class="addClause"
style="border: none; background: none" role="button"
data-bind="click: addNewClause, event: { keydown: onAddNewClauseKeyDown }, attr: { title: addNewClauseLine }"
tabindex="0"
> >
<div class="addClause" data-bind=" "> <div class="addClause-heading">
<div class="addClause-heading"> <span class="clause-table addClause-title">
<span class="clause-table addClause-title"> <img
<img class="addclauseProperty-Img" style="margin-bottom: 5px" src="/Add-property.svg" /> class="addclauseProperty-Img"
<span style="margin-left: 5px" data-bind="text: addNewClauseLine"></span> style="margin-bottom: 5px"
</span> src="/Add-property.svg"
</div> alt="Add new clause"
/>
<span style="margin-left: 5px" data-bind="text: addNewClauseLine"></span>
</span>
</div> </div>
</button> </div>
</div> </div>
</div> </div>
<!-- Tables Query Tab Query Helper - End--> <!-- Tables Query Tab Query Helper - End-->
@@ -163,20 +168,22 @@
<script type="text/html" id="queryClause-template"> <script type="text/html" id="queryClause-template">
<tr class="clause-table-row"> <tr class="clause-table-row">
<td class="clause-table-cell action-column"> <td class="clause-table-cell action-column">
<button <span
class="entity-Add-Cancel"
role="button"
tabindex="0"
data-bind="click: $parent.addClauseIndex.bind($data, $index()), event: { keydown: $parent.onAddClauseKeyDown.bind($data, $index()) }, attr:{title: $parent.insertNewFilterLine}" data-bind="click: $parent.addClauseIndex.bind($data, $index()), event: { keydown: $parent.onAddClauseKeyDown.bind($data, $index()) }, attr:{title: $parent.insertNewFilterLine}"
> >
<span class="entity-Add-Cancel" role="button"> <img class="querybuilder-addpropertyImg" src="/Add-property.svg" alt="Add clause" />
<img class="querybuilder-addpropertyImg" src="/Add-property.svg" alt="Add clause" /> </span>
</span> <span
</button> class="entity-Add-Cancel"
<button role="button"
tabindex="0"
data-bind="hasFocus: isDeleteButtonFocused, click: $parent.deleteClause.bind($data, $index()), event: { keydown: $parent.onDeleteClauseKeyDown.bind($data, $index()) }, attr:{title: $parent.removeThisFilterLine}" data-bind="hasFocus: isDeleteButtonFocused, click: $parent.deleteClause.bind($data, $index()), event: { keydown: $parent.onDeleteClauseKeyDown.bind($data, $index()) }, attr:{title: $parent.removeThisFilterLine}"
> >
<span class="entity-Add-Cancel" role="button"> <img class="querybuilder-cancelImg" src="/Entity_cancel.svg" alt="Delete clause" />
<img class="querybuilder-cancelImg" src="/Entity_cancel.svg" alt="Delete clause" /> </span>
</span>
</button>
</td> </td>
<td class="clause-table-cell group-control-column"> <td class="clause-table-cell group-control-column">
<input type="checkbox" aria-label="And/Or" data-bind="checked: checkedForGrouping" /> <input type="checkbox" aria-label="And/Or" data-bind="checked: checkedForGrouping" />

View File

@@ -1,85 +0,0 @@
import { Spinner, SpinnerSize, Stack, Text } from "@fluentui/react";
import { configContext } from "ConfigContext";
import { NotebookWorkspaceConnectionInfo, PostgresFirewallRule } from "Contracts/DataModels";
import { NotebookTerminalComponent } from "Explorer/Controls/Notebook/NotebookTerminalComponent";
import Explorer from "Explorer/Explorer";
import { useNotebook } from "Explorer/Notebook/useNotebook";
import { QuickstartFirewallNotification } from "Explorer/Quickstart/QuickstartFirewallNotification";
import { QuickstartGuide } from "Explorer/Quickstart/QuickstartGuide";
import { ReactTabKind, useTabs } from "hooks/useTabs";
import React, { useEffect, useState } from "react";
import { userContext } from "UserContext";
import { armRequest } from "Utils/arm/request";
interface QuickstartTabProps {
explorer: Explorer;
}
export const QuickstartTab: React.FC<QuickstartTabProps> = ({ explorer }: QuickstartTabProps): JSX.Element => {
const notebookServerInfo = useNotebook((state) => state.notebookServerInfo);
const [isAllPublicIPAddressEnabled, setIsAllPublicIPAddressEnabled] = useState<boolean>(true);
const getNotebookServerInfo = (): NotebookWorkspaceConnectionInfo => ({
authToken: notebookServerInfo.authToken,
notebookServerEndpoint: `${notebookServerInfo.notebookServerEndpoint?.replace(/\/+$/, "")}/postgresql`,
forwardingId: notebookServerInfo.forwardingId,
});
const checkFirewallRules = async (): Promise<void> => {
const firewallRulesUri = `${userContext.databaseAccount.id}/firewallRules`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response: any = await armRequest({
host: configContext.ARM_ENDPOINT,
path: firewallRulesUri,
method: "GET",
apiVersion: "2020-10-05-privatepreview",
});
const firewallRules: PostgresFirewallRule[] = response?.data?.value || response?.value || [];
const isEnabled = firewallRules.some(
(rule) => rule.properties.startIpAddress === "0.0.0.0" && rule.properties.endIpAddress === "255.255.255.255"
);
setIsAllPublicIPAddressEnabled(isEnabled);
// If the firewall rule is not added, check every 30 seconds to see if the user has added the rule
if (!isEnabled && useTabs.getState().activeReactTab === ReactTabKind.Quickstart) {
setTimeout(checkFirewallRules, 30000);
}
};
useEffect(() => {
checkFirewallRules();
});
useEffect(() => {
explorer.allocateContainer();
}, []);
return (
<Stack style={{ width: "100%" }} horizontal>
<Stack style={{ width: "50%" }}>
<QuickstartGuide />
</Stack>
<Stack style={{ width: "50%", borderLeft: "black solid 1px" }}>
{!isAllPublicIPAddressEnabled && <QuickstartFirewallNotification />}
{isAllPublicIPAddressEnabled && notebookServerInfo?.notebookServerEndpoint && (
<NotebookTerminalComponent
notebookServerInfo={getNotebookServerInfo()}
databaseAccount={userContext.databaseAccount}
tabId="QuickstartPSQLShell"
/>
)}
{isAllPublicIPAddressEnabled && !notebookServerInfo?.notebookServerEndpoint && (
<Stack style={{ margin: "auto 0" }}>
<Text block style={{ margin: "auto" }}>
Connecting to the PostgreSQL shell.
</Text>
<Text block style={{ margin: "auto" }}>
If the cluster was just created, this could take up to a minute.
</Text>
<Spinner styles={{ root: { marginTop: 16 } }} size={SpinnerSize.large}></Spinner>
</Stack>
)}
</Stack>
</Stack>
);
};

View File

@@ -1,59 +1,33 @@
import { MessageBar, MessageBarButton, MessageBarType } from "@fluentui/react";
import { sendMessage } from "Common/MessageHandler";
import { MessageTypes } from "Contracts/ExplorerContracts";
import { CollectionTabKind } from "Contracts/ViewModels"; import { CollectionTabKind } from "Contracts/ViewModels";
import Explorer from "Explorer/Explorer";
import { SplashScreen } from "Explorer/SplashScreen/SplashScreen";
import { ConnectTab } from "Explorer/Tabs/ConnectTab"; import { ConnectTab } from "Explorer/Tabs/ConnectTab";
import { PostgresConnectTab } from "Explorer/Tabs/PostgresConnectTab";
import { QuickstartTab } from "Explorer/Tabs/QuickstartTab";
import { useTeachingBubble } from "hooks/useTeachingBubble"; import { useTeachingBubble } from "hooks/useTeachingBubble";
import ko from "knockout"; import ko from "knockout";
import React, { MutableRefObject, useEffect, useRef, useState } from "react"; import React, { MutableRefObject, useEffect, useRef, useState } from "react";
import { userContext } from "UserContext";
import loadingIcon from "../../../images/circular_loader_black_16x16.gif"; import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
import errorIcon from "../../../images/close-black.svg"; import errorIcon from "../../../images/close-black.svg";
import { useObservable } from "../../hooks/useObservable"; import { useObservable } from "../../hooks/useObservable";
import { ReactTabKind, useTabs } from "../../hooks/useTabs"; import { useTabs } from "../../hooks/useTabs";
import TabsBase from "./TabsBase"; import TabsBase from "./TabsBase";
type Tab = TabsBase | (TabsBase & { render: () => JSX.Element }); type Tab = TabsBase | (TabsBase & { render: () => JSX.Element });
interface TabsProps { export const Tabs = (): JSX.Element => {
explorer: Explorer; const { openedTabs, activeTab } = useTabs();
} const isConnectTabOpen = useTabs((state) => state.isConnectTabOpen);
const isConnectTabActive = useTabs((state) => state.isConnectTabActive);
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
const { openedTabs, openedReactTabs, activeTab, activeReactTab, networkSettingsWarning } = useTabs();
return ( return (
<div className="tabsManagerContainer"> <div className="tabsManagerContainer">
{networkSettingsWarning && (
<MessageBar
messageBarType={MessageBarType.warning}
actions={
<MessageBarButton onClick={() => sendMessage({ type: MessageTypes.OpenPostgresNetworkingBlade })}>
Change network settings
</MessageBarButton>
}
messageBarIconProps={{ iconName: "WarningSolid", className: "messageBarWarningIcon" }}
>
{networkSettingsWarning}
</MessageBar>
)}
<div id="content" className="flexContainer hideOverflows"> <div id="content" className="flexContainer hideOverflows">
<div className="nav-tabs-margin"> <div className="nav-tabs-margin">
<ul className="nav nav-tabs level navTabHeight" id="navTabs" role="tablist"> <ul className="nav nav-tabs level navTabHeight" id="navTabs" role="tablist">
{openedReactTabs.map((tab) => ( {isConnectTabOpen && <TabNav key="connect" tab={undefined} active={isConnectTabActive} />}
<TabNav key={ReactTabKind[tab]} active={activeReactTab === tab} tabKind={tab} />
))}
{openedTabs.map((tab) => ( {openedTabs.map((tab) => (
<TabNav key={tab.tabId} tab={tab} active={activeTab === tab} /> <TabNav key={tab.tabId} tab={tab} active={activeTab === tab} />
))} ))}
</ul> </ul>
</div> </div>
<div className="tabPanesContainer"> <div className="tabPanesContainer">
{activeReactTab !== undefined && getReactTabContent(activeReactTab, explorer)} {isConnectTabActive && <ConnectTab />}
{openedTabs.map((tab) => ( {openedTabs.map((tab) => (
<TabPane key={tab.tabId} tab={tab} active={activeTab === tab} /> <TabPane key={tab.tabId} tab={tab} active={activeTab === tab} />
))} ))}
@@ -63,7 +37,7 @@ export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
); );
}; };
function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?: ReactTabKind }) { function TabNav({ tab, active }: { tab: Tab; active: boolean }) {
const [hovering, setHovering] = useState(false); const [hovering, setHovering] = useState(false);
const focusTab = useRef<HTMLLIElement>() as MutableRefObject<HTMLLIElement>; const focusTab = useRef<HTMLLIElement>() as MutableRefObject<HTMLLIElement>;
const tabId = tab ? tab.tabId : "connect"; const tabId = tab ? tab.tabId : "connect";
@@ -77,20 +51,8 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
<li <li
onMouseOver={() => setHovering(true)} onMouseOver={() => setHovering(true)}
onMouseLeave={() => setHovering(false)} onMouseLeave={() => setHovering(false)}
onClick={() => { onClick={() => (tab ? tab.onTabClick() : useTabs.getState().activateConnectTab())}
if (tab) { onKeyPress={({ nativeEvent: e }) => (tab ? tab.onKeyPressActivate(undefined, e) : onKeyPressConnectTab(e))}
tab.onTabClick();
} else if (tabKind !== undefined) {
useTabs.getState().activateReactTab(tabKind);
}
}}
onKeyPress={({ nativeEvent: e }) => {
if (tab) {
tab.onKeyPressActivate(undefined, e);
} else if (tabKind !== undefined) {
onKeyPressReactTab(e, tabKind);
}
}}
className={active ? "active tabList" : "tabList"} className={active ? "active tabList" : "tabList"}
title={useObservable(tab?.tabPath || ko.observable(""))} title={useObservable(tab?.tabPath || ko.observable(""))}
aria-selected={active} aria-selected={active}
@@ -103,18 +65,16 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
<span className="tabNavContentContainer"> <span className="tabNavContentContainer">
<a data-toggle="tab" href={"#" + tabId} tabIndex={-1}> <a data-toggle="tab" href={"#" + tabId} tabIndex={-1}>
<div className="tab_Content"> <div className="tab_Content">
<span className="statusIconContainer" style={{ width: tabKind === ReactTabKind.Home ? 0 : 18 }}> <span className="statusIconContainer">
{useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />} {useObservable(tab?.isExecutionError || ko.observable(false)) && <ErrorIcon tab={tab} active={active} />}
{useObservable(tab?.isExecuting || ko.observable(false)) && ( {useObservable(tab?.isExecuting || ko.observable(false)) && (
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" /> <img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
)} )}
</span> </span>
<span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable(ReactTabKind[tabKind]))}</span> <span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable("Connect"))}</span>
{tabKind !== ReactTabKind.Home && ( <span className="tabIconSection">
<span className="tabIconSection"> <CloseButton tab={tab} active={active} hovering={hovering} />
<CloseButton tab={tab} active={active} hovering={hovering} tabKind={tabKind} /> </span>
</span>
)}
</div> </div>
</a> </a>
</span> </span>
@@ -122,27 +82,14 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
); );
} }
const CloseButton = ({ const CloseButton = ({ tab, active, hovering }: { tab: Tab; active: boolean; hovering: boolean }) => (
tab,
active,
hovering,
tabKind,
}: {
tab: Tab;
active: boolean;
hovering: boolean;
tabKind?: ReactTabKind;
}) => (
<span <span
style={{ display: hovering || active ? undefined : "none" }} style={{ display: hovering || active ? undefined : "none" }}
title="Close" title="Close"
role="button" role="button"
aria-label="Close Tab" aria-label="Close Tab"
className="cancelButton" className="cancelButton"
onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => { onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeConnectTab())}
event.stopPropagation();
tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind);
}}
tabIndex={active ? 0 : undefined} tabIndex={active ? 0 : undefined}
onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)} onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)}
> >
@@ -197,22 +144,9 @@ function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
return <div {...attrs} ref={ref} data-bind="html:html" />; return <div {...attrs} ref={ref} data-bind="html:html" />;
} }
const onKeyPressReactTab = (e: KeyboardEvent, tabKind: ReactTabKind): void => { const onKeyPressConnectTab = (e: KeyboardEvent): void => {
if (e.key === "Enter" || e.key === "Space") { if (e.key === "Enter" || e.key === "Space") {
useTabs.getState().activateReactTab(tabKind); useTabs.getState().activateConnectTab();
e.stopPropagation(); e.stopPropagation();
} }
}; };
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
switch (activeReactTab) {
case ReactTabKind.Connect:
return userContext.apiType === "Postgres" ? <PostgresConnectTab /> : <ConnectTab />;
case ReactTabKind.Home:
return <SplashScreen explorer={explorer} />;
case ReactTabKind.Quickstart:
return <QuickstartTab explorer={explorer} />;
default:
throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
}
};

View File

@@ -1,9 +1,6 @@
import { Spinner, SpinnerSize } from "@fluentui/react"; import { Spinner, SpinnerSize } from "@fluentui/react";
import { configContext } from "ConfigContext";
import { QuickstartFirewallNotification } from "Explorer/Quickstart/QuickstartFirewallNotification";
import * as ko from "knockout"; import * as ko from "knockout";
import * as React from "react"; import * as React from "react";
import { armRequest } from "Utils/arm/request";
import { ReactAdapter } from "../../Bindings/ReactBindingHandler"; import { ReactAdapter } from "../../Bindings/ReactBindingHandler";
import * as DataModels from "../../Contracts/DataModels"; import * as DataModels from "../../Contracts/DataModels";
import * as ViewModels from "../../Contracts/ViewModels"; import * as ViewModels from "../../Contracts/ViewModels";
@@ -29,15 +26,10 @@ class NotebookTerminalComponentAdapter implements ReactAdapter {
constructor( constructor(
private getNotebookServerInfo: () => DataModels.NotebookWorkspaceConnectionInfo, private getNotebookServerInfo: () => DataModels.NotebookWorkspaceConnectionInfo,
private getDatabaseAccount: () => DataModels.DatabaseAccount, private getDatabaseAccount: () => DataModels.DatabaseAccount,
private getTabId: () => string, private getTabId: () => string
private isAllPublicIPAddressesEnabled: ko.Observable<boolean>
) {} ) {}
public renderComponent(): JSX.Element { public renderComponent(): JSX.Element {
if (!this.isAllPublicIPAddressesEnabled()) {
return <QuickstartFirewallNotification />;
}
return this.parameters() ? ( return this.parameters() ? (
<NotebookTerminalComponent <NotebookTerminalComponent
notebookServerInfo={this.getNotebookServerInfo()} notebookServerInfo={this.getNotebookServerInfo()}
@@ -54,33 +46,25 @@ export default class TerminalTab extends TabsBase {
public readonly html = '<div style="height: 100%" data-bind="react:notebookTerminalComponentAdapter"></div> '; public readonly html = '<div style="height: 100%" data-bind="react:notebookTerminalComponentAdapter"></div> ';
private container: Explorer; private container: Explorer;
private notebookTerminalComponentAdapter: NotebookTerminalComponentAdapter; private notebookTerminalComponentAdapter: NotebookTerminalComponentAdapter;
private isAllPublicIPAddressesEnabled: ko.Observable<boolean>;
constructor(options: TerminalTabOptions) { constructor(options: TerminalTabOptions) {
super(options); super(options);
this.container = options.container; this.container = options.container;
this.isAllPublicIPAddressesEnabled = ko.observable(true);
this.notebookTerminalComponentAdapter = new NotebookTerminalComponentAdapter( this.notebookTerminalComponentAdapter = new NotebookTerminalComponentAdapter(
() => this.getNotebookServerInfo(options), () => this.getNotebookServerInfo(options),
() => userContext?.databaseAccount, () => userContext?.databaseAccount,
() => this.tabId, () => this.tabId
this.isAllPublicIPAddressesEnabled
); );
this.notebookTerminalComponentAdapter.parameters = ko.computed<boolean>(() => { this.notebookTerminalComponentAdapter.parameters = ko.computed<boolean>(() => {
if ( if (
this.isTemplateReady() && this.isTemplateReady() &&
useNotebook.getState().isNotebookEnabled && useNotebook.getState().isNotebookEnabled &&
useNotebook.getState().notebookServerInfo?.notebookServerEndpoint && useNotebook.getState().notebookServerInfo?.notebookServerEndpoint
this.isAllPublicIPAddressesEnabled()
) { ) {
return true; return true;
} }
return false; return false;
}); });
if (options.kind === ViewModels.TerminalKind.Postgres) {
this.checkPostgresFirewallRules();
}
} }
public getContainer(): Explorer { public getContainer(): Explorer {
@@ -111,10 +95,6 @@ export default class TerminalTab extends TabsBase {
endpointSuffix = "cassandra"; endpointSuffix = "cassandra";
break; break;
case ViewModels.TerminalKind.Postgres:
endpointSuffix = "postgresql";
break;
default: default:
throw new Error(`Terminal kind: ${options.kind} not supported`); throw new Error(`Terminal kind: ${options.kind} not supported`);
} }
@@ -126,25 +106,4 @@ export default class TerminalTab extends TabsBase {
forwardingId: info.forwardingId, forwardingId: info.forwardingId,
}; };
} }
private async checkPostgresFirewallRules(): Promise<void> {
const firewallRulesUri = `${userContext.databaseAccount.id}/firewallRules`;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const response: any = await armRequest({
host: configContext.ARM_ENDPOINT,
path: firewallRulesUri,
method: "GET",
apiVersion: "2020-10-05-privatepreview",
});
const firewallRules: DataModels.PostgresFirewallRule[] = response?.data?.value || response?.value || [];
const isEnabled = firewallRules.some(
(rule) => rule.properties.startIpAddress === "0.0.0.0" && rule.properties.endIpAddress === "255.255.255.255"
);
this.isAllPublicIPAddressesEnabled(isEnabled);
// If the firewall rule is not added, check every 30 seconds to see if the user has added the rule
if (!isEnabled) {
setTimeout(() => this.checkPostgresFirewallRules(), 30000);
}
}
} }

View File

@@ -1160,6 +1160,23 @@ export default class Collection implements ViewModels.Collection {
this.onDocumentDBDocumentsClick(); this.onDocumentDBDocumentsClick();
} }
/**
* Get correct collection label depending on account API
*/
public getLabel(): string {
if (userContext.apiType === "Tables") {
return "Entities";
} else if (userContext.apiType === "Cassandra") {
return "Rows";
} else if (userContext.apiType === "Gremlin") {
return "Graph";
} else if (userContext.apiType === "Mongo") {
return "Documents";
}
return "Items";
}
public getDatabase(): ViewModels.Database { public getDatabase(): ViewModels.Database {
return useDatabases.getState().findDatabaseWithId(this.databaseId); return useDatabases.getState().findDatabaseWithId(this.databaseId);
} }

View File

@@ -1,6 +1,5 @@
import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react"; import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react";
import * as React from "react"; import * as React from "react";
import { getItemName } from "Utils/APITypeUtils";
import shallow from "zustand/shallow"; import shallow from "zustand/shallow";
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg"; import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
import DeleteIcon from "../../../images/delete.svg"; import DeleteIcon from "../../../images/delete.svg";
@@ -498,7 +497,7 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
const buildCollectionNode = (database: ViewModels.Database, collection: ViewModels.Collection): TreeNode => { const buildCollectionNode = (database: ViewModels.Database, collection: ViewModels.Collection): TreeNode => {
const children: TreeNode[] = []; const children: TreeNode[] = [];
children.push({ children.push({
label: getItemName(), label: collection.getLabel(),
id: collection.isSampleCollection ? "sampleItems" : "", id: collection.isSampleCollection ? "sampleItems" : "",
onClick: () => { onClick: () => {
collection.openTab(); collection.openTab();
@@ -532,13 +531,8 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
} }
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) { if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
let id = "";
if (collection.isSampleCollection) {
id = database.isDatabaseShared() ? "sampleSettings" : "sampleScaleSettings";
}
children.push({ children.push({
id, id: collection.isSampleCollection && !database.isDatabaseShared() ? "sampleScaleSettings" : "",
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings", label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
onClick: collection.onSettingsClick.bind(collection), onClick: collection.onSettingsClick.bind(collection),
isSelected: () => isSelected: () =>

View File

@@ -1,7 +1,6 @@
import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react"; import { Callout, DirectionalHint, ICalloutProps, ILinkProps, Link, Stack, Text } from "@fluentui/react";
import * as ko from "knockout"; import * as ko from "knockout";
import * as React from "react"; import * as React from "react";
import { getItemName } from "Utils/APITypeUtils";
import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg"; import CosmosDBIcon from "../../../images/Azure-Cosmos-DB.svg";
import DeleteIcon from "../../../images/delete.svg"; import DeleteIcon from "../../../images/delete.svg";
import GalleryIcon from "../../../images/GalleryIcon.svg"; import GalleryIcon from "../../../images/GalleryIcon.svg";
@@ -255,7 +254,7 @@ export class ResourceTreeAdapter implements ReactAdapter {
private buildCollectionNode(database: ViewModels.Database, collection: ViewModels.Collection): TreeNode { private buildCollectionNode(database: ViewModels.Database, collection: ViewModels.Collection): TreeNode {
const children: TreeNode[] = []; const children: TreeNode[] = [];
children.push({ children.push({
label: getItemName(), label: collection.getLabel(),
onClick: () => { onClick: () => {
collection.openTab(); collection.openTab();
// push to most recent // push to most recent

Some files were not shown because too many files have changed in this diff Show More