Sql DB project dashboard (#14899)
* First set of changes for workspace dashboard implementing the toolbar * Workspace dashboard container implementation (#14813) * First set of changes for workspace dashboard implementing the toolbar (#14160) * First set of changes for workspace dashboard implementing the toolbar * Addressed comments * Addressed one remaining comment * Removed an extra comma in interfaces file * Addressed comments * Addressed comments * Refactored a bit of code * Remove unnecessary await * Addressed comments * First set of changes for workspace dashboard container * Update targetPlatform icon+add Time column to deploy table * Addressed comments * Removed redundant class definition * Addressed comments * Addressed comments * Change enum to union type in dataworkspace typings * Fix tests * Addressed comments
20
extensions/sql-database-projects/images/add.svg
Normal file
@@ -0,0 +1,20 @@
|
||||
<svg width="12" height="13" viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<g clip-path="url(#clip1)">
|
||||
<g clip-path="url(#clip2)">
|
||||
<path d="M12 5.68887V6.48887H6.4V12.0889H5.6V6.48887H0V5.68887H5.6V0.0888672H6.4V5.68887H12Z" fill="#0078D4"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="12" height="12" fill="white" transform="translate(0 0.0888672)"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip1">
|
||||
<rect width="50" height="50" fill="white" transform="translate(0 0.0888672)"/>
|
||||
</clipPath>
|
||||
<clipPath id="clip2">
|
||||
<rect width="12" height="12" fill="white" transform="translate(0 0.0888672)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 667 B |
3
extensions/sql-database-projects/images/build.svg
Normal file
@@ -0,0 +1,3 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M3.60039 8H2.00039V6.4H3.60039V8ZM11.6004 4.8V12H0.400391V4.8H1.20039V8.8H10.8004V4.8H11.6004ZM5.20039 9.6H3.60039V11.2H5.20039V9.6ZM8.40039 9.6H6.80039V11.2H8.40039V9.6ZM5.20039 6.4H6.80039V8H5.20039V6.4ZM10.0004 8H8.40039V6.4H10.0004V8ZM5.60039 5.7625L3.71914 3.88125L4.28164 3.31875L5.20039 4.23125V0H6.00039V4.23125L6.91914 3.31875L7.48164 3.88125L5.60039 5.7625Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 498 B |
11
extensions/sql-database-projects/images/error.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M6.07422 12.0752C9.38793 12.0752 12.0742 9.3889 12.0742 6.0752C12.0742 2.76149 9.38793 0.0751953 6.07422 0.0751953C2.76051 0.0751953 0.0742188 2.76149 0.0742188 6.0752C0.0742188 9.3889 2.76051 12.0752 6.07422 12.0752Z" fill="#E00B1C"/>
|
||||
<path d="M9.51952 3.54599L8.45302 2.47949L5.99902 4.93349L3.54502 2.47949L2.47852 3.54599L4.93252 5.99999L2.47852 8.45399L3.54502 9.52049L5.99902 7.06649L8.45302 9.52049L9.51952 8.45399L7.06552 5.99999L9.51952 3.54599Z" fill="white"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="12" height="12" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 709 B |
7
extensions/sql-database-projects/images/inProgress.svg
Normal file
@@ -0,0 +1,7 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 12C9.31371 12 12 9.31371 12 6C12 2.68629 9.31371 0 6 0C2.68629 0 0 2.68629 0 6C0 9.31371 2.68629 12 6 12Z" fill="#015CDA"/>
|
||||
<path d="M3.75 5.9998C3.75049 5.8396 3.76834 5.67991 3.80325 5.52355L2.34825 5.1748C2.2845 5.44522 2.25154 5.72198 2.25 5.9998C2.25388 6.3091 2.2962 6.61671 2.376 6.91555L3.83175 6.56755C3.7801 6.38263 3.75262 6.19179 3.75 5.9998Z" fill="white"/>
|
||||
<path d="M4.26841 7.41846L3.09766 8.34471C3.45993 8.79675 3.92202 9.15871 4.44766 9.40221L5.07691 8.04546C4.76297 7.90109 4.48637 7.68658 4.26841 7.41846Z" fill="white"/>
|
||||
<path d="M4.21958 4.64118C4.4359 4.35737 4.71663 4.12909 5.03858 3.97518L4.40933 2.61768C3.87573 2.87116 3.40957 3.24712 3.04883 3.71493L4.21958 4.64118Z" fill="white"/>
|
||||
<path d="M6 2.25V3.75C6.59674 3.75 7.16903 3.98705 7.59099 4.40901C8.01295 4.83097 8.25 5.40326 8.25 6C8.25 6.59674 8.01295 7.16903 7.59099 7.59099C7.16903 8.01295 6.59674 8.25 6 8.25V9.75C6.99456 9.75 7.94839 9.35491 8.65165 8.65165C9.35491 7.94839 9.75 6.99456 9.75 6C9.75 5.00544 9.35491 4.05161 8.65165 3.34835C7.94839 2.64509 6.99456 2.25 6 2.25Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.2 KiB |
11
extensions/sql-database-projects/images/publish.svg
Normal file
@@ -0,0 +1,11 @@
|
||||
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M5.99922 1.51387V9.83887H6.74922V1.51387L9.44922 4.28887L10.0492 3.76387L6.37422 0.0888672L2.69922 3.76387L3.29922 4.28887L5.99922 1.51387Z" fill="#0078D4"/>
|
||||
<path d="M11.25 4.58887V11.3389H1.5V4.58887H0.75V12.0889H1.5H11.25H12V4.58887H11.25Z" fill="#0078D4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="12" height="12" fill="white" transform="translate(0.75 0.0888672)"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 537 B |
@@ -0,0 +1,3 @@
|
||||
<svg width="12" height="13" viewBox="0 0 12 13" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M9.75 5.33887C10.0586 5.33887 10.3496 5.39941 10.623 5.52051C10.8965 5.6377 11.1348 5.79785 11.3379 6.00098C11.541 6.2041 11.7012 6.44238 11.8184 6.71582C11.9395 6.98926 12 7.28027 12 7.58887C12 7.89746 11.9395 8.18848 11.8184 8.46191C11.7012 8.73535 11.541 8.97363 11.3379 9.17676C11.1348 9.37988 10.8965 9.54199 10.623 9.66309C10.3496 9.78027 10.0586 9.83887 9.75 9.83887C9.51562 9.83887 9.28711 9.80371 9.06445 9.7334C8.8418 9.66309 8.63672 9.55957 8.44922 9.42285C8.38672 9.48535 8.28125 9.59473 8.13281 9.75098C7.98828 9.90332 7.82031 10.0791 7.62891 10.2783C7.4375 10.4736 7.23438 10.6787 7.01953 10.8936C6.80859 11.1045 6.60938 11.2998 6.42188 11.4795C6.23438 11.6553 6.06836 11.8018 5.92383 11.9189C5.7793 12.0322 5.67969 12.0889 5.625 12.0889C5.52344 12.0889 5.43555 12.0518 5.36133 11.9775C5.28711 11.9033 5.25 11.8154 5.25 11.7139C5.25 11.6592 5.30664 11.5596 5.41992 11.415C5.53711 11.2705 5.68359 11.1045 5.85938 10.917C6.03906 10.7295 6.23438 10.5303 6.44531 10.3193C6.66016 10.1045 6.86523 9.90137 7.06055 9.70996C7.25977 9.51855 7.43555 9.35059 7.58789 9.20605C7.74414 9.05762 7.85352 8.95215 7.91602 8.88965C7.7793 8.70215 7.67578 8.49707 7.60547 8.27441C7.53516 8.05176 7.5 7.82324 7.5 7.58887C7.5 7.28027 7.55859 6.98926 7.67578 6.71582C7.79688 6.44238 7.95898 6.2041 8.16211 6.00098C8.36523 5.79785 8.60352 5.6377 8.87695 5.52051C9.15039 5.39941 9.44141 5.33887 9.75 5.33887ZM9.75 9.08887C9.95312 9.08887 10.1465 9.0498 10.3301 8.97168C10.5137 8.88965 10.6719 8.78223 10.8047 8.64941C10.9414 8.5127 11.0488 8.35449 11.127 8.1748C11.209 7.99121 11.25 7.7959 11.25 7.58887C11.25 7.38574 11.209 7.19238 11.127 7.00879C11.0488 6.8252 10.9414 6.66699 10.8047 6.53418C10.6719 6.39746 10.5137 6.29004 10.3301 6.21191C10.1465 6.12988 9.95312 6.08887 9.75 6.08887C9.54297 6.08887 9.34766 6.12988 9.16406 6.21191C8.98438 6.29004 8.82617 6.39746 8.68945 6.53418C8.55664 6.66699 8.44922 6.8252 8.36719 7.00879C8.28906 7.19238 8.25 7.38574 8.25 7.58887C8.25 7.7959 8.28906 7.99121 8.36719 8.1748C8.44922 8.35449 8.55664 8.5127 8.68945 8.64941C8.82617 8.78223 8.98438 8.88965 9.16406 8.97168C9.34766 9.0498 9.54297 9.08887 9.75 9.08887ZM1.5 8.33887V6.83887H0V0.0888672H9V1.58887H10.5V4.69434C10.375 4.66309 10.25 4.6377 10.125 4.61816C10 4.59863 9.875 4.58887 9.75 4.58887V2.33887H2.25V7.58887H6.75C6.75 7.71387 6.75977 7.83887 6.7793 7.96387C6.79883 8.08887 6.82422 8.21387 6.85547 8.33887H1.5ZM1.5 6.08887V1.58887H8.25V0.838867H0.75V6.08887H1.5Z" fill="#0078D4"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 2.5 KiB |
4
extensions/sql-database-projects/images/success.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="12" height="12" viewBox="0 0 12 12" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6 12C9.31371 12 12 9.31371 12 6C12 2.68629 9.31371 0 6 0C2.68629 0 0 2.68629 0 6C0 9.31371 2.68629 12 6 12Z" fill="#57A300"/>
|
||||
<path d="M2.6652 6.21818C2.6097 6.15893 2.5812 6.08093 2.5842 5.99993C2.5872 5.91818 2.6217 5.84318 2.6817 5.78693L3.30795 5.20793C3.36495 5.15618 3.4377 5.12768 3.51345 5.12768C3.59745 5.12768 3.67845 5.16293 3.73545 5.22443L5.33745 6.94343L8.1927 3.28718C8.25045 3.21293 8.33745 3.16943 8.43195 3.16943C8.49945 3.16943 8.5632 3.19118 8.6172 3.23243L9.2967 3.75668C9.42645 3.85268 9.4542 4.03943 9.3567 4.17218L5.7057 8.84693C5.56395 9.02843 5.2932 9.04043 5.1357 8.87168L2.6652 6.21818Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 744 B |
10
extensions/sql-database-projects/images/targetPlatform.svg
Normal file
@@ -0,0 +1,10 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0)">
|
||||
<path d="M12.7002 7.14809L15.0552 9.50009L12.7002 11.8521L12.0002 11.1521L13.1412 10.0001H7.00024V9.00009H13.1412L12.0002 7.85209L12.7002 7.14809ZM10.0002 11.0001H11.0002V12.5001C11.004 12.7175 10.9531 12.9324 10.8522 13.1251C10.7458 13.3164 10.611 13.4904 10.4522 13.6411C10.1565 13.9236 9.80964 14.1473 9.43024 14.3001C9.00477 14.4762 8.56565 14.6173 8.11724 14.7221C7.66241 14.8298 7.2001 14.903 6.73424 14.9411C6.27624 14.9751 5.86491 14.9948 5.50024 15.0001C5.13557 15.0054 4.72424 14.9848 4.26624 14.9381C3.80358 14.8955 3.34424 14.8223 2.89124 14.7191C2.4427 14.6183 2.00348 14.4798 1.57824 14.3051C1.19415 14.1539 0.843761 13.9282 0.547239 13.6411C0.391829 13.4926 0.259978 13.3213 0.15624 13.1331C0.0539872 12.9377 0.000467488 12.7206 0.000239503 12.5001V3.50009C-0.00395315 3.2826 0.0469607 3.0676 0.14824 2.87509C0.254632 2.6838 0.389509 2.50981 0.548239 2.35909C0.844004 2.07656 1.19084 1.85292 1.57024 1.70009C1.99571 1.52397 2.43483 1.38284 2.88324 1.27809C3.33807 1.17038 3.80038 1.09717 4.26624 1.05909C4.72424 1.02509 5.13557 1.00542 5.50024 1.00009C5.86491 0.994755 6.27624 1.01542 6.73424 1.06209C7.1969 1.1047 7.65624 1.17786 8.10924 1.28109C8.55793 1.38351 8.99716 1.52368 9.42224 1.70009C9.80633 1.85127 10.1567 2.07694 10.4532 2.36409C10.6087 2.51255 10.7405 2.68385 10.8442 2.87209C10.9458 3.06589 10.9993 3.28128 11.0002 3.50009V8.00009H10.0002V4.98409C9.68514 5.18601 9.34665 5.34887 8.99224 5.46909C8.6121 5.60047 8.22313 5.70473 7.82824 5.78109C7.43171 5.85867 7.03105 5.91342 6.62824 5.94509C6.22557 5.97709 5.84957 5.99542 5.50024 6.00009C5.15091 6.00475 4.77591 5.98909 4.37524 5.95309C3.97195 5.92166 3.57112 5.8642 3.17524 5.78109C2.78145 5.70002 2.39278 5.59584 2.01124 5.46909C1.65408 5.35334 1.31405 5.19022 1.00024 4.98409V12.5001C1.00321 12.6172 1.05078 12.7288 1.13324 12.8121C1.22768 12.9168 1.33523 13.0089 1.45324 13.0861C1.57584 13.1676 1.70379 13.2408 1.83624 13.3051C1.96624 13.3671 2.07024 13.4171 2.14824 13.4531C2.40457 13.5592 2.66868 13.6455 2.93824 13.7111C3.22163 13.7802 3.50832 13.8349 3.79724 13.8751C4.09457 13.9171 4.38357 13.9484 4.66424 13.9691C4.94491 13.9898 5.22357 14.0001 5.50024 14.0001C5.76691 14.0001 6.04291 13.9924 6.32824 13.9771C6.62131 13.9606 6.91335 13.9292 7.20324 13.8831C7.50057 13.8364 7.78457 13.7791 8.05524 13.7111C8.32737 13.6431 8.59464 13.5569 8.85524 13.4531C8.93324 13.4224 9.03724 13.3754 9.16724 13.3121C9.30122 13.248 9.42937 13.1724 9.55024 13.0861C9.66572 13.0056 9.77292 12.9138 9.87024 12.8121C9.9114 12.7712 9.94408 12.7226 9.96639 12.6691C9.9887 12.6155 10.0002 12.5581 10.0002 12.5001V11.0001ZM1.00024 3.50009C1.00321 3.61723 1.05078 3.72882 1.13324 3.81209C1.22768 3.91681 1.33523 4.0089 1.45324 4.08609C1.57584 4.16762 1.70379 4.24079 1.83624 4.30509L2.14824 4.45309C2.40403 4.56068 2.66826 4.64697 2.93824 4.71109C3.21924 4.77909 3.50524 4.83309 3.79724 4.87509C4.08924 4.91709 4.37824 4.94809 4.66424 4.96909C4.95024 4.99009 5.22924 5.00009 5.50024 5.00009C5.77124 5.00009 6.04224 4.99209 6.32824 4.97709C6.6203 4.96047 6.91134 4.92909 7.20024 4.88309C7.49757 4.83642 7.78391 4.77909 8.05924 4.71109C8.3288 4.64547 8.59291 4.55921 8.84924 4.45309C8.92724 4.42175 9.03124 4.37475 9.16124 4.31209C9.29502 4.24763 9.42314 4.17203 9.54424 4.08609C9.65972 4.00558 9.76692 3.9138 9.86424 3.81209C9.90649 3.77172 9.94028 3.72334 9.96363 3.66977C9.98698 3.6162 9.99942 3.55852 10.0002 3.50009C9.99726 3.38294 9.94969 3.27135 9.86724 3.18809C9.7728 3.08337 9.66525 2.99128 9.54724 2.91409C9.4245 2.83427 9.29655 2.76277 9.16424 2.70009L8.85224 2.55209C8.59541 2.44945 8.33136 2.36589 8.06224 2.30209C7.78091 2.23409 7.49357 2.17509 7.20024 2.12509C6.91306 2.07878 6.62367 2.0474 6.33324 2.03109C6.04924 2.01609 5.77124 2.00509 5.50024 2.00009C5.22924 1.99509 4.95824 2.00809 4.67224 2.02309C4.37917 2.03961 4.08713 2.07098 3.79724 2.11709C3.49991 2.16442 3.21357 2.22175 2.93824 2.28909C2.66868 2.35471 2.40457 2.44096 2.14824 2.54709C2.07024 2.57775 1.96624 2.62475 1.83624 2.68809C1.70246 2.75255 1.57434 2.82815 1.45324 2.91409C1.33776 2.99459 1.23056 3.08638 1.13324 3.18809C1.09153 3.22871 1.0583 3.2772 1.03547 3.33076C1.01264 3.38431 1.00066 3.44187 1.00024 3.50009V3.50009Z" fill="#0078D4"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0">
|
||||
<rect width="16" height="16" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4.3 KiB |
@@ -30,6 +30,31 @@ export const edgeSqlDatabaseProjectTypeId = 'SqlDbEdgeProj';
|
||||
export const edgeProjectTypeDisplayName = localize('edgeProjectTypeDisplayName', "SQL Edge");
|
||||
export const edgeProjectTypeDescription = localize('edgeProjectTypeDescription', "Start with the core pieces to develop and publish schemas for SQL Edge");
|
||||
|
||||
// Dashboard
|
||||
export const addItemAction = localize('addItemAction', "Add Item");
|
||||
export const schemaCompareAction = localize('schemaCompareAction', "Schema Compare");
|
||||
export const buildAction = localize('buildAction', "Build");
|
||||
export const publishAction = localize('publishAction', "Publish");
|
||||
export const changeTargetPlatformAction = localize('changeTargetPlatformAction', "Change Target Platform");
|
||||
|
||||
export const ID = localize('ID', "ID");
|
||||
export const Status = localize('Status', "Status");
|
||||
export const Time = localize('Time', "Time");
|
||||
export const Date = localize('Date', "Date");
|
||||
export const Builds = localize('Builds', "Builds");
|
||||
export const Deployments = localize('Deployments', "Deployments");
|
||||
|
||||
export const Success = localize('Success', "Success");
|
||||
export const Failed = localize('Failed', "Failed");
|
||||
export const InProgress = localize('InProgress', "In progress");
|
||||
|
||||
export const hr = localize('hr', "hr");
|
||||
export const min = localize('min', "min");
|
||||
export const sec = localize('sec', "sec");
|
||||
export const msec = localize('msec', "msec");
|
||||
|
||||
export const at = localize('at', "at");
|
||||
|
||||
// commands
|
||||
export const revealFileInOsCommand = 'revealFileInOS';
|
||||
export const schemaCompareStartCommand = 'schemaCompare.start';
|
||||
|
||||
@@ -29,6 +29,16 @@ export class IconPathHelper {
|
||||
|
||||
public static folder: IconPath;
|
||||
|
||||
public static add: IconPath;
|
||||
public static build: IconPath;
|
||||
public static publish: IconPath;
|
||||
public static schemaCompare: IconPath;
|
||||
public static targetPlatform: IconPath;
|
||||
|
||||
public static success: IconPath;
|
||||
public static error: IconPath;
|
||||
public static inProgress: IconPath;
|
||||
|
||||
public static setExtensionContext(extensionContext: vscode.ExtensionContext) {
|
||||
IconPathHelper.extensionContext = extensionContext;
|
||||
|
||||
@@ -48,6 +58,16 @@ export class IconPathHelper {
|
||||
IconPathHelper.connect = IconPathHelper.makeIcon('connect', true);
|
||||
|
||||
IconPathHelper.folder = IconPathHelper.makeIcon('folder');
|
||||
|
||||
IconPathHelper.add = IconPathHelper.makeIcon('add', true);
|
||||
IconPathHelper.build = IconPathHelper.makeIcon('build', true);
|
||||
IconPathHelper.publish = IconPathHelper.makeIcon('publish', true);
|
||||
IconPathHelper.schemaCompare = IconPathHelper.makeIcon('schemaCompare', true);
|
||||
IconPathHelper.targetPlatform = IconPathHelper.makeIcon('targetPlatform', true);
|
||||
|
||||
IconPathHelper.success = IconPathHelper.makeIcon('success', true);
|
||||
IconPathHelper.error = IconPathHelper.makeIcon('error', true);
|
||||
IconPathHelper.inProgress = IconPathHelper.makeIcon('inProgress', true);
|
||||
}
|
||||
|
||||
private static makeIcon(name: string, sameIcon: boolean = false) {
|
||||
|
||||
@@ -284,3 +284,37 @@ export function getPackageInfo(packageJson?: any): IPackageInfo | undefined {
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts time in milliseconds to hr, min, sec
|
||||
* @param duration time in milliseconds
|
||||
* @returns string in "hr, min, sec" or "msec" format
|
||||
*/
|
||||
export function timeConversion(duration: number): string {
|
||||
const portions: string[] = [];
|
||||
|
||||
const msInHour = 1000 * 60 * 60;
|
||||
const hours = Math.trunc(duration / msInHour);
|
||||
if (hours > 0) {
|
||||
portions.push(`${hours} ${constants.hr}`);
|
||||
duration = duration - (hours * msInHour);
|
||||
}
|
||||
|
||||
const msInMinute = 1000 * 60;
|
||||
const minutes = Math.trunc(duration / msInMinute);
|
||||
if (minutes > 0) {
|
||||
portions.push(`${minutes} ${constants.min}`);
|
||||
duration = duration - (minutes * msInMinute);
|
||||
}
|
||||
|
||||
const seconds = Math.trunc(duration / 1000);
|
||||
if (seconds > 0) {
|
||||
portions.push(`${seconds} ${constants.sec}`);
|
||||
}
|
||||
|
||||
if (hours === 0 && minutes === 0 && seconds === 0) {
|
||||
portions.push(`${duration} ${constants.msec}`);
|
||||
}
|
||||
|
||||
return portions.join(', ');
|
||||
}
|
||||
|
||||
@@ -31,6 +31,10 @@ import { ISystemDatabaseReferenceSettings, IDacpacReferenceSettings, IProjectRef
|
||||
import { DatabaseReferenceTreeItem } from '../models/tree/databaseReferencesTreeItem';
|
||||
import { CreateProjectFromDatabaseDialog } from '../dialogs/createProjectFromDatabaseDialog';
|
||||
import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/telemetry';
|
||||
import { IconPathHelper } from '../common/iconHelper';
|
||||
import { DashboardData, Status } from '../models/dashboardData/dashboardData';
|
||||
|
||||
const maxTableLength = 10;
|
||||
|
||||
/**
|
||||
* Controller for managing lifecycle of projects
|
||||
@@ -38,6 +42,8 @@ import { TelemetryActions, TelemetryReporter, TelemetryViews } from '../common/t
|
||||
export class ProjectsController {
|
||||
private netCoreTool: NetCoreTool;
|
||||
private buildHelper: BuildHelper;
|
||||
private buildInfo: DashboardData[] = [];
|
||||
private deployInfo: DashboardData[] = [];
|
||||
|
||||
projFileWatchers = new Map<string, vscode.FileSystemWatcher>();
|
||||
|
||||
@@ -46,6 +52,66 @@ export class ProjectsController {
|
||||
this.buildHelper = new BuildHelper();
|
||||
}
|
||||
|
||||
public get dashboardDeployData(): (string | dataworkspace.IconCellValue)[][] {
|
||||
const infoRows: (string | dataworkspace.IconCellValue)[][] = [];
|
||||
let count = 0;
|
||||
|
||||
for (let i = this.deployInfo.length - 1; i >= 0; i--) {
|
||||
let icon: azdata.IconPath;
|
||||
let text: string;
|
||||
if (this.deployInfo[i].status === Status.success) {
|
||||
icon = IconPathHelper.success;
|
||||
text = constants.Success;
|
||||
} else if (this.deployInfo[i].status === Status.failed) {
|
||||
icon = IconPathHelper.error;
|
||||
text = constants.Failed;
|
||||
} else {
|
||||
icon = IconPathHelper.inProgress;
|
||||
text = constants.InProgress;
|
||||
}
|
||||
|
||||
let infoRow: (string | dataworkspace.IconCellValue)[] = [count.toString(),
|
||||
{ text: text, icon: icon },
|
||||
this.deployInfo[i].target,
|
||||
this.deployInfo[i].timeToCompleteAction,
|
||||
this.deployInfo[i].startDate];
|
||||
infoRows.push(infoRow);
|
||||
count++;
|
||||
}
|
||||
|
||||
return infoRows;
|
||||
}
|
||||
|
||||
public get dashboardBuildData(): (string | dataworkspace.IconCellValue)[][] {
|
||||
const infoRows: (string | dataworkspace.IconCellValue)[][] = [];
|
||||
let count = 0;
|
||||
|
||||
for (let i = this.buildInfo.length - 1; i >= 0; i--) {
|
||||
let icon: azdata.IconPath;
|
||||
let text: string;
|
||||
if (this.buildInfo[i].status === Status.success) {
|
||||
icon = IconPathHelper.success;
|
||||
text = constants.Success;
|
||||
} else if (this.buildInfo[i].status === Status.failed) {
|
||||
icon = IconPathHelper.error;
|
||||
text = constants.Failed;
|
||||
} else {
|
||||
icon = IconPathHelper.inProgress;
|
||||
text = constants.InProgress;
|
||||
}
|
||||
|
||||
let infoRow: (string | dataworkspace.IconCellValue)[] = [count.toString(),
|
||||
{ text: text, icon: icon },
|
||||
this.buildInfo[i].target,
|
||||
this.buildInfo[i].timeToCompleteAction,
|
||||
this.buildInfo[i].startDate];
|
||||
infoRows.push(infoRow);
|
||||
count++;
|
||||
}
|
||||
|
||||
return infoRows;
|
||||
}
|
||||
|
||||
public refreshProjectsTree(workspaceTreeItem: dataworkspace.WorkspaceTreeItem): void {
|
||||
(workspaceTreeItem.treeDataProvider as SqlDatabaseProjectTreeViewProvider).notifyTreeDataChanged();
|
||||
}
|
||||
@@ -108,6 +174,14 @@ export class ProjectsController {
|
||||
const project: Project = this.getProjectFromContext(context);
|
||||
|
||||
const startTime = new Date();
|
||||
const currentBuildTimeInfo = `${startTime.toLocaleDateString()} ${constants.at} ${startTime.toLocaleTimeString()}`;
|
||||
|
||||
let buildInfoNew = new DashboardData(Status.inProgress, project.getProjectTargetVersion(), currentBuildTimeInfo);
|
||||
this.buildInfo.push(buildInfoNew);
|
||||
|
||||
if (this.buildInfo.length - 1 === maxTableLength) {
|
||||
this.buildInfo.shift(); // Remove the first element to maintain the length
|
||||
}
|
||||
|
||||
// Check mssql extension for project dlls (tracking issue #10273)
|
||||
await this.buildHelper.createBuildDirFolder();
|
||||
@@ -120,15 +194,26 @@ export class ProjectsController {
|
||||
|
||||
try {
|
||||
await this.netCoreTool.runDotnetCommand(options);
|
||||
const timeToBuild = new Date().getTime() - startTime.getTime();
|
||||
|
||||
const currentBuildIndex = this.buildInfo.findIndex(b => b.startDate === currentBuildTimeInfo);
|
||||
this.buildInfo[currentBuildIndex].status = Status.success;
|
||||
this.buildInfo[currentBuildIndex].timeToCompleteAction = utils.timeConversion(timeToBuild);
|
||||
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.ProjectController, TelemetryActions.build)
|
||||
.withAdditionalMeasurements({ duration: new Date().getTime() - startTime.getTime() })
|
||||
.withAdditionalMeasurements({ duration: timeToBuild })
|
||||
.send();
|
||||
|
||||
return project.dacpacOutputPath;
|
||||
} catch (err) {
|
||||
const timeToFailureBuild = new Date().getTime() - startTime.getTime();
|
||||
|
||||
const currentBuildIndex = this.buildInfo.findIndex(b => b.startDate === currentBuildTimeInfo);
|
||||
this.buildInfo[currentBuildIndex].status = Status.failed;
|
||||
this.buildInfo[currentBuildIndex].timeToCompleteAction = utils.timeConversion(timeToFailureBuild);
|
||||
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.ProjectController, TelemetryActions.build)
|
||||
.withAdditionalMeasurements({ duration: new Date().getTime() - startTime.getTime() })
|
||||
.withAdditionalMeasurements({ duration: timeToFailureBuild })
|
||||
.send();
|
||||
|
||||
vscode.window.showErrorMessage(constants.projBuildFailed(utils.getErrorMessage(err)));
|
||||
@@ -187,7 +272,16 @@ export class ProjectsController {
|
||||
|
||||
let result: mssql.DacFxResult;
|
||||
telemetryProps.profileUsed = (settings.profileUsed ?? false).toString();
|
||||
const actionStartTime = new Date().getTime();
|
||||
const currentDate = new Date();
|
||||
const actionStartTime = currentDate.getTime();
|
||||
const currentDeployTimeInfo = `${currentDate.toLocaleDateString()} ${constants.at} ${currentDate.toLocaleTimeString()}`;
|
||||
|
||||
let deployInfoNew = new DashboardData(Status.inProgress, project.getProjectTargetVersion(), currentDeployTimeInfo);
|
||||
this.deployInfo.push(deployInfoNew);
|
||||
|
||||
if (this.deployInfo.length - 1 === maxTableLength) {
|
||||
this.deployInfo.shift(); // Remove the first element to maintain the length
|
||||
}
|
||||
|
||||
try {
|
||||
if ((<IPublishSettings>settings).upgradeExisting) {
|
||||
@@ -200,20 +294,30 @@ export class ProjectsController {
|
||||
}
|
||||
} catch (err) {
|
||||
const actionEndTime = new Date().getTime();
|
||||
telemetryProps.actionDuration = (actionEndTime - actionStartTime).toString();
|
||||
const timeToFailureDeploy = actionEndTime - actionStartTime;
|
||||
telemetryProps.actionDuration = timeToFailureDeploy.toString();
|
||||
telemetryProps.totalDuration = (actionEndTime - buildStartTime).toString();
|
||||
|
||||
TelemetryReporter.createErrorEvent(TelemetryViews.ProjectController, TelemetryActions.publishProject)
|
||||
.withAdditionalProperties(telemetryProps)
|
||||
.send();
|
||||
|
||||
const currentDeployIndex = this.deployInfo.findIndex(d => d.startDate === currentDeployTimeInfo);
|
||||
this.deployInfo[currentDeployIndex].status = Status.failed;
|
||||
this.deployInfo[currentDeployIndex].timeToCompleteAction = utils.timeConversion(timeToFailureDeploy);
|
||||
|
||||
throw err;
|
||||
}
|
||||
|
||||
const actionEndTime = new Date().getTime();
|
||||
telemetryProps.actionDuration = (actionEndTime - actionStartTime).toString();
|
||||
const timeToDeploy = actionEndTime - actionStartTime;
|
||||
telemetryProps.actionDuration = timeToDeploy.toString();
|
||||
telemetryProps.totalDuration = (actionEndTime - buildStartTime).toString();
|
||||
|
||||
const currentDeployIndex = this.deployInfo.findIndex(d => d.startDate === currentDeployTimeInfo);
|
||||
this.deployInfo[currentDeployIndex].status = Status.success;
|
||||
this.deployInfo[currentDeployIndex].timeToCompleteAction = utils.timeConversion(timeToDeploy);
|
||||
|
||||
TelemetryReporter.createActionEvent(TelemetryViews.ProjectController, TelemetryActions.publishProject)
|
||||
.withAdditionalProperties(telemetryProps)
|
||||
.send();
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
export class DashboardData {
|
||||
public status: Status;
|
||||
public target: string;
|
||||
public timeToCompleteAction: string;
|
||||
public startDate: string;
|
||||
|
||||
constructor(status: Status, target: string, startDate: string) {
|
||||
this.status = status;
|
||||
this.target = target;
|
||||
this.timeToCompleteAction = '';
|
||||
this.startDate = startDate;
|
||||
}
|
||||
}
|
||||
|
||||
export enum Status {
|
||||
success,
|
||||
failed,
|
||||
inProgress
|
||||
}
|
||||
@@ -77,7 +77,45 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the list of files and directories to the project, and saves the project file
|
||||
* Gets the supported project types
|
||||
*/
|
||||
get projectActions(): (dataworkspace.IProjectAction | dataworkspace.IProjectActionGroup)[] {
|
||||
const addItemAction: dataworkspace.IProjectAction = {
|
||||
id: constants.addItemAction,
|
||||
icon: IconPathHelper.add,
|
||||
run: (treeItem: dataworkspace.WorkspaceTreeItem) => this.projectController.addItemPromptFromNode(treeItem)
|
||||
};
|
||||
|
||||
const schemaCompareAction: dataworkspace.IProjectAction = {
|
||||
id: constants.schemaCompareAction,
|
||||
icon: IconPathHelper.schemaCompare,
|
||||
run: (treeItem: dataworkspace.WorkspaceTreeItem) => this.projectController.schemaCompare(treeItem)
|
||||
};
|
||||
|
||||
const buildAction: dataworkspace.IProjectAction = {
|
||||
id: constants.buildAction,
|
||||
icon: IconPathHelper.build,
|
||||
run: (treeItem: dataworkspace.WorkspaceTreeItem) => this.projectController.buildProject(treeItem)
|
||||
};
|
||||
|
||||
const publishAction: dataworkspace.IProjectAction = {
|
||||
id: constants.publishAction,
|
||||
icon: IconPathHelper.publish,
|
||||
run: (treeItem: dataworkspace.WorkspaceTreeItem) => this.projectController.publishProject(treeItem)
|
||||
};
|
||||
|
||||
const changeTargetPlatformAction: dataworkspace.IProjectAction = {
|
||||
id: constants.changeTargetPlatformAction,
|
||||
icon: IconPathHelper.targetPlatform,
|
||||
run: (treeItem: dataworkspace.WorkspaceTreeItem) => this.projectController.changeTargetPlatform(treeItem)
|
||||
};
|
||||
|
||||
let group: dataworkspace.IProjectActionGroup = { actions: [addItemAction, schemaCompareAction, buildAction, publishAction] };
|
||||
|
||||
return [group, changeTargetPlatformAction];
|
||||
}
|
||||
|
||||
/** Adds the list of files and directories to the project, and saves the project file
|
||||
* @param projectFile The Uri of the project file
|
||||
* @param list list of uris of files and folders to add. Files and folders must already exist. Files and folders must already exist. No files or folders will be added if any do not exist.
|
||||
*/
|
||||
@@ -85,4 +123,31 @@ export class SqlDatabaseProjectProvider implements dataworkspace.IProjectProvide
|
||||
const project = await Project.openProject(projectFile.fsPath);
|
||||
await project.addToProject(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the data to be displayed in the project dashboard
|
||||
*/
|
||||
get dashboardComponents(): dataworkspace.IDashboardTable[] {
|
||||
const deployInfo: dataworkspace.IDashboardTable = {
|
||||
name: constants.Deployments,
|
||||
columns: [{ displayName: constants.ID, width: 75 },
|
||||
{ displayName: constants.Status, width: 180, type: 'icon' },
|
||||
{ displayName: constants.Target, width: 180 },
|
||||
{ displayName: constants.Time, width: 180 },
|
||||
{ displayName: constants.Date, width: 180 }],
|
||||
data: this.projectController.dashboardDeployData
|
||||
};
|
||||
|
||||
const buildInfo: dataworkspace.IDashboardTable = {
|
||||
name: constants.Builds,
|
||||
columns: [{ displayName: constants.ID, width: 75 },
|
||||
{ displayName: constants.Status, width: 180, type: 'icon' },
|
||||
{ displayName: constants.Target, width: 180 },
|
||||
{ displayName: constants.Time, width: 180 },
|
||||
{ displayName: constants.Date, width: 180 }],
|
||||
data: this.projectController.dashboardBuildData
|
||||
};
|
||||
|
||||
return [deployInfo, buildInfo];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -409,7 +409,9 @@ describe('ProjectsController', function (): void {
|
||||
|
||||
projController.setup(x => x.getDaxFxService()).returns(() => Promise.resolve(testContext.dacFxService.object));
|
||||
|
||||
await projController.object.publishProjectCallback(new Project(''), { connectionUri: '', databaseName: '' });
|
||||
const proj = await testUtils.createTestProject(baselines.openProjectFileBaseline);
|
||||
|
||||
await projController.object.publishProjectCallback(proj, { connectionUri: '', databaseName: '' });
|
||||
|
||||
should(builtDacpacPath).not.equal('', 'built dacpac path should be set');
|
||||
should(publishedDacpacPath).not.equal('', 'published dacpac path should be set');
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as should from 'should';
|
||||
import * as path from 'path';
|
||||
import * as os from 'os';
|
||||
import { createDummyFileStructure } from './testUtils';
|
||||
import { exists, trimUri, removeSqlCmdVariableFormatting, formatSqlCmdVariable, isValidSqlCmdVariableName } from '../common/utils';
|
||||
import { exists, trimUri, removeSqlCmdVariableFormatting, formatSqlCmdVariable, isValidSqlCmdVariableName, timeConversion } from '../common/utils';
|
||||
import { Uri } from 'vscode';
|
||||
|
||||
describe('Tests to verify utils functions', function (): void {
|
||||
@@ -78,5 +78,15 @@ describe('Tests to verify utils functions', function (): void {
|
||||
should(isValidSqlCmdVariableName('test\'')).equal(false);
|
||||
should(isValidSqlCmdVariableName('test-1')).equal(false);
|
||||
});
|
||||
|
||||
it('Should convert from milliseconds to hr min sec correctly', () => {
|
||||
should(timeConversion((60 * 60 * 1000) + (59 * 60 * 1000) + (59 * 1000))).equal('1 hr, 59 min, 59 sec');
|
||||
should(timeConversion((60 * 60 * 1000) + (59 * 60 * 1000) )).equal('1 hr, 59 min');
|
||||
should(timeConversion((60 * 60 * 1000) )).equal('1 hr');
|
||||
should(timeConversion((60 * 60 * 1000) + (59 * 1000))).equal('1 hr, 59 sec');
|
||||
should(timeConversion( (59 * 60 * 1000) + (59 * 1000))).equal('59 min, 59 sec');
|
||||
should(timeConversion( (59 * 1000))).equal('59 sec');
|
||||
should(timeConversion( (59))).equal('59 msec');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||