Compare commits
1 Commits
users/artr
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bd8f256039 |
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"JUNO_ENDPOINT": "https://localhost",
|
||||
"isTerminalEnabled": false,
|
||||
"isPhoenixEnabled": false
|
||||
}
|
||||
"JUNO_ENDPOINT": "https://tools.cosmos.azure.com",
|
||||
"isTerminalEnabled" : false,
|
||||
"isPhoenixEnabled" : false
|
||||
}
|
||||
|
||||
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -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 |
@@ -37,8 +37,8 @@ module.exports = {
|
||||
global: {
|
||||
branches: 25,
|
||||
functions: 25,
|
||||
lines: 28,
|
||||
statements: 28,
|
||||
lines: 29,
|
||||
statements: 29,
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
35
package-lock.json
generated
@@ -9,7 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "3.16.2",
|
||||
"@azure/cosmos": "3.16.1",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "1.2.1",
|
||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
||||
@@ -396,13 +396,12 @@
|
||||
"integrity": "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="
|
||||
},
|
||||
"node_modules/@azure/cosmos": {
|
||||
"version": "3.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.2.tgz",
|
||||
"integrity": "sha512-sceY5LWj0BHGj8PSyaVCfDRQLVZyoCfIY78kyIROJVEw0k+p9XFs8fhpykN8JklkCftL0WlaVY+X25SQwnhZsw==",
|
||||
"version": "3.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.1.tgz",
|
||||
"integrity": "sha512-9J76EMiF+ypZwO/Z7OS4PjrU/3hdRLe18dQh/Hj+jwXG2gKJ1NwgkYqcwu1HiCiX73A8+NCeA3PRDbegEnuuNQ==",
|
||||
"dependencies": {
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.2.0",
|
||||
"@azure/core-tracing": "^1.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"fast-json-stable-stringify": "^2.1.0",
|
||||
"jsbi": "^3.1.3",
|
||||
@@ -442,17 +441,6 @@
|
||||
"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": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
@@ -31470,13 +31458,12 @@
|
||||
}
|
||||
},
|
||||
"@azure/cosmos": {
|
||||
"version": "3.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.2.tgz",
|
||||
"integrity": "sha512-sceY5LWj0BHGj8PSyaVCfDRQLVZyoCfIY78kyIROJVEw0k+p9XFs8fhpykN8JklkCftL0WlaVY+X25SQwnhZsw==",
|
||||
"version": "3.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/cosmos/-/cosmos-3.16.1.tgz",
|
||||
"integrity": "sha512-9J76EMiF+ypZwO/Z7OS4PjrU/3hdRLe18dQh/Hj+jwXG2gKJ1NwgkYqcwu1HiCiX73A8+NCeA3PRDbegEnuuNQ==",
|
||||
"requires": {
|
||||
"@azure/core-auth": "^1.3.0",
|
||||
"@azure/core-rest-pipeline": "^1.2.0",
|
||||
"@azure/core-tracing": "^1.0.0",
|
||||
"debug": "^4.1.1",
|
||||
"fast-json-stable-stringify": "^2.1.0",
|
||||
"jsbi": "^3.1.3",
|
||||
@@ -31488,14 +31475,6 @@
|
||||
"uuid": "^8.3.0"
|
||||
},
|
||||
"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": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.2.0.tgz",
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "index.js",
|
||||
"dependencies": {
|
||||
"@azure/arm-cosmosdb": "9.1.0",
|
||||
"@azure/cosmos": "3.16.2",
|
||||
"@azure/cosmos": "3.16.1",
|
||||
"@azure/cosmos-language-service": "0.0.5",
|
||||
"@azure/identity": "1.2.1",
|
||||
"@azure/ms-rest-nodeauth": "3.0.7",
|
||||
@@ -232,4 +232,4 @@
|
||||
"prettier": {
|
||||
"printWidth": 120
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
66
preview/package-lock.json
generated
@@ -10,7 +10,7 @@
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"http-proxy-middleware": "^1.1.0",
|
||||
"node-fetch": "^2.6.1"
|
||||
"node-fetch": "^2.6.7"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-proxy": {
|
||||
@@ -446,11 +446,22 @@
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==",
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "4.x || >=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"encoding": "^0.1.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"encoding": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
@@ -616,6 +627,11 @@
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
@@ -651,6 +667,20 @@
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"node_modules/whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"dependencies": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
@@ -985,9 +1015,12 @@
|
||||
"integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
|
||||
},
|
||||
"node-fetch": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||
"version": "2.6.7",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
|
||||
"integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
|
||||
"requires": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"on-finished": {
|
||||
"version": "2.3.0",
|
||||
@@ -1118,6 +1151,11 @@
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
|
||||
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
|
||||
},
|
||||
"tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
||||
},
|
||||
"type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
@@ -1141,6 +1179,20 @@
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
|
||||
},
|
||||
"webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
||||
},
|
||||
"whatwg-url": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
||||
"requires": {
|
||||
"tr46": "~0.0.3",
|
||||
"webidl-conversions": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,6 @@
|
||||
"dependencies": {
|
||||
"express": "^4.17.1",
|
||||
"http-proxy-middleware": "^1.1.0",
|
||||
"node-fetch": "^2.6.1"
|
||||
"node-fetch": "^2.6.7"
|
||||
}
|
||||
}
|
||||
@@ -354,10 +354,6 @@ export enum ContainerStatusType {
|
||||
Disconnected = "Disconnected",
|
||||
}
|
||||
|
||||
export enum PoolIdType {
|
||||
DefaultPoolId = "default",
|
||||
}
|
||||
|
||||
export const EmulatorMasterKey =
|
||||
//[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Well known public masterKey for emulator")]
|
||||
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
|
||||
@@ -423,6 +419,6 @@ export class JunoEndpoints {
|
||||
public static readonly Test = "https://juno-test.documents-dev.windows-int.net";
|
||||
public static readonly Test2 = "https://juno-test2.documents-dev.windows-int.net";
|
||||
public static readonly Test3 = "https://juno-test3.documents-dev.windows-int.net";
|
||||
public static readonly Prod = "https://localhost";
|
||||
public static readonly Prod = "https://tools.cosmos.azure.com";
|
||||
public static readonly Stage = "https://tools-staging.cosmos.azure.com";
|
||||
}
|
||||
|
||||
@@ -299,7 +299,7 @@ export function createMongoCollectionWithProxy(
|
||||
db: params.databaseId,
|
||||
coll: params.collectionId,
|
||||
pk: shardKey,
|
||||
offerThroughput: params.autoPilotMaxThroughput || params.offerThroughput,
|
||||
offerThroughput: params.offerThroughput,
|
||||
cd: params.createNewDatabase,
|
||||
st: params.databaseLevelThroughput,
|
||||
is: !!shardKey,
|
||||
@@ -309,6 +309,7 @@ export function createMongoCollectionWithProxy(
|
||||
rg: userContext.resourceGroup,
|
||||
dba: databaseAccount.name,
|
||||
isAutoPilot: !!params.autoPilotMaxThroughput,
|
||||
autoPilotThroughput: params.autoPilotMaxThroughput?.toString(),
|
||||
};
|
||||
|
||||
const endpoint = getFeatureEndpointOrDefault("createCollectionWithProxy");
|
||||
|
||||
@@ -24,7 +24,7 @@ export const createCollection = async (params: DataModels.CreateCollectionParams
|
||||
);
|
||||
try {
|
||||
let collection: DataModels.Collection;
|
||||
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
if (params.createNewDatabase) {
|
||||
const createDatabaseParams: DataModels.CreateDatabaseParams = {
|
||||
autoPilotMaxThroughput: params.autoPilotMaxThroughput,
|
||||
|
||||
@@ -25,8 +25,7 @@ export async function createDatabase(params: DataModels.CreateDatabaseParams): P
|
||||
if (userContext.apiType === "Tables") {
|
||||
throw new Error("Creating database resources is not allowed for tables accounts");
|
||||
}
|
||||
const database: DataModels.Database = await (userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations
|
||||
const database: DataModels.Database = await (userContext.authType === AuthType.AAD && !userContext.useSDKOperations
|
||||
? createDatabaseWithARM(params)
|
||||
: createDatabaseWithSDK(params));
|
||||
|
||||
|
||||
@@ -20,11 +20,7 @@ export async function createStoredProcedure(
|
||||
): Promise<StoredProcedureDefinition & Resource> {
|
||||
const clearMessage = logConsoleProgress(`Creating stored procedure ${storedProcedure.id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
try {
|
||||
const getResponse = await getSqlStoredProcedure(
|
||||
userContext.subscriptionId,
|
||||
|
||||
@@ -14,11 +14,7 @@ export async function createTrigger(
|
||||
): Promise<TriggerDefinition | SqlTriggerResource> {
|
||||
const clearMessage = logConsoleProgress(`Creating trigger ${trigger.id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
try {
|
||||
const getResponse = await getSqlTrigger(
|
||||
userContext.subscriptionId,
|
||||
|
||||
@@ -20,11 +20,7 @@ export async function createUserDefinedFunction(
|
||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||
const clearMessage = logConsoleProgress(`Creating user defined function ${userDefinedFunction.id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
try {
|
||||
const getResponse = await getSqlUserDefinedFunction(
|
||||
userContext.subscriptionId,
|
||||
|
||||
@@ -12,7 +12,7 @@ import { handleError } from "../ErrorHandlingUtils";
|
||||
export async function deleteCollection(databaseId: string, collectionId: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting container ${collectionId}`);
|
||||
try {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
await deleteCollectionWithARM(databaseId, collectionId);
|
||||
} else {
|
||||
await client().database(databaseId).container(collectionId).delete();
|
||||
|
||||
@@ -12,7 +12,10 @@ export async function deleteDatabase(databaseId: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting database ${databaseId}`);
|
||||
|
||||
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);
|
||||
} else {
|
||||
await client().database(databaseId).delete();
|
||||
|
||||
@@ -12,11 +12,7 @@ export async function deleteStoredProcedure(
|
||||
): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting stored procedure ${storedProcedureId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
await deleteSqlStoredProcedure(
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
|
||||
@@ -8,11 +8,7 @@ import { handleError } from "../ErrorHandlingUtils";
|
||||
export async function deleteTrigger(databaseId: string, collectionId: string, triggerId: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting trigger ${triggerId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
await deleteSqlTrigger(
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
|
||||
@@ -8,11 +8,7 @@ import { handleError } from "../ErrorHandlingUtils";
|
||||
export async function deleteUserDefinedFunction(databaseId: string, collectionId: string, id: string): Promise<void> {
|
||||
const clearMessage = logConsoleProgress(`Deleting user defined function ${id}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
await deleteSqlUserDefinedFunction(
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
|
||||
@@ -14,11 +14,7 @@ export const readCollectionOffer = async (params: ReadCollectionOfferParams): Pr
|
||||
const clearMessage = logConsoleProgress(`Querying offer for collection ${params.collectionId}`);
|
||||
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType !== "Tables"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||
return await readCollectionOfferWithARM(params.databaseId, params.collectionId);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@ import { handleError } from "../ErrorHandlingUtils";
|
||||
export async function readCollections(databaseId: string): Promise<DataModels.Collection[]> {
|
||||
const clearMessage = logConsoleProgress(`Querying containers for database ${databaseId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType !== "Tables"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||
return await readCollectionsWithARM(databaseId);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@ export const readDatabaseOffer = async (params: ReadDatabaseOfferParams): Promis
|
||||
const clearMessage = logConsoleProgress(`Querying offer for database ${params.databaseId}`);
|
||||
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType !== "Tables"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||
return await readDatabaseOfferWithARM(params.databaseId);
|
||||
}
|
||||
|
||||
|
||||
@@ -13,11 +13,7 @@ export async function readDatabases(): Promise<DataModels.Database[]> {
|
||||
let databases: DataModels.Database[];
|
||||
const clearMessage = logConsoleProgress(`Querying databases`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType !== "Tables"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||
databases = await readDatabasesWithARM();
|
||||
} else {
|
||||
const sdkResponse = await client().databases.readAll().fetchAll();
|
||||
|
||||
@@ -12,11 +12,7 @@ export async function readStoredProcedures(
|
||||
): Promise<(StoredProcedureDefinition & Resource)[]> {
|
||||
const clearMessage = logConsoleProgress(`Querying stored procedures for container ${collectionId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
const rpResponse = await listSqlStoredProcedures(
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
|
||||
@@ -13,11 +13,7 @@ export async function readTriggers(
|
||||
): Promise<SqlTriggerResource[] | TriggerDefinition[]> {
|
||||
const clearMessage = logConsoleProgress(`Querying triggers for container ${collectionId}`);
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType === "SQL"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType === "SQL") {
|
||||
const rpResponse = await listSqlTriggers(
|
||||
userContext.subscriptionId,
|
||||
userContext.resourceGroup,
|
||||
|
||||
@@ -11,9 +11,9 @@ export async function readUserDefinedFunctions(
|
||||
collectionId: string
|
||||
): Promise<(UserDefinedFunctionDefinition & Resource)[]> {
|
||||
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 {
|
||||
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
|
||||
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||
const rpResponse = await listSqlUserDefinedFunctions(
|
||||
subscriptionId,
|
||||
resourceGroup,
|
||||
|
||||
@@ -33,11 +33,7 @@ export async function updateCollection(
|
||||
const clearMessage = logConsoleProgress(`Updating container ${collectionId}`);
|
||||
|
||||
try {
|
||||
if (
|
||||
userContext.authType === AuthType.AAD &&
|
||||
!userContext.features.enableSDKoperations &&
|
||||
userContext.apiType !== "Tables"
|
||||
) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations && userContext.apiType !== "Tables") {
|
||||
collection = await updateCollectionWithARM(databaseId, collectionId, newCollection);
|
||||
} else {
|
||||
const sdkResponse = await client()
|
||||
|
||||
@@ -56,7 +56,7 @@ export const updateOffer = async (params: UpdateOfferParams): Promise<Offer> =>
|
||||
const clearMessage = logConsoleProgress(`Updating offer for ${offerResourceText}`);
|
||||
|
||||
try {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.features.enableSDKoperations) {
|
||||
if (userContext.authType === AuthType.AAD && !userContext.useSDKOperations) {
|
||||
if (params.collectionId) {
|
||||
updatedOffer = await updateCollectionOfferWithARM(params);
|
||||
} else if (userContext.apiType === "Tables") {
|
||||
|
||||
@@ -20,9 +20,9 @@ export async function updateStoredProcedure(
|
||||
): Promise<StoredProcedureDefinition & Resource> {
|
||||
const clearMessage = logConsoleProgress(`Updating stored procedure ${storedProcedure.id}`);
|
||||
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(
|
||||
subscriptionId,
|
||||
resourceGroup,
|
||||
|
||||
@@ -13,9 +13,9 @@ export async function updateTrigger(
|
||||
trigger: SqlTriggerResource
|
||||
): Promise<SqlTriggerResource | TriggerDefinition> {
|
||||
const clearMessage = logConsoleProgress(`Updating trigger ${trigger.id}`);
|
||||
const { authType, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||
const { authType, useSDKOperations, apiType, subscriptionId, resourceGroup, databaseAccount } = userContext;
|
||||
try {
|
||||
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
|
||||
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||
const getResponse = await getSqlTrigger(
|
||||
subscriptionId,
|
||||
resourceGroup,
|
||||
|
||||
@@ -19,9 +19,9 @@ export async function updateUserDefinedFunction(
|
||||
userDefinedFunction: UserDefinedFunctionDefinition
|
||||
): Promise<UserDefinedFunctionDefinition & Resource> {
|
||||
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 {
|
||||
if (authType === AuthType.AAD && !userContext.features.enableSDKoperations && apiType === "SQL") {
|
||||
if (authType === AuthType.AAD && !useSDKOperations && apiType === "SQL") {
|
||||
const getResponse = await getSqlUserDefinedFunction(
|
||||
subscriptionId,
|
||||
resourceGroup,
|
||||
|
||||
@@ -69,7 +69,7 @@ let configContext: Readonly<ConfigContext> = {
|
||||
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
|
||||
GITHUB_CLIENT_ID: "6cb2f63cf6f7b5cbdeca", // Registered OAuth app: https://github.com/organizations/AzureCosmosDBNotebooks/settings/applications/1189306
|
||||
GITHUB_TEST_ENV_CLIENT_ID: "b63fc8cbf87fd3c6e2eb", // Registered OAuth app: https://github.com/organizations/AzureCosmosDBNotebooks/settings/applications/1777772
|
||||
JUNO_ENDPOINT: "https://localhost",
|
||||
JUNO_ENDPOINT: "https://tools.cosmos.azure.com",
|
||||
BACKEND_ENDPOINT: "https://main.documentdb.ext.azure.com",
|
||||
isTerminalEnabled: false,
|
||||
isPhoenixEnabled: false,
|
||||
|
||||
@@ -438,25 +438,18 @@ export interface NotebookWorkspaceConnectionInfo {
|
||||
|
||||
export interface ContainerInfo {
|
||||
durationLeftInMinutes: number;
|
||||
phoenixServerInfo: NotebookWorkspaceConnectionInfo;
|
||||
notebookServerInfo: NotebookWorkspaceConnectionInfo;
|
||||
status: ContainerStatusType;
|
||||
}
|
||||
|
||||
export interface IProvisionData {
|
||||
cosmosEndpoint: string;
|
||||
poolId: string;
|
||||
}
|
||||
|
||||
export interface IContainerData {
|
||||
forwardingId: string;
|
||||
}
|
||||
|
||||
export interface IDbAccountAllow {
|
||||
status: number;
|
||||
message?: string;
|
||||
type?: string;
|
||||
}
|
||||
|
||||
export interface IResponse<T> {
|
||||
status: number;
|
||||
data: T;
|
||||
@@ -481,12 +474,8 @@ export interface IMaxUsersPerDbAccountExceeded extends IPhoenixError {
|
||||
}
|
||||
|
||||
export interface IPhoenixConnectionInfoResult {
|
||||
readonly phoenixServiceInfo?: IPhoenixServiceInfo;
|
||||
}
|
||||
|
||||
export interface IPhoenixServiceInfo {
|
||||
readonly authToken?: string;
|
||||
readonly phoenixServiceUrl?: string;
|
||||
readonly notebookAuthToken?: string;
|
||||
readonly notebookServerUrl?: string;
|
||||
readonly forwardingId?: string;
|
||||
}
|
||||
|
||||
@@ -574,6 +563,4 @@ export enum PhoenixErrorType {
|
||||
RegionNotServicable = "RegionNotServicable",
|
||||
SubscriptionNotAllowed = "SubscriptionNotAllowed",
|
||||
UnknownError = "UnknownError",
|
||||
PhoenixFlightFallback = "PhoenixFlightFallback",
|
||||
UserMissingPermissionsError = "UserMissingPermissionsError",
|
||||
}
|
||||
|
||||
@@ -372,7 +372,6 @@ export enum TerminalKind {
|
||||
Default = 0,
|
||||
Mongo = 1,
|
||||
Cassandra = 2,
|
||||
Postgres = 3,
|
||||
}
|
||||
|
||||
export interface DataExplorerInputsFrame {
|
||||
|
||||
@@ -44,7 +44,7 @@ export const createDatabaseContextMenu = (container: Explorer, databaseId: strin
|
||||
},
|
||||
];
|
||||
|
||||
if (userContext.apiType !== "Tables" || userContext.features.enableSDKoperations) {
|
||||
if (userContext.apiType !== "Tables") {
|
||||
items.push({
|
||||
iconSrc: DeleteDatabaseIcon,
|
||||
onClick: () =>
|
||||
|
||||
@@ -74,8 +74,6 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
|
||||
this.props.databaseAccount?.properties.mongoEndpoint || this.props.databaseAccount?.properties.documentEndpoint;
|
||||
} else if (StringUtils.endsWith(notebookServerEndpoint, "cassandra")) {
|
||||
terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint;
|
||||
} else if (StringUtils.endsWith(notebookServerEndpoint, "postgresql")) {
|
||||
return (this.props.databaseAccount?.properties as any).postgresqlEndpoint;
|
||||
}
|
||||
|
||||
if (terminalEndpoint) {
|
||||
|
||||
@@ -28,7 +28,6 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
isSharded,
|
||||
isFreeTier,
|
||||
showFreeTierExceedThroughputTooltip,
|
||||
isQuickstart,
|
||||
setThroughputValue,
|
||||
setIsAutoscale,
|
||||
setIsThroughputCapExceeded,
|
||||
@@ -36,7 +35,7 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
|
||||
}: ThroughputInputProps) => {
|
||||
const [isAutoscaleSelected, setIsAutoScaleSelected] = useState<boolean>(true);
|
||||
const [throughput, setThroughput] = useState<number>(
|
||||
isFreeTier || isQuickstart ? AutoPilotUtils.autoPilotThroughput1K : AutoPilotUtils.autoPilotThroughput4K
|
||||
isFreeTier ? AutoPilotUtils.autoPilotThroughput1K : AutoPilotUtils.autoPilotThroughput4K
|
||||
);
|
||||
const [isCostAcknowledged, setIsCostAcknowledged] = useState<boolean>(false);
|
||||
const [throughputError, setThroughputError] = useState<string>("");
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import { createCollection } from "../../Common/dataAccess/createCollection";
|
||||
import { createDocument } from "../../Common/dataAccess/createDocument";
|
||||
import { createDocument as createMongoDocument } from "../../Common/MongoProxyClient";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { userContext } from "../../UserContext";
|
||||
@@ -29,7 +28,7 @@ export class ContainerSampleGenerator {
|
||||
dataFileContent = await import(
|
||||
/* webpackChunkName: "gremlinSampleJsonData" */ "../../../sampleData/gremlinSampleData.json"
|
||||
);
|
||||
} else if (userContext.apiType === "SQL" || userContext.apiType === "Mongo") {
|
||||
} else if (userContext.apiType === "SQL") {
|
||||
dataFileContent = await import(
|
||||
/* webpackChunkName: "sqlSampleJsonData" */ "../../../sampleData/sqlSampleData.json"
|
||||
);
|
||||
@@ -69,7 +68,7 @@ export class ContainerSampleGenerator {
|
||||
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) {
|
||||
throw new Error("No container to populate");
|
||||
}
|
||||
@@ -100,9 +99,7 @@ export class ContainerSampleGenerator {
|
||||
await Promise.all(
|
||||
this.sampleDataFile.data.map(async (doc) => {
|
||||
try {
|
||||
userContext.apiType === "Mongo"
|
||||
? await createMongoDocument(collection.databaseId, collection, shardKey, doc)
|
||||
: await createDocument(collection, doc);
|
||||
await createDocument(collection, doc);
|
||||
} catch (error) {
|
||||
NotificationConsoleUtils.logConsoleError(error);
|
||||
}
|
||||
|
||||
@@ -9,14 +9,19 @@ import shallow from "zustand/shallow";
|
||||
import { AuthType } from "../AuthType";
|
||||
import { BindingHandlersRegisterer } from "../Bindings/BindingHandlersRegisterer";
|
||||
import * as Constants from "../Common/Constants";
|
||||
import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook, PoolIdType } from "../Common/Constants";
|
||||
import { Areas, ConnectionStatusType, HttpStatusCodes, Notebook } from "../Common/Constants";
|
||||
import { readCollection } from "../Common/dataAccess/readCollection";
|
||||
import { readDatabases } from "../Common/dataAccess/readDatabases";
|
||||
import { getErrorMessage, getErrorStack, handleError } from "../Common/ErrorHandlingUtils";
|
||||
import * as Logger from "../Common/Logger";
|
||||
import { QueriesClient } from "../Common/QueriesClient";
|
||||
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 { GitHubOAuthService } from "../GitHub/GitHubOAuthService";
|
||||
import { useSidePanel } from "../hooks/useSidePanel";
|
||||
@@ -93,8 +98,7 @@ export default class Explorer {
|
||||
dataExplorerArea: Constants.Areas.ResourceTree,
|
||||
});
|
||||
this._isInitializingNotebooks = false;
|
||||
|
||||
this.phoenixClient = new PhoenixClient(userContext.databaseAccount.id);
|
||||
this.phoenixClient = new PhoenixClient();
|
||||
useNotebook.subscribe(
|
||||
() => this.refreshCommandBarButtons(),
|
||||
(state) => state.isNotebooksEnabledForAccount
|
||||
@@ -186,9 +190,7 @@ export default class Explorer {
|
||||
useNotebook.getState().setNotebookBasePath(userContext.features.notebookBasePath);
|
||||
}
|
||||
|
||||
if (!userContext.features.enablePGQuickstart || userContext.apiType !== "Postgres") {
|
||||
this.refreshExplorer();
|
||||
}
|
||||
this.refreshExplorer();
|
||||
}
|
||||
|
||||
public async initiateAndRefreshNotebookList(): Promise<void> {
|
||||
@@ -354,8 +356,7 @@ export default class Explorer {
|
||||
(notebookServerInfo && notebookServerInfo.notebookServerEndpoint === undefined))
|
||||
) {
|
||||
const provisionData: IProvisionData = {
|
||||
cosmosEndpoint: userContext?.databaseAccount?.properties?.documentEndpoint,
|
||||
poolId: PoolIdType.DefaultPoolId,
|
||||
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
|
||||
};
|
||||
const connectionStatus: ContainerConnectionInfo = {
|
||||
status: ConnectionStatusType.Connecting,
|
||||
@@ -368,8 +369,8 @@ export default class Explorer {
|
||||
});
|
||||
useNotebook.getState().setIsAllocating(true);
|
||||
connectionInfo = await this.phoenixClient.allocateContainer(provisionData);
|
||||
if (!connectionInfo?.data?.phoenixServiceUrl) {
|
||||
throw new Error(`PhoenixServiceUrl is invalid!`);
|
||||
if (!connectionInfo?.data?.notebookServerUrl) {
|
||||
throw new Error(`NotebookServerUrl is invalid!`);
|
||||
}
|
||||
await this.setNotebookInfo(connectionInfo, connectionStatus);
|
||||
TelemetryProcessor.traceSuccess(Action.PhoenixConnection, {
|
||||
@@ -405,7 +406,7 @@ export default class Explorer {
|
||||
}
|
||||
|
||||
private async setNotebookInfo(
|
||||
connectionInfo: IResponse<IPhoenixServiceInfo>,
|
||||
connectionInfo: IResponse<IPhoenixConnectionInfoResult>,
|
||||
connectionStatus: DataModels.ContainerConnectionInfo
|
||||
) {
|
||||
const containerData = {
|
||||
@@ -420,8 +421,8 @@ export default class Explorer {
|
||||
notebookServerEndpoint:
|
||||
(validateEndpoint(userContext.features.notebookServerUrl, allowedNotebookServerUrls) &&
|
||||
userContext.features.notebookServerUrl) ||
|
||||
connectionInfo.data.phoenixServiceUrl,
|
||||
authToken: userContext.features.notebookServerToken || connectionInfo.data.authToken,
|
||||
connectionInfo.data.notebookServerUrl,
|
||||
authToken: userContext.features.notebookServerToken || connectionInfo.data.notebookAuthToken,
|
||||
forwardingId: connectionInfo.data.forwardingId,
|
||||
});
|
||||
this.notebookManager?.notebookClient
|
||||
@@ -496,8 +497,8 @@ export default class Explorer {
|
||||
if (connectionInfo?.status !== HttpStatusCodes.OK) {
|
||||
throw new Error(`Reset Workspace: Received status code- ${connectionInfo?.status}`);
|
||||
}
|
||||
if (!connectionInfo?.data?.phoenixServiceUrl) {
|
||||
throw new Error(`Reset Workspace: PhoenixServiceUrl is invalid!`);
|
||||
if (!connectionInfo?.data?.notebookServerUrl) {
|
||||
throw new Error(`Reset Workspace: NotebookServerUrl is invalid!`);
|
||||
}
|
||||
if (useNotebook.getState().isPhoenixNotebooks) {
|
||||
await this.setNotebookInfo(connectionInfo, connectionStatus);
|
||||
@@ -1059,10 +1060,6 @@ export default class Explorer {
|
||||
title = "Cassandra Shell";
|
||||
break;
|
||||
|
||||
case ViewModels.TerminalKind.Postgres:
|
||||
title = "PSQL Shell";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error("Terminal kind: ${kind} not supported");
|
||||
}
|
||||
@@ -1122,7 +1119,7 @@ export default class Explorer {
|
||||
account: userContext.databaseAccount,
|
||||
container: this,
|
||||
junoClient: this.notebookManager?.junoClient,
|
||||
selectedTab: selectedTab || GalleryTabKind.OfficialSamples,
|
||||
selectedTab: selectedTab || GalleryTabKind.PublicGallery,
|
||||
notebookUrl,
|
||||
galleryItem,
|
||||
isFavorite,
|
||||
|
||||
@@ -6,9 +6,8 @@
|
||||
import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react";
|
||||
import { useNotebook } from "Explorer/Notebook/useNotebook";
|
||||
import * as React from "react";
|
||||
import { userContext } from "UserContext";
|
||||
import create, { UseStore } from "zustand";
|
||||
import { ConnectionStatusType, StyleConstants } from "../../../Common/Constants";
|
||||
import { StyleConstants } from "../../../Common/Constants";
|
||||
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
|
||||
import Explorer from "../../Explorer";
|
||||
import { useSelectedNode } from "../../useSelectedNode";
|
||||
@@ -34,22 +33,6 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
const buttons = useCommandBar((state) => state.contextButtons);
|
||||
const backgroundColor = StyleConstants.BaseLight;
|
||||
|
||||
if (userContext.features.enablePGQuickstart && 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 contextButtons = (buttons || []).concat(
|
||||
CommandBarComponentButtonFactory.createContextCommandBarButtons(container, selectedNodeState)
|
||||
@@ -70,12 +53,7 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
|
||||
const uiFabricControlButtons = CommandBarUtil.convertButton(controlButtons, backgroundColor);
|
||||
uiFabricControlButtons.forEach((btn: ICommandBarItemProps) => (btn.iconOnly = true));
|
||||
|
||||
const connectionInfo = useNotebook((state) => state.connectionInfo);
|
||||
|
||||
if (
|
||||
(useNotebook.getState().isPhoenixNotebooks || useNotebook.getState().isPhoenixFeatures) &&
|
||||
connectionInfo?.status !== ConnectionStatusType.Connect
|
||||
) {
|
||||
if (useNotebook.getState().isPhoenixNotebooks || useNotebook.getState().isPhoenixFeatures) {
|
||||
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus(container, "connectionStatus"));
|
||||
}
|
||||
|
||||
|
||||
@@ -95,8 +95,6 @@ export function createStaticCommandBarButtons(
|
||||
}
|
||||
}
|
||||
|
||||
notebookButtons.push(createOpenPsqlTerminalButton(container));
|
||||
|
||||
notebookButtons.forEach((btn) => {
|
||||
if (btn.commandButtonLabel.indexOf("Cassandra") !== -1) {
|
||||
if (!useNotebook.getState().isPhoenixFeatures) {
|
||||
@@ -106,14 +104,6 @@ export function createStaticCommandBarButtons(
|
||||
if (!useNotebook.getState().isPhoenixFeatures) {
|
||||
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.mongoShellTemporarilyDownMsg);
|
||||
}
|
||||
} else if (btn.commandButtonLabel.indexOf("PSQL") !== -1) {
|
||||
if (!useNotebook.getState().isPhoenixFeatures) {
|
||||
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) {
|
||||
applyNotebooksTemporarilyDownStyle(btn, Constants.Notebook.temporarilyDownMsg);
|
||||
}
|
||||
@@ -529,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 {
|
||||
const label = "Reset Workspace";
|
||||
return {
|
||||
@@ -613,18 +581,3 @@ function createStaticCommandBarButtonsForResourceToken(
|
||||
|
||||
return [newSqlQueryBtn, openQueryBtn];
|
||||
}
|
||||
|
||||
export function createPostgreButtons(container: Explorer): CommandButtonComponentProps[] {
|
||||
const postgreShellLabel = "Open PostgreSQL Shell";
|
||||
const openPostgreShellBtn = {
|
||||
iconSrc: HostedTerminalIcon,
|
||||
iconAlt: postgreShellLabel,
|
||||
onCommandClick: () => container.openNotebookTerminal(ViewModels.TerminalKind.Mongo),
|
||||
commandButtonLabel: postgreShellLabel,
|
||||
hasPopup: false,
|
||||
disabled: false,
|
||||
ariaLabel: postgreShellLabel,
|
||||
};
|
||||
|
||||
return [openPostgreShellBtn];
|
||||
}
|
||||
|
||||
@@ -5,11 +5,11 @@ import { useDialog } from "Explorer/Controls/Dialog";
|
||||
import promiseRetry, { AbortError } from "p-retry";
|
||||
import { PhoenixClient } from "Phoenix/PhoenixClient";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { ConnectionStatusType, HttpHeaders, HttpStatusCodes, Notebook, PoolIdType } from "../../Common/Constants";
|
||||
import { ConnectionStatusType, HttpHeaders, HttpStatusCodes, Notebook } from "../../Common/Constants";
|
||||
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
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 { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
|
||||
import { logConsoleProgress } from "../../Utils/NotificationConsoleUtils";
|
||||
@@ -23,7 +23,7 @@ export class NotebookContainerClient {
|
||||
private scheduleTimerId: NodeJS.Timeout;
|
||||
|
||||
constructor(private onConnectionLost: () => void) {
|
||||
this.phoenixClient = new PhoenixClient(userContext.databaseAccount.id);
|
||||
this.phoenixClient = new PhoenixClient();
|
||||
this.retryOptions = {
|
||||
retries: Notebook.retryAttempts,
|
||||
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;
|
||||
let response: IResponse<IPhoenixServiceInfo>;
|
||||
let response: IResponse<IPhoenixConnectionInfoResult>;
|
||||
try {
|
||||
response = await this._resetWorkspace();
|
||||
} catch (error) {
|
||||
@@ -142,7 +142,7 @@ export class NotebookContainerClient {
|
||||
return response;
|
||||
}
|
||||
|
||||
private async _resetWorkspace(): Promise<IResponse<IPhoenixServiceInfo>> {
|
||||
private async _resetWorkspace(): Promise<IResponse<IPhoenixConnectionInfoResult>> {
|
||||
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
|
||||
if (!notebookServerInfo || !notebookServerInfo.notebookServerEndpoint) {
|
||||
const error = "No server endpoint detected";
|
||||
@@ -154,7 +154,6 @@ export class NotebookContainerClient {
|
||||
if (useNotebook.getState().isPhoenixNotebooks) {
|
||||
const provisionData: IProvisionData = {
|
||||
cosmosEndpoint: userContext.databaseAccount.properties.documentEndpoint,
|
||||
poolId: PoolIdType.DefaultPoolId,
|
||||
};
|
||||
return await this.phoenixClient.resetContainer(provisionData);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ import Immutable from "immutable";
|
||||
import * as React from "react";
|
||||
import { connect } from "react-redux";
|
||||
import { Dispatch } from "redux";
|
||||
import * as Logger from "../../../Common/Logger";
|
||||
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
|
||||
import { traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
|
||||
import loadTransform from "../NotebookComponent/loadTransform";
|
||||
@@ -101,7 +100,6 @@ export class SchemaAnalyzer extends React.Component<SchemaAnalyzerProps, SchemaA
|
||||
// Only in cases where CosmosMongoKernel runs into an error we get a single output
|
||||
if (outputs.size === 1) {
|
||||
traceFailure(Action.SchemaAnalyzerClickAnalyze, data, this.clickAnalyzeTelemetryStartKey);
|
||||
Logger.logError(`Failed to analyze schema: ${JSON.stringify(data)}`, "SchemaAnalyzer/traceClickAnalyzeComplete");
|
||||
} else {
|
||||
traceSuccess(Action.SchemaAnalyzerClickAnalyze, data, this.clickAnalyzeTelemetryStartKey);
|
||||
}
|
||||
|
||||
@@ -4,12 +4,12 @@ import { PhoenixClient } from "Phoenix/PhoenixClient";
|
||||
import create, { UseStore } from "zustand";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import { ConnectionStatusType, HttpStatusCodes } from "../../Common/Constants";
|
||||
import { ConnectionStatusType } from "../../Common/Constants";
|
||||
import { getErrorMessage } from "../../Common/ErrorHandlingUtils";
|
||||
import * as Logger from "../../Common/Logger";
|
||||
import { configContext } from "../../ConfigContext";
|
||||
import * as DataModels from "../../Contracts/DataModels";
|
||||
import { ContainerConnectionInfo, ContainerInfo, PhoenixErrorType } from "../../Contracts/DataModels";
|
||||
import { ContainerConnectionInfo, ContainerInfo } from "../../Contracts/DataModels";
|
||||
import { useTabs } from "../../hooks/useTabs";
|
||||
import { IPinnedRepo } from "../../Juno/JunoClient";
|
||||
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
|
||||
@@ -96,7 +96,7 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
||||
containerStatus: {
|
||||
status: undefined,
|
||||
durationLeftInMinutes: undefined,
|
||||
phoenixServerInfo: undefined,
|
||||
notebookServerInfo: undefined,
|
||||
},
|
||||
isPhoenixNotebooks: undefined,
|
||||
isPhoenixFeatures: undefined,
|
||||
@@ -296,30 +296,22 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
|
||||
useNotebook.getState().setContainerStatus({
|
||||
status: undefined,
|
||||
durationLeftInMinutes: undefined,
|
||||
phoenixServerInfo: undefined,
|
||||
notebookServerInfo: undefined,
|
||||
});
|
||||
},
|
||||
setIsRefreshed: (isRefreshed: boolean) => set({ isRefreshed }),
|
||||
setContainerStatus: (containerStatus: ContainerInfo) => set({ containerStatus }),
|
||||
getPhoenixStatus: async () => {
|
||||
if (get().isPhoenixNotebooks === undefined || get().isPhoenixFeatures === undefined) {
|
||||
let isPhoenixNotebooks = false;
|
||||
let isPhoenixFeatures = false;
|
||||
|
||||
const isPublicInternetAllowed = isPublicInternetAccessAllowed();
|
||||
const phoenixClient = new PhoenixClient(userContext.databaseAccount.id);
|
||||
const dbAccountAllowedInfo = await phoenixClient.getDbAccountAllowedStatus();
|
||||
|
||||
if (dbAccountAllowedInfo.status === HttpStatusCodes.OK) {
|
||||
if (dbAccountAllowedInfo?.type === PhoenixErrorType.PhoenixFlightFallback) {
|
||||
isPhoenixNotebooks = isPublicInternetAllowed && userContext.features.phoenixNotebooks === true;
|
||||
isPhoenixFeatures = isPublicInternetAllowed && userContext.features.phoenixFeatures === true;
|
||||
} else {
|
||||
isPhoenixNotebooks = isPhoenixFeatures = isPublicInternetAllowed;
|
||||
}
|
||||
} else {
|
||||
isPhoenixNotebooks = isPhoenixFeatures = false;
|
||||
let isPhoenix = false;
|
||||
if (userContext.features.phoenixNotebooks || userContext.features.phoenixFeatures) {
|
||||
const phoenixClient = new PhoenixClient();
|
||||
isPhoenix = isPublicInternetAccessAllowed() && (await phoenixClient.isDbAcountWhitelisted());
|
||||
}
|
||||
|
||||
const isPhoenixNotebooks = userContext.features.phoenixNotebooks && isPhoenix;
|
||||
const isPhoenixFeatures = userContext.features.phoenixFeatures && isPhoenix;
|
||||
|
||||
set({ isPhoenixNotebooks: isPhoenixNotebooks });
|
||||
set({ isPhoenixFeatures: isPhoenixFeatures });
|
||||
}
|
||||
|
||||
@@ -346,7 +346,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
isDatabase={true}
|
||||
isSharded={this.state.isSharded}
|
||||
isFreeTier={this.isFreeTierAccount()}
|
||||
isQuickstart={this.props.isQuickstart}
|
||||
setThroughputValue={(throughput: number) => (this.newDatabaseThroughput = throughput)}
|
||||
setIsAutoscale={(isAutoscale: boolean) => (this.isNewDatabaseAutoscale = isAutoscale)}
|
||||
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
||||
@@ -582,7 +581,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
isDatabase={false}
|
||||
isSharded={this.state.isSharded}
|
||||
isFreeTier={this.isFreeTierAccount()}
|
||||
isQuickstart={this.props.isQuickstart}
|
||||
setThroughputValue={(throughput: number) => (this.collectionThroughput = throughput)}
|
||||
setIsAutoscale={(isAutoscale: boolean) => (this.isCollectionAutoscale = isAutoscale)}
|
||||
setIsThroughputCapExceeded={(isThroughputCapExceeded: boolean) =>
|
||||
@@ -1251,7 +1249,7 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
|
||||
collection.isSampleCollection = true;
|
||||
useTeachingBubble.getState().setSampleCollection(collection);
|
||||
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
|
||||
await database.expandDatabase();
|
||||
collection.expandCollection();
|
||||
|
||||
@@ -1,290 +0,0 @@
|
||||
import {
|
||||
DefaultButton,
|
||||
Icon,
|
||||
IconButton,
|
||||
Image,
|
||||
IPivotItemProps,
|
||||
Pivot,
|
||||
PivotItem,
|
||||
PrimaryButton,
|
||||
Stack,
|
||||
Text,
|
||||
TextField,
|
||||
} from "@fluentui/react";
|
||||
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 newTableCommand = `CREATE TABLE github_users
|
||||
(
|
||||
user_id bigint,
|
||||
url text,
|
||||
login text,
|
||||
.....`;
|
||||
const distributeTableCommand = `SELECT create_distributed_table('github_users', 'user_id');
|
||||
SELECT create_distributed_table('github_events', 'user_id');`;
|
||||
const loadDataCommand = `-- download users and store in table
|
||||
|
||||
COPY github_users FROM PROGRAM 'curl https://examples.citusdata.com/
|
||||
users.csv' WITH (FORMAT CSV)`;
|
||||
const queryCommand = `-- Find all events for a single user.
|
||||
-- (A common transactional/operational query)
|
||||
|
||||
SELECT created_at, event_type, repo->>'name' AS repo_name
|
||||
FROM github_events
|
||||
WHERE user_id = 3861633;`;
|
||||
|
||||
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>
|
||||
<Text variant="medium">Gettings started in Cosmos DB</Text>
|
||||
{currentStep < 5 && (
|
||||
<Pivot style={{ marginTop: 10, width: "100%" }} selectedKey={GuideSteps[currentStep]}>
|
||||
<PivotItem
|
||||
headerText="Login"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 0)}
|
||||
itemKey={GuideSteps[0]}
|
||||
onClick={() => setCurrentStep(0)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
This tutorial walks you through the most essential Cosmos DB PostgreSQL statements that will be used
|
||||
in the PostgreSQL shell (on the right). You can also choose to go through this quick start by
|
||||
connecting to PGAdmin or other tooling of your choice. <br />
|
||||
<br /> Before you can interact with your data using PGShell, you will need to login - please follow
|
||||
instructions on the right to enter your password
|
||||
</Text>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="New table"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 1)}
|
||||
itemKey={GuideSteps[1]}
|
||||
onClick={() => setCurrentStep(1)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
After logging in, let’s create some new tables for storing data. We will start with two sample tables
|
||||
- one for storing github users and one for storing github events
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>New table</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="newTableCommand"
|
||||
multiline
|
||||
rows={6}
|
||||
readOnly
|
||||
defaultValue={newTableCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#newTableCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Distribute table"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 2)}
|
||||
itemKey={GuideSteps[2]}
|
||||
onClick={() => setCurrentStep(2)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
Congratulations, you have now created your first 2 tables.
|
||||
<br />
|
||||
<br />
|
||||
Your table needs to be sharded on the worker nodes. You need to distribute table before you load any
|
||||
data or run any queries
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 150 }}>Distribute table</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="distributeTableCommand"
|
||||
multiline
|
||||
rows={2}
|
||||
readOnly
|
||||
defaultValue={distributeTableCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#distributeTableCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Load data"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 3)}
|
||||
itemKey={GuideSteps[3]}
|
||||
onClick={() => setCurrentStep(3)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
We're ready to fill the tables with sample data.
|
||||
<br />
|
||||
<br />
|
||||
For this quick start, we'll use a dataset previously captured from the GitHub API. Run the
|
||||
command below to load the data
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>Load data</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="loadDataCommand"
|
||||
multiline
|
||||
rows={4}
|
||||
readOnly
|
||||
defaultValue={loadDataCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#loadDataCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
<PivotItem
|
||||
headerText="Query"
|
||||
onRenderItemLink={(props, defaultRenderer) => customPivotHeaderRenderer(props, defaultRenderer, 4)}
|
||||
itemKey={GuideSteps[4]}
|
||||
onClick={() => setCurrentStep(4)}
|
||||
>
|
||||
<Stack style={{ marginTop: 20 }}>
|
||||
<Text>
|
||||
github_users is a distributed table, meaning its data is divided between multiple shards. Hyperscale
|
||||
(Citus) automatically runs the count on all shards in parallel, and combines the results. Let’s try a
|
||||
query.
|
||||
</Text>
|
||||
<DefaultButton style={{ marginTop: 16, width: 110 }}>Try query</DefaultButton>
|
||||
<Stack horizontal style={{ marginTop: 16 }}>
|
||||
<TextField
|
||||
id="queryCommand"
|
||||
multiline
|
||||
rows={6}
|
||||
readOnly
|
||||
defaultValue={queryCommand}
|
||||
styles={{ root: { width: "90%" } }}
|
||||
/>
|
||||
<IconButton
|
||||
iconProps={{
|
||||
iconName: "Copy",
|
||||
}}
|
||||
onClick={() => onCopyBtnClicked("#queryCommand")}
|
||||
/>
|
||||
</Stack>
|
||||
<Youtube videoId="Jvgh64rvdXU" style={{ margin: "20px 0" }} opts={{ width: "60%" }} />
|
||||
</Stack>
|
||||
</PivotItem>
|
||||
</Pivot>
|
||||
)}
|
||||
{currentStep === 5 && (
|
||||
<Stack style={{ margin: "auto" }} horizontalAlign="center">
|
||||
<Image src={CompleteIcon} />
|
||||
<Text variant="mediumPlus" style={{ fontWeight: 600, 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>
|
||||
);
|
||||
};
|
||||
@@ -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 API 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 <></>;
|
||||
}
|
||||
};
|
||||
@@ -1,39 +1,37 @@
|
||||
/**
|
||||
* Accordion top class
|
||||
*/
|
||||
import {
|
||||
Coachmark,
|
||||
DirectionalHint,
|
||||
Image,
|
||||
Link,
|
||||
Stack,
|
||||
TeachingBubble,
|
||||
TeachingBubbleContent,
|
||||
Text,
|
||||
} from "@fluentui/react";
|
||||
import { TerminalKind } from "Contracts/ViewModels";
|
||||
import { Coachmark, DirectionalHint, Image, Link, Stack, TeachingBubbleContent, Text } from "@fluentui/react";
|
||||
import { useCarousel } from "hooks/useCarousel";
|
||||
import { usePostgres } from "hooks/usePostgres";
|
||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||
import { useTabs } from "hooks/useTabs";
|
||||
import * as React from "react";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
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 ContainersIcon from "../../../images/Containers.svg";
|
||||
import LinkIcon from "../../../images/Link_blue.svg";
|
||||
import NotebookIcon from "../../../images/notebook/Notebook-resource.svg";
|
||||
import NotebookColorIcon from "../../../images/Notebooks.svg";
|
||||
import PowerShellIcon from "../../../images/PowerShell.svg";
|
||||
import QuickStartIcon from "../../../images/Quickstart_Lightning.svg";
|
||||
import ScaleAndSettingsIcon from "../../../images/Scale_15x15.svg";
|
||||
import CollectionIcon from "../../../images/tree-collection.svg";
|
||||
import { AuthType } from "../../AuthType";
|
||||
import * as Constants from "../../Common/Constants";
|
||||
import * as ViewModels from "../../Contracts/ViewModels";
|
||||
import { useSidePanel } from "../../hooks/useSidePanel";
|
||||
import { userContext } from "../../UserContext";
|
||||
import { getCollectionName } from "../../Utils/APITypeUtils";
|
||||
import { getCollectionName, getDatabaseName } from "../../Utils/APITypeUtils";
|
||||
import { FeaturePanelLauncher } from "../Controls/FeaturePanel/FeaturePanelLauncher";
|
||||
import { DataSamplesUtil } from "../DataSamples/DataSamplesUtil";
|
||||
import Explorer from "../Explorer";
|
||||
import * as MostRecentActivity from "../MostRecentActivity/MostRecentActivity";
|
||||
import { useNotebook } from "../Notebook/useNotebook";
|
||||
import { AddDatabasePanel } from "../Panes/AddDatabasePanel/AddDatabasePanel";
|
||||
import { BrowseQueriesPane } from "../Panes/BrowseQueriesPane/BrowseQueriesPane";
|
||||
import { useDatabases } from "../useDatabases";
|
||||
import { useSelectedNode } from "../useSelectedNode";
|
||||
|
||||
@@ -85,12 +83,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
() => this.setState({}),
|
||||
(state) => state.showCoachMark
|
||||
),
|
||||
},
|
||||
{
|
||||
dispose: usePostgres.subscribe(
|
||||
() => this.setState({}),
|
||||
(state) => state.showPostgreTeachingBubble
|
||||
),
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -109,33 +101,11 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
<div className="splashScreenContainer">
|
||||
<div className="splashScreen">
|
||||
<div className="title">
|
||||
{userContext.apiType === "Postgres" ? "Welcome to Cosmos DB - PostgreSQL" : "Welcome to Cosmos DB"}
|
||||
Welcome to Cosmos DB
|
||||
<FeaturePanelLauncher />
|
||||
</div>
|
||||
<div className="subtitle">
|
||||
{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="subtitle">Globally distributed, multi-model database service for any scale</div>
|
||||
<div className="mainButtonsContainer">
|
||||
{userContext.apiType === "Postgres" && usePostgres.getState().showPostgreTeachingBubble && (
|
||||
<TeachingBubble
|
||||
headline="New to Cosmos DB PGSQL?"
|
||||
target={"#quickstartDescription"}
|
||||
hasCloseButton
|
||||
onDismiss={() => usePostgres.getState().setShowPostgreTeachingBubble(false)}
|
||||
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) => (
|
||||
<Stack
|
||||
horizontal
|
||||
@@ -190,49 +160,20 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
</TeachingBubbleContent>
|
||||
</Coachmark>
|
||||
)}
|
||||
{userContext.apiType === "Postgres" ? (
|
||||
<Stack horizontal style={{ margin: "0 auto" }} tokens={{ childrenGap: "15%" }}>
|
||||
<Stack>
|
||||
<Text
|
||||
variant="large"
|
||||
style={{
|
||||
marginBottom: 16,
|
||||
fontFamily: '"Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif',
|
||||
}}
|
||||
>
|
||||
Next steps
|
||||
</Text>
|
||||
{this.getNextStepItems()}
|
||||
</Stack>
|
||||
<Stack>
|
||||
<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>
|
||||
) : (
|
||||
<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 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>
|
||||
</form>
|
||||
@@ -253,15 +194,16 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
public createMainItems(): SplashScreenItem[] {
|
||||
const heroes: SplashScreenItem[] = [];
|
||||
|
||||
if (userContext.apiType === "SQL" || userContext.apiType === "Mongo" || userContext.apiType === "Postgres") {
|
||||
if (userContext.apiType === "SQL" || userContext.apiType === "Mongo") {
|
||||
const launchQuickstartBtn = {
|
||||
id: "quickstartDescription",
|
||||
iconSrc: QuickStartIcon,
|
||||
title: "Launch quick start",
|
||||
description: "Launch a quick start tutorial to get started with sample data",
|
||||
showLinkIcon: userContext.apiType === "Mongo",
|
||||
onClick: () => {
|
||||
userContext.apiType === "Postgres"
|
||||
? useTabs.getState().openAndActivateReactTab(ReactTabKind.Quickstart)
|
||||
userContext.apiType === "Mongo"
|
||||
? window.open("http://aka.ms/mongodbquickstart", "_blank")
|
||||
: this.container.onNewCollectionClicked({ isQuickstart: true });
|
||||
traceOpen(Action.LaunchQuickstart, { apiType: userContext.apiType });
|
||||
},
|
||||
@@ -277,41 +219,118 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
heroes.push(newNotebookBtn);
|
||||
}
|
||||
|
||||
if (userContext.apiType === "Postgres") {
|
||||
const postgreShellBtn = {
|
||||
iconSrc: PowerShellIcon,
|
||||
title: "PostgreSQL Shell",
|
||||
description: "Create table and interact with data using PostgreSQL’s shell interface",
|
||||
onClick: () => this.container.openNotebookTerminal(TerminalKind.Mongo),
|
||||
};
|
||||
heroes.push(postgreShellBtn);
|
||||
} else {
|
||||
const 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 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 = {
|
||||
iconSrc: ConnectIcon,
|
||||
title: userContext.apiType === "Postgres" ? "Connect with PG Admin" : "Connect",
|
||||
description:
|
||||
userContext.apiType === "Postgres"
|
||||
? "Prefer using your own choice of tooling? Find the connection string you need to connect"
|
||||
: "Prefer PGadmin? Find your connection strings here",
|
||||
onClick: () => useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect),
|
||||
title: "Connect",
|
||||
description: "Prefer using your own choice of tooling? Find the connection string you need to connect",
|
||||
onClick: () => useTabs.getState().openAndActivateConnectTab(),
|
||||
};
|
||||
heroes.push(connectBtn);
|
||||
|
||||
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) {
|
||||
return {
|
||||
iconSrc: CollectionIcon,
|
||||
@@ -353,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) {
|
||||
if (event.charCode === Constants.KeyCodes.Space || event.charCode === Constants.KeyCodes.Enter) {
|
||||
callback();
|
||||
@@ -364,7 +406,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
let items: { link: string; title: string; description: string }[];
|
||||
switch (userContext.apiType) {
|
||||
case "SQL":
|
||||
case "Postgres":
|
||||
items = [
|
||||
{
|
||||
link: "https://aka.ms/msl-modeling-partitioning-2",
|
||||
@@ -511,7 +552,6 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
let items: { link: string; title: string; description: string }[];
|
||||
switch (userContext.apiType) {
|
||||
case "SQL":
|
||||
case "Postgres":
|
||||
items = [
|
||||
{
|
||||
link: "https://aka.ms/msl-sdk-connect",
|
||||
@@ -630,76 +670,4 @@ export class SplashScreen extends React.Component<SplashScreenProps> {
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
private getNextStepItems(): JSX.Element {
|
||||
const items: { link: string; title: string; description: string }[] = [
|
||||
{
|
||||
link: "",
|
||||
title: "Performance tuning",
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
{
|
||||
link: "",
|
||||
title: "Join Citus community",
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
{
|
||||
link: "",
|
||||
title: "Useful diagnostic queries",
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{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: "",
|
||||
title: "Data modeling",
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
{
|
||||
link: "",
|
||||
title: "How to choose a distribution Column",
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
{
|
||||
link: "",
|
||||
title: "Build apps with Python/ Java/ Django",
|
||||
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Stack>
|
||||
{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>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -811,7 +811,6 @@ export default class DocumentsTab extends TabsBase {
|
||||
ariaLabel: label,
|
||||
hasPopup: false,
|
||||
disabled: !this.newDocumentButton.enabled(),
|
||||
id: "mongoNewDocumentBtn",
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -600,43 +600,56 @@ export default class QueryTabComponent extends React.Component<IQueryTabComponen
|
||||
metricsMap.forEach((queryMetrics) => {
|
||||
if (queryMetrics) {
|
||||
aggregatedMetrics.documentLoadTime =
|
||||
queryMetrics.documentLoadTime &&
|
||||
this._normalize(queryMetrics.documentLoadTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.documentLoadTime);
|
||||
this._normalize(aggregatedMetrics.documentLoadTime);
|
||||
aggregatedMetrics.documentWriteTime =
|
||||
queryMetrics.documentWriteTime &&
|
||||
this._normalize(queryMetrics.documentWriteTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.documentWriteTime);
|
||||
this._normalize(aggregatedMetrics.documentWriteTime);
|
||||
aggregatedMetrics.indexHitDocumentCount =
|
||||
queryMetrics.indexHitDocumentCount &&
|
||||
this._normalize(queryMetrics.indexHitDocumentCount) +
|
||||
this._normalize(aggregatedMetrics.indexHitDocumentCount);
|
||||
this._normalize(aggregatedMetrics.indexHitDocumentCount);
|
||||
aggregatedMetrics.outputDocumentCount =
|
||||
queryMetrics.outputDocumentCount &&
|
||||
this._normalize(queryMetrics.outputDocumentCount) + this._normalize(aggregatedMetrics.outputDocumentCount);
|
||||
aggregatedMetrics.outputDocumentSize =
|
||||
queryMetrics.outputDocumentSize &&
|
||||
this._normalize(queryMetrics.outputDocumentSize) + this._normalize(aggregatedMetrics.outputDocumentSize);
|
||||
aggregatedMetrics.indexLookupTime =
|
||||
queryMetrics.indexLookupTime &&
|
||||
this._normalize(queryMetrics.indexLookupTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.indexLookupTime);
|
||||
this._normalize(aggregatedMetrics.indexLookupTime);
|
||||
aggregatedMetrics.retrievedDocumentCount =
|
||||
queryMetrics.retrievedDocumentCount &&
|
||||
this._normalize(queryMetrics.retrievedDocumentCount) +
|
||||
this._normalize(aggregatedMetrics.retrievedDocumentCount);
|
||||
this._normalize(aggregatedMetrics.retrievedDocumentCount);
|
||||
aggregatedMetrics.retrievedDocumentSize =
|
||||
queryMetrics.retrievedDocumentSize &&
|
||||
this._normalize(queryMetrics.retrievedDocumentSize) +
|
||||
this._normalize(aggregatedMetrics.retrievedDocumentSize);
|
||||
this._normalize(aggregatedMetrics.retrievedDocumentSize);
|
||||
aggregatedMetrics.vmExecutionTime =
|
||||
queryMetrics.vmExecutionTime &&
|
||||
this._normalize(queryMetrics.vmExecutionTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.vmExecutionTime);
|
||||
this._normalize(aggregatedMetrics.vmExecutionTime);
|
||||
aggregatedMetrics.totalQueryExecutionTime =
|
||||
queryMetrics.totalQueryExecutionTime &&
|
||||
this._normalize(queryMetrics.totalQueryExecutionTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.totalQueryExecutionTime);
|
||||
this._normalize(aggregatedMetrics.totalQueryExecutionTime);
|
||||
|
||||
aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime =
|
||||
aggregatedMetrics.runtimeExecutionTimes &&
|
||||
this._normalize(queryMetrics.runtimeExecutionTimes.queryEngineExecutionTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime);
|
||||
this._normalize(aggregatedMetrics.runtimeExecutionTimes.queryEngineExecutionTime);
|
||||
aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime =
|
||||
aggregatedMetrics.runtimeExecutionTimes &&
|
||||
this._normalize(queryMetrics.runtimeExecutionTimes.systemFunctionExecutionTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime);
|
||||
this._normalize(aggregatedMetrics.runtimeExecutionTimes.systemFunctionExecutionTime);
|
||||
aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime =
|
||||
aggregatedMetrics.runtimeExecutionTimes &&
|
||||
this._normalize(queryMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime.totalMilliseconds()) +
|
||||
this._normalize(aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime);
|
||||
this._normalize(aggregatedMetrics.runtimeExecutionTimes.userDefinedFunctionExecutionTime);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
import { Spinner, SpinnerSize, Stack } from "@fluentui/react";
|
||||
import { NotebookWorkspaceConnectionInfo } from "Contracts/DataModels";
|
||||
import { NotebookTerminalComponent } from "Explorer/Controls/Notebook/NotebookTerminalComponent";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { useNotebook } from "Explorer/Notebook/useNotebook";
|
||||
import { QuickstartGuide } from "Explorer/Quickstart/QuickstartGuide";
|
||||
import React, { useEffect } from "react";
|
||||
import { userContext } from "UserContext";
|
||||
|
||||
interface QuickstartTabProps {
|
||||
explorer: Explorer;
|
||||
}
|
||||
|
||||
export const QuickstartTab: React.FC<QuickstartTabProps> = ({ explorer }: QuickstartTabProps): JSX.Element => {
|
||||
const notebookServerInfo = useNotebook((state) => state.notebookServerInfo);
|
||||
useEffect(() => {
|
||||
explorer.allocateContainer();
|
||||
}, []);
|
||||
const getNotebookServerInfo = (): NotebookWorkspaceConnectionInfo => ({
|
||||
authToken: notebookServerInfo.authToken,
|
||||
notebookServerEndpoint: `${notebookServerInfo.notebookServerEndpoint?.replace(/\/+$/, "")}/mongo`,
|
||||
forwardingId: notebookServerInfo.forwardingId,
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack style={{ width: "100%" }} horizontal>
|
||||
<Stack style={{ width: "50%" }}>
|
||||
<QuickstartGuide />
|
||||
</Stack>
|
||||
<Stack style={{ width: "50%", borderLeft: "black solid 1px" }}>
|
||||
{notebookServerInfo?.notebookServerEndpoint && (
|
||||
<NotebookTerminalComponent
|
||||
notebookServerInfo={getNotebookServerInfo()}
|
||||
databaseAccount={userContext.databaseAccount}
|
||||
tabId="EmbbedTerminal"
|
||||
/>
|
||||
)}
|
||||
{!notebookServerInfo?.notebookServerEndpoint && (
|
||||
<Spinner styles={{ root: { marginTop: 10 } }} size={SpinnerSize.large}></Spinner>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
);
|
||||
};
|
||||
@@ -1,41 +1,33 @@
|
||||
import { CollectionTabKind } from "Contracts/ViewModels";
|
||||
import Explorer from "Explorer/Explorer";
|
||||
import { SplashScreen } from "Explorer/SplashScreen/SplashScreen";
|
||||
import { ConnectTab } from "Explorer/Tabs/ConnectTab";
|
||||
import { QuickstartTab } from "Explorer/Tabs/QuickstartTab";
|
||||
import { useTeachingBubble } from "hooks/useTeachingBubble";
|
||||
import ko from "knockout";
|
||||
import React, { MutableRefObject, useEffect, useRef, useState } from "react";
|
||||
import loadingIcon from "../../../images/circular_loader_black_16x16.gif";
|
||||
import errorIcon from "../../../images/close-black.svg";
|
||||
import { useObservable } from "../../hooks/useObservable";
|
||||
import { ReactTabKind, useTabs } from "../../hooks/useTabs";
|
||||
import { useTabs } from "../../hooks/useTabs";
|
||||
import TabsBase from "./TabsBase";
|
||||
|
||||
type Tab = TabsBase | (TabsBase & { render: () => JSX.Element });
|
||||
|
||||
interface TabsProps {
|
||||
explorer: Explorer;
|
||||
}
|
||||
|
||||
export const Tabs = ({ explorer }: TabsProps): JSX.Element => {
|
||||
const { openedTabs, openedReactTabs, activeTab, activeReactTab } = useTabs();
|
||||
|
||||
export const Tabs = (): JSX.Element => {
|
||||
const { openedTabs, activeTab } = useTabs();
|
||||
const isConnectTabOpen = useTabs((state) => state.isConnectTabOpen);
|
||||
const isConnectTabActive = useTabs((state) => state.isConnectTabActive);
|
||||
return (
|
||||
<div className="tabsManagerContainer">
|
||||
<div id="content" className="flexContainer hideOverflows">
|
||||
<div className="nav-tabs-margin">
|
||||
<ul className="nav nav-tabs level navTabHeight" id="navTabs" role="tablist">
|
||||
{openedReactTabs.map((tab) => (
|
||||
<TabNav key={ReactTabKind[tab]} active={activeReactTab === tab} tabKind={tab} />
|
||||
))}
|
||||
{isConnectTabOpen && <TabNav key="connect" tab={undefined} active={isConnectTabActive} />}
|
||||
{openedTabs.map((tab) => (
|
||||
<TabNav key={tab.tabId} tab={tab} active={activeTab === tab} />
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
<div className="tabPanesContainer">
|
||||
{activeReactTab !== undefined && getReactTabContent(activeReactTab, explorer)}
|
||||
{isConnectTabActive && <ConnectTab />}
|
||||
{openedTabs.map((tab) => (
|
||||
<TabPane key={tab.tabId} tab={tab} active={activeTab === tab} />
|
||||
))}
|
||||
@@ -45,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 focusTab = useRef<HTMLLIElement>() as MutableRefObject<HTMLLIElement>;
|
||||
const tabId = tab ? tab.tabId : "connect";
|
||||
@@ -59,20 +51,8 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
|
||||
<li
|
||||
onMouseOver={() => setHovering(true)}
|
||||
onMouseLeave={() => setHovering(false)}
|
||||
onClick={() => {
|
||||
if (tab) {
|
||||
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);
|
||||
}
|
||||
}}
|
||||
onClick={() => (tab ? tab.onTabClick() : useTabs.getState().activateConnectTab())}
|
||||
onKeyPress={({ nativeEvent: e }) => (tab ? tab.onKeyPressActivate(undefined, e) : onKeyPressConnectTab(e))}
|
||||
className={active ? "active tabList" : "tabList"}
|
||||
title={useObservable(tab?.tabPath || ko.observable(""))}
|
||||
aria-selected={active}
|
||||
@@ -85,18 +65,16 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
|
||||
<span className="tabNavContentContainer">
|
||||
<a data-toggle="tab" href={"#" + tabId} tabIndex={-1}>
|
||||
<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?.isExecuting || ko.observable(false)) && (
|
||||
<img className="loadingIcon" title="Loading" src={loadingIcon} alt="Loading" />
|
||||
)}
|
||||
</span>
|
||||
<span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable(ReactTabKind[tabKind]))}</span>
|
||||
{tabKind !== ReactTabKind.Home && (
|
||||
<span className="tabIconSection">
|
||||
<CloseButton tab={tab} active={active} hovering={hovering} tabKind={tabKind} />
|
||||
</span>
|
||||
)}
|
||||
<span className="tabNavText">{useObservable(tab?.tabTitle || ko.observable("Connect"))}</span>
|
||||
<span className="tabIconSection">
|
||||
<CloseButton tab={tab} active={active} hovering={hovering} />
|
||||
</span>
|
||||
</div>
|
||||
</a>
|
||||
</span>
|
||||
@@ -104,27 +82,14 @@ function TabNav({ tab, active, tabKind }: { tab?: Tab; active: boolean; tabKind?
|
||||
);
|
||||
}
|
||||
|
||||
const CloseButton = ({
|
||||
tab,
|
||||
active,
|
||||
hovering,
|
||||
tabKind,
|
||||
}: {
|
||||
tab: Tab;
|
||||
active: boolean;
|
||||
hovering: boolean;
|
||||
tabKind?: ReactTabKind;
|
||||
}) => (
|
||||
const CloseButton = ({ tab, active, hovering }: { tab: Tab; active: boolean; hovering: boolean }) => (
|
||||
<span
|
||||
style={{ display: hovering || active ? undefined : "none" }}
|
||||
title="Close"
|
||||
role="button"
|
||||
aria-label="Close Tab"
|
||||
className="cancelButton"
|
||||
onClick={(event: React.MouseEvent<HTMLSpanElement, MouseEvent>) => {
|
||||
event.stopPropagation();
|
||||
tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeReactTab(tabKind);
|
||||
}}
|
||||
onClick={() => (tab ? tab.onCloseTabButtonClick() : useTabs.getState().closeConnectTab())}
|
||||
tabIndex={active ? 0 : undefined}
|
||||
onKeyPress={({ nativeEvent: e }) => tab.onKeyPressClose(undefined, e)}
|
||||
>
|
||||
@@ -179,22 +144,9 @@ function TabPane({ tab, active }: { tab: Tab; active: boolean }) {
|
||||
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") {
|
||||
useTabs.getState().activateReactTab(tabKind);
|
||||
useTabs.getState().activateConnectTab();
|
||||
e.stopPropagation();
|
||||
}
|
||||
};
|
||||
|
||||
const getReactTabContent = (activeReactTab: ReactTabKind, explorer: Explorer): JSX.Element => {
|
||||
switch (activeReactTab) {
|
||||
case ReactTabKind.Connect:
|
||||
return <ConnectTab />;
|
||||
case ReactTabKind.Home:
|
||||
return <SplashScreen explorer={explorer} />;
|
||||
case ReactTabKind.Quickstart:
|
||||
return <QuickstartTab explorer={explorer} />;
|
||||
default:
|
||||
throw Error(`Unsupported tab kind ${ReactTabKind[activeReactTab]}`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -95,10 +95,6 @@ export default class TerminalTab extends TabsBase {
|
||||
endpointSuffix = "cassandra";
|
||||
break;
|
||||
|
||||
case ViewModels.TerminalKind.Postgres:
|
||||
endpointSuffix = "postgresql";
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new Error(`Terminal kind: ${options.kind} not supported`);
|
||||
}
|
||||
|
||||
@@ -531,13 +531,8 @@ export const ResourceTree: React.FC<ResourceTreeProps> = ({ container }: Resourc
|
||||
}
|
||||
|
||||
if (userContext.apiType !== "Cassandra" || !isServerlessAccount()) {
|
||||
let id = "";
|
||||
if (collection.isSampleCollection) {
|
||||
id = database.isDatabaseShared() ? "sampleSettings" : "sampleScaleSettings";
|
||||
}
|
||||
|
||||
children.push({
|
||||
id,
|
||||
id: collection.isSampleCollection && !database.isDatabaseShared() ? "sampleScaleSettings" : "",
|
||||
label: database.isDatabaseShared() || isServerlessAccount() ? "Settings" : "Scale & Settings",
|
||||
onClick: collection.onSettingsClick.bind(collection),
|
||||
isSelected: () =>
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { Link, Stack, TeachingBubble, Text } from "@fluentui/react";
|
||||
import { ReactTabKind, useTabs } from "hooks/useTabs";
|
||||
import { 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";
|
||||
import { traceCancel } from "Shared/Telemetry/TelemetryProcessor";
|
||||
|
||||
export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
|
||||
export const QuickstartTutorial: React.FC = (): JSX.Element => {
|
||||
const { step, isSampleDBExpanded, isDocumentsTabOpened, sampleCollection, setStep } = useTeachingBubble();
|
||||
|
||||
const onDimissTeachingBubble = (): void => {
|
||||
@@ -14,10 +13,6 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
|
||||
traceCancel(Action.CancelUITour, { step });
|
||||
};
|
||||
|
||||
if (userContext.apiType !== "SQL") {
|
||||
return <></>;
|
||||
}
|
||||
|
||||
switch (step) {
|
||||
case 1:
|
||||
return isSampleDBExpanded ? (
|
||||
@@ -151,10 +146,7 @@ export const SQLQuickstartTutorial: React.FC = (): JSX.Element => {
|
||||
hasCloseButton
|
||||
primaryButtonProps={{
|
||||
text: "Launch connect",
|
||||
onClick: () => {
|
||||
traceSuccess(Action.CompleteUITour);
|
||||
useTabs.getState().openAndActivateReactTab(ReactTabKind.Connect);
|
||||
},
|
||||
onClick: () => useTabs.getState().openAndActivateConnectTab(),
|
||||
}}
|
||||
secondaryButtonProps={{
|
||||
text: "Previous",
|
||||
@@ -2,7 +2,6 @@ import { initializeIcons, Link, Text } from "@fluentui/react";
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import * as React from "react";
|
||||
import * as ReactDOM from "react-dom";
|
||||
import { userContext } from "UserContext";
|
||||
import { initializeConfiguration } from "../ConfigContext";
|
||||
import { GalleryHeaderComponent } from "../Explorer/Controls/Header/GalleryHeaderComponent";
|
||||
import {
|
||||
@@ -26,9 +25,7 @@ const onInit = async () => {
|
||||
|
||||
const props: GalleryAndNotebookViewerComponentProps = {
|
||||
junoClient: new JunoClient(),
|
||||
selectedTab:
|
||||
galleryViewerProps.selectedTab ||
|
||||
(userContext.features.publicGallery ? GalleryTab.PublicGallery : GalleryTab.OfficialSamples),
|
||||
selectedTab: galleryViewerProps.selectedTab || GalleryTab.PublicGallery,
|
||||
sortBy: galleryViewerProps.sortBy || SortBy.MostRecent,
|
||||
searchText: galleryViewerProps.searchText,
|
||||
};
|
||||
|
||||
36
src/Main.tsx
@@ -1,9 +1,8 @@
|
||||
// CSS Dependencies
|
||||
import { initializeIcons } from "@fluentui/react";
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import { QuickstartCarousel } from "Explorer/Quickstart/QuickstartCarousel";
|
||||
import { MongoQuickstartTutorial } from "Explorer/Quickstart/Tutorials/MongoQuickstartTutorial";
|
||||
import { SQLQuickstartTutorial } from "Explorer/Quickstart/Tutorials/SQLQuickstartTutorial";
|
||||
import { QuickstartCarousel } from "Explorer/Tutorials/QuickstartCarousel";
|
||||
import { QuickstartTutorial } from "Explorer/Tutorials/QuickstartTutorial";
|
||||
import { useCarousel } from "hooks/useCarousel";
|
||||
import React, { useState } from "react";
|
||||
import ReactDOM from "react-dom";
|
||||
@@ -29,6 +28,8 @@ import "../less/TableStyles/EntityEditor.less";
|
||||
import "../less/TableStyles/fulldatatables.less";
|
||||
import "../less/TableStyles/queryBuilder.less";
|
||||
import "../less/tree.less";
|
||||
import { CollapsedResourceTree } from "./Common/CollapsedResourceTree";
|
||||
import { ResourceTreeContainer } from "./Common/ResourceTreeContainer";
|
||||
import "./Explorer/Controls/Accordion/AccordionComponent.less";
|
||||
import "./Explorer/Controls/CollapsiblePanel/CollapsiblePanelComponent.less";
|
||||
import { Dialog } from "./Explorer/Controls/Dialog";
|
||||
@@ -45,10 +46,12 @@ import "./Explorer/Menus/NotificationConsole/NotificationConsole.less";
|
||||
import { NotificationConsole } from "./Explorer/Menus/NotificationConsole/NotificationConsoleComponent";
|
||||
import "./Explorer/Panes/PanelComponent.less";
|
||||
import { SidePanel } from "./Explorer/Panes/PanelContainerComponent";
|
||||
import { SplashScreen } from "./Explorer/SplashScreen/SplashScreen";
|
||||
import "./Explorer/SplashScreen/SplashScreen.less";
|
||||
import { Tabs } from "./Explorer/Tabs/Tabs";
|
||||
import { useConfig } from "./hooks/useConfig";
|
||||
import { useKnockoutExplorer } from "./hooks/useKnockoutExplorer";
|
||||
import { useTabs } from "./hooks/useTabs";
|
||||
import "./Libs/jquery";
|
||||
import "./Shared/appInsights";
|
||||
|
||||
@@ -56,6 +59,8 @@ initializeIcons();
|
||||
|
||||
const App: React.FunctionComponent = () => {
|
||||
const [isLeftPaneExpanded, setIsLeftPaneExpanded] = useState<boolean>(true);
|
||||
const openedTabs = useTabs((state) => state.openedTabs);
|
||||
const isConnectTabOpen = useTabs((state) => state.isConnectTabOpen);
|
||||
const isCarouselOpen = useCarousel((state) => state.shouldOpen);
|
||||
|
||||
const config = useConfig();
|
||||
@@ -81,7 +86,27 @@ const App: React.FunctionComponent = () => {
|
||||
<CommandBar container={explorer} />
|
||||
{/* Collections Tree and Tabs - Begin */}
|
||||
<div className="resourceTreeAndTabs">
|
||||
<Tabs explorer={explorer} />
|
||||
{/* Collections Tree - Start */}
|
||||
<div id="resourcetree" data-test="resourceTreeId" className="resourceTree">
|
||||
<div className="collectionsTreeWithSplitter">
|
||||
{/* Collections Tree Expanded - Start */}
|
||||
<ResourceTreeContainer
|
||||
container={explorer}
|
||||
toggleLeftPaneExpanded={toggleLeftPaneExpanded}
|
||||
isLeftPaneExpanded={isLeftPaneExpanded}
|
||||
/>
|
||||
{/* Collections Tree Expanded - End */}
|
||||
{/* Collections Tree Collapsed - Start */}
|
||||
<CollapsedResourceTree
|
||||
toggleLeftPaneExpanded={toggleLeftPaneExpanded}
|
||||
isLeftPaneExpanded={isLeftPaneExpanded}
|
||||
/>
|
||||
{/* Collections Tree Collapsed - End */}
|
||||
</div>
|
||||
</div>
|
||||
{/* Collections Tree - End */}
|
||||
{openedTabs.length === 0 && !isConnectTabOpen && <SplashScreen explorer={explorer} />}
|
||||
<Tabs />
|
||||
</div>
|
||||
{/* Collections Tree and Tabs - End */}
|
||||
<div
|
||||
@@ -96,8 +121,7 @@ const App: React.FunctionComponent = () => {
|
||||
<SidePanel />
|
||||
<Dialog />
|
||||
{<QuickstartCarousel isOpen={isCarouselOpen} />}
|
||||
{<SQLQuickstartTutorial />}
|
||||
{<MongoQuickstartTutorial />}
|
||||
{<QuickstartTutorial />}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -17,11 +17,11 @@ import {
|
||||
ContainerConnectionInfo,
|
||||
ContainerInfo,
|
||||
IContainerData,
|
||||
IDbAccountAllow,
|
||||
IMaxAllocationTimeExceeded,
|
||||
IMaxDbAccountsPerUserExceeded,
|
||||
IMaxUsersPerDbAccountExceeded,
|
||||
IPhoenixConnectionInfoResult,
|
||||
IPhoenixError,
|
||||
IPhoenixServiceInfo,
|
||||
IProvisionData,
|
||||
IResponse,
|
||||
PhoenixErrorType,
|
||||
@@ -32,7 +32,6 @@ import { userContext } from "../UserContext";
|
||||
import { getAuthorizationHeader } from "../Utils/AuthorizationUtils";
|
||||
|
||||
export class PhoenixClient {
|
||||
private armResourceId: string;
|
||||
private containerHealthHandler: NodeJS.Timeout;
|
||||
private retryOptions: promiseRetry.Options = {
|
||||
retries: Notebook.retryAttempts,
|
||||
@@ -40,42 +39,30 @@ export class PhoenixClient {
|
||||
minTimeout: Notebook.retryAttemptDelayMs,
|
||||
};
|
||||
|
||||
constructor(armResourceId: string) {
|
||||
this.armResourceId = armResourceId;
|
||||
}
|
||||
|
||||
public async allocateContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixServiceInfo>> {
|
||||
public async allocateContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixConnectionInfoResult>> {
|
||||
return this.executeContainerAssignmentOperation(provisionData, "allocate");
|
||||
}
|
||||
|
||||
public async resetContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixServiceInfo>> {
|
||||
public async resetContainer(provisionData: IProvisionData): Promise<IResponse<IPhoenixConnectionInfoResult>> {
|
||||
return this.executeContainerAssignmentOperation(provisionData, "reset");
|
||||
}
|
||||
|
||||
private async executeContainerAssignmentOperation(
|
||||
provisionData: IProvisionData,
|
||||
operation: string
|
||||
): Promise<IResponse<IPhoenixServiceInfo>> {
|
||||
): Promise<IResponse<IPhoenixConnectionInfoResult>> {
|
||||
let response;
|
||||
try {
|
||||
response = await fetch(`${this.getPhoenixControlPlanePathPrefix()}/containerconnections/multicontainer`, {
|
||||
response = await fetch(`${this.getPhoenixControlPlanePathPrefix()}/containerconnections`, {
|
||||
method: operation === "allocate" ? "POST" : "PATCH",
|
||||
headers: PhoenixClient.getHeaders(),
|
||||
body: JSON.stringify(provisionData),
|
||||
});
|
||||
const responseJson = await response?.json();
|
||||
if (response.ok) {
|
||||
const phoenixConnectionInfoResult = responseJson as IPhoenixConnectionInfoResult[];
|
||||
if (
|
||||
!phoenixConnectionInfoResult ||
|
||||
phoenixConnectionInfoResult.length === 0 ||
|
||||
!phoenixConnectionInfoResult[0]
|
||||
) {
|
||||
throw new Error("Received invalid phoenix connection response.");
|
||||
}
|
||||
return {
|
||||
status: response.status,
|
||||
data: phoenixConnectionInfoResult[0].phoenixServiceInfo,
|
||||
data: responseJson,
|
||||
};
|
||||
}
|
||||
const phoenixError = responseJson as IPhoenixError;
|
||||
@@ -116,7 +103,7 @@ export class PhoenixClient {
|
||||
const containerStatus = await response.json();
|
||||
return {
|
||||
durationLeftInMinutes: containerStatus?.durationLeftInMinutes,
|
||||
phoenixServerInfo: containerStatus?.phoenixServerInfo,
|
||||
notebookServerInfo: containerStatus?.notebookServerInfo,
|
||||
status: ContainerStatusType.Active,
|
||||
};
|
||||
} else if (response.status === HttpStatusCodes.NotFound) {
|
||||
@@ -160,7 +147,7 @@ export class PhoenixClient {
|
||||
useNotebook.getState().setIsRefreshed(!useNotebook.getState().isRefreshed);
|
||||
return {
|
||||
durationLeftInMinutes: undefined,
|
||||
phoenixServerInfo: undefined,
|
||||
notebookServerInfo: undefined,
|
||||
status: ContainerStatusType.Disconnected,
|
||||
};
|
||||
}
|
||||
@@ -174,17 +161,15 @@ export class PhoenixClient {
|
||||
}
|
||||
}
|
||||
|
||||
public async getDbAccountAllowedStatus(): Promise<IDbAccountAllow> {
|
||||
public async isDbAcountWhitelisted(): Promise<boolean> {
|
||||
const startKey = TelemetryProcessor.traceStart(Action.PhoenixDBAccountAllowed, {
|
||||
dataExplorerArea: Areas.Notebook,
|
||||
});
|
||||
let responseJson;
|
||||
try {
|
||||
const response = await window.fetch(`${this.getPhoenixControlPlanePathPrefix()}`, {
|
||||
method: "GET",
|
||||
headers: PhoenixClient.getHeaders(),
|
||||
});
|
||||
responseJson = await response?.json();
|
||||
if (response.status !== HttpStatusCodes.OK) {
|
||||
throw new Error(`Received status code: ${response?.status}`);
|
||||
}
|
||||
@@ -195,11 +180,7 @@ export class PhoenixClient {
|
||||
},
|
||||
startKey
|
||||
);
|
||||
return {
|
||||
status: response.status,
|
||||
message: responseJson?.message,
|
||||
type: responseJson?.type,
|
||||
};
|
||||
return response.status === HttpStatusCodes.OK;
|
||||
} catch (error) {
|
||||
TelemetryProcessor.traceFailure(
|
||||
Action.PhoenixDBAccountAllowed,
|
||||
@@ -211,25 +192,26 @@ export class PhoenixClient {
|
||||
startKey
|
||||
);
|
||||
Logger.logError(getErrorMessage(error), "PhoenixClient/IsDbAcountWhitelisted");
|
||||
return {
|
||||
status: HttpStatusCodes.Forbidden,
|
||||
message: responseJson?.message,
|
||||
type: responseJson?.type,
|
||||
};
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public getPhoenixControlPlanePathPrefix(): string {
|
||||
const toolsEndpoint =
|
||||
public static getPhoenixEndpoint(): string {
|
||||
const phoenixEndpoint =
|
||||
userContext.features.phoenixEndpoint ?? userContext.features.junoEndpoint ?? configContext.JUNO_ENDPOINT;
|
||||
|
||||
if (!validateEndpoint(toolsEndpoint, allowedJunoOrigins)) {
|
||||
const error = `${toolsEndpoint} not allowed as tools endpoint`;
|
||||
if (!validateEndpoint(phoenixEndpoint, allowedJunoOrigins)) {
|
||||
const error = `${phoenixEndpoint} not allowed as juno endpoint`;
|
||||
console.error(error);
|
||||
throw new Error(error);
|
||||
}
|
||||
|
||||
return `${toolsEndpoint}/api/controlplane/toolscontainer/cosmosaccounts${this.armResourceId}`;
|
||||
return phoenixEndpoint;
|
||||
}
|
||||
|
||||
public getPhoenixControlPlanePathPrefix(): string {
|
||||
return `${PhoenixClient.getPhoenixEndpoint()}/api/controlplane/toolscontainer/cosmosaccounts${
|
||||
userContext.databaseAccount.id
|
||||
}`;
|
||||
}
|
||||
|
||||
private static getHeaders(): HeadersInit {
|
||||
@@ -247,13 +229,34 @@ export class PhoenixClient {
|
||||
const maxAllocationTimeExceeded = errInfo as IMaxAllocationTimeExceeded;
|
||||
const allocateAfterTimestamp = new Date(maxAllocationTimeExceeded?.earliestAllocationTimestamp);
|
||||
allocateAfterTimestamp.setDate(allocateAfterTimestamp.getDate() + 1);
|
||||
return `${errInfo.message}` + ". Please try again after " + `${allocateAfterTimestamp.toLocaleString()}`;
|
||||
return (
|
||||
`${errInfo.message}` +
|
||||
" Max allocation time for a day to a user is " +
|
||||
`${maxAllocationTimeExceeded.maxAllocationTimePerDayPerUserInMinutes}` +
|
||||
". Please try again after " +
|
||||
`${allocateAfterTimestamp.toLocaleString()}`
|
||||
);
|
||||
}
|
||||
case PhoenixErrorType.MaxDbAccountsPerUserExceeded: {
|
||||
const maxDbAccountsPerUserExceeded = errInfo as IMaxDbAccountsPerUserExceeded;
|
||||
return (
|
||||
`${errInfo.message}` +
|
||||
" Max simultaneous connections allowed per user is " +
|
||||
`${maxDbAccountsPerUserExceeded.maxSimultaneousConnectionsPerUser}` +
|
||||
"."
|
||||
);
|
||||
}
|
||||
case PhoenixErrorType.MaxUsersPerDbAccountExceeded: {
|
||||
const maxUsersPerDbAccountExceeded = errInfo as IMaxUsersPerDbAccountExceeded;
|
||||
return (
|
||||
`${errInfo.message}` +
|
||||
" Max simultaneous users allowed per DbAccount is " +
|
||||
`${maxUsersPerDbAccountExceeded.maxSimultaneousUsersPerDbAccount}` +
|
||||
"."
|
||||
);
|
||||
}
|
||||
case PhoenixErrorType.MaxDbAccountsPerUserExceeded:
|
||||
case PhoenixErrorType.MaxUsersPerDbAccountExceeded:
|
||||
case PhoenixErrorType.AllocationValidationResult:
|
||||
case PhoenixErrorType.RegionNotServicable:
|
||||
case PhoenixErrorType.UserMissingPermissionsError:
|
||||
case PhoenixErrorType.SubscriptionNotAllowed: {
|
||||
return `${errInfo.message}`;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ export type Features = {
|
||||
readonly mongoProxyEndpoint?: string;
|
||||
readonly mongoProxyAPIs?: string;
|
||||
readonly enableThroughputCap: boolean;
|
||||
readonly enablePGQuickstart: boolean;
|
||||
|
||||
// can be set via both flight and feature flag
|
||||
autoscaleDefault: boolean;
|
||||
@@ -91,7 +90,6 @@ export function extractFeatures(given = new URLSearchParams(window.location.sear
|
||||
partitionKeyDefault2: "true" === get("pkpartitionkeytest"),
|
||||
notebooksDownBanner: "true" === get("notebooksDownBanner"),
|
||||
enableThroughputCap: "true" === get("enablethroughputcap"),
|
||||
enablePGQuickstart: "true" === get("enablepgquickstart"),
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ import SqlX from "./SqlX";
|
||||
import {
|
||||
FetchPricesResponse,
|
||||
PriceMapAndCurrencyCode,
|
||||
RegionItem,
|
||||
RegionsResponse,
|
||||
SqlxServiceResource,
|
||||
UpdateDedicatedGatewayRequestParameters,
|
||||
@@ -140,7 +139,7 @@ const getGeneralPath = (subscriptionId: string, resourceGroup: string, name: str
|
||||
return `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${name}`;
|
||||
};
|
||||
|
||||
export const getRegions = async (): Promise<Array<RegionItem>> => {
|
||||
export const getRegions = async (): Promise<Array<string>> => {
|
||||
const telemetryData = {
|
||||
feature: "Calculate approximate cost",
|
||||
function: "getRegions",
|
||||
@@ -150,6 +149,8 @@ export const getRegions = async (): Promise<Array<RegionItem>> => {
|
||||
const getRegionsTimestamp = selfServeTraceStart(telemetryData);
|
||||
|
||||
try {
|
||||
const regions = new Array<string>();
|
||||
|
||||
const response = await armRequestWithoutPolling<RegionsResponse>({
|
||||
host: configContext.ARM_ENDPOINT,
|
||||
path: getGeneralPath(userContext.subscriptionId, userContext.resourceGroup, userContext.databaseAccount.name),
|
||||
@@ -157,12 +158,20 @@ export const getRegions = async (): Promise<Array<RegionItem>> => {
|
||||
apiVersion: "2021-04-01-preview",
|
||||
});
|
||||
|
||||
if (response.result.location !== undefined) {
|
||||
regions.push(response.result.location.split(" ").join("").toLowerCase());
|
||||
} else {
|
||||
for (const location of response.result.locations) {
|
||||
regions.push(location.locationName.split(" ").join("").toLowerCase());
|
||||
}
|
||||
}
|
||||
|
||||
selfServeTraceSuccess(telemetryData, getRegionsTimestamp);
|
||||
return response.result.properties.locations;
|
||||
return regions;
|
||||
} catch (err) {
|
||||
const failureTelemetry = { err, selfServeClassName: SqlX.name };
|
||||
selfServeTraceFailure(failureTelemetry, getRegionsTimestamp);
|
||||
return new Array<RegionItem>();
|
||||
return new Array<string>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -170,7 +179,7 @@ const getFetchPricesPathForRegion = (subscriptionId: string): string => {
|
||||
return `/subscriptions/${subscriptionId}/providers/Microsoft.CostManagement/fetchPrices`;
|
||||
};
|
||||
|
||||
export const getPriceMapAndCurrencyCode = async (regions: Array<RegionItem>): Promise<PriceMapAndCurrencyCode> => {
|
||||
export const getPriceMapAndCurrencyCode = async (regions: Array<string>): Promise<PriceMapAndCurrencyCode> => {
|
||||
const telemetryData = {
|
||||
feature: "Calculate approximate cost",
|
||||
function: "getPriceMapAndCurrencyCode",
|
||||
@@ -182,7 +191,7 @@ export const getPriceMapAndCurrencyCode = async (regions: Array<RegionItem>): Pr
|
||||
try {
|
||||
const priceMap = new Map<string, Map<string, number>>();
|
||||
let currencyCode;
|
||||
for (const regionItem of regions) {
|
||||
for (const region of regions) {
|
||||
const regionPriceMap = new Map<string, number>();
|
||||
|
||||
const response = await armRequestWithoutPolling<FetchPricesResponse>({
|
||||
@@ -193,7 +202,7 @@ export const getPriceMapAndCurrencyCode = async (regions: Array<RegionItem>): Pr
|
||||
queryParams: {
|
||||
filter:
|
||||
"armRegionName eq '" +
|
||||
regionItem.locationName.split(" ").join("").toLowerCase() +
|
||||
region +
|
||||
"' and serviceFamily eq 'Databases' and productName eq 'Azure Cosmos DB Dedicated Gateway - General Purpose'",
|
||||
},
|
||||
});
|
||||
@@ -206,7 +215,7 @@ export const getPriceMapAndCurrencyCode = async (regions: Array<RegionItem>): Pr
|
||||
}
|
||||
regionPriceMap.set(item.skuName, item.retailPrice);
|
||||
}
|
||||
priceMap.set(regionItem.locationName, regionPriceMap);
|
||||
priceMap.set(region, regionPriceMap);
|
||||
}
|
||||
|
||||
selfServeTraceSuccess(telemetryData, getPriceMapAndCurrencyCodeTimestamp);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import { RegionItem } from "SelfServe/SqlX/SqlxTypes";
|
||||
import { IsDisplayable, OnChange, PropertyInfo, RefreshOptions, Values } from "../Decorators";
|
||||
import {
|
||||
selfServeTrace,
|
||||
@@ -209,7 +208,7 @@ const ApproximateCostDropDownInfo: Info = {
|
||||
|
||||
let priceMap: Map<string, Map<string, number>>;
|
||||
let currencyCode: string;
|
||||
let regions: Array<RegionItem>;
|
||||
let regions: Array<string>;
|
||||
|
||||
const calculateCost = (skuName: string, instanceCount: number): Description => {
|
||||
const telemetryData = {
|
||||
@@ -222,47 +221,27 @@ const calculateCost = (skuName: string, instanceCount: number): Description => {
|
||||
|
||||
try {
|
||||
let costPerHour = 0;
|
||||
let costBreakdown = "";
|
||||
for (const regionItem of regions) {
|
||||
const incrementalCost = priceMap.get(regionItem.locationName).get(skuName.replace("Cosmos.", ""));
|
||||
for (const region of regions) {
|
||||
const incrementalCost = priceMap.get(region).get(skuName.replace("Cosmos.", ""));
|
||||
if (incrementalCost === undefined) {
|
||||
throw new Error(`${regionItem.locationName} not found in price map.`);
|
||||
} else if (incrementalCost === 0) {
|
||||
throw new Error(`${regionItem.locationName} cost per hour = 0`);
|
||||
throw new Error("Value not found in map.");
|
||||
}
|
||||
|
||||
let regionalInstanceCount = instanceCount;
|
||||
if (regionItem.isZoneRedundant) {
|
||||
regionalInstanceCount = Math.ceil(instanceCount * 1.5);
|
||||
}
|
||||
|
||||
const regionalCostPerHour = incrementalCost * regionalInstanceCount;
|
||||
costBreakdown += `
|
||||
${regionItem.locationName} ${regionItem.isZoneRedundant ? "(AZ)" : ""}
|
||||
${regionalCostPerHour} ${currencyCode} (${regionalInstanceCount} instances * ${incrementalCost} ${currencyCode})\
|
||||
`;
|
||||
|
||||
if (regionalCostPerHour === 0) {
|
||||
throw new Error(`${regionItem.locationName} Cost per hour = 0`);
|
||||
}
|
||||
|
||||
costPerHour += regionalCostPerHour;
|
||||
costPerHour += incrementalCost;
|
||||
}
|
||||
|
||||
if (costPerHour === 0) {
|
||||
throw new Error("Cost per hour = 0");
|
||||
}
|
||||
|
||||
costPerHour *= instanceCount;
|
||||
costPerHour = Math.round(costPerHour * 100) / 100;
|
||||
|
||||
selfServeTraceSuccess(telemetryData, calculateCostTimestamp);
|
||||
return {
|
||||
textTKey: `${costPerHour} ${currencyCode}
|
||||
${costBreakdown}`,
|
||||
textTKey: `${costPerHour} ${currencyCode}`,
|
||||
type: DescriptionType.Text,
|
||||
};
|
||||
} catch (err) {
|
||||
alert(err);
|
||||
const failureTelemetry = { err, regions, priceMap, selfServeClassName: SqlX.name };
|
||||
selfServeTraceFailure(failureTelemetry, calculateCostTimestamp);
|
||||
|
||||
|
||||
@@ -48,14 +48,10 @@ export type PriceItem = {
|
||||
};
|
||||
|
||||
export type RegionsResponse = {
|
||||
properties: RegionsProperties;
|
||||
};
|
||||
|
||||
export type RegionsProperties = {
|
||||
locations: Array<RegionItem>;
|
||||
location: string;
|
||||
};
|
||||
|
||||
export type RegionItem = {
|
||||
locationName: string;
|
||||
isZoneRedundant: boolean;
|
||||
};
|
||||
|
||||
@@ -130,7 +130,6 @@ export enum Action {
|
||||
CompleteCarousel,
|
||||
LaunchUITour,
|
||||
CancelUITour,
|
||||
CompleteUITour,
|
||||
}
|
||||
|
||||
export const ActionModifiers = {
|
||||
|
||||
@@ -24,10 +24,6 @@ export class JupyterLabAppFactory {
|
||||
this.isShellStarted = content?.includes("Connected to") && content?.includes("cqlsh");
|
||||
}
|
||||
|
||||
private isPostgresShellStarted(content: string | undefined) {
|
||||
this.isShellStarted = content?.includes("cqlsh");
|
||||
}
|
||||
|
||||
constructor(closeTab: () => void) {
|
||||
this.onShellExited = closeTab;
|
||||
this.isShellStarted = false;
|
||||
@@ -40,9 +36,6 @@ export class JupyterLabAppFactory {
|
||||
case "Cassandra":
|
||||
this.checkShellStarted = this.isCassandraShellStarted;
|
||||
break;
|
||||
case "Postgres":
|
||||
this.checkShellStarted = this.isPostgresShellStarted;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { useCarousel } from "hooks/useCarousel";
|
||||
import { usePostgres } from "hooks/usePostgres";
|
||||
import { Action } from "Shared/Telemetry/TelemetryConstants";
|
||||
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
|
||||
import { AuthType } from "./AuthType";
|
||||
@@ -37,6 +36,7 @@ interface UserContext {
|
||||
readonly accessToken?: string;
|
||||
readonly authorizationToken?: string;
|
||||
readonly resourceToken?: string;
|
||||
readonly useSDKOperations: boolean;
|
||||
readonly subscriptionType?: SubscriptionType;
|
||||
readonly quotaId?: string;
|
||||
// API Type is not yet provided by ARM. You need to manually inspect all the capabilities+kind so we abstract that logic in userContext
|
||||
@@ -55,12 +55,13 @@ interface UserContext {
|
||||
collectionCreationDefaults: CollectionCreationDefaults;
|
||||
}
|
||||
|
||||
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra" | "Postgres";
|
||||
export type ApiType = "SQL" | "Mongo" | "Gremlin" | "Tables" | "Cassandra";
|
||||
export type PortalEnv = "localhost" | "blackforest" | "fairfax" | "mooncake" | "prod" | "dev";
|
||||
|
||||
const ONE_WEEK_IN_MS = 604800000;
|
||||
|
||||
const features = extractFeatures();
|
||||
const { enableSDKoperations: useSDKOperations } = features;
|
||||
|
||||
const userContext: UserContext = {
|
||||
apiType: "SQL",
|
||||
@@ -68,6 +69,7 @@ const userContext: UserContext = {
|
||||
isTryCosmosDBSubscription: false,
|
||||
portalEnv: "prod",
|
||||
features,
|
||||
useSDKOperations,
|
||||
addCollectionFlight: CollectionCreation.DefaultAddCollectionDefaultFlight,
|
||||
subscriptionType: CollectionCreation.DefaultSubscriptionType,
|
||||
collectionCreationDefaults: CollectionCreationDefaults,
|
||||
@@ -93,15 +95,13 @@ function updateUserContext(newContext: Partial<UserContext>): void {
|
||||
ONE_WEEK_IN_MS
|
||||
);
|
||||
|
||||
if (!localStorage.getItem(newContext.databaseAccount.id)) {
|
||||
if (newContext.apiType === "Postgres") {
|
||||
usePostgres.getState().setShowPostgreTeachingBubble(true);
|
||||
localStorage.setItem(newContext.databaseAccount.id, "true");
|
||||
} else if (userContext.isTryCosmosDBSubscription || isNewAccount) {
|
||||
useCarousel.getState().setShouldOpen(true);
|
||||
localStorage.setItem(newContext.databaseAccount.id, "true");
|
||||
traceOpen(Action.OpenCarousel);
|
||||
}
|
||||
if (
|
||||
!localStorage.getItem(newContext.databaseAccount.id) &&
|
||||
(userContext.isTryCosmosDBSubscription || isNewAccount)
|
||||
) {
|
||||
useCarousel.getState().setShouldOpen(true);
|
||||
localStorage.setItem(newContext.databaseAccount.id, "true");
|
||||
traceOpen(Action.OpenCarousel);
|
||||
}
|
||||
}
|
||||
Object.assign(userContext, newContext);
|
||||
@@ -111,11 +111,6 @@ function apiType(account: DatabaseAccount | undefined): ApiType {
|
||||
if (!account) {
|
||||
return "SQL";
|
||||
}
|
||||
|
||||
if (features.enablePGQuickstart) {
|
||||
return "Postgres";
|
||||
}
|
||||
|
||||
const capabilities = account.properties?.capabilities;
|
||||
if (capabilities) {
|
||||
if (capabilities.find((c) => c.name === "EnableCassandra")) {
|
||||
|
||||
@@ -17,8 +17,6 @@ export const getCollectionName = (isPlural?: boolean): string => {
|
||||
case "Gremlin":
|
||||
collectionName = "Graph";
|
||||
break;
|
||||
case "Postgres":
|
||||
return "";
|
||||
default:
|
||||
unknownApiType = userContext.apiType;
|
||||
throw new Error(`Unknown API type: ${unknownApiType}`);
|
||||
|
||||
@@ -50,7 +50,6 @@ export const allowedBackendEndpoints: ReadonlyArray<string> = [
|
||||
"https://main.documentdb.ext.azure.com",
|
||||
"https://main.documentdb.ext.azure.cn",
|
||||
"https://main.documentdb.ext.azure.us",
|
||||
"https://main.cosmos.ext.azure",
|
||||
"https://localhost:12901",
|
||||
"https://localhost:1234",
|
||||
];
|
||||
@@ -59,7 +58,6 @@ export const allowedMongoProxyEndpoints: ReadonlyArray<string> = [
|
||||
"https://main.documentdb.ext.azure.com",
|
||||
"https://main.documentdb.ext.azure.cn",
|
||||
"https://main.documentdb.ext.azure.us",
|
||||
"https://main.cosmos.ext.azure",
|
||||
"https://localhost:12901",
|
||||
];
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
import create, { UseStore } from "zustand";
|
||||
|
||||
interface TeachingBubbleState {
|
||||
showPostgreTeachingBubble: boolean;
|
||||
setShowPostgreTeachingBubble: (showPostgreTeachingBubble: boolean) => void;
|
||||
}
|
||||
|
||||
export const usePostgres: UseStore<TeachingBubbleState> = create((set) => ({
|
||||
showPostgreTeachingBubble: false,
|
||||
setShowPostgreTeachingBubble: (showPostgreTeachingBubble: boolean) => set({ showPostgreTeachingBubble }),
|
||||
}));
|
||||
@@ -6,44 +6,37 @@ import TabsBase from "../Explorer/Tabs/TabsBase";
|
||||
|
||||
interface TabsState {
|
||||
openedTabs: TabsBase[];
|
||||
openedReactTabs: ReactTabKind[];
|
||||
activeTab: TabsBase | undefined;
|
||||
activeReactTab: ReactTabKind | undefined;
|
||||
activeTab: TabsBase;
|
||||
isConnectTabOpen: boolean;
|
||||
isConnectTabActive: boolean;
|
||||
activateTab: (tab: TabsBase) => void;
|
||||
activateNewTab: (tab: TabsBase) => void;
|
||||
activateReactTab: (tabkind: ReactTabKind) => void;
|
||||
updateTab: (tab: TabsBase) => void;
|
||||
getTabs: (tabKind: ViewModels.CollectionTabKind, comparator?: (tab: TabsBase) => boolean) => TabsBase[];
|
||||
refreshActiveTab: (comparator: (tab: TabsBase) => boolean) => void;
|
||||
closeTabsByComparator: (comparator: (tab: TabsBase) => boolean) => void;
|
||||
closeTab: (tab: TabsBase) => void;
|
||||
closeAllNotebookTabs: (hardClose: boolean) => void;
|
||||
openAndActivateReactTab: (tabKind: ReactTabKind) => void;
|
||||
closeReactTab: (tabKind: ReactTabKind) => void;
|
||||
}
|
||||
|
||||
export enum ReactTabKind {
|
||||
Connect,
|
||||
Home,
|
||||
Quickstart,
|
||||
activateConnectTab: () => void;
|
||||
openAndActivateConnectTab: () => void;
|
||||
closeConnectTab: () => void;
|
||||
}
|
||||
|
||||
export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
openedTabs: [],
|
||||
openedReactTabs: [ReactTabKind.Home],
|
||||
activeTab: undefined,
|
||||
activeReactTab: ReactTabKind.Home,
|
||||
isConnectTabOpen: false,
|
||||
isConnectTabActive: false,
|
||||
activateTab: (tab: TabsBase): void => {
|
||||
if (get().openedTabs.some((openedTab) => openedTab.tabId === tab.tabId)) {
|
||||
set({ activeTab: tab, activeReactTab: undefined });
|
||||
set({ activeTab: tab, isConnectTabActive: false });
|
||||
tab.onActivate();
|
||||
}
|
||||
},
|
||||
activateNewTab: (tab: TabsBase): void => {
|
||||
set((state) => ({ openedTabs: [...state.openedTabs, tab], activeTab: tab, activeReactTab: undefined }));
|
||||
set((state) => ({ openedTabs: [...state.openedTabs, tab], activeTab: tab, isConnectTabActive: false }));
|
||||
tab.onActivate();
|
||||
},
|
||||
activateReactTab: (tabKind: ReactTabKind): void => set({ activeTab: undefined, activeReactTab: tabKind }),
|
||||
updateTab: (tab: TabsBase) => {
|
||||
if (get().activeTab?.tabId === tab.tabId) {
|
||||
set({ activeTab: tab });
|
||||
@@ -80,7 +73,7 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
return true;
|
||||
});
|
||||
if (updatedTabs.length === 0) {
|
||||
set({ activeTab: undefined, activeReactTab: ReactTabKind.Home });
|
||||
set({ activeTab: undefined, isConnectTabActive: get().isConnectTabOpen });
|
||||
}
|
||||
|
||||
if (tab.tabId === activeTab.tabId && tabIndex !== -1) {
|
||||
@@ -118,28 +111,21 @@ export const useTabs: UseStore<TabsState> = create((set, get) => ({
|
||||
});
|
||||
|
||||
if (get().openedTabs.length === 0) {
|
||||
set({ activeTab: undefined, activeReactTab: ReactTabKind.Home });
|
||||
set({ activeTab: undefined, isConnectTabActive: get().isConnectTabOpen });
|
||||
}
|
||||
}
|
||||
},
|
||||
openAndActivateReactTab: (tabKind: ReactTabKind) => {
|
||||
if (get().openedReactTabs.indexOf(tabKind) === -1) {
|
||||
set((state) => ({
|
||||
openedReactTabs: [...state.openedReactTabs, tabKind],
|
||||
}));
|
||||
activateConnectTab: () => {
|
||||
if (get().isConnectTabOpen) {
|
||||
set({ isConnectTabActive: true, activeTab: undefined });
|
||||
}
|
||||
|
||||
set({ activeTab: undefined, activeReactTab: tabKind });
|
||||
},
|
||||
closeReactTab: (tabKind: ReactTabKind) => {
|
||||
const { activeReactTab, openedTabs, openedReactTabs } = get();
|
||||
const updatedOpenedReactTabs = openedReactTabs.filter((tab: ReactTabKind) => tabKind !== tab);
|
||||
if (activeReactTab === tabKind) {
|
||||
openedTabs?.length > 0
|
||||
? set({ activeTab: openedTabs[0], activeReactTab: undefined })
|
||||
: set({ activeTab: undefined, activeReactTab: updatedOpenedReactTabs[0] });
|
||||
openAndActivateConnectTab: () => set({ isConnectTabActive: true, isConnectTabOpen: true, activeTab: undefined }),
|
||||
closeConnectTab: () => {
|
||||
const { isConnectTabActive, openedTabs } = get();
|
||||
if (isConnectTabActive && openedTabs?.length > 0) {
|
||||
set({ activeTab: openedTabs[0] });
|
||||
}
|
||||
|
||||
set({ openedReactTabs: updatedOpenedReactTabs });
|
||||
set({ isConnectTabActive: false, isConnectTabOpen: false });
|
||||
},
|
||||
}));
|
||||
|
||||