Compare commits

..

1 Commits

Author SHA1 Message Date
Victor Meng
dc63ade6c6 Update copilot endpoints 2023-08-01 16:19:52 -07:00
196 changed files with 32419 additions and 9447 deletions

View File

@@ -144,5 +144,4 @@ src/Explorer/Notebook/NotebookRenderer/decorators/kbd-shortcuts/index.tsx
src/Explorer/Notebook/temp/inputs/connected-editors/codemirror.tsx
src/Explorer/Tree/ResourceTreeAdapter.tsx
__mocks__/monaco-editor.ts
src/Explorer/Tree/ResourceTree.tsx
src/Utils/PriorityBasedExecutionUtils.ts
src/Explorer/Tree/ResourceTree.tsx

View File

@@ -85,8 +85,6 @@ jobs:
path: .cache
key: ${{ runner.os }}-build-cache
- run: npm run pack:prod
env:
NODE_OPTIONS: '--max-old-space-size=4096'
- run: cp -r ./Contracts ./dist/contracts
- run: cp -r ./configs ./dist/configs
- uses: actions/upload-artifact@v2

View File

@@ -23,6 +23,5 @@
"source.fixAll.eslint": true,
"source.organizeImports": true
},
"typescript.preferences.importModuleSpecifier": "non-relative",
"editor.defaultFormatter": "esbenp.prettier-vscode"
"typescript.preferences.importModuleSpecifier": "non-relative"
}

View File

@@ -1,3 +0,0 @@
<svg width="19" height="17" viewBox="0 0 19 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7 0C5.89543 0 5 0.895431 5 2V12C5 13.1046 5.89543 14 7 14H13C14.1046 14 15 13.1046 15 12V2C15 0.89543 14.1046 0 13 0H7ZM6 2C6 1.44772 6.44772 1 7 1H13C13.5523 1 14 1.44772 14 2V12C14 12.5523 13.5523 13 13 13H7C6.44772 13 6 12.5523 6 12V2ZM3 4.00001C3 3.25973 3.4022 2.61339 4 2.26758V12.5C4 13.8807 5.11929 15 6.5 15H12.7324C12.3866 15.5978 11.7403 16 11 16H6.5C4.567 16 3 14.433 3 12.5V4.00001Z" fill="#242424"/>
</svg>

Before

Width:  |  Height:  |  Size: 527 B

View File

@@ -1,3 +1,3 @@
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="10" height="14" viewBox="0 0 10 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 2.5C10 3.88071 7.76142 5 5 5C2.23858 5 0 3.88071 0 2.5C0 1.11929 2.23858 0 5 0C7.76142 0 10 1.11929 10 2.5ZM0 11.5V4.487C1.057 5.413 2.864 6 5 6C7.136 6 8.943 5.413 10 4.487V11.5C10 12.925 7.851 14 5 14C2.149 14 0 12.925 0 11.5Z" fill="#0078D4"/>
</svg>

Before

Width:  |  Height:  |  Size: 363 B

After

Width:  |  Height:  |  Size: 363 B

View File

@@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.25028 7.30723C9.08872 7.49072 9.00001 7.74463 9.00001 8C9.00001 8.27614 8.77615 8.5 8.50001 8.5C8.22387 8.5 8.00001 8.27614 8.00001 8C8.00001 7.52689 8.1613 7.0308 8.49974 6.64641C8.84684 6.25219 9.3597 6 10 6C10.6403 6 11.1532 6.25219 11.5003 6.64641C11.8387 7.0308 12 7.52689 12 8C12 8.48947 11.8839 8.86964 11.6976 9.18921C11.5347 9.46855 11.3225 9.68963 11.1528 9.86652L11.1115 9.90956C10.9247 10.1051 10.7821 10.2639 10.6773 10.4641C10.5773 10.6551 10.5 10.9085 10.5 11.2929C10.5 11.5691 10.2762 11.7929 10 11.7929C9.72387 11.7929 9.50001 11.5691 9.50001 11.2929C9.50001 10.7611 9.61018 10.3464 9.79143 10.0002C9.96788 9.66319 10.2003 9.41576 10.3885 9.21878L10.4106 9.19559C10.5985 8.99908 10.7328 8.85858 10.8337 8.68547C10.9286 8.52273 11 8.31707 11 8C11 7.74463 10.9113 7.49072 10.7497 7.30723C10.5968 7.13358 10.3597 7 10 7C9.64033 7 9.40318 7.13358 9.25028 7.30723ZM9.99991 14.2122C10.3863 14.2122 10.6995 13.899 10.6995 13.5126C10.6995 13.1262 10.3863 12.813 9.99991 12.813C9.61353 12.813 9.3003 13.1262 9.3003 13.5126C9.3003 13.899 9.61353 14.2122 9.99991 14.2122ZM2.00001 10C2.00001 5.58172 5.58173 2 10 2C14.4183 2 18 5.58172 18 10C18 14.4183 14.4183 18 10 18C8.65078 18 7.37829 17.6656 6.26225 17.0748L2.62128 17.9851C2.45089 18.0277 2.27065 17.9777 2.14646 17.8536C2.02227 17.7294 1.97234 17.5491 2.01494 17.3787L2.92518 13.7378C2.33442 12.6217 2.00001 11.3492 2.00001 10ZM10 3C6.13402 3 3.00001 6.13401 3.00001 10C3.00001 11.245 3.32462 12.4128 3.89345 13.4247C3.95602 13.536 3.97363 13.6671 3.94266 13.791L3.18719 16.8128L6.20904 16.0574C6.33294 16.0264 6.46399 16.044 6.57531 16.1066C7.58726 16.6754 8.75497 17 10 17C13.866 17 17 13.866 17 10C17 6.13401 13.866 3 10 3Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.8 KiB

View File

@@ -1,3 +1,3 @@
<svg width="12" height="14" viewBox="0 0 12 14" fill="none" xmlns="http://www.w3.org/2000/svg">
<svg width="13" height="17" viewBox="0 0 13 17" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.21207 0C3.73772 0 3.32085 0.314446 3.19054 0.770537L0.940937 8.64415C0.747029 9.32283 1.25663 9.99841 1.96246 9.99841H3.22974L2.06002 14.6773C1.79611 15.7329 3.10089 16.4551 3.85526 15.6726L12.5318 6.81506L12.5354 6.81137C13.1762 6.1436 12.7152 5 11.7688 5H9.20509L10.4665 1.40582L10.469 1.39836C10.6983 0.710426 10.1863 0 9.46114 0H4.21207Z" fill="#0078D4"/>
</svg>

Before

Width:  |  Height:  |  Size: 475 B

After

Width:  |  Height:  |  Size: 475 B

View File

@@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M6 4C4.89543 4 4 4.89543 4 6V7C4 8.10457 4.89543 9 6 9H14C15.1046 9 16 8.10457 16 7V6C16 4.89543 15.1046 4 14 4H6ZM5 6C5 5.44772 5.44772 5 6 5H14C14.5523 5 15 5.44772 15 6V7C15 7.55228 14.5523 8 14 8H6C5.44772 8 5 7.55228 5 7V6ZM6 11C4.89543 11 4 11.8954 4 13V14C4 15.1046 4.89543 16 6 16H14C15.1046 16 16 15.1046 16 14V13C16 11.8954 15.1046 11 14 11H6ZM5 13C5 12.4477 5.44772 12 6 12H14C14.5523 12 15 12.4477 15 13V14C15 14.5523 14.5523 15 14 15H6C5.44772 15 5 14.5523 5 14V13Z" fill="#242424"/>
</svg>

Before

Width:  |  Height:  |  Size: 609 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4829 0.703737C9.68406 -0.133389 8.39129 0.316883 8.05198 1.29418C7.77205 2.10043 7.4084 3.06594 7.05406 3.77684C5.99442 5.90276 5.37583 7.11234 3.66974 8.62586C3.44337 8.82668 3.15163 8.9885 2.82905 9.11601C1.69991 9.56233 0.638089 10.7321 0.915812 12.1207L1.26885 13.8859C1.45455 14.8144 2.14894 15.5583 3.06251 15.8075L8.66224 17.3347C11.2078 18.0289 13.8017 16.3942 14.2737 13.7983L14.9576 10.0365C15.2924 8.19503 13.8777 6.49989 12.006 6.49989H11.1225L11.1328 6.44766C11.2129 6.03948 11.3093 5.47735 11.3738 4.86473C11.438 4.25446 11.4721 3.58034 11.4218 2.9522C11.3725 2.33584 11.2379 1.70305 10.9176 1.22254C10.8081 1.05832 10.6455 0.874161 10.4829 0.703737Z" fill="#605E5C"/>
</svg>

Before

Width:  |  Height:  |  Size: 799 B

View File

@@ -1,3 +0,0 @@
<svg width="16" height="18" viewBox="0 0 16 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.4829 0.703737C9.68406 -0.133389 8.39129 0.316883 8.05198 1.29418C7.77205 2.10043 7.4084 3.06594 7.05406 3.77684C5.99442 5.90276 5.37583 7.11234 3.66974 8.62586C3.44337 8.82668 3.15163 8.9885 2.82905 9.11601C1.69991 9.56233 0.638089 10.7321 0.915812 12.1207L1.26885 13.8859C1.45455 14.8144 2.14894 15.5583 3.06251 15.8075L8.66224 17.3347C11.2078 18.0289 13.8017 16.3942 14.2737 13.7983L14.9576 10.0365C15.2924 8.19503 13.8777 6.49989 12.006 6.49989H11.1225L11.1328 6.44766C11.2129 6.03948 11.3093 5.47735 11.3738 4.86473C11.438 4.25446 11.4721 3.58034 11.4218 2.9522C11.3725 2.33584 11.2379 1.70305 10.9176 1.22254C10.8081 1.05832 10.6455 0.874161 10.4829 0.703737Z" fill="#0078D4"/>
</svg>

Before

Width:  |  Height:  |  Size: 799 B

View File

@@ -1,3 +0,0 @@
<svg width="15" height="18" viewBox="0 0 15 18" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.55198 1.29418C7.89129 0.316883 9.18406 -0.133389 9.98289 0.703737C10.1455 0.874162 10.3081 1.05832 10.4176 1.22254C10.7379 1.70305 10.8725 2.33584 10.9218 2.9522C10.9721 3.58034 10.938 4.25446 10.8738 4.86473C10.8093 5.47735 10.7129 6.03948 10.6328 6.44766C10.6294 6.46535 10.6259 6.48277 10.6225 6.49989H11.506C13.3777 6.49989 14.7924 8.19503 14.4576 10.0365L13.7737 13.7983C13.3017 16.3942 10.7078 18.0289 8.16224 17.3347L2.56251 15.8075C1.64894 15.5583 0.954555 14.8144 0.768846 13.8859L0.415812 12.1207C0.138089 10.7321 1.19991 9.56233 2.32905 9.11601C2.65163 8.9885 2.94337 8.82668 3.16974 8.62586C4.87583 7.11234 5.49442 5.90276 6.55406 3.77684C6.9084 3.06594 7.27205 2.10043 7.55198 1.29418ZM9.51651 6.87851L9.51689 6.87696L9.51869 6.86962L9.5262 6.83852C9.53284 6.81068 9.54264 6.76892 9.55487 6.71482C9.57935 6.60658 9.61349 6.44919 9.65152 6.25525C9.72773 5.86655 9.81878 5.33493 9.8793 4.76005C9.94006 4.18282 9.96852 3.57569 9.92502 3.03195C9.88058 2.47644 9.76518 2.04673 9.58552 1.77724C9.52643 1.68859 9.41385 1.55593 9.25942 1.3941C9.06051 1.18565 8.63137 1.23417 8.49666 1.62217C8.21411 2.43598 7.83339 3.45183 7.44904 4.22294C6.38216 6.36338 5.69326 7.72396 3.83336 9.37392C3.49304 9.67583 3.08878 9.89099 2.69665 10.046C1.81631 10.394 1.25035 11.1944 1.39639 11.9246L1.74943 13.6898C1.86085 14.2469 2.27748 14.6932 2.82562 14.8427L8.42536 16.3699C10.4052 16.9099 12.4227 15.6384 12.7898 13.6194L13.4738 9.85766C13.697 8.62998 12.7538 7.49989 11.506 7.49989H10.0015C9.84758 7.49989 9.7022 7.42895 9.60745 7.3076C9.51272 7.18627 9.47921 7.02785 9.51651 6.87851C9.51651 6.87847 9.5165 6.87855 9.51651 6.87851Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5 2.5C5 2.22386 4.77614 2 4.5 2C4.22386 2 4 2.22386 4 2.5V4H2.5C2.22386 4 2 4.22386 2 4.5C2 4.77614 2.22386 5 2.5 5H4.5C4.77614 5 5 4.77614 5 4.5V2.5ZM16 2.5C16 2.22386 15.7761 2 15.5 2C15.2239 2 15 2.22386 15 2.5V4.5C15 4.77614 15.2239 5 15.5 5H17.5C17.7761 5 18 4.77614 18 4.5C18 4.22386 17.7761 4 17.5 4H16V2.5ZM7 5C6.44771 5 6 5.44772 6 6V14C6 14.5523 6.44772 15 7 15H13C13.5523 15 14 14.5523 14 14V6C14 5.44772 13.5523 5 13 5H7ZM7 6H13V14H7V6ZM4.5 18C4.77614 18 5 17.7761 5 17.5V15.5C5 15.2239 4.77614 15 4.5 15H2.5C2.22386 15 2 15.2239 2 15.5C2 15.7761 2.22386 16 2.5 16H4V17.5C4 17.7761 4.22386 18 4.5 18ZM15.5 18C15.7761 18 16 17.7761 16 17.5V16H17.5C17.7761 16 18 15.7761 18 15.5C18 15.2239 17.7761 15 17.5 15H15.5C15.2239 15 15 15.2239 15 15.5V17.5C15 17.7761 15.2239 18 15.5 18ZM8.5 8C8.22386 8 8 8.22386 8 8.5C8 8.77614 8.22386 9 8.5 9H11.5C11.7761 9 12 8.77614 12 8.5C12 8.22386 11.7761 8 11.5 8H8.5ZM8.5 10C8.22386 10 8 10.2239 8 10.5C8 10.7761 8.22386 11 8.5 11H10.5C10.7761 11 11 10.7761 11 10.5C11 10.2239 10.7761 10 10.5 10H8.5Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M9.14645 2.64645C9.34171 2.45118 9.65829 2.45118 9.85355 2.64645L11.3536 4.14645C11.5488 4.34171 11.5488 4.65829 11.3536 4.85355L9.85355 6.35355C9.65829 6.54882 9.34171 6.54882 9.14645 6.35355C8.95118 6.15829 8.95118 5.84171 9.14645 5.64645L9.7885 5.00439C7.12517 5.11522 5 7.30943 5 10C5 11.568 5.72118 12.9672 6.85185 13.8847C7.06627 14.0587 7.09904 14.3736 6.92503 14.588C6.75103 14.8024 6.43615 14.8352 6.22172 14.6612C4.86712 13.5619 4 11.882 4 10C4 6.75447 6.57689 4.1108 9.79629 4.00339L9.14645 3.35355C8.95118 3.15829 8.95118 2.84171 9.14645 2.64645ZM13.075 5.41199C13.249 5.19756 13.5639 5.1648 13.7783 5.3388C15.1329 6.43806 16 8.11795 16 10C16 13.2455 13.4231 15.8892 10.2037 15.9966L10.8536 16.6464C11.0488 16.8417 11.0488 17.1583 10.8536 17.3536C10.6583 17.5488 10.3417 17.5488 10.1464 17.3536L8.64645 15.8536C8.55268 15.7598 8.5 15.6326 8.5 15.5C8.5 15.3674 8.55268 15.2402 8.64645 15.1464L10.1464 13.6464C10.3417 13.4512 10.6583 13.4512 10.8536 13.6464C11.0488 13.8417 11.0488 14.1583 10.8536 14.3536L10.2115 14.9956C12.8748 14.8848 15 12.6906 15 10C15 8.43201 14.2788 7.03283 13.1482 6.1153C12.9337 5.94129 12.901 5.62641 13.075 5.41199Z" fill="#242424"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,34 +0,0 @@
<svg width="20" height="22" viewBox="0 0 20 22" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.79997 1.36139L9.59997 1.54445V6.72957L6.71997 7.39864L5.75998 8.71588V10.7866C5.75998 12.178 6.51265 13.4605 7.72739 14.139L10.4421 15.6554L5.75997 18.1318L3.81352 18.4092L1.96738 17.378C0.75264 16.6995 -3.05176e-05 15.417 -3.05176e-05 14.0256V7.97332C-3.05176e-05 6.58155 0.753043 5.29871 1.9683 4.62034L7.3904 1.59367L7.38722 1.59591L7.79997 1.36139Z" fill="url(#paint0_radial_1157_162756)"/>
<path d="M7.79997 1.36139L9.59997 1.54445V6.72957L6.71997 7.39864L5.75998 8.71588V10.7866C5.75998 12.178 6.51265 13.4605 7.72739 14.139L10.4421 15.6554L5.75997 18.1318L3.81352 18.4092L1.96738 17.378C0.75264 16.6995 -3.05176e-05 15.417 -3.05176e-05 14.0256V7.97332C-3.05176e-05 6.58155 0.753043 5.29871 1.9683 4.62034L7.3904 1.59367L7.38722 1.59591L7.79997 1.36139Z" fill="url(#paint1_linear_1157_162756)"/>
<path d="M13.4397 8.11841L18.2397 10.9984L19.1997 11.9584V14.025C19.1997 15.4164 18.447 16.6989 17.2323 17.3774L11.4723 20.5948C10.3085 21.2448 8.89088 21.2448 7.72711 20.5948L1.96711 17.3774C1.85515 17.3149 1.74713 17.2472 1.64325 17.1748L1.96708 17.3557C3.13085 18.0057 4.54849 18.0057 5.71226 17.3557L11.4723 14.1383C12.687 13.4598 13.4397 12.1773 13.4397 10.7859V8.11841Z" fill="url(#paint2_radial_1157_162756)"/>
<path d="M13.4397 8.11841L18.2397 10.9984L19.1997 11.9584V14.025C19.1997 15.4164 18.447 16.6989 17.2323 17.3774L11.4723 20.5948C10.3085 21.2448 8.89088 21.2448 7.72711 20.5948L1.96711 17.3774C1.85515 17.3149 1.74713 17.2472 1.64325 17.1748L1.96708 17.3557C3.13085 18.0057 4.54849 18.0057 5.71226 17.3557L11.4723 14.1383C12.687 13.4598 13.4397 12.1773 13.4397 10.7859V8.11841Z" fill="url(#paint3_linear_1157_162756)"/>
<path d="M17.2316 4.62014L11.4716 1.40484C10.3083 0.755475 8.89151 0.755475 7.72821 1.40484L7.38921 1.59407C6.37448 2.30824 5.75989 3.47665 5.75989 4.73397V8.74548L7.72821 7.64674C8.89151 6.99738 10.3083 6.99738 11.4716 7.64674L17.2316 10.862C18.4192 11.525 19.1654 12.7652 19.1987 14.1202C19.1995 14.0886 19.1999 14.057 19.1999 14.0254V7.97311C19.1999 6.58134 18.4468 5.29851 17.2316 4.62014Z" fill="url(#paint4_radial_1157_162756)"/>
<path d="M17.2316 4.62014L11.4716 1.40484C10.3083 0.755475 8.89151 0.755475 7.72821 1.40484L7.38921 1.59407C6.37448 2.30824 5.75989 3.47665 5.75989 4.73397V8.74548L7.72821 7.64674C8.89151 6.99738 10.3083 6.99738 11.4716 7.64674L17.2316 10.862C18.4192 11.525 19.1654 12.7652 19.1987 14.1202C19.1995 14.0886 19.1999 14.057 19.1999 14.0254V7.97311C19.1999 6.58134 18.4468 5.29851 17.2316 4.62014Z" fill="url(#paint5_linear_1157_162756)"/>
<defs>
<radialGradient id="paint0_radial_1157_162756" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(8.1032 6.84805) rotate(112.544) scale(14.0711 11.584)">
<stop offset="0.206732" stop-color="#4995D0"/>
<stop offset="0.875628" stop-color="#0078D4"/>
</radialGradient>
<linearGradient id="paint1_linear_1157_162756" x1="6.63744" y1="16.8883" x2="5.87214" y2="15.464" gradientUnits="userSpaceOnUse">
<stop offset="0.9999" stop-color="#0078D4"/>
<stop offset="1" stop-color="#0078D4" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint2_radial_1157_162756" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(4.13968 15.6306) rotate(-3.9995) scale(14.7718 9.27561)">
<stop offset="0.140029" stop-color="#80C8FF"/>
<stop offset="0.952721" stop-color="#0078D4"/>
</radialGradient>
<linearGradient id="paint3_linear_1157_162756" x1="16.1362" y1="10.2483" x2="15.3298" y2="11.6531" gradientUnits="userSpaceOnUse">
<stop offset="0.9999" stop-color="#3F8AC3"/>
<stop offset="1" stop-color="#8C66BA" stop-opacity="0"/>
</linearGradient>
<radialGradient id="paint4_radial_1157_162756" cx="0" cy="0" r="1" gradientUnits="userSpaceOnUse" gradientTransform="translate(15.9793 10.7505) rotate(-138.33) scale(13.6809 7.80282)">
<stop stop-color="#7BC6FF"/>
<stop offset="0.839255" stop-color="#0078D4"/>
</radialGradient>
<linearGradient id="paint5_linear_1157_162756" x1="5.75989" y1="6.14584" x2="7.32799" y2="6.14584" gradientUnits="userSpaceOnUse">
<stop offset="0.9999" stop-color="#0078D4"/>
<stop offset="1" stop-color="#436DCD" stop-opacity="0"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.2 KiB

View File

@@ -1,29 +0,0 @@
<svg width="121" height="94" viewBox="0 0 121 94" fill="none" xmlns="http://www.w3.org/2000/svg">
<path opacity="0.3" d="M3.25029 80.7474H97.1699C97.8805 80.7474 98.5648 80.471 99.078 79.9578C99.5913 79.4446 99.8676 78.7603 99.8676 78.0497V13.8575C99.8676 12.3704 98.3148 11.0018 96.2224 11.0018L4.53992 12.3968C4.18461 12.3968 3.84247 12.4626 3.51348 12.5942C3.18449 12.7389 2.89498 12.9231 2.64495 13.1863C2.39492 13.4364 2.19752 13.7259 2.05277 14.0549C1.90801 14.3838 1.85538 14.7392 1.85538 15.0813L0.552582 78.076C0.552582 78.7866 0.82893 79.4709 1.34215 79.971C1.85537 80.471 2.53967 80.7474 3.25029 80.7474Z" fill="#1F1D20"/>
<path d="M96.9332 9.80411H2.67139C1.19752 9.80411 0 11.0016 0 12.4755V76.7993C0 78.2732 1.19752 79.4707 2.67139 79.4707H96.9463C98.4202 79.4707 99.6177 78.2732 99.6177 76.7993V12.4755C99.6045 11.0016 98.407 9.80411 96.9332 9.80411Z" fill="url(#paint0_linear_1157_163007)"/>
<path d="M95.6963 13.7121H50.1379V74.904H95.6963V13.7121Z" fill="white"/>
<path d="M50.7829 13.7121H5.22461V74.904H50.7829V13.7121Z" fill="#CDCDD0"/>
<path d="M14.3309 0V60.6918C14.3309 60.6918 26.4903 59.4811 36.3468 64.4291C46.2165 69.3771 50.7829 74.8514 50.7829 74.8514V14.1465C50.7829 14.1465 45.0979 6.90876 36.3468 4.23737C29.2275 2.05289 14.3309 0 14.3309 0Z" fill="#EAEAEA"/>
<path d="M59.1387 42.9135L56.2699 41.6633L53.388 42.9135V9.80411H59.1387V42.9135Z" fill="url(#paint1_linear_1157_163007)"/>
<path opacity="0.15" d="M86.7212 25.6883H66.7713C65.9028 25.6883 65.2053 26.3989 65.2053 27.2543C65.2053 28.1228 65.9159 28.8202 66.7713 28.8202H86.7212C87.5897 28.8202 88.2872 28.1096 88.2872 27.2543C88.3003 26.3857 87.5897 25.6883 86.7212 25.6883Z" fill="#1F1D20"/>
<path opacity="0.15" d="M86.7212 32.5045H66.7713C65.9028 32.5045 65.2053 33.2151 65.2053 34.0705C65.2053 34.939 65.9159 35.6365 66.7713 35.6365H86.7212C87.5897 35.6365 88.2872 34.9258 88.2872 34.0705C88.3003 33.2019 87.5897 32.5045 86.7212 32.5045Z" fill="#1F1D20"/>
<path opacity="0.15" fill-rule="evenodd" clip-rule="evenodd" d="M66.7715 39.3336H86.695C87.5636 39.3336 88.261 40.0442 88.261 40.8995C88.261 41.7681 87.5504 42.4655 86.695 42.4655H66.7715C65.903 42.4655 65.2055 41.7549 65.2055 40.8995C65.1923 40.0442 65.8898 39.3336 66.7715 39.3336Z" fill="#1F1D20"/>
<path d="M86.7212 25.1614H66.7713C65.9028 25.1614 65.2053 25.872 65.2053 26.7273C65.2053 27.5959 65.9159 28.2933 66.7713 28.2933H86.7212C87.5897 28.2933 88.2872 27.5827 88.2872 26.7273C88.3003 25.8588 87.5897 25.1614 86.7212 25.1614Z" fill="#50E6FF"/>
<path d="M86.7212 31.9917H66.7713C65.9028 31.9917 65.2053 32.7023 65.2053 33.5577C65.2053 34.4262 65.9159 35.1237 66.7713 35.1237H86.7212C87.5897 35.1237 88.2872 34.4131 88.2872 33.5577C88.3003 32.6892 87.5897 31.9917 86.7212 31.9917Z" fill="#32B0E7"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M66.7715 38.808H86.695C87.5636 38.808 88.261 39.5186 88.261 40.3739C88.261 41.2425 87.5504 41.9399 86.695 41.9399H66.7715C65.903 41.9531 65.2055 41.2293 65.2055 40.3739C65.1923 39.5186 65.8898 38.808 66.7715 38.808Z" fill="#185A97"/>
<path opacity="0.2" d="M120.295 60.2875H80.476V85.9653C80.476 87.0514 81.3515 87.9269 82.4375 87.9269H86.6156V94L92.733 87.9269H118.333C119.419 87.9269 120.295 87.0514 120.295 85.9653V60.2875Z" fill="#1F1D21"/>
<path d="M118.965 58.6804H81.8058C81.0744 58.6804 80.476 59.2788 80.476 60.0103V84.9898C80.476 85.7213 81.0744 86.3197 81.8058 86.3197H86.6156V92.3928L92.733 86.3197H118.965C119.696 86.3197 120.295 85.7213 120.295 84.9898V60.0103C120.295 59.2788 119.696 58.6804 118.965 58.6804Z" fill="#49C8EF"/>
<path d="M106.564 67.8017H94.1846C93.697 67.8017 93.298 68.2006 93.298 68.6883C93.298 69.1759 93.697 69.5748 94.1846 69.5748H106.564C107.051 69.5748 107.45 69.1759 107.45 68.6883C107.45 68.2006 107.051 67.8017 106.564 67.8017Z" fill="#C3F1FF"/>
<path d="M106.564 71.6913H94.1846C93.697 71.6913 93.298 72.0903 93.298 72.5779C93.298 73.0655 93.697 73.4645 94.1846 73.4645H106.564C107.051 73.4645 107.45 73.0655 107.45 72.5779C107.45 72.1014 107.051 71.6913 106.564 71.6913Z" fill="#C3F1FF"/>
<path d="M106.564 75.6026H94.1846C93.697 75.6026 93.298 76.0016 93.298 76.4892C93.298 76.9768 93.697 77.3758 94.1846 77.3758H106.564C107.051 77.3758 107.45 76.9768 107.45 76.4892C107.45 75.9905 107.051 75.6026 106.564 75.6026Z" fill="#C3F1FF"/>
<defs>
<linearGradient id="paint0_linear_1157_163007" x1="49.8133" y1="14.2868" x2="49.8133" y2="85.0398" gradientUnits="userSpaceOnUse">
<stop stop-color="#007ED8"/>
<stop offset="0.7065" stop-color="#002D4C"/>
</linearGradient>
<linearGradient id="paint1_linear_1157_163007" x1="36.5785" y1="-9.69372" x2="104.813" y2="115.29" gradientUnits="userSpaceOnUse">
<stop stop-color="#007ED8"/>
<stop offset="0.7065" stop-color="#002D4C"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 4.6 KiB

View File

@@ -1,3 +0,0 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M5.5 4C4.67157 4 4 4.67157 4 5.5V6.5C4 6.77614 3.77614 7 3.5 7C3.22386 7 3 6.77614 3 6.5V5.5C3 4.11929 4.11929 3 5.5 3H6.5C6.77614 3 7 3.22386 7 3.5C7 3.77614 6.77614 4 6.5 4H5.5ZM16 5.5C16 4.67157 15.3284 4 14.5 4H13.5C13.2239 4 13 3.77614 13 3.5C13 3.22386 13.2239 3 13.5 3H14.5C15.8807 3 17 4.11929 17 5.5V6.5C17 6.77614 16.7761 7 16.5 7C16.2239 7 16 6.77614 16 6.5V5.5ZM16 14.5C16 15.3284 15.3284 16 14.5 16H13.5C13.2239 16 13 16.2239 13 16.5C13 16.7761 13.2239 17 13.5 17H14.5C15.8807 17 17 15.8807 17 14.5V13.5C17 13.2239 16.7761 13 16.5 13C16.2239 13 16 13.2239 16 13.5V14.5ZM4 14.5C4 15.3284 4.67157 16 5.5 16H6.75C7.02614 16 7.25 16.2239 7.25 16.5C7.25 16.7761 7.02614 17 6.75 17H5.5C4.11929 17 3 15.8807 3 14.5V13.25C3 12.9739 3.22386 12.75 3.5 12.75C3.77614 12.75 4 12.9739 4 13.25V14.5ZM8.5 7C7.67157 7 7 7.67157 7 8.5V11.5C7 12.3284 7.67157 13 8.5 13H11.5C12.3284 13 13 12.3284 13 11.5V8.5C13 7.67157 12.3284 7 11.5 7H8.5ZM8 8.5C8 8.22386 8.22386 8 8.5 8H11.5C11.7761 8 12 8.22386 12 8.5V11.5C12 11.7761 11.7761 12 11.5 12H8.5C8.22386 12 8 11.7761 8 11.5V8.5Z" fill="#424242"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,3 +0,0 @@
<svg width="20" height="22" viewBox="0 0 28 28" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M12.5849 1.28273C11.0125 0.262814 8.98746 0.262813 7.41509 1.28273L2.16509 4.68813C0.8149 5.56393 0 7.06384 0 8.6732V13.3268C0 14.9361 0.814898 16.4361 2.16509 17.3119L7.41509 20.7173C8.98746 21.7372 11.0125 21.7372 12.5849 20.7173L17.8349 17.3119C19.1851 16.4361 20 14.9361 20 13.3268V8.6732C20 7.06384 19.1851 5.56393 17.8349 4.68813L12.5849 1.28273ZM9.50097 2.05627C10.2759 1.93601 11.0848 2.09764 11.7686 2.54117L17.0186 5.94657C17.9424 6.54581 18.5 7.57205 18.5 8.6732V11.3955C18.287 11.1926 18.0465 11.0117 17.7802 10.8585L11.8647 7.4571C10.7104 6.79343 9.29086 6.79152 8.13486 7.45209L7.5 7.81487V4.41942C7.5 3.54181 8.01028 2.74428 8.80712 2.37651L9.50097 2.05627ZM17.8644 15.2257L17.7932 15.3503C17.5776 15.6214 17.3172 15.8597 17.0186 16.0534L11.7686 19.4588C10.6928 20.1567 9.30721 20.1567 8.23138 19.4588L5.86807 17.9259C6.11557 17.8361 6.35595 17.7193 6.58487 17.5754L12.2457 14.0172C13.3374 13.3309 14 12.1318 14 10.8423V10.4152L17.0324 12.1589C18.1077 12.7771 18.4798 14.1489 17.8644 15.2257ZM12.5 9.55272V10.8423C12.5 11.616 12.1025 12.3354 11.4474 12.7472L10.0303 13.6379L8.57078 12.7398C7.90535 12.3303 7.5 11.6049 7.5 10.8235V9.54249L8.87907 8.75445C9.57267 8.35811 10.4244 8.35926 11.1169 8.75746L12.5 9.55272ZM8.61445 14.5279L5.78662 16.3054C5.02045 16.787 4.04031 16.7627 3.29894 16.2437L2.5521 15.721C1.88767 15.1111 1.5 14.245 1.5 13.3268V8.6732C1.5 7.57205 2.05756 6.5458 2.98138 5.94657L6.0268 3.97116C6.00907 4.11873 6 4.26836 6 4.41942V10.8235C6 12.1258 6.67558 13.3348 7.78463 14.0173L8.61445 14.5279Z" fill="#0078D4"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,3 +0,0 @@
<svg width="14" height="13" viewBox="0 0 14 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3 0C1.61929 0 0.5 1.11929 0.5 2.5V9.5C0.5 10.8807 1.61929 12 3 12H4.75716C4.50353 11.6929 4.28261 11.3578 4.09971 11H3C2.17157 11 1.5 10.3284 1.5 9.5V2.5C1.5 1.67157 2.17157 1 3 1H10C10.8284 1 11.5 1.67157 11.5 2.5V3.59971C11.8578 3.78261 12.1929 4.00353 12.5 4.25716V2.5C12.5 1.11929 11.3807 0 10 0H3ZM9 13C11.4853 13 13.5 10.9853 13.5 8.5C13.5 6.01472 11.4853 4 9 4C6.51472 4 4.5 6.01472 4.5 8.5C4.5 10.9853 6.51472 13 9 13ZM10.8536 6.64645C11.0488 6.84171 11.0488 7.15829 10.8536 7.35355L9.70711 8.5L10.8536 9.64645C11.0488 9.84171 11.0488 10.1583 10.8536 10.3536C10.6583 10.5488 10.3417 10.5488 10.1464 10.3536L9 9.20711L7.85355 10.3536C7.65829 10.5488 7.34171 10.5488 7.14645 10.3536C6.95118 10.1583 6.95118 9.84171 7.14645 9.64645L8.29289 8.5L7.14645 7.35355C6.95118 7.15829 6.95118 6.84171 7.14645 6.64645C7.34171 6.45118 7.65829 6.45118 7.85355 6.64645L9 7.79289L10.1464 6.64645C10.3417 6.45118 10.6583 6.45118 10.8536 6.64645Z" fill="#0078D4"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.0 KiB

View File

@@ -1,20 +0,0 @@
<svg width="40" height="40" viewBox="0 0 40 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M1.11108 12.8623H38.8889V33.9245C38.8889 34.2593 38.7559 34.5803 38.5192 34.8171C38.2825 35.0538 37.9614 35.1867 37.6266 35.1867H2.37331C2.03854 35.1867 1.71749 35.0538 1.48078 34.8171C1.24407 34.5803 1.11108 34.2593 1.11108 33.9245V12.8623Z" fill="url(#paint0_linear_307_12833)"/>
<path d="M2.37997 4.81349H37.62C37.7857 4.81349 37.9499 4.84614 38.103 4.90958C38.2561 4.97301 38.3953 5.06598 38.5125 5.18319C38.6297 5.3004 38.7227 5.43955 38.7861 5.59269C38.8495 5.74582 38.8822 5.90996 38.8822 6.07572V12.8624H1.11108V6.07572C1.11108 5.9094 1.14395 5.74472 1.2078 5.59114C1.27165 5.43756 1.36522 5.29812 1.48313 5.18083C1.60105 5.06353 1.74098 4.97069 1.89489 4.90766C2.0488 4.84462 2.21366 4.81262 2.37997 4.81349V4.81349Z" fill="#0078D4"/>
<path opacity="0.9" d="M12.6021 15.8242H5.74876C5.40144 15.8242 5.11987 16.1058 5.11987 16.4531V19.3064C5.11987 19.6538 5.40144 19.9353 5.74876 19.9353H12.6021C12.9494 19.9353 13.231 19.6538 13.231 19.3064V16.4531C13.231 16.1058 12.9494 15.8242 12.6021 15.8242Z" fill="white"/>
<path opacity="0.9" d="M23.4821 15.7666H16.6288C16.2814 15.7666 15.9999 16.0482 15.9999 16.3955V19.2488C15.9999 19.5961 16.2814 19.8777 16.6288 19.8777H23.4821C23.8294 19.8777 24.111 19.5961 24.111 19.2488V16.3955C24.111 16.0482 23.8294 15.7666 23.4821 15.7666Z" fill="white"/>
<path opacity="0.9" d="M34.3621 15.7666H27.5088C27.1614 15.7666 26.8799 16.0482 26.8799 16.3955V19.2488C26.8799 19.5961 27.1614 19.8777 27.5088 19.8777H34.3621C34.7094 19.8777 34.991 19.5961 34.991 19.2488V16.3955C34.991 16.0482 34.7094 15.7666 34.3621 15.7666Z" fill="white"/>
<path opacity="0.9" d="M12.7221 21.7051H5.86876C5.52143 21.7051 5.23987 21.9866 5.23987 22.334V25.1873C5.23987 25.5346 5.52143 25.8162 5.86876 25.8162H12.7221C13.0694 25.8162 13.351 25.5346 13.351 25.1873V22.334C13.351 21.9866 13.0694 21.7051 12.7221 21.7051Z" fill="white"/>
<path d="M23.6021 21.6465H16.7488C16.4014 21.6465 16.1199 21.928 16.1199 22.2754V25.1287C16.1199 25.476 16.4014 25.7576 16.7488 25.7576H23.6021C23.9494 25.7576 24.231 25.476 24.231 25.1287V22.2754C24.231 21.928 23.9494 21.6465 23.6021 21.6465Z" fill="#ECF4FD"/>
<path d="M34.4821 21.6465H27.6288C27.2814 21.6465 26.9999 21.928 26.9999 22.2754V25.1287C26.9999 25.476 27.2814 25.7576 27.6288 25.7576H34.4821C34.8294 25.7576 35.111 25.476 35.111 25.1287V22.2754C35.111 21.928 34.8294 21.6465 34.4821 21.6465Z" fill="#ECF4FD"/>
<path d="M12.7221 27.6426H5.86876C5.52143 27.6426 5.23987 27.9241 5.23987 28.2715V31.1248C5.23987 31.4721 5.52143 31.7537 5.86876 31.7537H12.7221C13.0694 31.7537 13.351 31.4721 13.351 31.1248V28.2715C13.351 27.9241 13.0694 27.6426 12.7221 27.6426Z" fill="#ECF4FD"/>
<path d="M23.6021 27.585H16.7488C16.4014 27.585 16.1199 27.8665 16.1199 28.2139V31.0672C16.1199 31.4145 16.4014 31.6961 16.7488 31.6961H23.6021C23.9494 31.6961 24.231 31.4145 24.231 31.0672V28.2139C24.231 27.8665 23.9494 27.585 23.6021 27.585Z" fill="#ECF4FD"/>
<path d="M34.4821 27.585H27.6288C27.2814 27.585 26.9999 27.8665 26.9999 28.2139V31.0672C26.9999 31.4145 27.2814 31.6961 27.6288 31.6961H34.4821C34.8294 31.6961 35.111 31.4145 35.111 31.0672V28.2139C35.111 27.8665 34.8294 27.585 34.4821 27.585Z" fill="#ECF4FD"/>
<defs>
<linearGradient id="paint0_linear_307_12833" x1="20" y1="35.1867" x2="20" y2="12.8623" gradientUnits="userSpaceOnUse">
<stop stop-color="#0078D4"/>
<stop offset="0.502" stop-color="#4093E6"/>
<stop offset="0.775" stop-color="#5EA0EF"/>
</linearGradient>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -68,8 +68,7 @@ module.exports = {
// A map from regular expressions to module names that allow to stub out resources with a single module
moduleNameMapper: {
"^.*[.](png|gif|less|css)$": "<rootDir>/mockModule",
"(.*)$[.](svg)": "<rootDir>/mockModule/$1",
"^.*[.](svg|png|gif|less|css)$": "<rootDir>/mockModule",
"@nteract/stateful-components/(.*)$": "<rootDir>/mockModule",
"@fluentui/react/lib/(.*)$": "@fluentui/react/lib-commonjs/$1", // https://github.com/microsoft/fluentui/wiki/Version-8-release-notes
"monaco-editor/(.*)$": "<rootDir>/__mocks__/monaco-editor",
@@ -166,7 +165,6 @@ module.exports = {
transform: {
"^.+\\.html?$": "html-loader-jest",
"^.+\\.[t|j]sx?$": "babel-jest",
"^.+\\.svg$": "<rootDir>/svgTransform.js",
},
// An array of regexp pattern strings that are matched against all source file paths, matched files will skip transformation

View File

@@ -10,7 +10,6 @@
@DataExplorerFont: wf_segoe-ui_normal, "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
@SemiboldFont: "Segoe UI Semibold", "Segoe UI", "Segoe WP", Tahoma, Arial, sans-serif;
@GrayScale: "grayscale()";
@NoColor: "brightness(0) saturate(100%)";
@xSmallFontSize: 4px;
@smallFontSize: 8px;
@@ -148,41 +147,14 @@
// CommandBar
@CommandBarButtonHeight: 40px;
/**********************************************************************************
Portal Consts
/**********************************************************************************/
@PortalAccentMediumHigh: #0058ad;
@PortalAccentMedium: #004e87;
@PortalAccentLight: #eef7ff;
@PortalAccentAccentExtra: #ddf0ff;
/**********************************************************************************
Fabric Consts
/**********************************************************************************/
@FabricFont: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif;
@FabricBoxBorderRadius: 8px;
@FabricBoxBorderShadow: 0 0 2px rgba(0, 0, 0, 0.12), 0 2px 4px rgba(0, 0, 0, 0.14);
@FabricBoxMargin: 4px 3px 4px 3px;
@FabricAccentMediumHigh: #0c695a;
@FabricAccentMedium: #117865;
@FabricAccentLight: #f5f5f5;
@FabricAccentExtra: #ebebeb;
@FabricButtonBorderRadius: 4px;
/**********************************************************************************
Common Flex Property
/**********************************************************************************/
.flex-display(@display: flex) {
display:~"-webkit-@{display}";
display:~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display:~"-ms-@{display}"; // IE11
display: ~"-webkit-@{display}";
display: ~"-ms-@{display}box"; // IE10 uses -ms-flexbox
display: ~"-ms-@{display}"; // IE11
display: @display;
}
@@ -196,15 +168,13 @@
High contrast mode active
**************************************************************************************/
@media all and (-ms-high-contrast: none),
(-ms-high-contrast: active) {
@media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
.selectedRadio,
.selectedRadio:hover,
.selectedRadio:active,
.selectedRadio.dirty,
.tab [type="radio"]:checked~label,
.tab [type="radio"]:checked~label:hover {
.tab [type="radio"]:checked ~ label,
.tab [type="radio"]:checked ~ label:hover {
-ms-high-contrast-adjust: none;
-webkit-text-fill-color: HighlightText;
color: HighlightText;
@@ -213,7 +183,6 @@
}
.queryMetricsSummaryTuple {
th,
td {
&:nth-child(2) {
@@ -333,4 +302,4 @@
width: 0;
height: 0;
border-color: @InfoPointerColor transparent;
}
}

View File

@@ -108,7 +108,7 @@ table.storage thead td {
background-color: @BaseLight;
/*[{datatable-header-background}]*/
text-align: left;
color: #333333;
color: #808080;
/*[{datatable-header-text}]*/
outline: none;
}

View File

@@ -2646,11 +2646,6 @@ a:link {
width: @ActiveTabWidth;
}
.nav-tabs > li.active > .tabNavContentContainer > .tab_Content > .tabNavText {
font-weight: bolder;
border-bottom: 2px solid rgba(0,120,212,1);
}
.nav-tabs > li.active:focus > .tabNavContentContainer {
.focus();
}

View File

@@ -1,211 +0,0 @@
@import "./Common/Constants";
html {
font-family: @FabricFont;
}
body {
font-family: @FabricFont;
background-color: #f5f5f5;
}
a {
color: @FabricAccentMedium;
text-decoration: none;
}
a:hover,
a:focus {
color: @FabricAccentMediumHigh;
text-decoration: underline;
}
#divExplorer {
background-color: #f5f5f5;
}
.resourceTreeAndTabs {
border-radius: @FabricBoxBorderRadius;
box-shadow: @FabricBoxBorderShadow;
margin: @FabricBoxMargin;
margin-top: 4px;
background-color: #ffffff;
}
.tabsManagerContainer {
background-color: #fafafa
}
.nav-tabs-margin {
padding-top: 8px;
background-color: #fafafa
}
.commandBarContainer {
background-color: #ffffff;
border-bottom: none;
border-radius: @FabricBoxBorderRadius;
box-shadow: @FabricBoxBorderShadow;
margin: @FabricBoxMargin;
padding-top: 2px;
}
.dividerContainer {
padding: @SmallSpace 0px @SmallSpace 0px;
.flex-display();
span {
border-left: @ButtonBorderWidth solid @BaseMedium;
margin: 0 10px 0 10px;
}
}
.nav-tabs>li>.tabNavContentContainer>.tab_Content:hover {
border-bottom: 2px solid #e0e0e0;
}
.nav-tabs>li.active>.tabNavContentContainer>.tab_Content,
.nav-tabs>li.active>.tabNavContentContainer>.tab_Content:hover {
border-bottom: 2px solid @FabricAccentMedium;
}
.nav-tabs>li.active>.tabNavContentContainer>.tab_Content>.tabNavText {
border-bottom: 0px none transparent;
}
.tabNavContentContainer {
padding: @SmallSpace 0px @SmallSpace 0px;
&:hover {
background-color: transparent;
border-color: transparent;
}
.tab_Content {
border-right: 0px none transparent;
margin: 0px @SmallSpace 0px @SmallSpace;
width: calc(@TabsWidth - (@SmallSpace * 2));
padding-bottom: @SmallSpace;
.statusIconContainer {
margin-left: 0px;
}
.tabIconSection {
.cancelButton {
padding: 0px 0px 0px @SmallSpace;
&:hover {
background-color: transparent;
}
&:focus {
background-color: transparent;
}
&:active {
background-color: transparent;
}
}
}
}
}
.resourceTree {
padding: 12px;
}
.accordion {
.accordionItemContainer {
.accordionItemHeader {
border-radius: 4px;
}
}
}
.treeComponent {
.nodeItem {
&:focus {
outline: 2px @FabricAccentMedium;
}
.treeNodeHeader {
padding: 5px 5px;
border-radius: 4px;
&:hover {
background-color: @FabricAccentLight;
.treeMenuEllipsis {
opacity: 1;
}
}
&.showingMenu {
background-color: #eee;
}
}
.selected {
&>.treeNodeHeader {
background-color: @FabricAccentExtra;
}
}
}
}
.dataExplorerErrorConsoleContainer {
border-radius: @FabricBoxBorderRadius;
box-shadow: @FabricBoxBorderShadow;
margin: @FabricBoxMargin;
width: auto;
align-self: auto;
}
.filterbtnstyle {
background: #fff;
color: #000;
border: solid 1px #d1d1d1;
border-radius: 4px;
}
.filterbtnstyle:hover {
background: @FabricAccentLight;
color: #000;
border: solid 1px #d1d1d1;
}
.filterbtnstyle:active {
background: @FabricAccentLight;
color: #000;
border: solid 1px #d1d1d1;
}
.filterbtnstyle:focus {
background: #fff;
color: #000;
border: solid 1px #d1d1d1;
}
.gridRowSelected .tabdocumentsGridElement:hover {
background-color: @FabricAccentLight !important;
}
.refreshcol {
filter: brightness(0) saturate(100%);
}
.refreshcol1 {
filter: brightness(0) saturate(100%);
}
.fileImportImg img {
filter: brightness(0) saturate(100%);
}

33010
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@
"@babel/plugin-proposal-class-properties": "7.12.1",
"@babel/plugin-proposal-decorators": "7.12.12",
"@fluentui/react": "8.14.3",
"@fluentui/react-components": "9.30.1",
"@jupyterlab/services": "6.0.2",
"@jupyterlab/terminal": "3.0.3",
"@microsoft/applicationinsights-web": "2.6.1",
@@ -199,7 +198,6 @@
"pack:fast": "webpack --mode development --progress",
"copyToConsumers": "node copyToConsumers",
"test": "rimraf coverage && jest",
"test:debug": "jest --runInBand",
"test:e2e": "jest -c ./jest.config.playwright.js --detectOpenHandles",
"watch": "npm run start",
"wait-for-server": "wait-on -t 240000 -i 5000 -v https-get://0.0.0.0:1234/",

View File

@@ -358,13 +358,15 @@ export enum ContainerStatusType {
export enum PoolIdType {
DefaultPoolId = "default",
QueryCopilot = "query-copilot",
}
export const EmulatorMasterKey =
//[SuppressMessage("Microsoft.Security", "CS002:SecretInNextLine", Justification="Well known public masterKey for emulator")]
"C2y6yDjf5/R+ob0N8A7Cgv30VRDJIWEHLM+4QDU5DE2nQ9nDuVTqobD4b8mGGyPMbIZnqyMsEcaGQy67XIw/Jw==";
// A variable @MyVariable defined in Constants.less is accessible as StyleConstants.MyVariable
export const StyleConstants = require("less-vars-loader!../../less/Common/Constants.less");
export class Notebook {
public static readonly defaultBasePath = "./notebooks";
public static readonly heartbeatDelayMs = 60000;
@@ -427,12 +429,6 @@ export class JunoEndpoints {
public static readonly Stage = "https://tools-staging.cosmos.azure.com";
}
export class PriorityLevel {
public static readonly High = "high";
public static readonly Low = "low";
public static readonly Default = "low";
}
export const QueryCopilotSampleDatabaseId = "CopilotSampleDb";
export const QueryCopilotSampleContainerId = "SampleContainer";
@@ -603,69 +599,3 @@ export const QueryCopilotSampleContainerSchema = {
},
},
};
export const ShortenedQueryCopilotSampleContainerSchema = {
containerSchema: {
product: {
sampleData: {
categoryName: "Components, Saddles",
name: "LL Road Seat/Saddle",
price: 27.12,
tags: [
{
id: "0573D684-9140-4DEE-89AF-4E4A90E65666",
name: "Tag-113",
},
{
id: "6C2F05C8-1E61-4912-BE1A-C67A378429BB",
name: "Tag-5",
},
],
},
schema: {
properties: {
categoryName: {
type: "string",
},
name: {
type: "string",
},
price: {
type: "number",
},
tags: {
items: {
properties: {
id: {
type: "string",
},
name: {
type: "string",
},
},
type: "object",
},
type: "array",
},
},
type: "object",
},
},
},
userPrompt: "find all products",
};

View File

@@ -4,9 +4,6 @@ import { userContext } from "../UserContext";
import { logConsoleError } from "../Utils/NotificationConsoleUtils";
import { EmulatorMasterKey, HttpHeaders } from "./Constants";
import { getErrorMessage } from "./ErrorHandlingUtils";
import { LocalStorageUtility, StorageKey } from "Shared/StorageUtility";
import { PriorityLevel } from "../Common/Constants";
import * as PriorityBasedExecutionUtils from "../Utils/PriorityBasedExecutionUtils";
const _global = typeof self === "undefined" ? window : self;
@@ -108,13 +105,6 @@ export function client(): Cosmos.CosmosClient {
if (configContext.PROXY_PATH !== undefined) {
(options as any).plugins = [{ on: "request", plugin: requestPlugin }];
}
if (userContext.features.enablePriorityBasedThrottling && userContext.apiType === "SQL") {
const plugins = (options as any).plugins || [];
plugins.push({ on: "request", plugin: PriorityBasedExecutionUtils.requestPlugin });
(options as any).plugins = plugins;
}
_client = new Cosmos.CosmosClient(options);
return _client;
}

View File

@@ -39,6 +39,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
/>
<TextField
label={entityValueLabel && entityValueLabel}
id="entityTimeId"
autoFocus
type="time"
value={entityTimeValue}
@@ -53,6 +54,7 @@ export const EntityValue: FunctionComponent<TableEntityProps> = ({
<TextField
label={entityValueLabel && entityValueLabel}
className="addEntityTextField"
id="entityValueId"
disabled={isEntityValueDisable}
type={entityValueType}
placeholder={entityValuePlaceholder}

View File

@@ -1,14 +1,12 @@
import { ResourceTree } from "Explorer/Tree/ResourceTree";
import React, { FunctionComponent, MutableRefObject, useEffect, useRef } from "react";
import arrowLeftImg from "../../images/imgarrowlefticon.svg";
import refreshImg from "../../images/refresh-cosmos.svg";
import { AuthType } from "../AuthType";
import Explorer from "../Explorer/Explorer";
import { ResourceTokenTree } from "../Explorer/Tree/ResourceTokenTree";
import { ResourceTree2 } from "../Explorer/Tree2/ResourceTree";
import { ResourceTree } from "../Explorer/Tree/ResourceTree";
import { userContext } from "../UserContext";
import { getApiShortDisplayName } from "../Utils/APITypeUtils";
import { Platform, configContext } from "./../ConfigContext";
import { NormalizedEventKey } from "./Constants";
export interface ResourceTreeContainerProps {
@@ -78,8 +76,6 @@ export const ResourceTreeContainer: FunctionComponent<ResourceTreeContainerProps
<ResourceTokenTree />
) : userContext.features.enableKoResourceTree ? (
<div style={{ overflowY: "auto" }} data-bind="react:resourceTree" />
) : configContext.platform === Platform.Fabric ? (
<ResourceTree2 container={container} />
) : (
<ResourceTree container={container} />
)}

View File

@@ -1,18 +0,0 @@
import { Platform, configContext } from "../ConfigContext";
// eslint-disable-next-line @typescript-eslint/no-var-requires
export const StyleConstants = require("less-vars-loader!../../less/Common/Constants.less");
export function updateStyles(): void {
if (configContext.platform === Platform.Fabric) {
StyleConstants.AccentMediumHigh = StyleConstants.FabricAccentMediumHigh;
StyleConstants.AccentMedium = StyleConstants.FabricAccentMedium;
StyleConstants.AccentLight = StyleConstants.FabricAccentLight;
StyleConstants.AccentAccentExtra = StyleConstants.FabricAccentMediumHigh;
} else {
StyleConstants.AccentMediumHigh = StyleConstants.PortalAccentMediumHigh;
StyleConstants.AccentMedium = StyleConstants.PortalAccentMedium;
StyleConstants.AccentLight = StyleConstants.PortalAccentLight;
StyleConstants.AccentAccentExtra = StyleConstants.PortalAccentMediumHigh;
}
}

View File

@@ -106,6 +106,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
<Stack horizontal tokens={sectionStackTokens}>
<TextField
label={entityPropertyLabel && entityPropertyLabel}
id="entityPropertyId"
autoFocus
disabled={isPropertyTypeDisable}
placeholder={entityPropertyPlaceHolder}
@@ -119,6 +120,7 @@ export const TableEntity: FunctionComponent<TableEntityProps> = ({
onChange={onEntityTypeChange}
options={options}
disabled={isPropertyTypeDisable}
id="entityTypeId"
styles={dropdownStyles}
/>
<EntityValue

View File

@@ -1,14 +1,14 @@
import {
allowedAadEndpoints,
allowedArcadiaEndpoints,
allowedArmEndpoints,
allowedBackendEndpoints,
allowedEmulatorEndpoints,
allowedGraphEndpoints,
allowedHostedExplorerEndpoints,
allowedJunoOrigins,
allowedMongoBackendEndpoints,
allowedMsalRedirectEndpoints,
defaultAllowedArmEndpoints,
defaultAllowedBackendEndpoints,
validateEndpoint,
} from "Utils/EndpointValidation";
@@ -16,13 +16,10 @@ export enum Platform {
Portal = "Portal",
Hosted = "Hosted",
Emulator = "Emulator",
Fabric = "Fabric",
}
export interface ConfigContext {
platform: Platform;
allowedArmEndpoints: ReadonlyArray<string>;
allowedBackendEndpoints: ReadonlyArray<string>;
allowedParentFrameOrigins: ReadonlyArray<string>;
gitSha?: string;
proxyPath?: string;
@@ -52,8 +49,6 @@ export interface ConfigContext {
// Default configuration
let configContext: Readonly<ConfigContext> = {
platform: Platform.Portal,
allowedArmEndpoints: defaultAllowedArmEndpoints,
allowedBackendEndpoints: defaultAllowedBackendEndpoints,
allowedParentFrameOrigins: [
`^https:\\/\\/cosmos\\.azure\\.(com|cn|us)$`,
`^https:\\/\\/[\\.\\w]*portal\\.azure\\.(com|cn|us)$`,
@@ -68,7 +63,7 @@ let configContext: Readonly<ConfigContext> = {
ARM_AUTH_AREA: "https://management.azure.com/",
ARM_ENDPOINT: "https://management.azure.com/",
ARM_API_VERSION: "2016-06-01",
GRAPH_ENDPOINT: "https://graph.microsoft.com",
GRAPH_ENDPOINT: "https://graph.windows.net",
GRAPH_API_VERSION: "1.6",
ARCADIA_ENDPOINT: "https://workspaceartifacts.projectarcadia.net",
ARCADIA_LIVY_ENDPOINT_DNS_ZONE: "dev.azuresynapse.net",
@@ -82,7 +77,7 @@ let configContext: Readonly<ConfigContext> = {
export function resetConfigContext(): void {
if (process.env.NODE_ENV !== "test") {
throw new Error("resetConfigContext can only be called in a test environment");
throw new Error("resetConfigContext can only becalled in a test environment");
}
configContext = {} as ConfigContext;
}
@@ -92,7 +87,7 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
return;
}
if (!validateEndpoint(newContext.ARM_ENDPOINT, configContext.allowedArmEndpoints || defaultAllowedArmEndpoints)) {
if (!validateEndpoint(newContext.ARM_ENDPOINT, allowedArmEndpoints)) {
delete newContext.ARM_ENDPOINT;
}
@@ -112,12 +107,7 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
delete newContext.ARCADIA_ENDPOINT;
}
if (
!validateEndpoint(
newContext.BACKEND_ENDPOINT,
configContext.allowedBackendEndpoints || defaultAllowedBackendEndpoints
)
) {
if (!validateEndpoint(newContext.BACKEND_ENDPOINT, allowedBackendEndpoints)) {
delete newContext.BACKEND_ENDPOINT;
}
@@ -140,7 +130,7 @@ export function updateConfigContext(newContext: Partial<ConfigContext>): void {
Object.assign(configContext, newContext);
}
// Injected for local development. These will be removed in the production bundle by webpack
// Injected for local develpment. These will be removed in the production bundle by webpack
if (process.env.NODE_ENV === "development") {
const port: string = process.env.PORT || "1234";
updateConfigContext({
@@ -188,7 +178,6 @@ export async function initializeConfiguration(): Promise<ConfigContext> {
console.error(`Invalid platform query parameter: ${platform}`);
break;
case Platform.Portal:
case Platform.Fabric:
case Platform.Hosted:
case Platform.Emulator:
updateConfigContext({ platform });

View File

@@ -1,14 +1,11 @@
import { ConnectionStatusType, ContainerStatusType } from "../Common/Constants";
export interface ArmEntity {
export interface DatabaseAccount {
id: string;
name: string;
location: string;
type: string;
kind: string;
}
export interface DatabaseAccount extends ArmEntity {
properties: DatabaseAccountExtendedProperties;
systemData?: DatabaseAccountSystemData;
}
@@ -38,7 +35,6 @@ export interface DatabaseAccountExtendedProperties {
locations?: DatabaseAccountResponseLocation[];
postgresqlEndpoint?: string;
publicNetworkAccess?: string;
vcoreMongoEndpoint?: string;
}
export interface DatabaseAccountResponseLocation {
@@ -579,7 +575,7 @@ export interface ContainerConnectionInfo {
//need to add ram and rom info
}
export interface FirewallRule {
export interface PostgresFirewallRule {
id: string;
name: string;
type: string;

View File

@@ -39,8 +39,6 @@ export enum MessageTypes {
OpenPostgresNetworkingBlade,
OpenCosmosDBNetworkingBlade,
DisplayNPSSurvey,
OpenVCoreMongoNetworkingBlade,
OpenVCoreMongoConnectionStringsBlade,
}
export { ActionContracts, Diagnostics, Versions };
export { Versions, ActionContracts, Diagnostics };

View File

@@ -372,7 +372,6 @@ export enum TerminalKind {
Mongo = 1,
Cassandra = 2,
Postgres = 3,
VCoreMongo = 4,
}
export interface DataExplorerInputsFrame {
@@ -398,7 +397,6 @@ export interface DataExplorerInputsFrame {
defaultCollectionThroughput?: CollectionCreationDefaults;
isPostgresAccount?: boolean;
isReplica?: boolean;
isVCoreMongoAccount?: boolean;
clientIpAddress?: string;
// TODO: Update this param in the OSS extension to remove isFreeTier, isMarlinServerGroup, and make nodes a flat array instead of an nested array
connectionStringParams?: any;

View File

@@ -1,7 +1,7 @@
import dayjs from "dayjs";
import * as Plotly from "plotly.js-cartesian-dist-min";
import { StyleConstants } from "../../Common/Constants";
import { sendCachedDataMessage, sendReadyMessage } from "../../Common/MessageHandler";
import { StyleConstants } from "../../Common/StyleConstants";
import { MessageTypes } from "../../Contracts/ExplorerContracts";
import { isInvalidParentFrameOrigin } from "../../Utils/MessageValidation";
import "./Heatmap.less";

View File

@@ -1,4 +1,3 @@
import { useDatabases } from "Explorer/useDatabases";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceOpen } from "Shared/Telemetry/TelemetryProcessor";
import { ReactTabKind, useTabs } from "hooks/useTabs";
@@ -18,7 +17,6 @@ import * as ViewModels from "../Contracts/ViewModels";
import { userContext } from "../UserContext";
import { getCollectionName, getDatabaseName } from "../Utils/APITypeUtils";
import { useSidePanel } from "../hooks/useSidePanel";
import { Platform, configContext } from "./../ConfigContext";
import { TreeNodeMenuItem } from "./Controls/TreeComponent/TreeComponent";
import Explorer from "./Explorer";
import { useNotebook } from "./Notebook/useNotebook";
@@ -100,13 +98,11 @@ export const createCollectionContextMenuButton = (
});
}
if (
configContext.platform !== Platform.Fabric &&
(userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
) {
if (userContext.apiType === "SQL" || userContext.apiType === "Gremlin") {
items.push({
iconSrc: AddStoredProcedureIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewStoredProcedureClick(selectedCollection, undefined);
},
label: "New Stored Procedure",
@@ -115,6 +111,7 @@ export const createCollectionContextMenuButton = (
items.push({
iconSrc: AddUdfIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewUserDefinedFunctionClick(selectedCollection);
},
label: "New UDF",
@@ -123,6 +120,7 @@ export const createCollectionContextMenuButton = (
items.push({
iconSrc: AddTriggerIcon,
onClick: () => {
const selectedCollection: ViewModels.Collection = useSelectedNode.getState().findSelectedCollection();
selectedCollection && selectedCollection.onNewTriggerClick(selectedCollection, undefined);
},
label: "New Trigger",
@@ -131,15 +129,13 @@ export const createCollectionContextMenuButton = (
items.push({
iconSrc: DeleteCollectionIcon,
onClick: () => {
useSelectedNode.getState().setSelectedNode(selectedCollection);
onClick: () =>
useSidePanel
.getState()
.openSidePanel(
"Delete " + getCollectionName(),
<DeleteCollectionConfirmationPane refreshDatabases={() => container.refreshAllDatabases()} />
);
},
),
label: `Delete ${getCollectionName()}`,
styleClass: "deleteCollectionMenuItem",
});
@@ -150,24 +146,14 @@ export const createCollectionContextMenuButton = (
export const createSampleCollectionContextMenuButton = (): TreeNodeMenuItem[] => {
const items: TreeNodeMenuItem[] = [];
if (userContext.apiType === "SQL") {
const copilotVersion = userContext.features.copilotVersion;
if (copilotVersion === "v1.0") {
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => {
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
},
label: "New SQL Query",
});
} else if (copilotVersion === "v2.0") {
const sampleCollection = useDatabases.getState().sampleDataResourceTokenCollection;
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => sampleCollection && sampleCollection.onNewQueryClick(sampleCollection, undefined),
label: "New SQL Query",
});
}
items.push({
iconSrc: AddSqlQueryIcon,
onClick: () => {
useTabs.getState().openAndActivateReactTab(ReactTabKind.QueryCopilot);
traceOpen(Action.OpenQueryCopilotFromNewQuery, { apiType: userContext.apiType });
},
label: "New SQL Query",
});
}
return items;

View File

@@ -49,6 +49,7 @@ export class CollapsibleSectionComponent extends React.Component<CollapsibleSect
onClick={this.toggleCollapsed}
onKeyPress={this.onKeyPress}
tabIndex={0}
aria-name="Advanced"
role="button"
aria-expanded={this.state.isExpanded}
>

View File

@@ -4,6 +4,7 @@ exports[`CollapsibleSectionComponent renders 1`] = `
<Fragment>
<Stack
aria-expanded={true}
aria-name="Advanced"
className="collapsibleSection"
horizontal={true}
onClick={[Function]}

View File

@@ -13,14 +13,8 @@ export interface EditorReactProps {
ariaLabel: string; // Sets what will be read to the user to define the control
onContentSelected?: (selectedContent: string) => void; // Called when text is selected
onContentChanged?: (newContent: string) => void; // Called when text is changed
theme?: string; // Monaco editor theme
wordWrap?: monaco.editor.IEditorOptions["wordWrap"];
lineNumbers?: monaco.editor.IEditorOptions["lineNumbers"];
lineNumbersMinChars?: monaco.editor.IEditorOptions["lineNumbersMinChars"];
lineDecorationsWidth?: monaco.editor.IEditorOptions["lineDecorationsWidth"];
minimap?: monaco.editor.IEditorOptions["minimap"];
scrollBeyondLastLine?: monaco.editor.IEditorOptions["scrollBeyondLastLine"];
monacoContainerStyles?: React.CSSProperties;
theme?: string; // Monaco editor theme
}
export class EditorReact extends React.Component<EditorReactProps, EditorReactStates> {
@@ -60,11 +54,7 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
return (
<React.Fragment>
{!this.state.showEditor && <Spinner size={SpinnerSize.large} className="spinner" />}
<div
className="jsonEditor"
style={this.props.monacoContainerStyles}
ref={(elt: HTMLElement) => this.setRef(elt)}
/>
<div className="jsonEditor" ref={(elt: HTMLElement) => this.setRef(elt)} />
</React.Fragment>
);
}
@@ -94,19 +84,14 @@ export class EditorReact extends React.Component<EditorReactProps, EditorReactSt
*/
private async createEditor(createCallback: (e: monaco.editor.IStandaloneCodeEditor) => void) {
const options: monaco.editor.IEditorConstructionOptions = {
language: this.props.language,
value: this.props.content,
language: this.props.language,
readOnly: this.props.isReadOnly,
ariaLabel: this.props.ariaLabel,
fontSize: 12,
automaticLayout: true,
theme: this.props.theme,
wordWrap: this.props.wordWrap || "off",
lineNumbers: this.props.lineNumbers || "off",
lineNumbersMinChars: this.props.lineNumbersMinChars,
lineDecorationsWidth: this.props.lineDecorationsWidth,
minimap: this.props.minimap,
scrollBeyondLastLine: this.props.scrollBeyondLastLine,
fontSize: 12,
ariaLabel: this.props.ariaLabel,
theme: this.props.theme,
automaticLayout: true,
};
this.rootNode.innerHTML = "";

View File

@@ -32,20 +32,6 @@ const testCassandraAccount: DataModels.DatabaseAccount = {
},
};
const testPostgresAccount: DataModels.DatabaseAccount = {
...testAccount,
properties: {
postgresqlEndpoint: "https://testPostgresEndpoint.azure.com/",
},
};
const testVCoreMongoAccount: DataModels.DatabaseAccount = {
...testAccount,
properties: {
vcoreMongoEndpoint: "https://testVCoreMongoEndpoint.azure.com/",
},
};
const testNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
authToken: "authToken",
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com",
@@ -64,18 +50,6 @@ const testCassandraNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInf
forwardingId: "Id",
};
const testPostgresNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
authToken: "authToken",
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com/postgresql",
forwardingId: "Id",
};
const testVCoreMongoNotebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo = {
authToken: "authToken",
notebookServerEndpoint: "https://testNotebookServerEndpoint.azure.com/mongovcore",
forwardingId: "Id",
};
describe("NotebookTerminalComponent", () => {
it("renders terminal", () => {
const props: NotebookTerminalComponentProps = {
@@ -120,27 +94,4 @@ describe("NotebookTerminalComponent", () => {
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("renders Postgres shell", () => {
const props: NotebookTerminalComponentProps = {
databaseAccount: testPostgresAccount,
notebookServerInfo: testPostgresNotebookServerInfo,
tabId: undefined,
};
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
it("renders vCore Mongo shell", () => {
const props: NotebookTerminalComponentProps = {
databaseAccount: testVCoreMongoAccount,
notebookServerInfo: testVCoreMongoNotebookServerInfo,
tabId: undefined,
username: "username",
};
const wrapper = shallow(<NotebookTerminalComponent {...props} />);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -14,7 +14,6 @@ export interface NotebookTerminalComponentProps {
notebookServerInfo: DataModels.NotebookWorkspaceConnectionInfo;
databaseAccount: DataModels.DatabaseAccount;
tabId: string;
username?: string;
}
export class NotebookTerminalComponent extends React.Component<NotebookTerminalComponentProps> {
@@ -51,7 +50,7 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
return;
}
let props: TerminalProps = {
const props: TerminalProps = {
terminalEndpoint: this.tryGetTerminalEndpoint(),
notebookServerEndpoint: this.props.notebookServerInfo?.notebookServerEndpoint,
authToken: this.props.notebookServerInfo?.authToken,
@@ -62,13 +61,6 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
tabId: this.props.tabId,
};
if (this.props.username) {
props = {
...props,
username: this.props.username,
};
}
postRobot.send(this.terminalWindow, "props", props, {
domain: window.location.origin,
});
@@ -86,8 +78,6 @@ export class NotebookTerminalComponent extends React.Component<NotebookTerminalC
terminalEndpoint = this.props.databaseAccount?.properties.cassandraEndpoint;
} else if (StringUtils.endsWith(notebookServerEndpoint, "postgresql")) {
return this.props.databaseAccount?.properties.postgresqlEndpoint;
} else if (StringUtils.endsWith(notebookServerEndpoint, "mongovcore")) {
return this.props.databaseAccount?.properties.vcoreMongoEndpoint;
}
if (terminalEndpoint) {

View File

@@ -1,17 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NotebookTerminalComponent renders Postgres shell 1`] = `
<div
className="notebookTerminalContainer"
>
<iframe
onLoad={[Function]}
src="terminal.html"
title="Terminal to Notebook Server"
/>
</div>
`;
exports[`NotebookTerminalComponent renders cassandra shell 1`] = `
<div
className="notebookTerminalContainer"
@@ -59,15 +47,3 @@ exports[`NotebookTerminalComponent renders terminal 1`] = `
/>
</div>
`;
exports[`NotebookTerminalComponent renders vCore Mongo shell 1`] = `
<div
className="notebookTerminalContainer"
>
<iframe
onLoad={[Function]}
src="terminal.html"
title="Terminal to Notebook Server"
/>
</div>
`;

View File

@@ -23,9 +23,9 @@ import * as React from "react";
import * as _ from "underscore";
import SaveQueryBannerIcon from "../../../../images/save_query_banner.png";
import * as Constants from "../../../Common/Constants";
import { StyleConstants } from "../../../Common/Constants";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { QueriesClient } from "../../../Common/QueriesClient";
import { StyleConstants } from "../../../Common/StyleConstants";
import * as DataModels from "../../../Contracts/DataModels";
import { Action } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";

View File

@@ -5,18 +5,18 @@ import DiscardIcon from "../../../../images/discard.svg";
import SaveIcon from "../../../../images/save-cosmos.svg";
import { AuthType } from "../../../AuthType";
import * as Constants from "../../../Common/Constants";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import { getIndexTransformationProgress } from "../../../Common/dataAccess/getIndexTransformationProgress";
import { readMongoDBCollectionThroughRP } from "../../../Common/dataAccess/readMongoDBCollection";
import { updateCollection } from "../../../Common/dataAccess/updateCollection";
import { updateOffer } from "../../../Common/dataAccess/updateOffer";
import { getErrorMessage, getErrorStack } from "../../../Common/ErrorHandlingUtils";
import * as DataModels from "../../../Contracts/DataModels";
import * as ViewModels from "../../../Contracts/ViewModels";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import { trace, traceFailure, traceStart, traceSuccess } from "../../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../../UserContext";
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
import { MongoDBCollectionResource, MongoIndex } from "../../../Utils/arm/generatedClients/cosmos/types";
import * as AutoPilotUtils from "../../../Utils/AutoPilotUtils";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import { useCommandBar } from "../../Menus/CommandBar/CommandBarComponentAdapter";
import { SettingsTabV2 } from "../../Tabs/SettingsTabV2";
@@ -37,15 +37,15 @@ import {
AddMongoIndexProps,
ChangeFeedPolicyState,
GeospatialConfigType,
MongoIndexTypes,
SettingsV2TabTypes,
TtlType,
getMongoNotification,
getTabTitle,
hasDatabaseSharedThroughput,
isDirty,
MongoIndexTypes,
parseConflictResolutionMode,
parseConflictResolutionProcedure,
SettingsV2TabTypes,
TtlType,
} from "./SettingsUtils";
interface SettingsV2TabInfo {
@@ -78,8 +78,6 @@ export interface SettingsComponentState {
timeToLiveBaseline: TtlType;
timeToLiveSeconds: number;
timeToLiveSecondsBaseline: number;
displayedTtlSeconds: string;
displayedTtlSecondsBaseline: string;
geospatialConfigType: GeospatialConfigType;
geospatialConfigTypeBaseline: GeospatialConfigType;
analyticalStorageTtlSelection: TtlType;
@@ -166,8 +164,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
timeToLiveBaseline: undefined,
timeToLiveSeconds: undefined,
timeToLiveSecondsBaseline: undefined,
displayedTtlSeconds: undefined,
displayedTtlSecondsBaseline: undefined,
geospatialConfigType: undefined,
geospatialConfigTypeBaseline: undefined,
analyticalStorageTtlSelection: undefined,
@@ -373,7 +369,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
throughput: this.state.throughputBaseline,
timeToLive: this.state.timeToLiveBaseline,
timeToLiveSeconds: this.state.timeToLiveSecondsBaseline,
displayedTtlSeconds: this.state.displayedTtlSecondsBaseline,
geospatialConfigType: this.state.geospatialConfigTypeBaseline,
indexingPolicyContent: this.state.indexingPolicyContentBaseline,
indexesToAdd: [],
@@ -484,9 +479,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
private onTimeToLiveSecondsChange = (newTimeToLiveSeconds: number): void =>
this.setState({ timeToLiveSeconds: newTimeToLiveSeconds });
private onDisplayedTtlChange = (newDisplayedTtlSeconds: string): void =>
this.setState({ displayedTtlSeconds: newDisplayedTtlSeconds });
private onGeoSpatialConfigTypeChange = (newGeoSpatialConfigType: GeospatialConfigType): void =>
this.setState({ geospatialConfigType: newGeoSpatialConfigType });
@@ -616,8 +608,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
break;
}
const displayedTtlSeconds: string = timeToLive === TtlType.On ? timeToLiveSeconds.toString() : "";
let analyticalStorageTtlSelection: TtlType;
let analyticalStorageTtlSeconds: number;
if (this.isAnalyticalStorageEnabled) {
@@ -655,8 +645,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
timeToLiveBaseline: timeToLive,
timeToLiveSeconds: timeToLiveSeconds,
timeToLiveSecondsBaseline: timeToLiveSeconds,
displayedTtlSeconds: displayedTtlSeconds,
displayedTtlSecondsBaseline: displayedTtlSeconds,
analyticalStorageTtlSelection: analyticalStorageTtlSelection,
analyticalStorageTtlSelectionBaseline: analyticalStorageTtlSelection,
analyticalStorageTtlSeconds: analyticalStorageTtlSeconds,
@@ -998,8 +986,6 @@ export class SettingsComponent extends React.Component<SettingsComponentProps, S
timeToLiveSeconds: this.state.timeToLiveSeconds,
timeToLiveSecondsBaseline: this.state.timeToLiveSecondsBaseline,
onTimeToLiveSecondsChange: this.onTimeToLiveSecondsChange,
displayedTtlSeconds: this.state.displayedTtlSeconds,
onDisplayedTtlSecondsChange: this.onDisplayedTtlChange,
geospatialConfigType: this.state.geospatialConfigType,
geospatialConfigTypeBaseline: this.state.geospatialConfigTypeBaseline,
onGeoSpatialConfigTypeChange: this.onGeoSpatialConfigTypeChange,

View File

@@ -23,8 +23,7 @@ import {
Text,
} from "@fluentui/react";
import * as React from "react";
import { Urls } from "../../../Common/Constants";
import { StyleConstants } from "../../../Common/StyleConstants";
import { StyleConstants, Urls } from "../../../Common/Constants";
import { hoursInAMonth } from "../../../Shared/Constants";
import {
computeRUUsagePriceHourly,

View File

@@ -20,10 +20,6 @@ describe("SubSettingsComponent", () => {
onTimeToLiveSecondsChange: () => {
return;
},
displayedTtlSeconds: "1000",
onDisplayedTtlSecondsChange: () => {
return;
},
geospatialConfigType: GeospatialConfigType.Geography,
geospatialConfigTypeBaseline: GeospatialConfigType.Geography,

View File

@@ -15,13 +15,13 @@ import {
import {
ChangeFeedPolicyState,
GeospatialConfigType,
getSanitizedInputValue,
IsComponentDirtyResult,
isDirty,
TtlOff,
TtlOn,
TtlOnNoDefault,
TtlType,
getSanitizedInputValue,
isDirty,
} from "../SettingsUtils";
import { ToolTipLabelComponent } from "./ToolTipLabelComponent";
@@ -34,8 +34,6 @@ export interface SubSettingsComponentProps {
timeToLiveSeconds: number;
timeToLiveSecondsBaseline: number;
onTimeToLiveSecondsChange: (newTimeToLiveSeconds: number) => void;
displayedTtlSeconds: string;
onDisplayedTtlSecondsChange: (newDisplayedTtlSeconds: string) => void;
geospatialConfigType: GeospatialConfigType;
geospatialConfigTypeBaseline: GeospatialConfigType;
@@ -75,14 +73,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
this.onComponentUpdate();
}
componentDidUpdate(prevProps: SubSettingsComponentProps): void {
if (
(prevProps.timeToLive === TtlType.Off || prevProps.timeToLive === TtlType.OnNoDefault) &&
this.props.timeToLive === TtlType.On &&
this.props.timeToLiveBaseline !== TtlType.On
) {
this.props.onDisplayedTtlSecondsChange("");
}
componentDidUpdate(): void {
this.onComponentUpdate();
}
@@ -102,8 +93,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
public IsComponentDirty = (): IsComponentDirtyResult => {
if (
(this.props.timeToLive === TtlType.On && !this.props.timeToLiveSeconds) ||
(this.props.analyticalStorageTtlSelection === TtlType.On && !this.props.analyticalStorageTtlSeconds) ||
(this.props.timeToLive === TtlType.On && this.props.displayedTtlSeconds === "")
(this.props.analyticalStorageTtlSelection === TtlType.On && !this.props.analyticalStorageTtlSeconds)
) {
return { isSaveable: false, isDiscardable: true };
} else if (
@@ -148,7 +138,6 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
newValue?: string
): void => {
const newTimeToLiveSeconds = getSanitizedInputValue(newValue, Int32.Max);
this.props.onDisplayedTtlSecondsChange(newTimeToLiveSeconds.toString());
this.props.onTimeToLiveSecondsChange(newTimeToLiveSeconds);
};
@@ -215,7 +204,7 @@ export class SubSettingsComponent extends React.Component<SubSettingsComponentPr
required
min={1}
max={Int32.Max}
value={this.props.displayedTtlSeconds}
value={this.props.timeToLiveSeconds?.toString()}
onChange={this.onTimeToLiveSecondsChange}
suffix="second(s)"
/>

View File

@@ -150,14 +150,12 @@ exports[`SettingsComponent renders 1`] = `
"usageSizeInKB": [Function],
}
}
displayedTtlSeconds="5"
geospatialConfigType="Geometry"
geospatialConfigTypeBaseline="Geometry"
isAnalyticalStorageEnabled={false}
onAnalyticalStorageTtlSecondsChange={[Function]}
onAnalyticalStorageTtlSelectionChange={[Function]}
onChangeFeedPolicyChange={[Function]}
onDisplayedTtlSecondsChange={[Function]}
onGeoSpatialConfigTypeChange={[Function]}
onSubSettingsDiscardableChange={[Function]}
onSubSettingsSaveableChange={[Function]}

View File

@@ -249,7 +249,6 @@ export const ThroughputInput: FunctionComponent<ThroughputInputProps> = ({
onChange={(event, newInput?: string) => onThroughputValueChange(newInput)}
step={AutoPilotUtils.autoPilotIncrementStep}
min={AutoPilotUtils.autoPilotThroughput1K}
max={isSharded ? Number.MAX_SAFE_INTEGER.toString() : "10000"}
value={throughput.toString()}
ariaLabel={`${isDatabase ? "Database" : getCollectionName()} max RU/s`}
required={true}

View File

@@ -1644,7 +1644,6 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
errorMessage=""
id="autoscaleRUValueField"
key=".0:$.2"
max="9007199254740991"
min={1000}
onChange={[Function]}
required={true}
@@ -1668,7 +1667,6 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
deferredValidationTime={200}
errorMessage=""
id="autoscaleRUValueField"
max="9007199254740991"
min={1000}
onChange={[Function]}
required={true}
@@ -1966,7 +1964,6 @@ exports[`ThroughputInput Pane should render Default properly 1`] = `
aria-label="Container max RU/s"
className="ms-TextField-field field-64"
id="autoscaleRUValueField"
max="9007199254740991"
min={1000}
onBlur={[Function]}
onChange={[Function]}

View File

@@ -18,7 +18,6 @@ import LoadingIndicator_3Squares from "../../../../images/LoadingIndicator_3Squa
import TriangleDownIcon from "../../../../images/Triangle-down.svg";
import TriangleRightIcon from "../../../../images/Triangle-right.svg";
import * as Constants from "../../../Common/Constants";
import { StyleConstants } from "../../../Common/StyleConstants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
@@ -238,7 +237,7 @@ export class TreeNodeComponent extends React.Component<TreeNodeComponentProps, T
private renderContextMenuButton(node: TreeNode): JSX.Element {
const menuItemLabel = "More";
const buttonStyles: Partial<IButtonStyles> = {
rootFocused: { outline: `1px dashed ${StyleConstants.FocusColor}` },
rootFocused: { outline: `1px dashed ${Constants.StyleConstants.FocusColor}` },
};
return (

View File

@@ -55,7 +55,7 @@ exports[`TreeNodeComponent does not render children by default 1`] = `
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src={Object {}}
src=""
tabIndex={0}
/>
<span
@@ -158,7 +158,7 @@ exports[`TreeNodeComponent renders a simple node (sorted children, expanded) 1`]
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src={Object {}}
src=""
tabIndex={0}
/>
<span
@@ -309,7 +309,7 @@ exports[`TreeNodeComponent renders loading icon 1`] = `
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src={Object {}}
src=""
tabIndex={0}
/>
<span
@@ -383,7 +383,7 @@ exports[`TreeNodeComponent renders sorted children, expanded, leaves and parents
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src={Object {}}
src=""
tabIndex={0}
/>
<span
@@ -553,7 +553,7 @@ exports[`TreeNodeComponent renders unsorted children by default 1`] = `
className="expandCollapseIcon"
onKeyPress={[Function]}
role="button"
src={Object {}}
src=""
tabIndex={0}
/>
<span

View File

@@ -1,142 +0,0 @@
import {
Button,
Menu,
MenuItem,
MenuList,
MenuPopover,
MenuTrigger,
Spinner,
Tree,
TreeItem,
TreeItemLayout,
} from "@fluentui/react-components";
import { MoreHorizontal20Regular } from "@fluentui/react-icons";
import * as React from "react";
export interface TreeNode2MenuItem {
label: string;
onClick: () => void;
iconSrc?: string;
isDisabled?: boolean;
styleClass?: string;
}
export interface TreeNode2 {
label: string;
id?: string;
children?: TreeNode2[];
contextMenu?: TreeNode2MenuItem[];
iconSrc?: string;
// isExpanded?: boolean;
className?: string;
isAlphaSorted?: boolean;
// data?: any; // Piece of data corresponding to this node
timestamp?: number;
isLeavesParentsSeparate?: boolean; // Display parents together first, then leaves
isLoading?: boolean;
isScrollable?: boolean;
isSelected?: () => boolean;
onClick?: () => void; // Only if a leaf, other click will expand/collapse
onExpanded?: () => void;
onCollapsed?: () => void;
onContextMenuOpen?: () => void;
}
export interface TreeNode2ComponentProps {
node: TreeNode2;
className?: string;
treeNodeId: string;
globalOpenIds: string[];
}
const getTreeIcon = (iconSrc: string): JSX.Element => <img src={iconSrc} alt="" style={{ width: 20, height: 20 }} />;
export const TreeNode2Component: React.FC<TreeNode2ComponentProps> = ({
node,
treeNodeId,
globalOpenIds,
}: TreeNode2ComponentProps): JSX.Element => {
// const defaultOpenItems = node.isExpanded ? children?.map((child: TreeNode2) => child.label) : undefined;
const [isExpanded, setIsExpanded] = React.useState<boolean>(false);
// Compute whether node is expanded
React.useEffect(() => {
const isNowExpanded = globalOpenIds && globalOpenIds.includes(treeNodeId);
if (!isExpanded && isNowExpanded) {
// Catch the transition non-expanded to expanded
node.onExpanded?.();
}
setIsExpanded(isNowExpanded);
}, [globalOpenIds, treeNodeId, node, isExpanded]);
const getSortedChildren = (treeNode: TreeNode2): TreeNode2[] => {
if (!treeNode || !treeNode.children) {
return undefined;
}
const compareFct = (a: TreeNode2, b: TreeNode2) => a.label.localeCompare(b.label);
let unsortedChildren;
if (treeNode.isLeavesParentsSeparate) {
// Separate parents and leave
const parents: TreeNode2[] = treeNode.children.filter((node) => node.children);
const leaves: TreeNode2[] = treeNode.children.filter((node) => !node.children);
if (treeNode.isAlphaSorted) {
parents.sort(compareFct);
leaves.sort(compareFct);
}
unsortedChildren = parents.concat(leaves);
} else {
unsortedChildren = treeNode.isAlphaSorted ? treeNode.children.sort(compareFct) : treeNode.children;
}
return unsortedChildren;
};
return (
<TreeItem value={treeNodeId} itemType={node.children !== undefined ? "branch" : "leaf"} style={{ height: "100%" }}>
<TreeItemLayout
className={node.className}
actions={
node.contextMenu && (
<Menu>
<MenuTrigger disableButtonEnhancement>
<Button aria-label="More options" appearance="subtle" icon={<MoreHorizontal20Regular />} />
</MenuTrigger>
<MenuPopover>
<MenuList>
{node.contextMenu.map((menuItem) => (
<MenuItem disabled={menuItem.isDisabled} key={menuItem.label} onClick={menuItem.onClick}>
{menuItem.label}
</MenuItem>
))}
</MenuList>
</MenuPopover>
</Menu>
)
}
expandIcon={node.isLoading ? <Spinner size="extra-tiny" /> : undefined}
iconBefore={node.iconSrc && getTreeIcon(node.iconSrc)}
>
<span onClick={() => node.onClick?.()}>{node.label}</span>
</TreeItemLayout>
{!node.isLoading && node.children?.length > 0 && (
<Tree
// defaultOpenItems={defaultOpenItems}
style={{ overflow: node.isScrollable ? "auto" : undefined }}
>
{getSortedChildren(node).map((childNode: TreeNode2) => (
<TreeNode2Component
key={childNode.label}
node={childNode}
treeNodeId={`${treeNodeId}/${childNode.label}`}
globalOpenIds={globalOpenIds}
/>
))}
</Tree>
)}
</TreeItem>
);
};

View File

@@ -1,11 +1,7 @@
import { Link } from "@fluentui/react/lib/Link";
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
import { sendMessage } from "Common/MessageHandler";
import { Platform, configContext } from "ConfigContext";
import { MessageTypes } from "Contracts/ExplorerContracts";
import { IGalleryItem } from "Juno/JunoClient";
import { allowedNotebookServerUrls, validateEndpoint } from "Utils/EndpointValidation";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import * as ko from "knockout";
import React from "react";
import _ from "underscore";
@@ -27,7 +23,7 @@ import { PhoenixClient } from "../Phoenix/PhoenixClient";
import * as ExplorerSettings from "../Shared/ExplorerSettings";
import { Action, ActionModifiers } from "../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../Shared/Telemetry/TelemetryProcessor";
import { isAccountNewerThanThresholdInMs, userContext } from "../UserContext";
import { userContext } from "../UserContext";
import { getCollectionName, getUploadName } from "../Utils/APITypeUtils";
import { stringToBlob } from "../Utils/BlobUtils";
import { isCapabilityEnabled } from "../Utils/CapabilityUtils";
@@ -262,62 +258,6 @@ export default class Explorer {
// TODO: return result
}
private getRandomInt(max: number) {
return Math.floor(Math.random() * max);
}
public openNPSSurveyDialog(): void {
if (!Platform.Portal) {
return;
}
const NINETY_DAYS_IN_MS = 7776000000;
const ONE_DAY_IN_MS = 86400000;
const isAccountNewerThanNinetyDays = isAccountNewerThanThresholdInMs(
userContext.databaseAccount?.systemData?.createdAt || "",
NINETY_DAYS_IN_MS
);
const lastSubmitted: string = localStorage.getItem("lastSubmitted");
if (lastSubmitted !== null) {
let lastSubmittedDate: number = parseInt(lastSubmitted);
if (isNaN(lastSubmittedDate)) {
lastSubmittedDate = 0;
}
const nowMs: number = Date.now();
const millisecsSinceLastSubmitted = nowMs - lastSubmittedDate;
if (millisecsSinceLastSubmitted < NINETY_DAYS_IN_MS) {
return;
}
}
// Try Cosmos DB subscription - survey shown to random 25% of users at day 1 in Data Explorer.
if (userContext.isTryCosmosDBSubscription) {
if (
isAccountNewerThanThresholdInMs(userContext.databaseAccount?.systemData?.createdAt || "", ONE_DAY_IN_MS) &&
this.getRandomInt(100) < 25
) {
sendMessage({ type: MessageTypes.DisplayNPSSurvey });
localStorage.setItem("lastSubmitted", Date.now().toString());
}
} else {
// An existing account is lesser than 90 days old. For existing account show to random 10 % of users in Data Explorer.
if (isAccountNewerThanNinetyDays) {
if (this.getRandomInt(100) < 10) {
sendMessage({ type: MessageTypes.DisplayNPSSurvey });
localStorage.setItem("lastSubmitted", Date.now().toString());
}
} else {
// An existing account is greater than 90 days. For existing account show to random 25 % of users in Data Explorer.
if (this.getRandomInt(100) < 25) {
sendMessage({ type: MessageTypes.DisplayNPSSurvey });
localStorage.setItem("lastSubmitted", Date.now().toString());
}
}
}
}
public async refreshDatabaseForResourceToken(): Promise<void> {
const databaseId = userContext.parsedResourceToken?.databaseId;
const collectionId = userContext.parsedResourceToken?.collectionId;
@@ -403,15 +343,9 @@ export default class Explorer {
this._isInitializingNotebooks = false;
}
public async allocateContainer(poolId: PoolIdType): Promise<void> {
const shouldUseNotebookStates = poolId === PoolIdType.DefaultPoolId ? true : false;
const notebookServerInfo = shouldUseNotebookStates
? useNotebook.getState().notebookServerInfo
: useQueryCopilot.getState().notebookServerInfo;
const isAllocating = shouldUseNotebookStates
? useNotebook.getState().isAllocating
: useQueryCopilot.getState().isAllocatingContainer;
public async allocateContainer(): Promise<void> {
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
const isAllocating = useNotebook.getState().isAllocating;
if (
isAllocating === false &&
(notebookServerInfo === undefined ||
@@ -419,28 +353,23 @@ export default class Explorer {
) {
const provisionData: IProvisionData = {
cosmosEndpoint: userContext?.databaseAccount?.properties?.documentEndpoint,
poolId: shouldUseNotebookStates ? undefined : poolId,
poolId: PoolIdType.DefaultPoolId,
};
const connectionStatus: ContainerConnectionInfo = {
status: ConnectionStatusType.Connecting,
};
shouldUseNotebookStates && useNotebook.getState().setConnectionInfo(connectionStatus);
useNotebook.getState().setConnectionInfo(connectionStatus);
let connectionInfo;
try {
TelemetryProcessor.traceStart(Action.PhoenixConnection, {
dataExplorerArea: Areas.Notebook,
});
shouldUseNotebookStates
? useNotebook.getState().setIsAllocating(true)
: useQueryCopilot.getState().setIsAllocatingContainer(true);
useNotebook.getState().setIsAllocating(true);
connectionInfo = await this.phoenixClient.allocateContainer(provisionData);
if (!connectionInfo?.data?.phoenixServiceUrl) {
throw new Error(`PhoenixServiceUrl is invalid!`);
}
await this.setNotebookInfo(shouldUseNotebookStates, connectionInfo, connectionStatus);
await this.setNotebookInfo(connectionInfo, connectionStatus);
TelemetryProcessor.traceSuccess(Action.PhoenixConnection, {
dataExplorerArea: Areas.Notebook,
});
@@ -452,9 +381,7 @@ export default class Explorer {
errorStack: getErrorStack(error),
});
connectionStatus.status = ConnectionStatusType.Failed;
shouldUseNotebookStates
? useNotebook.getState().resetContainerConnection(connectionStatus)
: useQueryCopilot.getState().resetContainerConnection();
useNotebook.getState().resetContainerConnection(connectionStatus);
if (error?.status === HttpStatusCodes.Forbidden && error.message) {
useDialog.getState().showOkModalDialog("Connection Failed", `${error.message}`);
} else {
@@ -467,9 +394,7 @@ export default class Explorer {
}
throw error;
} finally {
shouldUseNotebookStates
? useNotebook.getState().setIsAllocating(false)
: useQueryCopilot.getState().setIsAllocatingContainer(false);
useNotebook.getState().setIsAllocating(false);
this.refreshCommandBarButtons();
this.refreshNotebookList();
this._isInitializingNotebooks = false;
@@ -478,7 +403,6 @@ export default class Explorer {
}
private async setNotebookInfo(
shouldUseNotebookStates: boolean,
connectionInfo: IResponse<IPhoenixServiceInfo>,
connectionStatus: DataModels.ContainerConnectionInfo
) {
@@ -486,26 +410,21 @@ export default class Explorer {
forwardingId: connectionInfo.data.forwardingId,
dbAccountName: userContext.databaseAccount.name,
};
await this.phoenixClient.initiateContainerHeartBeat(shouldUseNotebookStates, containerData);
await this.phoenixClient.initiateContainerHeartBeat(containerData);
connectionStatus.status = ConnectionStatusType.Connected;
shouldUseNotebookStates && useNotebook.getState().setConnectionInfo(connectionStatus);
const noteBookServerInfo = {
useNotebook.getState().setConnectionInfo(connectionStatus);
useNotebook.getState().setNotebookServerInfo({
notebookServerEndpoint:
(validateEndpoint(userContext.features.notebookServerUrl, allowedNotebookServerUrls) &&
userContext.features.notebookServerUrl) ||
connectionInfo.data.phoenixServiceUrl,
authToken: userContext.features.notebookServerToken || connectionInfo.data.authToken,
forwardingId: connectionInfo.data.forwardingId,
};
shouldUseNotebookStates
? useNotebook.getState().setNotebookServerInfo(noteBookServerInfo)
: useQueryCopilot.getState().setNotebookServerInfo(noteBookServerInfo);
shouldUseNotebookStates &&
this.notebookManager?.notebookClient
.getMemoryUsage()
.then((memoryUsageInfo) => useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo));
});
this.notebookManager?.notebookClient
.getMemoryUsage()
.then((memoryUsageInfo) => useNotebook.getState().setMemoryUsageInfo(memoryUsageInfo));
}
public resetNotebookWorkspace(): void {
@@ -579,7 +498,7 @@ export default class Explorer {
throw new Error(`Reset Workspace: PhoenixServiceUrl is invalid!`);
}
if (useNotebook.getState().isPhoenixNotebooks) {
await this.setNotebookInfo(true, connectionInfo, connectionStatus);
await this.setNotebookInfo(connectionInfo, connectionStatus);
useNotebook.getState().setIsRefreshed(!useNotebook.getState().isRefreshed);
}
logConsoleInfo("Successfully reset notebook workspace");
@@ -689,8 +608,6 @@ export default class Explorer {
private _initSettings() {
if (!ExplorerSettings.hasSettingsDefined()) {
ExplorerSettings.createDefaultSettings();
} else {
ExplorerSettings.ensurePriorityLevel();
}
}
@@ -794,7 +711,7 @@ export default class Explorer {
throw new Error(`Invalid notebookContentItem: ${notebookContentItem}`);
}
if (notebookContentItem.type === NotebookContentItemType.Notebook && useNotebook.getState().isPhoenixNotebooks) {
await this.allocateContainer(PoolIdType.DefaultPoolId);
await this.allocateContainer();
}
const notebookTabs = useTabs
@@ -1019,7 +936,7 @@ export default class Explorer {
}
if (useNotebook.getState().isPhoenixNotebooks) {
if (isGithubTree) {
await this.allocateContainer(PoolIdType.DefaultPoolId);
await this.allocateContainer();
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.createNewNoteBook(parent, isGithubTree);
} else {
@@ -1028,7 +945,7 @@ export default class Explorer {
undefined,
"Create",
async () => {
await this.allocateContainer(PoolIdType.DefaultPoolId);
await this.allocateContainer();
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.createNewNoteBook(parent, isGithubTree);
},
@@ -1107,7 +1024,7 @@ export default class Explorer {
public async openNotebookTerminal(kind: ViewModels.TerminalKind): Promise<void> {
if (useNotebook.getState().isPhoenixFeatures) {
await this.allocateContainer(PoolIdType.DefaultPoolId);
await this.allocateContainer();
const notebookServerInfo = useNotebook.getState().notebookServerInfo;
if (notebookServerInfo && notebookServerInfo.notebookServerEndpoint !== undefined) {
this.connectToNotebookTerminal(kind);
@@ -1144,10 +1061,6 @@ export default class Explorer {
title = "PSQL Shell";
break;
case ViewModels.TerminalKind.VCoreMongo:
title = "VCoreMongo Shell";
break;
default:
throw new Error("Terminal kind: ${kind} not supported");
}
@@ -1255,7 +1168,7 @@ export default class Explorer {
await useNotebook.getState().getPhoenixStatus();
}
if (useNotebook.getState().isPhoenixNotebooks) {
await this.allocateContainer(PoolIdType.DefaultPoolId);
await this.allocateContainer();
}
// We still use github urls like https://github.com/Azure-Samples/cosmos-notebooks/blob/master/CSharp_quickstarts/GettingStarted_CSharp.ipynb
@@ -1292,7 +1205,7 @@ export default class Explorer {
undefined,
"Upload",
async () => {
await this.allocateContainer(PoolIdType.DefaultPoolId);
await this.allocateContainer();
parent = parent || this.resourceTree.myNotebooksContentRoot;
this.uploadFilePanel(parent);
},
@@ -1334,7 +1247,7 @@ export default class Explorer {
}
public async refreshExplorer(): Promise<void> {
if (userContext.apiType !== "Postgres" && userContext.apiType !== "VCoreMongo") {
if (userContext.apiType !== "Postgres") {
userContext.authType === AuthType.ResourceToken
? this.refreshDatabaseForResourceToken()
: this.refreshAllDatabases();
@@ -1343,10 +1256,9 @@ export default class Explorer {
// TODO: remove reference to isNotebookEnabled and isNotebooksEnabledForAccount
const isNotebookEnabled =
configContext.platform !== Platform.Fabric &&
(userContext.features.notebooksDownBanner ||
useNotebook.getState().isPhoenixNotebooks ||
useNotebook.getState().isPhoenixFeatures);
userContext.features.notebooksDownBanner ||
useNotebook.getState().isPhoenixNotebooks ||
useNotebook.getState().isPhoenixFeatures;
useNotebook.getState().setIsNotebookEnabled(isNotebookEnabled);
useNotebook
.getState()

View File

@@ -128,7 +128,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
>
<img
alt="Delete"
src={Object {}}
src=""
/>
</AccessibleElement>
</td>
@@ -185,7 +185,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
>
<img
alt="Delete"
src={Object {}}
src=""
/>
</AccessibleElement>
</td>
@@ -203,7 +203,7 @@ exports[`<EditorNodePropertiesComponent /> renders component 1`] = `
>
<img
alt="Add"
src={Object {}}
src=""
/>
Add Property
</AccessibleElement>
@@ -317,7 +317,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
>
<img
alt="Delete"
src={Object {}}
src=""
/>
</AccessibleElement>
</td>
@@ -379,7 +379,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
>
<img
alt="Delete"
src={Object {}}
src=""
/>
</AccessibleElement>
</td>
@@ -397,7 +397,7 @@ exports[`<EditorNodePropertiesComponent /> renders proper unicode 1`] = `
>
<img
alt="Add"
src={Object {}}
src=""
/>
Add Property
</AccessibleElement>

View File

@@ -5,12 +5,10 @@
*/
import { CommandBar as FluentCommandBar, ICommandBarItemProps } from "@fluentui/react";
import { useNotebook } from "Explorer/Notebook/useNotebook";
import { userContext } from "UserContext";
import * as React from "react";
import { userContext } from "UserContext";
import create, { UseStore } from "zustand";
import { ConnectionStatusType, PoolIdType } from "../../../Common/Constants";
import { StyleConstants } from "../../../Common/StyleConstants";
import { Platform, configContext } from "../../../ConfigContext";
import { ConnectionStatusType, StyleConstants } from "../../../Common/Constants";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
import Explorer from "../../Explorer";
import { useSelectedNode } from "../../useSelectedNode";
@@ -36,11 +34,8 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
const buttons = useCommandBar((state) => state.contextButtons);
const backgroundColor = StyleConstants.BaseLight;
if (userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo") {
const buttons =
userContext.apiType === "Postgres"
? CommandBarComponentButtonFactory.createPostgreButtons(container)
: CommandBarComponentButtonFactory.createVCoreMongoButtons(container);
if (userContext.apiType === "Postgres") {
const buttons = CommandBarComponentButtonFactory.createPostgreButtons(container);
return (
<div className="commandBarContainer">
<FluentCommandBar
@@ -81,32 +76,18 @@ export const CommandBar: React.FC<Props> = ({ container }: Props) => {
(useNotebook.getState().isPhoenixNotebooks || useNotebook.getState().isPhoenixFeatures) &&
connectionInfo?.status !== ConnectionStatusType.Connect
) {
uiFabricControlButtons.unshift(
CommandBarUtil.createConnectionStatus(container, PoolIdType.DefaultPoolId, "connectionStatus")
);
uiFabricControlButtons.unshift(CommandBarUtil.createConnectionStatus(container, "connectionStatus"));
}
const rootStyle =
configContext.platform === Platform.Fabric
? {
root: {
backgroundColor: "transparent",
padding: "0px 14px 0px 14px",
},
}
: {
root: {
backgroundColor: backgroundColor,
},
};
return (
<div className="commandBarContainer">
<FluentCommandBar
ariaLabel="Use left and right arrow keys to navigate between commands"
items={uiFabricStaticButtons.concat(uiFabricTabsButtons)}
farItems={uiFabricControlButtons}
styles={rootStyle}
styles={{
root: { backgroundColor: backgroundColor },
}}
overflowButtonProps={{ ariaLabel: "More commands" }}
/>
</div>

View File

@@ -142,8 +142,8 @@ describe("CommandBarComponentButtonFactory tests", () => {
});
});
describe("Open Mongo shell button", () => {
const openMongoShellBtnLabel = "Open Mongo shell";
describe("Open Mongo Shell button", () => {
const openMongoShellBtnLabel = "Open Mongo Shell";
const selectedNodeState = useSelectedNode.getState();
beforeAll(() => {
@@ -247,8 +247,8 @@ describe("CommandBarComponentButtonFactory tests", () => {
});
});
describe("Open Cassandra shell button", () => {
const openCassandraShellBtnLabel = "Open Cassandra shell";
describe("Open Cassandra Shell button", () => {
const openCassandraShellBtnLabel = "Open Cassandra Shell";
const selectedNodeState = useSelectedNode.getState();
beforeAll(() => {
@@ -343,31 +343,6 @@ describe("CommandBarComponentButtonFactory tests", () => {
});
});
describe("Open Postgres and vCore Mongo buttons", () => {
const openPostgresShellButtonLabel = "Open PSQL shell";
const openVCoreMongoShellButtonLabel = "Open MongoDB (vcore) shell";
beforeAll(() => {
mockExplorer = {} as Explorer;
});
it("creates Postgres shell button", () => {
const buttons = CommandBarComponentButtonFactory.createPostgreButtons(mockExplorer);
const openPostgresShellButton = buttons.find(
(button) => button.commandButtonLabel === openPostgresShellButtonLabel
);
expect(openPostgresShellButton).toBeDefined();
});
it("creates vCore Mongo shell button", () => {
const buttons = CommandBarComponentButtonFactory.createVCoreMongoButtons(mockExplorer);
const openVCoreMongoShellButton = buttons.find(
(button) => button.commandButtonLabel === openVCoreMongoShellButtonLabel
);
expect(openVCoreMongoShellButton).toBeDefined();
});
});
describe("GitHub buttons", () => {
const connectToGitHubBtnLabel = "Connect to GitHub";
const manageGitHubSettingsBtnLabel = "Manage GitHub settings";

View File

@@ -54,11 +54,7 @@ export function createStaticCommandBarButtons(
const buttons: CommandButtonComponentProps[] = [];
buttons.push(newCollectionBtn);
if (
configContext.platform !== Platform.Fabric &&
userContext.apiType !== "Tables" &&
userContext.apiType !== "Cassandra"
) {
if (userContext.apiType !== "Tables" && userContext.apiType !== "Cassandra") {
const addSynapseLink = createOpenSynapseLinkDialogButton(container);
if (addSynapseLink) {
@@ -98,9 +94,9 @@ export function createStaticCommandBarButtons(
) {
notebookButtons.push(createDivider());
if (userContext.apiType === "Cassandra") {
notebookButtons.push(createOpenTerminalButtonByKind(container, ViewModels.TerminalKind.Cassandra));
notebookButtons.push(createOpenCassandraTerminalButton(container));
} else {
notebookButtons.push(createOpenTerminalButtonByKind(container, ViewModels.TerminalKind.Mongo));
notebookButtons.push(createOpenMongoTerminalButton(container));
}
}
@@ -261,9 +257,7 @@ export function createDivider(): CommandButtonComponentProps {
}
function areScriptsSupported(): boolean {
return (
configContext.platform !== Platform.Fabric && (userContext.apiType === "SQL" || userContext.apiType === "Gremlin")
);
return userContext.apiType === "SQL" || userContext.apiType === "Gremlin";
}
function createNewCollectionGroup(container: Explorer): CommandButtonComponentProps {
@@ -505,25 +499,8 @@ function createOpenTerminalButton(container: Explorer): CommandButtonComponentPr
};
}
function createOpenTerminalButtonByKind(
container: Explorer,
terminalKind: ViewModels.TerminalKind
): CommandButtonComponentProps {
const terminalFriendlyName = (): string => {
switch (terminalKind) {
case ViewModels.TerminalKind.Cassandra:
return "Cassandra";
case ViewModels.TerminalKind.Mongo:
return "Mongo";
case ViewModels.TerminalKind.Postgres:
return "PSQL";
case ViewModels.TerminalKind.VCoreMongo:
return "MongoDB (vcore)";
default:
return "";
}
};
const label = `Open ${terminalFriendlyName()} shell`;
function createOpenMongoTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Mongo Shell";
const tooltip =
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
const disableButton =
@@ -533,7 +510,7 @@ function createOpenTerminalButtonByKind(
iconAlt: label,
onCommandClick: () => {
if (useNotebook.getState().isNotebookEnabled) {
container.openNotebookTerminal(terminalKind);
container.openNotebookTerminal(ViewModels.TerminalKind.Mongo);
}
},
commandButtonLabel: label,
@@ -544,6 +521,51 @@ function createOpenTerminalButtonByKind(
};
}
function createOpenCassandraTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open Cassandra Shell";
const tooltip =
"This feature is not yet available in your account's region. View supported regions here: https://aka.ms/cosmos-enable-notebooks.";
const disableButton =
!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled;
return {
iconSrc: HostedTerminalIcon,
iconAlt: label,
onCommandClick: () => {
if (useNotebook.getState().isNotebookEnabled) {
container.openNotebookTerminal(ViewModels.TerminalKind.Cassandra);
}
},
commandButtonLabel: label,
hasPopup: false,
disabled: disableButton,
ariaLabel: label,
tooltipText: !disableButton ? "" : tooltip,
};
}
function createOpenPsqlTerminalButton(container: Explorer): CommandButtonComponentProps {
const label = "Open PSQL Shell";
const disableButton =
(!useNotebook.getState().isNotebooksEnabledForAccount && !useNotebook.getState().isNotebookEnabled) ||
useSelectedNode.getState().isQueryCopilotCollectionSelected();
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 {
@@ -608,13 +630,7 @@ function createStaticCommandBarButtonsForResourceToken(
}
export function createPostgreButtons(container: Explorer): CommandButtonComponentProps[] {
const openPostgreShellBtn = createOpenTerminalButtonByKind(container, ViewModels.TerminalKind.Postgres);
const openPostgreShellBtn = createOpenPsqlTerminalButton(container);
return [openPostgreShellBtn];
}
export function createVCoreMongoButtons(container: Explorer): CommandButtonComponentProps[] {
const openVCoreMongoTerminalButton = createOpenTerminalButtonByKind(container, ViewModels.TerminalKind.VCoreMongo);
return [openVCoreMongoTerminalButton];
}

View File

@@ -9,9 +9,7 @@ import {
import * as React from "react";
import _ from "underscore";
import ChevronDownIcon from "../../../../images/Chevron_down.svg";
import { PoolIdType } from "../../../Common/Constants";
import { StyleConstants } from "../../../Common/StyleConstants";
import { configContext, Platform } from "../../../ConfigContext";
import { StyleConstants } from "../../../Common/Constants";
import { Action, ActionModifiers } from "../../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../../Shared/Telemetry/TelemetryProcessor";
import { CommandButtonComponentProps } from "../../Controls/CommandButton/CommandButtonComponent";
@@ -26,14 +24,11 @@ import { MemoryTracker } from "./MemoryTrackerComponent";
export const convertButton = (btns: CommandButtonComponentProps[], backgroundColor: string): ICommandBarItemProps[] => {
const buttonHeightPx = StyleConstants.CommandBarButtonHeight;
const hoverColor =
configContext.platform == Platform.Fabric ? StyleConstants.FabricAccentLight : StyleConstants.AccentLight;
const getFilter = (isDisabled: boolean): string => {
if (isDisabled) {
return StyleConstants.GrayScale;
}
return configContext.platform == Platform.Fabric ? StyleConstants.NoColor : undefined;
return undefined;
};
return btns
@@ -73,7 +68,6 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
height: buttonHeightPx,
paddingRight: 0,
paddingLeft: 0,
borderRadius: configContext.platform == Platform.Fabric ? StyleConstants.FabricButtonBorderRadius : "0px",
minWidth: 24,
marginLeft: isSplit ? 0 : 5,
marginRight: isSplit ? 0 : 5,
@@ -85,17 +79,17 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
splitButtonMenuButton: {
backgroundColor: backgroundColor,
selectors: {
":hover": { backgroundColor: hoverColor },
":hover": { backgroundColor: StyleConstants.AccentLight },
},
width: 16,
},
label: { fontSize: StyleConstants.mediumFontSize },
rootHovered: { backgroundColor: hoverColor },
rootPressed: { backgroundColor: hoverColor },
rootHovered: { backgroundColor: StyleConstants.AccentLight },
rootPressed: { backgroundColor: StyleConstants.AccentLight },
splitButtonMenuButtonExpanded: {
backgroundColor: StyleConstants.AccentExtra,
selectors: {
":hover": { backgroundColor: hoverColor },
":hover": { backgroundColor: StyleConstants.AccentLight },
},
},
splitButtonDivider: {
@@ -126,7 +120,7 @@ export const convertButton = (btns: CommandButtonComponentProps[], backgroundCol
// TODO Remove all this crazy styling once we adopt Ui-Fabric Azure themes
selectors: {
".ms-ContextualMenu-itemText": { fontSize: StyleConstants.mediumFontSize },
".ms-ContextualMenu-link:hover": { backgroundColor: hoverColor },
".ms-ContextualMenu-link:hover": { backgroundColor: StyleConstants.AccentLight },
".ms-ContextualMenu-icon": { width: 16, height: 16 },
},
},
@@ -210,9 +204,9 @@ export const createMemoryTracker = (key: string): ICommandBarItemProps => {
};
};
export const createConnectionStatus = (container: Explorer, poolId: PoolIdType, key: string): ICommandBarItemProps => {
export const createConnectionStatus = (container: Explorer, key: string): ICommandBarItemProps => {
return {
key,
onRender: () => <ConnectionStatus container={container} poolId={poolId} />,
onRender: () => <ConnectionStatus container={container} />,
};
};

View File

@@ -14,15 +14,14 @@ import { useId } from "@fluentui/react-hooks";
import { ActionButton, DefaultButton } from "@fluentui/react/lib/Button";
import * as React from "react";
import "../../../../less/hostedexplorer.less";
import { ConnectionStatusType, ContainerStatusType, Notebook, PoolIdType } from "../../../Common/Constants";
import { ConnectionStatusType, ContainerStatusType, Notebook } from "../../../Common/Constants";
import Explorer from "../../Explorer";
import { useNotebook } from "../../Notebook/useNotebook";
import "../CommandBar/ConnectionStatusComponent.less";
interface Props {
container: Explorer;
poolId: PoolIdType;
}
export const ConnectionStatus: React.FC<Props> = ({ container, poolId }: Props): JSX.Element => {
export const ConnectionStatus: React.FC<Props> = ({ container }: Props): JSX.Element => {
const connectionInfo = useNotebook((state) => state.connectionInfo);
const [second, setSecond] = React.useState("00");
const [minute, setMinute] = React.useState("00");
@@ -94,7 +93,7 @@ export const ConnectionStatus: React.FC<Props> = ({ container, poolId }: Props):
(connectionInfo.status === ConnectionStatusType.Connect || connectionInfo.status === ConnectionStatusType.Reconnect)
) {
return (
<ActionButton className="commandReactBtn" onClick={() => container.allocateContainer(poolId)}>
<ActionButton className="commandReactBtn" onClick={() => container.allocateContainer()}>
<TooltipHost content={toolTipContent}>
<Stack className="connectionStatusContainer" horizontal>
<Icon iconName="ConnectVirtualMachine" className="connectIcon" />
@@ -134,9 +133,7 @@ export const ConnectionStatus: React.FC<Props> = ({ container, poolId }: Props):
id={buttonId}
className={connectionInfo.status === ConnectionStatusType.Failed ? "commandReactBtn" : "connectedReactBtn"}
onClick={(e: React.MouseEvent<HTMLSpanElement>) =>
connectionInfo.status === ConnectionStatusType.Failed
? container.allocateContainer(poolId)
: e.preventDefault()
connectionInfo.status === ConnectionStatusType.Failed ? container.allocateContainer() : e.preventDefault()
}
>
<Stack className="connectionStatusContainer" horizontal>

View File

@@ -122,9 +122,7 @@ export class NotificationConsoleComponent extends React.Component<
{userContext.features.pr && <PrPreview pr={userContext.features.pr} />}
<span className="consoleSplitter" />
<span className="headerStatus">
<span className="headerStatusEllipsis" aria-live="assertive" aria-atomic="true">
{this.state.headerStatus}
</span>
<span className="headerStatusEllipsis">{this.state.headerStatus}</span>
</span>
</div>
<div

View File

@@ -22,7 +22,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
>
<img
alt="in progress items"
src={Object {}}
src=""
/>
<span
className="numInProgress"
@@ -35,7 +35,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
>
<img
alt="error items"
src={Object {}}
src=""
/>
<span
className="numErroredItems"
@@ -48,7 +48,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
>
<img
alt="info items"
src={Object {}}
src=""
/>
<span
className="numInfoItems"
@@ -64,8 +64,6 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
className="headerStatus"
>
<span
aria-atomic="true"
aria-live="assertive"
className="headerStatusEllipsis"
/>
</span>
@@ -150,7 +148,7 @@ exports[`NotificationConsoleComponent renders the console 1`] = `
>
<img
alt="clear notifications image"
src={Object {}}
src=""
/>
Clear Notifications
</span>
@@ -185,7 +183,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
>
<img
alt="in progress items"
src={Object {}}
src=""
/>
<span
className="numInProgress"
@@ -198,7 +196,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
>
<img
alt="error items"
src={Object {}}
src=""
/>
<span
className="numErroredItems"
@@ -211,7 +209,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
>
<img
alt="info items"
src={Object {}}
src=""
/>
<span
className="numInfoItems"
@@ -227,8 +225,6 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
className="headerStatus"
>
<span
aria-atomic="true"
aria-live="assertive"
className="headerStatusEllipsis"
>
message
@@ -315,7 +311,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
>
<img
alt="clear notifications image"
src={Object {}}
src=""
/>
Clear Notifications
</span>
@@ -330,7 +326,7 @@ exports[`NotificationConsoleComponent renders the console 2`] = `
<img
alt="info"
className="infoIcon"
src={Object {}}
src=""
/>
<span
className="date"

View File

@@ -100,6 +100,9 @@ const addInitialCodeCellEpic = (
*/
const formWebSocketURL = (serverConfig: NotebookServiceConfig, kernelId: string, sessionId?: string): string => {
const params = new URLSearchParams();
if (serverConfig.token) {
params.append("token", serverConfig.token);
}
if (sessionId) {
params.append("session_id", sessionId);
}

View File

@@ -3,7 +3,7 @@ import distanceInWordsToNow from "date-fns/distance_in_words_to_now";
import React from "react";
import { connect } from "react-redux";
import styled from "styled-components";
import { StyleConstants } from "../../../Common/StyleConstants";
import { StyleConstants } from "../../../Common/Constants";
interface Props {
lastSaved?: Date | null;

View File

@@ -1,6 +1,6 @@
import { isPublicInternetAccessAllowed } from "Common/DatabaseAccountUtility";
import { PhoenixClient } from "Phoenix/PhoenixClient";
import { cloneDeep } from "lodash";
import { PhoenixClient } from "Phoenix/PhoenixClient";
import create, { UseStore } from "zustand";
import { AuthType } from "../../AuthType";
import * as Constants from "../../Common/Constants";
@@ -10,13 +10,13 @@ import * as Logger from "../../Common/Logger";
import { configContext } from "../../ConfigContext";
import * as DataModels from "../../Contracts/DataModels";
import { ContainerConnectionInfo, ContainerInfo, PhoenixErrorType } from "../../Contracts/DataModels";
import { useTabs } from "../../hooks/useTabs";
import { IPinnedRepo } from "../../Juno/JunoClient";
import { Action, ActionModifiers } from "../../Shared/Telemetry/TelemetryConstants";
import * as TelemetryProcessor from "../../Shared/Telemetry/TelemetryProcessor";
import { userContext } from "../../UserContext";
import { getAuthorizationHeader } from "../../Utils/AuthorizationUtils";
import * as GitHubUtils from "../../Utils/GitHubUtils";
import { useTabs } from "../../hooks/useTabs";
import { NotebookContentItem, NotebookContentItemType } from "./NotebookContentItem";
import NotebookManager from "./NotebookManager";
@@ -124,7 +124,7 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
}
const firstWriteLocation =
userContext.apiType === "Postgres" || userContext.apiType === "VCoreMongo"
userContext.apiType === "Postgres"
? databaseAccount?.location
: databaseAccount?.properties?.writeLocations?.[0]?.locationName.toLowerCase();
const disallowedLocationsUri = `${configContext.BACKEND_ENDPOINT}/api/disallowedLocations`;
@@ -316,10 +316,8 @@ export const useNotebook: UseStore<NotebookState> = create((set, get) => ({
isPhoenixNotebooks = isPublicInternetAllowed && userContext.features.phoenixNotebooks === true;
isPhoenixFeatures =
isPublicInternetAllowed &&
// phoenix needs to be enabled for Postgres and VCoreMongo accounts since the PSQL and mongo shell requires phoenix containers
(userContext.features.phoenixFeatures === true ||
userContext.apiType === "Postgres" ||
userContext.apiType === "VCoreMongo");
// phoenix needs to be enabled for Postgres accounts since the PSQL shell requires phoenix containers
(userContext.features.phoenixFeatures === true || userContext.apiType === "Postgres");
} else {
isPhoenixNotebooks = isPhoenixFeatures = isPublicInternetAllowed;
}

View File

@@ -1425,8 +1425,6 @@ export class AddCollectionPanel extends React.Component<AddCollectionPanelProps,
this.setState({ isExecuting: false });
TelemetryProcessor.traceSuccess(Action.CreateCollection, telemetryData, startKey);
useSidePanel.getState().closeSidePanel();
// open NPS Survey Dialog once the collection is created
this.props.explorer.openNPSSurveyDialog();
} catch (error) {
const errorMessage: string = getErrorMessage(error);
this.setState({ isExecuting: false, errorMessage, showErrorDetails: true });

View File

@@ -1,12 +1,12 @@
import { IDropdownOption } from "@fluentui/react";
import React, { FormEvent, FunctionComponent, useEffect, useState } from "react";
import { HttpStatusCodes, PoolIdType } from "../../../Common/Constants";
import { HttpStatusCodes } from "../../../Common/Constants";
import { getErrorMessage, handleError } from "../../../Common/ErrorHandlingUtils";
import { GitHubOAuthService } from "../../../GitHub/GitHubOAuthService";
import { useSidePanel } from "../../../hooks/useSidePanel";
import { IPinnedRepo, JunoClient } from "../../../Juno/JunoClient";
import * as GitHubUtils from "../../../Utils/GitHubUtils";
import * as NotificationConsoleUtils from "../../../Utils/NotificationConsoleUtils";
import { useSidePanel } from "../../../hooks/useSidePanel";
import Explorer from "../../Explorer";
import { NotebookContentItem, NotebookContentItemType } from "../../Notebook/NotebookContentItem";
import { useNotebook } from "../../Notebook/useNotebook";
@@ -109,7 +109,7 @@ export const CopyNotebookPane: FunctionComponent<CopyNotebookPanelProps> = ({
};
isGithubTree = false;
if (useNotebook.getState().isPhoenixNotebooks) {
await container.allocateContainer(PoolIdType.DefaultPoolId);
await container.allocateContainer();
}
break;

View File

@@ -9,11 +9,11 @@ import {
Stack,
Text,
} from "@fluentui/react";
import { GitHubReposTitle } from "Explorer/Tree/ResourceTree";
import React, { FormEvent, FunctionComponent } from "react";
import { IPinnedRepo } from "../../../Juno/JunoClient";
import * as GitHubUtils from "../../../Utils/GitHubUtils";
import { useNotebook } from "../../Notebook/useNotebook";
import { ResourceTreeAdapter } from "../../Tree/ResourceTreeAdapter";
interface Location {
type: "MyNotebooks" | "GitHub";
@@ -65,7 +65,7 @@ export const CopyNotebookPaneComponent: FunctionComponent<CopyNotebookPaneProps>
options.push({
key: "GitHub-Header",
text: GitHubReposTitle,
text: ResourceTreeAdapter.GitHubReposTitle,
itemType: SelectableOptionMenuItemType.Header,
});

View File

@@ -4340,7 +4340,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="deleteparam"
onClick={[Function]}
role="button"
src={Object {}}
src=""
width={20}
>
<ImageBase
@@ -4350,7 +4350,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="deleteparam"
onClick={[Function]}
role="button"
src={Object {}}
src=""
styles={[Function]}
theme={
Object {
@@ -4640,12 +4640,12 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
alt="Delete param"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
id="deleteparam"
key="fabricImage[object Object]"
key="fabricImage"
onClick={[Function]}
onError={[Function]}
onLoad={[Function]}
role="button"
src={Object {}}
src=""
/>
</div>
</ImageBase>
@@ -4661,7 +4661,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="addparam"
onClick={[Function]}
role="button"
src={Object {}}
src=""
width={20}
>
<ImageBase
@@ -4671,7 +4671,7 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
id="addparam"
onClick={[Function]}
role="button"
src={Object {}}
src=""
styles={[Function]}
theme={
Object {
@@ -4961,12 +4961,12 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
alt="Add param"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
id="addparam"
key="fabricImage[object Object]"
key="fabricImage"
onClick={[Function]}
onError={[Function]}
onLoad={[Function]}
role="button"
src={Object {}}
src=""
/>
</div>
</ImageBase>
@@ -4989,13 +4989,13 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
alt="Add param"
height={30}
key=".0:$.0"
src={Object {}}
src=""
width={20}
>
<ImageBase
alt="Add param"
height={30}
src={Object {}}
src=""
styles={[Function]}
theme={
Object {
@@ -5284,10 +5284,10 @@ exports[`Excute Sproc Param Pane should render Default properly 1`] = `
<img
alt="Add param"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-87"
key="fabricImage[object Object]"
key="fabricImage"
onError={[Function]}
onLoad={[Function]}
src={Object {}}
src=""
/>
</div>
</ImageBase>

View File

@@ -39,7 +39,7 @@ exports[`Load Query Pane should render Default properly 1`] = `
className="fileIcon"
height={20}
imageFit={4}
src={Object {}}
src=""
width={20}
/>
<input

View File

@@ -41,18 +41,12 @@ export const SettingsPane: FunctionComponent = () => {
? LocalStorageUtility.getEntryNumber(StorageKey.MaxDegreeOfParellism)
: Constants.Queries.DefaultMaxDegreeOfParallelism
);
const [priorityLevel, setPriorityLevel] = useState<string>(
LocalStorageUtility.hasItem(StorageKey.PriorityLevel)
? LocalStorageUtility.getEntryString(StorageKey.PriorityLevel)
: Constants.PriorityLevel.Default
);
const explorerVersion = configContext.gitSha;
const shouldShowQueryPageOptions = userContext.apiType === "SQL";
const shouldShowGraphAutoVizOption = userContext.apiType === "Gremlin";
const shouldShowCrossPartitionOption = userContext.apiType !== "Gremlin";
const shouldShowParallelismOption = userContext.apiType !== "Gremlin";
const shouldShowPriorityLevelOption =
userContext.features.enablePriorityBasedThrottling && userContext.apiType === "SQL";
const handlerOnSubmit = (e: MouseEvent<HTMLButtonElement>) => {
setIsExecuting(true);
@@ -64,7 +58,6 @@ export const SettingsPane: FunctionComponent = () => {
LocalStorageUtility.setEntryString(StorageKey.ContainerPaginationEnabled, containerPaginationEnabled.toString());
LocalStorageUtility.setEntryString(StorageKey.IsCrossPartitionQueryEnabled, crossPartitionQueryEnabled.toString());
LocalStorageUtility.setEntryNumber(StorageKey.MaxDegreeOfParellism, maxDegreeOfParallelism);
LocalStorageUtility.setEntryString(StorageKey.PriorityLevel, priorityLevel.toString());
if (shouldShowGraphAutoVizOption) {
LocalStorageUtility.setEntryBoolean(
@@ -83,7 +76,6 @@ export const SettingsPane: FunctionComponent = () => {
StorageKey.MaxDegreeOfParellism
)}`
);
logConsoleInfo(`Updated priority level setting to ${LocalStorageUtility.getEntryString(StorageKey.PriorityLevel)}`);
if (shouldShowGraphAutoVizOption) {
logConsoleInfo(
@@ -124,18 +116,6 @@ export const SettingsPane: FunctionComponent = () => {
{ key: "true", text: "JSON" },
];
const priorityLevelOptionList: IChoiceGroupOption[] = [
{ key: Constants.PriorityLevel.Low, text: "Low" },
{ key: Constants.PriorityLevel.High, text: "High" },
];
const handleOnPriorityLevelOptionChange = (
ev: React.FormEvent<HTMLInputElement>,
option: IChoiceGroupOption
): void => {
setPriorityLevel(option.key);
};
const handleOnPageOptionChange = (ev: React.FormEvent<HTMLInputElement>, option: IChoiceGroupOption): void => {
setPageOption(option.key);
};
@@ -280,29 +260,6 @@ export const SettingsPane: FunctionComponent = () => {
</div>
</div>
)}
{shouldShowPriorityLevelOption && (
<div className="settingsSection">
<div className="settingsSectionPart">
<fieldset>
<legend id="priorityLevel" className="settingsSectionLabel legendLabel">
Priority Level
</legend>
<InfoTooltip>
Sets the priority level for data-plane requests from Data Explorer when using Priority-Based
Execution. If &quot;None&quot; is selected, Data Explorer will not specify priority level, and the
server-side default priority level will be used.
</InfoTooltip>
<ChoiceGroup
ariaLabelledBy="priorityLevel"
selectedKey={priorityLevel}
options={priorityLevelOptionList}
styles={choiceButtonStyles}
onChange={handleOnPriorityLevelOptionChange}
/>
</fieldset>
</div>
</div>
)}
{shouldShowGraphAutoVizOption && (
<div className="settingsSection">
<div className="settingsSectionPart">

View File

@@ -44,13 +44,13 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
alt="Add Property"
height={30}
key=".0:$.0"
src={Object {}}
src=""
width={16}
>
<ImageBase
alt="Add Property"
height={30}
src={Object {}}
src=""
styles={[Function]}
theme={
Object {
@@ -339,10 +339,10 @@ exports[`Excute Add Table Entity Pane should render Default properly 1`] = `
<img
alt="Add Property"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55"
key="fabricImage[object Object]"
key="fabricImage"
onError={[Function]}
onLoad={[Function]}
src={Object {}}
src=""
/>
</div>
</ImageBase>

View File

@@ -39,13 +39,13 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
alt="Add Entity"
height={30}
key=".0:$.0"
src={Object {}}
src=""
width={16}
>
<ImageBase
alt="Add Entity"
height={30}
src={Object {}}
src=""
styles={[Function]}
theme={
Object {
@@ -334,10 +334,10 @@ exports[`Excute Edit Table Entity Pane should render Default properly 1`] = `
<img
alt="Add Entity"
className="ms-Image-image ms-Image-image--portrait is-notLoaded is-fadeIn image-55"
key="fabricImage[object Object]"
key="fabricImage"
onError={[Function]}
onLoad={[Function]}
src={Object {}}
src=""
/>
</div>
</ImageBase>

View File

@@ -1,15 +1,8 @@
import {
DetailsList,
DetailsListLayoutMode,
DirectionalHint,
IColumn,
SelectionMode,
TooltipHost,
} from "@fluentui/react";
import { DetailsList, DetailsListLayoutMode, IColumn, SelectionMode } from "@fluentui/react";
import { Upload } from "Common/Upload/Upload";
import { UploadDetailsRecord } from "Contracts/ViewModels";
import { logConsoleError } from "Utils/NotificationConsoleUtils";
import React, { ChangeEvent, FunctionComponent, useState } from "react";
import { logConsoleError } from "Utils/NotificationConsoleUtils";
import { getErrorMessage } from "../../Tables/Utilities";
import { useSelectedNode } from "../../useSelectedNode";
import { RightPaneForm, RightPaneFormProps } from "../RightPaneForm/RightPaneForm";
@@ -81,21 +74,12 @@ export const UploadItemsPane: FunctionComponent = () => {
];
const _renderItemColumn = (item: UploadDetailsRecord, index: number, column: IColumn) => {
let fieldContent: string;
const tooltipId = `tooltip-${index}-${column.key}`;
switch (column.key) {
case "status":
fieldContent = `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
break;
return `${item.numSucceeded} created, ${item.numThrottled} throttled, ${item.numFailed} errors`;
default:
fieldContent = item.fileName;
return item.fileName;
}
return (
<TooltipHost content={fieldContent} id={tooltipId} directionalHint={DirectionalHint.rightCenter}>
{fieldContent}
</TooltipHost>
);
};
return (

View File

@@ -11,9 +11,8 @@ import {
Stack,
Text,
} from "@fluentui/react";
import { QueryCopilotSampleDatabaseId } from "Common/Constants";
import { QueryCopilotSampleDatabaseId, StyleConstants } from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils";
import { StyleConstants } from "Common/StyleConstants";
import { createCollection } from "Common/dataAccess/createCollection";
import * as DataModels from "Contracts/DataModels";
import { ContainerSampleGenerator } from "Explorer/DataSamples/ContainerSampleGenerator";

View File

@@ -1,7 +1,6 @@
import { Checkbox, ChoiceGroup, DefaultButton, IconButton, PrimaryButton, TextField } from "@fluentui/react";
import Explorer from "Explorer/Explorer";
import { QueryCopilotFeedbackModal } from "Explorer/QueryCopilot/Modal/QueryCopilotFeedbackModal";
import { SubmitFeedback } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
import { submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import { getUserEmail } from "Utils/UserUtils";
import { shallow } from "enzyme";
import { useQueryCopilot } from "hooks/useQueryCopilot";
@@ -10,8 +9,8 @@ import React from "react";
jest.mock("Utils/UserUtils");
(getUserEmail as jest.Mock).mockResolvedValue("test@email.com");
jest.mock("Explorer/QueryCopilot/Shared/QueryCopilotClient");
SubmitFeedback as jest.Mock;
jest.mock("Explorer/QueryCopilot/QueryCopilotUtilities");
submitFeedback as jest.Mock;
describe("Query Copilot Feedback Modal snapshot test", () => {
beforeEach(() => {
@@ -20,14 +19,14 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
it("shoud render and match snapshot", () => {
useQueryCopilot.getState().openFeedbackModal("test query", false, "test prompt");
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
expect(wrapper.props().isOpen).toBeTruthy();
expect(wrapper).toMatchSnapshot();
});
it("should close on cancel click", () => {
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const cancelButton = wrapper.find(IconButton);
cancelButton.simulate("click");
@@ -38,7 +37,7 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
});
it("should get user unput", () => {
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const testUserInput = "test user input";
const userInput = wrapper.find(TextField).first();
@@ -49,7 +48,7 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
});
it("should record user contact choice no", () => {
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const contactAllowed = wrapper.find(ChoiceGroup);
contactAllowed.simulate("change", {}, { key: "no" });
@@ -60,7 +59,7 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
});
it("should record user contact choice yes", () => {
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const contactAllowed = wrapper.find(ChoiceGroup);
contactAllowed.simulate("change", {}, { key: "yes" });
@@ -71,7 +70,7 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
});
it("should not render dont show again button", () => {
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const dontShowAgain = wrapper.find(Checkbox);
@@ -81,7 +80,7 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
it("should render dont show again button and check it ", () => {
useQueryCopilot.getState().openFeedbackModal("test query", true, "test prompt");
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const dontShowAgain = wrapper.find(Checkbox);
dontShowAgain.simulate("change", {}, true);
@@ -92,7 +91,7 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
});
it("should cancel submission", () => {
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={new Explorer()} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const cancelButton = wrapper.find(DefaultButton);
cancelButton.simulate("click");
@@ -103,23 +102,19 @@ describe("Query Copilot Feedback Modal snapshot test", () => {
});
it("should submit submission", () => {
const explorer = new Explorer();
const wrapper = shallow(<QueryCopilotFeedbackModal explorer={explorer} />);
const wrapper = shallow(<QueryCopilotFeedbackModal />);
const submitButton = wrapper.find(PrimaryButton);
submitButton.simulate("click");
wrapper.setProps({});
expect(SubmitFeedback).toHaveBeenCalledTimes(1);
expect(SubmitFeedback).toHaveBeenCalledWith({
params: {
likeQuery: false,
generatedQuery: "",
userPrompt: "",
description: "",
contact: getUserEmail(),
},
explorer: explorer,
expect(submitFeedback).toHaveBeenCalledTimes(1);
expect(submitFeedback).toHaveBeenCalledWith({
likeQuery: false,
generatedQuery: "",
userPrompt: "",
description: "",
contact: getUserEmail(),
});
expect(wrapper.props().isOpen).toBeFalsy();
expect(wrapper).toMatchSnapshot();

View File

@@ -10,13 +10,12 @@ import {
Text,
TextField,
} from "@fluentui/react";
import Explorer from "Explorer/Explorer";
import { SubmitFeedback } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
import { submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import React from "react";
import { getUserEmail } from "../../../Utils/UserUtils";
export const QueryCopilotFeedbackModal = ({ explorer }: { explorer: Explorer }): JSX.Element => {
export const QueryCopilotFeedbackModal: React.FC = (): JSX.Element => {
const {
generatedQuery,
userPrompt,
@@ -79,13 +78,11 @@ export const QueryCopilotFeedbackModal = ({ explorer }: { explorer: Explorer }):
}}
></ChoiceGroup>
<Text style={{ fontSize: 12, marginBottom: 14 }}>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the{" "}
{
<Link href="https://privacy.microsoft.com/privacystatement" target="_blank">
Privacy statement
</Link>
}{" "}
for more information.
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your
organization will be able to view and manage your feedback data.{" "}
<Link href="https://privacy.microsoft.com/privacystatement" target="_blank">
Privacy statement
</Link>
</Text>
{likeQuery && (
<Checkbox
@@ -101,10 +98,7 @@ export const QueryCopilotFeedbackModal = ({ explorer }: { explorer: Explorer }):
onClick={() => {
closeFeedbackModal();
setHideFeedbackModalForLikedQueries(doNotShowAgainChecked);
SubmitFeedback({
params: { generatedQuery, likeQuery, description, userPrompt, contact },
explorer: explorer,
});
submitFeedback({ generatedQuery, likeQuery, description, userPrompt, contact });
}}
>
Submit

View File

@@ -42,8 +42,8 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
</Stack>
</Stack>
<Stack horizontalAlign="center">
<Stack.Item align="center" style={{ textAlign: "center" }}>
<Text className="title bold">Welcome to Query Copilot for Azure Cosmos DB (Private Preview)</Text>
<Stack.Item align="center">
<Text className="title bold">Welcome to Copilot in CosmosDB</Text>
</Stack.Item>
<Stack.Item align="center" className="text">
<Stack horizontal>
@@ -52,7 +52,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
</StackItem>
<StackItem align="start">
<Text className="bold">
Let Query Copilot do the work for you
Let copilot do the work for you
<br />
</Text>
</StackItem>
@@ -60,7 +60,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
<Text>
Ask Copilot to generate a query by describing the query in your words.
<br />
<Link href="https://aka.ms/cdb-copilot-learn-more">Learn more</Link>
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
</Text>
</Stack.Item>
<Stack.Item align="center" className="text">
@@ -78,7 +78,7 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
<Text>
AI-generated content can have mistakes. Make sure its accurate and appropriate before using it.
<br />
<Link href="https://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
<Link href="http://aka.ms/cdb-copilot-preview-terms">Read preview terms</Link>
</Text>
</Stack.Item>
<Stack.Item align="center" className="text">
@@ -88,16 +88,15 @@ export const WelcomeModal = ({ visible }: { visible: boolean }): JSX.Element =>
</StackItem>
<StackItem align="start">
<Text className="bold">
Query Copilot works on a sample database.
Copilot currently works only a sample database
<br />
</Text>
</StackItem>
</Stack>
<Text>
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you
at no cost.
Copilot is setup on a sample database we have configured for you at no cost
<br />
<Link href="https://aka.ms/cdb-copilot-learn-more">Learn more</Link>
<Link href="http://aka.ms/cdb-copilot-learn-more">Learn more</Link>
</Text>
</Stack.Item>
</Stack>

View File

@@ -118,7 +118,7 @@ exports[`Query Copilot Feedback Modal snapshot test shoud render and match snaps
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -126,8 +126,6 @@ exports[`Query Copilot Feedback Modal snapshot test shoud render and match snaps
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -273,7 +271,7 @@ exports[`Query Copilot Feedback Modal snapshot test should cancel submission 1`]
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -281,8 +279,6 @@ exports[`Query Copilot Feedback Modal snapshot test should cancel submission 1`]
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -428,7 +424,7 @@ exports[`Query Copilot Feedback Modal snapshot test should close on cancel click
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -436,8 +432,6 @@ exports[`Query Copilot Feedback Modal snapshot test should close on cancel click
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -583,7 +577,7 @@ exports[`Query Copilot Feedback Modal snapshot test should get user unput 1`] =
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -591,8 +585,6 @@ exports[`Query Copilot Feedback Modal snapshot test should get user unput 1`] =
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -738,7 +730,7 @@ exports[`Query Copilot Feedback Modal snapshot test should not render dont show
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -746,8 +738,6 @@ exports[`Query Copilot Feedback Modal snapshot test should not render dont show
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -893,7 +883,7 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -901,8 +891,6 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -1048,7 +1036,7 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -1056,8 +1044,6 @@ exports[`Query Copilot Feedback Modal snapshot test should record user contact c
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}
@@ -1203,7 +1189,7 @@ exports[`Query Copilot Feedback Modal snapshot test should render dont show agai
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -1211,8 +1197,6 @@ exports[`Query Copilot Feedback Modal snapshot test should render dont show agai
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<StyledCheckboxBase
checked={true}
@@ -1373,7 +1357,7 @@ exports[`Query Copilot Feedback Modal snapshot test should submit submission 1`]
}
}
>
By pressing submit, your feedback will be used to improve Microsoft products and services. Please see the
By pressing submit, your feedback will be used to improve Microsoft products and services. IT admins for your organization will be able to view and manage your feedback data.
<StyledLinkBase
href="https://privacy.microsoft.com/privacystatement"
@@ -1381,8 +1365,6 @@ exports[`Query Copilot Feedback Modal snapshot test should submit submission 1`]
>
Privacy statement
</StyledLinkBase>
for more information.
</Text>
<Stack
horizontal={true}

View File

@@ -20,7 +20,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
>
<StackItem>
<Image
src={Object {}}
src=""
/>
</StackItem>
</Stack>
@@ -60,16 +60,11 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
>
<StackItem
align="center"
style={
Object {
"textAlign": "center",
}
}
>
<Text
className="title bold"
>
Welcome to Query Copilot for Azure Cosmos DB (Private Preview)
Welcome to Copilot in CosmosDB
</Text>
</StackItem>
<StackItem
@@ -84,7 +79,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
className="imageTextPadding"
>
<Image
src={Object {}}
src=""
/>
</StackItem>
<StackItem
@@ -93,7 +88,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
<Text
className="bold"
>
Let Query Copilot do the work for you
Let copilot do the work for you
<br />
</Text>
</StackItem>
@@ -102,7 +97,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
Ask Copilot to generate a query by describing the query in your words.
<br />
<StyledLinkBase
href="https://aka.ms/cdb-copilot-learn-more"
href="http://aka.ms/cdb-copilot-learn-more"
>
Learn more
</StyledLinkBase>
@@ -120,7 +115,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
className="imageTextPadding"
>
<Image
src={Object {}}
src=""
/>
</StackItem>
<StackItem
@@ -138,7 +133,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
AI-generated content can have mistakes. Make sure its accurate and appropriate before using it.
<br />
<StyledLinkBase
href="https://aka.ms/cdb-copilot-preview-terms"
href="http://aka.ms/cdb-copilot-preview-terms"
>
Read preview terms
</StyledLinkBase>
@@ -156,7 +151,7 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
className="imageTextPadding"
>
<Image
src={Object {}}
src=""
/>
</StackItem>
<StackItem
@@ -165,16 +160,16 @@ exports[`Query Copilot Welcome Modal snapshot test should render when isOpen is
<Text
className="bold"
>
Query Copilot works on a sample database.
Copilot currently works only a sample database
<br />
</Text>
</StackItem>
</Stack>
<Text>
While in Private Preview, Query Copilot is setup to work on sample database we have configured for you at no cost.
Copilot is setup on a sample database we have configured for you at no cost
<br />
<StyledLinkBase
href="https://aka.ms/cdb-copilot-learn-more"
href="http://aka.ms/cdb-copilot-learn-more"
>
Learn more
</StyledLinkBase>

View File

@@ -40,7 +40,7 @@ exports[`Copy Popup snapshot test should render when showCopyPopup is true 1`] =
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 15,

View File

@@ -5,7 +5,9 @@ import { QueryCopilotTab } from "./QueryCopilotTab";
describe("Query copilot tab snapshot test", () => {
it("should render with initial input", () => {
const wrapper = shallow(<QueryCopilotTab explorer={new Explorer()} />);
const wrapper = shallow(
<QueryCopilotTab initialInput="Write a query to return all records in this table" explorer={new Explorer()} />
);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -1,4 +1,5 @@
/* eslint-disable no-console */
import { FeedOptions } from "@azure/cosmos";
import {
Callout,
CommandBarButton,
@@ -16,26 +17,27 @@ import {
TextField,
} from "@fluentui/react";
import { useBoolean } from "@fluentui/react-hooks";
import {
ContainerStatusType,
PoolIdType,
QueryCopilotSampleContainerSchema,
ShortenedQueryCopilotSampleContainerSchema,
} from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils";
import { createUri } from "Common/UrlUtility";
import { JunoEndpoints, QueryCopilotSampleContainerId, QueryCopilotSampleContainerSchema } from "Common/Constants";
import { getErrorMessage, handleError } from "Common/ErrorHandlingUtils";
import { shouldEnableCrossPartitionKey } from "Common/HeadersUtility";
import { MinimalQueryIterator } from "Common/IteratorUtilities";
import { queryDocumentsPage } from "Common/dataAccess/queryDocumentsPage";
import { QueryResults } from "Contracts/ViewModels";
import { CommandButtonComponentProps } from "Explorer/Controls/CommandButton/CommandButtonComponent";
import { EditorReact } from "Explorer/Controls/Editor/EditorReact";
import Explorer from "Explorer/Explorer";
import { useCommandBar } from "Explorer/Menus/CommandBar/CommandBarComponentAdapter";
import { SaveQueryPane } from "Explorer/Panes/SaveQueryPane/SaveQueryPane";
import { WelcomeModal } from "Explorer/QueryCopilot/Modal/WelcomeModal";
import { CopyPopup } from "Explorer/QueryCopilot/Popup/CopyPopup";
import { DeletePopup } from "Explorer/QueryCopilot/Popup/DeletePopup";
import { OnExecuteQueryClick, SubmitFeedback } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
import { GenerateSQLQueryResponse, QueryCopilotProps } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
import { QueryCopilotResults } from "Explorer/QueryCopilot/Shared/QueryCopilotResults";
import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/Shared/SamplePrompts/SamplePrompts";
import { querySampleDocuments, submitFeedback } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import { SamplePrompts, SamplePromptsProps } from "Explorer/QueryCopilot/SamplePrompts/SamplePrompts";
import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { queryPagesUntilContentPresent } from "Utils/QueryUtils";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import { useSidePanel } from "hooks/useSidePanel";
import React, { useRef, useState } from "react";
@@ -53,46 +55,50 @@ interface SuggestedPrompt {
text: string;
}
interface QueryCopilotTabProps {
initialInput: string;
explorer: Explorer;
}
interface GenerateSQLQueryResponse {
apiVersion: string;
sql: string;
explanation: string;
generateStart: string;
generateEnd: string;
}
const promptStyles: IButtonStyles = {
root: { border: 0, selectors: { ":hover": { outline: "1px dashed #605e5c" } } },
label: { fontWeight: 400, textAlign: "left", paddingLeft: 8 },
};
export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: QueryCopilotProps): JSX.Element => {
export const QueryCopilotTab: React.FC<QueryCopilotTabProps> = ({
initialInput,
explorer,
}: QueryCopilotTabProps): JSX.Element => {
const hideFeedbackModalForLikedQueries = useQueryCopilot((state) => state.hideFeedbackModalForLikedQueries);
const [userPrompt, setUserPrompt] = useState<string>(initialInput || "");
const [generatedQuery, setGeneratedQuery] = useState<string>("");
const [generatedQueryComments, setGeneratedQueryComments] = useState<string>("");
const [query, setQuery] = useState<string>("");
const [selectedQuery, setSelectedQuery] = useState<string>("");
const [isGeneratingQuery, setIsGeneratingQuery] = useState<boolean>(false);
const [isExecuting, setIsExecuting] = useState<boolean>(false);
const [likeQuery, setLikeQuery] = useState<boolean>();
const [dislikeQuery, setDislikeQuery] = useState<boolean>();
const [showCallout, setShowCallout] = useState<boolean>(false);
const [showSamplePrompts, setShowSamplePrompts] = useState<boolean>(false);
const [queryIterator, setQueryIterator] = useState<MinimalQueryIterator>();
const [queryResults, setQueryResults] = useState<QueryResults>();
const [errorMessage, setErrorMessage] = useState<string>("");
const [copilotTeachingBubbleVisible, { toggle: toggleCopilotTeachingBubbleVisible }] = useBoolean(false);
const inputEdited = useRef(false);
const {
hideFeedbackModalForLikedQueries,
userPrompt,
setUserPrompt,
generatedQuery,
setGeneratedQuery,
query,
setQuery,
selectedQuery,
setSelectedQuery,
isGeneratingQuery,
setIsGeneratingQuery,
likeQuery,
setLikeQuery,
dislikeQuery,
setDislikeQuery,
showCallout,
setShowCallout,
showSamplePrompts,
setShowSamplePrompts,
isSamplePromptsOpen,
setIsSamplePromptsOpen,
showDeletePopup,
setShowDeletePopup,
showFeedbackBar,
setShowFeedbackBar,
showCopyPopup,
setshowCopyPopup,
showErrorMessageBar,
setShowErrorMessageBar,
setGeneratedQueryComments,
} = useQueryCopilot();
const [isSamplePromptsOpen, setIsSamplePromptsOpen] = useState<boolean>(false);
const [showDeletePopup, setShowDeletePopup] = useState<boolean>(false);
const [showFeedbackBar, setShowFeedbackBar] = useState<boolean>(false);
const [showCopyPopup, setshowCopyPopup] = useState<boolean>(false);
const [showErrorMessageBar, setShowErrorMessageBar] = useState<boolean>(false);
const sampleProps: SamplePromptsProps = {
isSamplePromptsOpen: isSamplePromptsOpen,
@@ -160,27 +166,15 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
const generateSQLQuery = async (): Promise<void> => {
try {
setIsGeneratingQuery(true);
setShowDeletePopup(false);
useTabs.getState().setIsTabExecuting(true);
useTabs.getState().setIsQueryErrorThrown(false);
if (
useQueryCopilot.getState().containerStatus.status !== ContainerStatusType.Active &&
!userContext.features.disableCopilotPhoenixGateaway
) {
await explorer.allocateContainer(PoolIdType.QueryCopilot);
}
const payload = {
containerSchema: userContext.features.enableCopilotFullSchema
? QueryCopilotSampleContainerSchema
: ShortenedQueryCopilotSampleContainerSchema,
containerSchema: QueryCopilotSampleContainerSchema,
userPrompt: userPrompt,
};
setShowDeletePopup(false);
useQueryCopilot.getState().refreshCorrelationId();
const serverInfo = useQueryCopilot.getState().notebookServerInfo;
const queryUri = userContext.features.disableCopilotPhoenixGateaway
? createUri("https://copilotorchestrater.azurewebsites.net/", "generateSQLQuery")
: createUri(serverInfo.notebookServerEndpoint, "generateSQLQuery");
const response = await fetch(queryUri, {
const response = await fetch(`${JunoEndpoints.Prod}/generateSQLQuery`, {
method: "POST",
headers: {
"content-type": "application/json",
@@ -219,12 +213,64 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
}
};
const onExecuteQueryClick = async (): Promise<void> => {
traceStart(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
userPrompt: userPrompt,
generatedQuery: generatedQuery,
generatedQueryComments: generatedQueryComments,
executedQuery: selectedQuery || query,
});
const queryToExecute = selectedQuery || query;
const queryIterator = querySampleDocuments(queryToExecute, {
enableCrossPartitionQuery: shouldEnableCrossPartitionKey(),
} as FeedOptions);
setQueryIterator(queryIterator);
setTimeout(async () => {
await queryDocumentsPerPage(0, queryIterator);
}, 100);
};
const queryDocumentsPerPage = async (firstItemIndex: number, queryIterator: MinimalQueryIterator): Promise<void> => {
try {
setIsExecuting(true);
useTabs.getState().setIsTabExecuting(true);
useTabs.getState().setIsQueryErrorThrown(false);
const queryResults: QueryResults = await queryPagesUntilContentPresent(
firstItemIndex,
async (firstItemIndex: number) =>
queryDocumentsPage(QueryCopilotSampleContainerId, queryIterator, firstItemIndex)
);
setQueryResults(queryResults);
setErrorMessage("");
setShowErrorMessageBar(false);
traceSuccess(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
});
} catch (error) {
const errorMessage = getErrorMessage(error);
traceFailure(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
errorMessage: errorMessage,
});
setErrorMessage(errorMessage);
handleError(errorMessage, "executeQueryCopilotTab");
useTabs.getState().setIsQueryErrorThrown(true);
setShowErrorMessageBar(true);
} finally {
setIsExecuting(false);
useTabs.getState().setIsTabExecuting(false);
}
};
const getCommandbarButtons = (): CommandButtonComponentProps[] => {
const executeQueryBtnLabel = selectedQuery ? "Execute Selection" : "Execute Query";
const executeQueryBtn = {
iconSrc: ExecuteQueryIcon,
iconAlt: executeQueryBtnLabel,
onCommandClick: () => OnExecuteQueryClick(),
onCommandClick: () => onExecuteQueryClick(),
commandButtonLabel: executeQueryBtnLabel,
ariaLabel: executeQueryBtnLabel,
hasPopup: false,
@@ -282,13 +328,16 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
}, [query, selectedQuery]);
React.useEffect(() => {
if (initialInput) {
generateSQLQuery();
}
showTeachingBubble();
useTabs.getState().setIsQueryErrorThrown(false);
}, []);
return (
<Stack className="tab-pane" style={{ padding: 24, width: "100%" }}>
<div style={isGeneratingQuery ? { height: "100%" } : { overflowY: "auto", height: "100%" }}>
<div style={{ overflowY: "auto", height: "100%" }}>
<Stack horizontal verticalAlign="center">
<Image src={CopilotIcon} />
<Text style={{ marginLeft: 8, fontWeight: 600, fontSize: 16 }}>Copilot</Text>
@@ -304,7 +353,6 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
}}
onKeyDown={(e) => {
if (e.key === "Enter") {
inputEdited.current = true;
startGenerateQueryProcess();
}
}}
@@ -375,7 +423,6 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
onClick={() => {
setUserPrompt(history);
setShowSamplePrompts(false);
inputEdited.current = true;
}}
onRenderIcon={() => <Image src={RecentIcon} />}
styles={promptStyles}
@@ -405,7 +452,6 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
onClick={() => {
setUserPrompt(prompt.text);
setShowSamplePrompts(false);
inputEdited.current = true;
}}
onRenderIcon={() => <Image src={HintIcon} />}
styles={promptStyles}
@@ -434,7 +480,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
}}
>
Learn about{" "}
<Link target="_blank" href="https://aka.ms/cdb-copilot-writing">
<Link target="_blank" href="http://aka.ms/cdb-copilot-writing">
writing effective prompts
</Link>
</Text>
@@ -448,7 +494,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
<Stack style={{ marginTop: 8, marginBottom: 24 }}>
<Text style={{ fontSize: 12 }}>
AI-generated content can have mistakes. Make sure it&apos;s accurate and appropriate before using it.{" "}
<Link href="https://aka.ms/cdb-copilot-preview-terms" target="_blank">
<Link href="http://aka.ms/cdb-copilot-preview-terms" target="_blank">
Read preview terms
</Link>
{showErrorMessageBar && (
@@ -471,15 +517,7 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
target="#likeBtn"
onDismiss={() => {
setShowCallout(false);
SubmitFeedback({
params: {
generatedQuery: generatedQuery,
likeQuery: likeQuery,
description: "",
userPrompt: userPrompt,
},
explorer: explorer,
});
submitFeedback({ generatedQuery, likeQuery, description: "", userPrompt: userPrompt });
}}
directionalHint={DirectionalHint.topCenter}
>
@@ -551,7 +589,16 @@ export const QueryCopilotTab: React.FC<QueryCopilotProps> = ({ explorer }: Query
onContentChanged={(newQuery: string) => setQuery(newQuery)}
onContentSelected={(selectedQuery: string) => setSelectedQuery(selectedQuery)}
/>
<QueryCopilotResults />
<QueryResultSection
isMongoDB={false}
queryEditorContent={selectedQuery || query}
error={errorMessage}
queryResults={queryResults}
isExecuting={isExecuting}
executeQueryDocumentsPage={(firstItemIndex: number) =>
queryDocumentsPerPage(firstItemIndex, queryIterator)
}
/>
</SplitterLayout>
</Stack>
<WelcomeModal visible={localStorage.getItem("hideWelcomeModal") !== "true"} />

View File

@@ -1,10 +1,11 @@
import { FeedOptions } from "@azure/cosmos";
import { QueryCopilotSampleContainerSchema } from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils";
import { sampleDataClient } from "Common/SampleDataClient";
import * as commonUtils from "Common/dataAccess/queryDocuments";
import DocumentId from "Explorer/Tree/DocumentId";
import { querySampleDocuments, readSampleDocument } from "./QueryCopilotUtilities";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import { querySampleDocuments, readSampleDocument, submitFeedback } from "./QueryCopilotUtilities";
jest.mock("Explorer/Tree/DocumentId", () => {
return jest.fn().mockImplementation(() => {
return {
@@ -15,21 +16,23 @@ jest.mock("Explorer/Tree/DocumentId", () => {
});
jest.mock("Utils/NotificationConsoleUtils", () => ({
logConsoleProgress: jest.fn().mockReturnValue((): void => undefined),
logConsoleProgress: jest.fn(),
logConsoleError: jest.fn(),
}));
jest.mock("@azure/cosmos", () => ({
FeedOptions: jest.fn(),
QueryIterator: jest.fn(),
Constants: {
HttpHeaders: {},
},
}));
jest.mock("Common/ErrorHandlingUtils", () => ({
handleError: jest.fn(),
}));
jest.mock("Utils/NotificationConsoleUtils", () => ({
logConsoleProgress: jest.fn().mockReturnValue((): void => undefined),
}));
jest.mock("Common/dataAccess/queryDocuments", () => ({
getCommonQueryOptions: jest.fn((options) => options),
}));
@@ -38,27 +41,95 @@ jest.mock("Common/SampleDataClient");
jest.mock("node-fetch");
jest.mock("Explorer/Explorer", () => {
class MockExplorer {
allocateContainer = jest.fn().mockResolvedValueOnce({});
}
return MockExplorer;
});
jest.mock("hooks/useQueryCopilot", () => {
const mockQueryCopilotStore = {
shouldAllocateContainer: true,
setShouldAllocateContainer: jest.fn(),
correlationId: "mocked-correlation-id",
};
return {
useQueryCopilot: jest.fn(() => mockQueryCopilotStore),
};
});
describe("QueryCopilotUtilities", () => {
beforeEach(() => jest.clearAllMocks());
describe("submitFeedback", () => {
const payload = {
like: "like",
generatedSql: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
containerSchema: QueryCopilotSampleContainerSchema,
};
it("should call fetch with the payload with like", async () => {
const mockFetch = jest.fn().mockResolvedValueOnce({});
globalThis.fetch = mockFetch;
useQueryCopilot.getState().refreshCorrelationId();
await submitFeedback({
likeQuery: true,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
});
expect(mockFetch).toHaveBeenCalledWith(
"https://copilotorchestrater.azurewebsites.net/feedback",
expect.objectContaining({
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
})
);
const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(actualBody).toEqual(payload);
});
it("should call fetch with the payload with unlike and empty parameters", async () => {
payload.like = "dislike";
payload.description = "";
payload.contact = "";
const mockFetch = jest.fn().mockResolvedValueOnce({});
globalThis.fetch = mockFetch;
useQueryCopilot.getState().refreshCorrelationId();
await submitFeedback({
likeQuery: false,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: undefined,
contact: undefined,
});
expect(mockFetch).toHaveBeenCalledWith(
"https://copilotorchestrater.azurewebsites.net/feedback",
expect.objectContaining({
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
})
);
const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(actualBody).toEqual(payload);
});
it("should handle errors and call handleError", async () => {
globalThis.fetch = jest.fn().mockRejectedValueOnce(new Error("Mock error"));
await submitFeedback({
likeQuery: true,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
}).catch((error) => {
expect(error.message).toEqual("Mock error");
});
expect(handleError).toHaveBeenCalledWith(new Error("Mock error"), expect.any(String));
});
});
describe("querySampleDocuments", () => {
(sampleDataClient as jest.Mock).mockReturnValue({

View File

@@ -1,11 +1,50 @@
import { FeedOptions, Item, ItemDefinition, QueryIterator, Resource } from "@azure/cosmos";
import { QueryCopilotSampleContainerId, QueryCopilotSampleDatabaseId } from "Common/Constants";
import {
JunoEndpoints,
QueryCopilotSampleContainerId,
QueryCopilotSampleContainerSchema,
QueryCopilotSampleDatabaseId,
} from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils";
import { sampleDataClient } from "Common/SampleDataClient";
import { getPartitionKeyValue } from "Common/dataAccess/getPartitionKeyValue";
import { getCommonQueryOptions } from "Common/dataAccess/queryDocuments";
import DocumentId from "Explorer/Tree/DocumentId";
import { logConsoleProgress } from "Utils/NotificationConsoleUtils";
import { useQueryCopilot } from "hooks/useQueryCopilot";
interface FeedbackParams {
likeQuery: boolean;
generatedQuery: string;
userPrompt: string;
description?: string;
contact?: string;
}
export const submitFeedback = async (params: FeedbackParams): Promise<void> => {
try {
const { likeQuery, generatedQuery, userPrompt, description, contact } = params;
const payload = {
containerSchema: QueryCopilotSampleContainerSchema,
like: likeQuery ? "like" : "dislike",
generatedSql: generatedQuery,
userPrompt,
description: description || "",
contact: contact || "",
};
await fetch(`${JunoEndpoints.Prod}/feedback`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
body: JSON.stringify(payload),
});
} catch (error) {
handleError(error, "copilotSubmitFeedback");
}
};
export const querySampleDocuments = (query: string, options: FeedOptions): QueryIterator<ItemDefinition & Resource> => {
options = getCommonQueryOptions(options);

View File

@@ -1,8 +1,8 @@
import { DefaultButton, FontIcon, IconButton, Image, Modal, Stack, Text } from "@fluentui/react";
import React, { Dispatch, SetStateAction } from "react";
import ComplexPrompts from "../../../../../images/ComplexPrompts.svg";
import IntermediatePrompts from "../../../../../images/IntermediatePrompts.svg";
import SimplePrompts from "../../../../../images/SimplePrompts.svg";
import ComplexPrompts from "../../../../images/ComplexPrompts.svg";
import IntermediatePrompts from "../../../../images/IntermediatePrompts.svg";
import SimplePrompts from "../../../../images/SimplePrompts.svg";
export interface SamplePromptsProps {
isSamplePromptsOpen: boolean;

View File

@@ -87,7 +87,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 25,
@@ -191,7 +191,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 25,
@@ -295,7 +295,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 25,
@@ -477,7 +477,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 25,
@@ -581,7 +581,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 25,
@@ -685,7 +685,7 @@ exports[`Sample Prompts snapshot test should render properly if isSamplePromptsO
verticalAlign="center"
>
<Image
src={Object {}}
src=""
style={
Object {
"height": 25,

View File

@@ -1,138 +0,0 @@
import { QueryCopilotSampleContainerSchema, ShortenedQueryCopilotSampleContainerSchema } from "Common/Constants";
import { handleError } from "Common/ErrorHandlingUtils";
import { createUri } from "Common/UrlUtility";
import Explorer from "Explorer/Explorer";
import { SubmitFeedback } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
import { userContext } from "UserContext";
import { useQueryCopilot } from "hooks/useQueryCopilot";
jest.mock("@azure/cosmos", () => ({
Constants: {
HttpHeaders: {},
},
}));
jest.mock("Common/ErrorHandlingUtils", () => ({
handleError: jest.fn(),
}));
jest.mock("Common/SampleDataClient");
jest.mock("node-fetch");
jest.mock("Explorer/Explorer", () => {
class MockExplorer {
allocateContainer = jest.fn().mockResolvedValueOnce({});
}
return MockExplorer;
});
describe("Query Copilot Client", () => {
beforeEach(() => jest.clearAllMocks());
describe("SubmitFeedback", () => {
const payload = {
like: "like",
generatedSql: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
containerSchema: userContext.features.enableCopilotFullSchema
? QueryCopilotSampleContainerSchema
: ShortenedQueryCopilotSampleContainerSchema,
};
const mockStore = useQueryCopilot.getState();
mockStore.correlationId = "mocked-correlation-id";
mockStore.notebookServerInfo = {
notebookServerEndpoint: "mocked-endpoint",
authToken: "mocked-token",
forwardingId: "mocked-forwarding-id",
};
const feedbackUri = userContext.features.disableCopilotPhoenixGateaway
? createUri("https://copilotorchestrater.azurewebsites.net/", "feedback")
: createUri(useQueryCopilot.getState().notebookServerInfo.notebookServerEndpoint, "feedback");
it("should call fetch with the payload with like", async () => {
const mockFetch = jest.fn().mockResolvedValueOnce({});
globalThis.fetch = mockFetch;
await SubmitFeedback({
params: {
likeQuery: true,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
},
explorer: new Explorer(),
});
expect(mockFetch).toHaveBeenCalledWith(
feedbackUri,
expect.objectContaining({
headers: expect.objectContaining({
"x-ms-correlationid": "mocked-correlation-id",
}),
})
);
const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(actualBody).toEqual(payload);
});
it("should call fetch with the payload with unlike and empty parameters", async () => {
payload.like = "dislike";
payload.description = "";
payload.contact = "";
const mockFetch = jest.fn().mockResolvedValueOnce({});
globalThis.fetch = mockFetch;
await SubmitFeedback({
params: {
likeQuery: false,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: undefined,
contact: undefined,
},
explorer: new Explorer(),
});
expect(mockFetch).toHaveBeenCalledWith(
feedbackUri,
expect.objectContaining({
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": "mocked-correlation-id",
},
})
);
const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body);
expect(actualBody).toEqual(payload);
});
it("should handle errors and call handleError", async () => {
globalThis.fetch = jest.fn().mockRejectedValueOnce(new Error("Mock error"));
await SubmitFeedback({
params: {
likeQuery: true,
generatedQuery: "GeneratedQuery",
userPrompt: "UserPrompt",
description: "Description",
contact: "Contact",
},
explorer: new Explorer(),
}).catch((error) => {
expect(error.message).toEqual("Mock error");
});
expect(handleError).toHaveBeenCalledWith(new Error("Mock error"), expect.any(String));
});
});
});

View File

@@ -1,199 +0,0 @@
import { FeedOptions } from "@azure/cosmos";
import {
ContainerStatusType,
PoolIdType,
QueryCopilotSampleContainerId,
QueryCopilotSampleContainerSchema,
ShortenedQueryCopilotSampleContainerSchema,
} from "Common/Constants";
import { getErrorMessage, handleError } from "Common/ErrorHandlingUtils";
import { shouldEnableCrossPartitionKey } from "Common/HeadersUtility";
import { MinimalQueryIterator } from "Common/IteratorUtilities";
import { createUri } from "Common/UrlUtility";
import { queryDocumentsPage } from "Common/dataAccess/queryDocumentsPage";
import { QueryResults } from "Contracts/ViewModels";
import Explorer from "Explorer/Explorer";
import { querySampleDocuments } from "Explorer/QueryCopilot/QueryCopilotUtilities";
import { FeedbackParams, GenerateSQLQueryResponse } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
import { Action } from "Shared/Telemetry/TelemetryConstants";
import { traceFailure, traceStart, traceSuccess } from "Shared/Telemetry/TelemetryProcessor";
import { userContext } from "UserContext";
import { queryPagesUntilContentPresent } from "Utils/QueryUtils";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import { useTabs } from "hooks/useTabs";
export const SendQueryRequest = async ({
userPrompt,
explorer,
}: {
userPrompt: string;
explorer: Explorer;
}): Promise<void> => {
if (userPrompt.trim() !== "") {
useQueryCopilot
.getState()
.setChatMessages([...useQueryCopilot.getState().chatMessages, { source: 0, message: userPrompt }]);
useQueryCopilot.getState().setIsGeneratingQuery(true);
useQueryCopilot.getState().setShouldIncludeInMessages(true);
useTabs.getState().setIsTabExecuting(true);
useTabs.getState().setIsQueryErrorThrown(false);
try {
if (
useQueryCopilot.getState().containerStatus.status !== ContainerStatusType.Active &&
!userContext.features.disableCopilotPhoenixGateaway
) {
await explorer.allocateContainer(PoolIdType.QueryCopilot);
}
useQueryCopilot.getState().refreshCorrelationId();
const serverInfo = useQueryCopilot.getState().notebookServerInfo;
const queryUri = userContext.features.disableCopilotPhoenixGateaway
? createUri("https://copilotorchestrater.azurewebsites.net/", "generateSQLQuery")
: createUri(serverInfo.notebookServerEndpoint, "generateSQLQuery");
const payload = {
containerSchema: userContext.features.enableCopilotFullSchema
? QueryCopilotSampleContainerSchema
: ShortenedQueryCopilotSampleContainerSchema,
userPrompt: userPrompt,
};
const response = await fetch(queryUri, {
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
body: JSON.stringify(payload),
});
const generateSQLQueryResponse: GenerateSQLQueryResponse = await response?.json();
if (response.ok) {
if (generateSQLQueryResponse?.sql) {
const bubbleMessage = `Here is a query which will help you with provided prompt.\r\n **Prompt:** "${userPrompt}"`;
if (useQueryCopilot.getState().shouldIncludeInMessages) {
useQueryCopilot.getState().setChatMessages([
...useQueryCopilot.getState().chatMessages,
{
source: 1,
message: bubbleMessage,
sqlQuery: generateSQLQueryResponse.sql,
explanation: generateSQLQueryResponse.explanation,
},
]);
useQueryCopilot.getState().setShowExplanationBubble(true);
useQueryCopilot.getState().setGeneratedQuery(generateSQLQueryResponse.sql);
useQueryCopilot.getState().setGeneratedQueryComments(generateSQLQueryResponse.explanation);
}
}
} else {
handleError(JSON.stringify(generateSQLQueryResponse), "copilotInternalServerError");
useTabs.getState().setIsQueryErrorThrown(true);
}
} catch (error) {
handleError(error, "executeNaturalLanguageQuery");
useTabs.getState().setIsQueryErrorThrown(true);
throw error;
} finally {
useQueryCopilot.getState().setUserPrompt("");
useQueryCopilot.getState().setIsGeneratingQuery(false);
useTabs.getState().setIsTabExecuting(false);
}
}
};
export const SubmitFeedback = async ({
params,
explorer,
}: {
params: FeedbackParams;
explorer: Explorer;
}): Promise<void> => {
try {
const { likeQuery, generatedQuery, userPrompt, description, contact } = params;
const payload = {
containerSchema: userContext.features.enableCopilotFullSchema
? QueryCopilotSampleContainerSchema
: ShortenedQueryCopilotSampleContainerSchema,
like: likeQuery ? "like" : "dislike",
generatedSql: generatedQuery,
userPrompt,
description: description || "",
contact: contact || "",
};
if (
useQueryCopilot.getState().containerStatus.status !== ContainerStatusType.Active &&
!userContext.features.disableCopilotPhoenixGateaway
) {
await explorer.allocateContainer(PoolIdType.QueryCopilot);
}
const serverInfo = useQueryCopilot.getState().notebookServerInfo;
const feedbackUri = userContext.features.disableCopilotPhoenixGateaway
? createUri("https://copilotorchestrater.azurewebsites.net/", "feedback")
: createUri(serverInfo.notebookServerEndpoint, "feedback");
await fetch(feedbackUri, {
method: "POST",
headers: {
"content-type": "application/json",
"x-ms-correlationid": useQueryCopilot.getState().correlationId,
},
body: JSON.stringify(payload),
});
} catch (error) {
handleError(error, "copilotSubmitFeedback");
}
};
export const OnExecuteQueryClick = async (): Promise<void> => {
traceStart(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
userPrompt: useQueryCopilot.getState().userPrompt,
generatedQuery: useQueryCopilot.getState().generatedQuery,
generatedQueryComments: useQueryCopilot.getState().generatedQueryComments,
executedQuery: useQueryCopilot.getState().selectedQuery || useQueryCopilot.getState().query,
});
const queryToExecute = useQueryCopilot.getState().selectedQuery || useQueryCopilot.getState().query;
const queryIterator = querySampleDocuments(queryToExecute, {
enableCrossPartitionQuery: shouldEnableCrossPartitionKey(),
} as FeedOptions);
useQueryCopilot.getState().setQueryIterator(queryIterator);
setTimeout(async () => {
await QueryDocumentsPerPage(0, queryIterator);
}, 100);
};
export const QueryDocumentsPerPage = async (
firstItemIndex: number,
queryIterator: MinimalQueryIterator
): Promise<void> => {
try {
useQueryCopilot.getState().setIsExecuting(true);
useTabs.getState().setIsTabExecuting(true);
useTabs.getState().setIsQueryErrorThrown(false);
const queryResults: QueryResults = await queryPagesUntilContentPresent(
firstItemIndex,
async (firstItemIndex: number) => queryDocumentsPage(QueryCopilotSampleContainerId, queryIterator, firstItemIndex)
);
useQueryCopilot.getState().setQueryResults(queryResults);
useQueryCopilot.getState().setErrorMessage("");
useQueryCopilot.getState().setShowErrorMessageBar(false);
traceSuccess(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
});
} catch (error) {
const errorMessage = getErrorMessage(error);
traceFailure(Action.ExecuteQueryGeneratedFromQueryCopilot, {
correlationId: useQueryCopilot.getState().correlationId,
errorMessage: errorMessage,
});
useQueryCopilot.getState().setErrorMessage(errorMessage);
handleError(errorMessage, "executeQueryCopilotTab");
useTabs.getState().setIsQueryErrorThrown(true);
useQueryCopilot.getState().setShowErrorMessageBar(true);
} finally {
useQueryCopilot.getState().setIsExecuting(false);
useTabs.getState().setIsTabExecuting(false);
}
};

View File

@@ -1,34 +0,0 @@
import Explorer from "Explorer/Explorer";
export interface GenerateSQLQueryResponse {
apiVersion: string;
sql: string;
explanation: string;
generateStart: string;
generateEnd: string;
}
enum MessageSource {
User,
AI,
AIExplanation,
}
export interface CopilotMessage {
source: MessageSource;
message: string;
sqlQuery?: string;
explanation?: string;
}
export interface FeedbackParams {
likeQuery: boolean;
generatedQuery: string;
userPrompt: string;
description?: string;
contact?: string;
}
export interface QueryCopilotProps {
explorer: Explorer;
}

View File

@@ -1,19 +0,0 @@
import { QueryDocumentsPerPage } from "Explorer/QueryCopilot/Shared/QueryCopilotClient";
import { QueryResultSection } from "Explorer/Tabs/QueryTab/QueryResultSection";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import React from "react";
export const QueryCopilotResults: React.FC = (): JSX.Element => {
return (
<QueryResultSection
isMongoDB={false}
queryEditorContent={useQueryCopilot.getState().selectedQuery || useQueryCopilot.getState().query}
error={useQueryCopilot.getState().errorMessage}
queryResults={useQueryCopilot.getState().queryResults}
isExecuting={useQueryCopilot.getState().isExecuting}
executeQueryDocumentsPage={(firstItemIndex: number) =>
QueryDocumentsPerPage(firstItemIndex, useQueryCopilot.getState().queryIterator)
}
/>
);
};

View File

@@ -1,69 +0,0 @@
import { Text } from "@fluentui/react";
import { shallow } from "enzyme";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import React from "react";
import { ExplanationButton } from "./ExplanationButton";
describe("Explanation Button", () => {
const initialStoreState = useQueryCopilot.getState();
beforeEach(() => {
useQueryCopilot.setState(initialStoreState, true);
useQueryCopilot.getState().showExplanationBubble = true;
useQueryCopilot.getState().shouldIncludeInMessages = false;
jest.useFakeTimers();
});
afterEach(() => {
jest.clearAllMocks();
jest.useRealTimers();
});
it("should render explanation bubble with generated comments", () => {
useQueryCopilot.getState().shouldIncludeInMessages = true;
const wrapper = shallow(<ExplanationButton />);
expect(wrapper.find("Stack")).toHaveLength(1);
expect(wrapper.find("Text")).toHaveLength(1);
expect(wrapper).toMatchSnapshot();
});
it("should render 'Explain this query' link", () => {
useQueryCopilot.getState().shouldIncludeInMessages = true;
const mockSetChatMessages = jest.fn();
const mockSetIsGeneratingExplanation = jest.fn();
const mockSetShouldIncludeInMessages = jest.fn();
const mockSetShowExplanationBubble = jest.fn();
useQueryCopilot.getState().setChatMessages = mockSetChatMessages;
useQueryCopilot.getState().setIsGeneratingExplanation = mockSetIsGeneratingExplanation;
useQueryCopilot.getState().setShouldIncludeInMessages = mockSetShouldIncludeInMessages;
useQueryCopilot.getState().setShowExplanationBubble = mockSetShowExplanationBubble;
const wrapper = shallow(<ExplanationButton />);
const textElement = wrapper.find(Text);
textElement.simulate("click");
expect(mockSetChatMessages).toHaveBeenCalledWith([
...initialStoreState.chatMessages,
{ source: 0, message: "Explain this query to me" },
]);
expect(mockSetIsGeneratingExplanation).toHaveBeenCalledWith(true);
expect(mockSetShouldIncludeInMessages).toHaveBeenCalledWith(true);
expect(mockSetShowExplanationBubble).toHaveBeenCalledWith(false);
jest.advanceTimersByTime(3000);
expect(mockSetIsGeneratingExplanation).toHaveBeenCalledWith(false);
expect(mockSetChatMessages).toHaveBeenCalled();
});
it("should render nothing when conditions are not met", () => {
useQueryCopilot.getState().showExplanationBubble = false;
const wrapper = shallow(<ExplanationButton />);
expect(wrapper.isEmptyRender()).toBe(true);
expect(wrapper).toMatchSnapshot();
});
});

View File

@@ -1,61 +0,0 @@
import { Stack, Text } from "@fluentui/react";
import { useQueryCopilot } from "hooks/useQueryCopilot";
import React from "react";
export const ExplanationButton: React.FC = (): JSX.Element => {
const {
showExplanationBubble,
isGeneratingQuery,
chatMessages,
setChatMessages,
generatedQuery,
generatedQueryComments,
isGeneratingExplanation,
setIsGeneratingExplanation,
setShouldIncludeInMessages,
setShowExplanationBubble,
} = useQueryCopilot();
const showExplanation = () => {
setChatMessages([...chatMessages, { source: 0, message: "Explain this query to me" }]);
setIsGeneratingExplanation(true);
setShouldIncludeInMessages(true);
setShowExplanationBubble(false);
setTimeout(() => {
if (useQueryCopilot.getState().shouldIncludeInMessages) {
setIsGeneratingExplanation(false);
setChatMessages([...chatMessages, { source: 2, message: generatedQueryComments, sqlQuery: generatedQuery }]);
}
}, 3000);
};
return (
showExplanationBubble &&
!isGeneratingQuery &&
!isGeneratingExplanation && (
<Stack
style={{
display: "flex",
alignItems: "center",
padding: "5px 5px 5px 50px",
margin: "5px",
}}
>
<Text
onClick={showExplanation}
style={{
cursor: "pointer",
border: "1.5px solid #B0BEFF",
width: "100%",
padding: "2px",
borderRadius: "4px",
marginBottom: "5px",
}}
>
Explain this query to me
</Text>
</Stack>
)
);
};

View File

@@ -1,32 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Explanation Button should render explanation bubble with generated comments 1`] = `
<Stack
style={
Object {
"alignItems": "center",
"display": "flex",
"margin": "5px",
"padding": "5px 5px 5px 50px",
}
}
>
<Text
onClick={[Function]}
style={
Object {
"border": "1.5px solid #B0BEFF",
"borderRadius": "4px",
"cursor": "pointer",
"marginBottom": "5px",
"padding": "2px",
"width": "100%",
}
}
>
Explain this query to me
</Text>
</Stack>
`;
exports[`Explanation Button should render nothing when conditions are not met 1`] = `""`;

View File

@@ -1,26 +0,0 @@
import { Stack, Text } from "@fluentui/react";
import { CopilotMessage } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
import { FeedbackButtons } from "Explorer/QueryCopilot/V2/Bubbles/Output/Buttons/Feedback/FeedbackButtons";
import React from "react";
export const ExplanationBubble = ({ copilotMessage }: { copilotMessage: CopilotMessage }): JSX.Element => {
return (
<Stack
horizontalAlign="start"
verticalAlign="start"
tokens={{ padding: 8, childrenGap: 8 }}
style={{
backgroundColor: "white",
borderRadius: "8px",
margin: "5px 10px",
textAlign: "start",
}}
>
<Text>{copilotMessage.message}</Text>
<FeedbackButtons sqlQuery={copilotMessage.sqlQuery} />
<Text style={{ fontWeight: 400, fontSize: "10px", lineHeight: "14px" }}>
AI-generated content may be incorrect
</Text>
</Stack>
);
};

View File

@@ -1,17 +0,0 @@
import { CopilotMessage } from "Explorer/QueryCopilot/Shared/QueryCopilotInterfaces";
import { ExplanationBubble } from "Explorer/QueryCopilot/V2/Bubbles/Explanation/ExplainationBubble";
import { shallow } from "enzyme";
import React from "react";
describe("Explanation Bubble snapshot tests", () => {
it("should render", () => {
const mockCopilotMessage: CopilotMessage = {
source: 2,
message: "Mock message",
};
const wrapper = shallow(<ExplanationBubble copilotMessage={mockCopilotMessage} />);
expect(wrapper).toMatchSnapshot();
});
});

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