From 667053cdf5abf447184bbc0a3f0bab33ce103273 Mon Sep 17 00:00:00 2001 From: Janne Savolainen Date: Wed, 6 Jul 2022 01:44:03 +0300 Subject: [PATCH] Replace status bar item application update with different tray icon based on status of the update (#5769) * Remove the auto-update status bar item for not being needed anymore Signed-off-by: Janne Savolainen * Make adding of new tray icons easier by complying to Open Closed Principle Signed-off-by: Janne Savolainen * Start showing different tray icon when checking for updates Signed-off-by: Janne Savolainen * Include placeholder icon for checking for updates Signed-off-by: Janne Savolainen * Simplify code Signed-off-by: Janne Savolainen * Add first keyframe for downloading spinner Signed-off-by: Sebastian Malton Co-authored-by: Sebastian Malton --- build/generate-tray-icons.ts | 23 ++- build/tray/trayIconCheckingForUpdates.png | Bin 0 -> 504 bytes build/tray/trayIconCheckingForUpdates@2x.png | Bin 0 -> 1190 bytes build/tray/trayIconCheckingForUpdates@3x.png | Bin 0 -> 1897 bytes build/tray/trayIconCheckingForUpdates@4x.png | Bin 0 -> 2786 bytes .../trayIconCheckingForUpdatesTemplate.png | Bin 0 -> 442 bytes .../trayIconCheckingForUpdatesTemplate@2x.png | Bin 0 -> 993 bytes .../trayIconCheckingForUpdatesTemplate@3x.png | Bin 0 -> 1544 bytes .../trayIconCheckingForUpdatesTemplate@4x.png | Bin 0 -> 2206 bytes ...acters-in-page-registrations.test.tsx.snap | 24 +-- .../navigate-to-extension-page.test.tsx.snap | 60 +------- .../navigating-between-routes.test.tsx.snap | 24 +-- ...ation-using-application-menu.test.tsx.snap | 24 +-- ...g-update-using-topbar-button.test.tsx.snap | 12 +- .../installing-update-using-tray.test.ts.snap | 78 +--------- .../installing-update.test.ts.snap | 78 +--------- ...eriodical-checking-of-updates.test.ts.snap | 12 +- ...selection-of-update-stability.test.ts.snap | 12 +- .../installing-update-using-tray.test.ts | 28 ---- .../installing-update.test.ts | 51 ++++--- ...gation-using-application-menu.test.ts.snap | 24 +-- ...elm-repository-in-preferences.test.ts.snap | 144 ++---------------- ...tory-from-list-in-preferences.test.ts.snap | 120 ++------------- ...m-repositories-in-preferences.test.ts.snap | 120 ++------------- ...ive-repository-in-preferences.test.ts.snap | 48 +----- .../closing-preferences.test.tsx.snap | 96 +----------- ...on-to-application-preferences.test.ts.snap | 24 +-- ...igation-to-editor-preferences.test.ts.snap | 24 +-- ...tension-specific-preferences.test.tsx.snap | 120 ++------------- ...ion-to-kubernetes-preferences.test.ts.snap | 24 +-- ...vigation-to-proxy-preferences.test.ts.snap | 24 +-- ...ion-to-telemetry-preferences.test.tsx.snap | 60 +------- ...ation-to-terminal-preferences.test.ts.snap | 24 +-- ...gation-using-application-menu.test.ts.snap | 24 +-- .../navigation-using-tray.test.ts.snap | 24 +-- ...-originating-from-extensions.test.tsx.snap | 9 -- ...gation-using-application-menu.test.ts.snap | 36 +---- ...application-update-tray-item.injectable.ts | 8 +- ...ecking-for-updates-tray-icon.injectable.ts | 34 +++++ ...dy-to-be-installed-tray-icon.injectable.ts | 27 ++++ ...ate-is-ready-to-be-installed.injectable.ts | 25 +++ .../electron-tray/electron-tray.injectable.ts | 6 +- .../get-tray-icon-path.injectable.ts | 37 +++++ .../menu-icon/normal-tray-icon.injectable.ts | 26 ++++ .../tray/menu-icon/reactive.injectable.ts | 17 +-- .../menu-icon/tray-icon-injection-token.ts | 16 ++ .../tray/menu-icon/tray-icon.injectable.ts | 33 ++++ src/main/tray/tray-icon-path.injectable.ts | 37 ----- .../components/icon/arrow-spinner.svg | 6 + .../status-bar/auto-update-component.tsx | 107 ------------- .../auto-update-status-bar-item.injectable.ts | 22 --- .../test-utils/get-application-builder.tsx | 7 +- 52 files changed, 370 insertions(+), 1409 deletions(-) create mode 100644 build/tray/trayIconCheckingForUpdates.png create mode 100644 build/tray/trayIconCheckingForUpdates@2x.png create mode 100644 build/tray/trayIconCheckingForUpdates@3x.png create mode 100644 build/tray/trayIconCheckingForUpdates@4x.png create mode 100644 build/tray/trayIconCheckingForUpdatesTemplate.png create mode 100644 build/tray/trayIconCheckingForUpdatesTemplate@2x.png create mode 100644 build/tray/trayIconCheckingForUpdatesTemplate@3x.png create mode 100644 build/tray/trayIconCheckingForUpdatesTemplate@4x.png create mode 100644 src/main/application-update/tray-icons/checking-for-updates-tray-icon.injectable.ts create mode 100644 src/main/application-update/tray-icons/update-is-ready-to-be-installed-tray-icon.injectable.ts create mode 100644 src/main/application-update/update-is-ready-to-be-installed.injectable.ts create mode 100644 src/main/tray/menu-icon/get-tray-icon-path.injectable.ts create mode 100644 src/main/tray/menu-icon/normal-tray-icon.injectable.ts create mode 100644 src/main/tray/menu-icon/tray-icon-injection-token.ts create mode 100644 src/main/tray/menu-icon/tray-icon.injectable.ts delete mode 100644 src/main/tray/tray-icon-path.injectable.ts create mode 100644 src/renderer/components/icon/arrow-spinner.svg delete mode 100644 src/renderer/components/status-bar/auto-update-component.tsx delete mode 100644 src/renderer/components/status-bar/auto-update-status-bar-item.injectable.ts diff --git a/build/generate-tray-icons.ts b/build/generate-tray-icons.ts index ed90d27832..487ba8d348 100644 --- a/build/generate-tray-icons.ts +++ b/build/generate-tray-icons.ts @@ -12,6 +12,7 @@ const size = Number(process.env.OUTPUT_SIZE || "16"); const outputFolder = process.env.OUTPUT_DIR || "./build/tray"; const inputFile = process.env.INPUT_SVG_PATH || "./src/renderer/components/icon/logo-lens.svg"; const noticeFile = process.env.NOTICE_SVG_PATH || "./src/renderer/components/icon/notice.svg"; +const spinnerFile = process.env.SPINNER_SVG_PATH || "./src/renderer/components/icon/arrow-spinner.svg"; async function ensureOutputFoler() { await ensureDir(outputFolder); @@ -58,8 +59,9 @@ async function generateImages(image: Buffer, size: number, name: string) { ]); } -async function generateUpdateAvailableImages(baseImage: Buffer, system: TargetSystems) { - const noticeIconImage = await getNoticeIconImage(system); +async function generateImageWithSvg(baseImage: Buffer, system: TargetSystems, filePath: string) { + const svgFile = await getIconImage(system, filePath); + const circleBuffer = await sharp(Buffer.from(` @@ -78,7 +80,7 @@ async function generateUpdateAvailableImages(baseImage: Buffer, system: TargetSy }, { input: ( - await sharp(noticeIconImage) + await sharp(svgFile) .resize({ width: 60, height: 60, @@ -92,8 +94,8 @@ async function generateUpdateAvailableImages(baseImage: Buffer, system: TargetSy .toBuffer(); } -async function getNoticeIconImage(system: TargetSystems) { - const svgData = await readFile(noticeFile, { encoding: "utf-8" }); +async function getIconImage(system: TargetSystems, filePath: string) { + const svgData = await readFile(filePath, { encoding: "utf-8" }); const root = new JSDOM(svgData).window.document.getElementsByTagName("svg")[0]; root.innerHTML += getSvgStyling(system === "macos" ? "light" : "dark"); @@ -107,18 +109,25 @@ async function generateTrayIcons() { await ensureOutputFoler(); const baseIconTemplateImage = await getBaseIconImage("macos"); - const updateAvailableTemplateImage = await generateUpdateAvailableImages(baseIconTemplateImage, "macos"); const baseIconImage = await getBaseIconImage("windows-or-linux"); - const updateAvailableImage = await generateUpdateAvailableImages(baseIconImage, "windows-or-linux"); + + const updateAvailableTemplateImage = await generateImageWithSvg(baseIconTemplateImage, "macos", noticeFile); + const updateAvailableImage = await generateImageWithSvg(baseIconImage, "windows-or-linux", noticeFile); + + const checkingForUpdatesTemplateImage = await generateImageWithSvg(baseIconTemplateImage, "macos", spinnerFile); + const checkingForUpdatesImage = await generateImageWithSvg(baseIconImage, "windows-or-linux", spinnerFile); await Promise.all([ // Templates are for macOS only generateImages(baseIconTemplateImage, size, "trayIconTemplate"), generateImages(updateAvailableTemplateImage, size, "trayIconUpdateAvailableTemplate"), + generateImages(updateAvailableTemplateImage, size, "trayIconUpdateAvailableTemplate"), + generateImages(checkingForUpdatesTemplateImage, size, "trayIconCheckingForUpdatesTemplate"), // Non-templates are for windows and linux generateImages(baseIconImage, size, "trayIcon"), generateImages(updateAvailableImage, size, "trayIconUpdateAvailable"), + generateImages(checkingForUpdatesImage, size, "trayIconCheckingForUpdates"), ]); console.log("Generated all images"); diff --git a/build/tray/trayIconCheckingForUpdates.png b/build/tray/trayIconCheckingForUpdates.png new file mode 100644 index 0000000000000000000000000000000000000000..4e18a7ae186ed311c8536abc2daa8e6d73c43fe6 GIT binary patch literal 504 zcmVxy}q^YZlaI&gT-bI#11x$k?XQmb4Y zK-mwdH-UTVoO-$VrB7%1uS#%!2i525Z~wQ8>JxQU?MvT7?Gnsq0P3II&#LE2Cg8hz zA^kf`f-~wf^_2PzBEDfi)LvjC|9|E8t9m@(RGDBQFUHmDwbE~?H*9Zf1;PNZn}<=} z5p^5*0tB>0^^^KqeUob`9tFCq+6x8q1NCZFQ<(2nAE}Sk8TD>(16-<7s<1uauez_E z&fu<^%%9u9n5mNGR@JRvBQnWaI;Jisfzdb9z~Lr@LKM&ktmNPfXGK2~`=t6l uxteO7#-?0lq=6XWXqx&shff*2MuLBFEN42Fine$F0000MJ+_V7<@mN&9~Ra8IJyt6Bnu@BFI_b ztB~fmWS&h5j8!C$CMHjN{u+{hRftNf>ny-ig^;nQKX%~idz|Fza7B}}f5r#e-~sR_ z$*a8fLee~#>@jnt-LGc!w**tBSisr*58zCp+<3TPIY|{0+PA@EpVu#Pu?aZt`k=LU z*#R=vz+gi#17K~AfsKiInQFIq&qIm8Bgt)(B%dX@%bMwbXAJ?wSk}I>6~I|AmHb-f z_$MiSz9ji=r7!#+oDV|G=l&rpoKpx%hzIR&6{lN^RGM(jXuKvR&e-22o&|8)G(QXh zbodARtnY&KukR567uE_%rNX_*rNPetmPMEQJu~#Ubj9;#6jiURo?#JX&RHw*hqEaP zQMg(3Pl>k7bGgm-Dd9%>ZsvrT|z2;ChnV+$94}gaFHy&}swT zF8h7u4lz;du1UzPw!l$U(3pJR3{G3qJ^~O%5Xl`1#E6|CW+@KTnja_mst|z2m#2N3 z%(E$bK^2Q&>%y?g1F7z-r%b2#x{u@z0N0XKP*23+D_k6QE`pOTHoIJWCIPHSf{M9d zKY(>fc#U640lqn6sqx{pMWilPN(0_0m`L;eg=N}+1@Le>w>#pcNf%FPM*DiGnM6Zz zQ&Gc#8&G=*H9qR|t>#61$UQdzxXTvY*zblIT%A_~IF?&yM_Y}$@Pvs(6;$JzuEkGB z4E1V3xFrb?3~Sf0uTwz^P4_wAx>9fqfc8#!JfFrGy^_@$QwTAauVEzbAbF$5k1gPW zh=Y-=YSKi$G9L(ylRLun2NO}<5q9|hGVgtDfmB|Z1*p9XvJfvN|IeiExWVfxE`m?f znKlgpNQiYwQ)Ss(B)rcX3aA(evwF%gYN&D@3x|cgEJG0Je3$6*($I z#KZ;8+t2*$$}Y-T(iWGb@ph7X0qpg-y@F*Nfr{_?kJFS+Ye;@X@~|JLzu8J3C=M1W z*ZnS96`;!+wHL0Nk)Gy4y$dn}Sx{M^C%VpRTzwb*2Wy5BMMiQp8~^|S07*qoM6N<$ Ef^JzSlK=n! literal 0 HcmV?d00001 diff --git a/build/tray/trayIconCheckingForUpdates@3x.png b/build/tray/trayIconCheckingForUpdates@3x.png new file mode 100644 index 0000000000000000000000000000000000000000..30a112d7a14f7ad2e36ee2de5f6e7471b2e5ac9b GIT binary patch literal 1897 zcmV-v2bTDWP)cQ`0|R?ZYtTE?8iY0qYG6;$poc~F!W=cpEb@B0eqXG8*E)V@oxS%t_j+CM zKdkyECztM?jhM5_s?{kHPM$i_+B9q_a>2CNOCR72T48#U<=8I z{N6$UQ!;1(O$xBJ&I)iJ`DF`8K27p-lE>IyUMd64lC{s+B5AR1cbDSj05&-2ET;er z0{D;QfDHgA?FRrxaH?2t70Itjt^v?3F4;XQBog?zUPbB4@;%XX0UAJnRKW2!otObUInuA4slNC5>2$!~x*; zXk!|#l&Y<<`$mB1OIiZ4qHu+FZxH3o>@Wc|iI5DXeBTnxNlSO-EFkQQR7i5H|C>{x zKKHI`s+bF4cUmixMw_AU*`S!S1wIqTxOR}u<#Kk(+2GLt z2whT{!bm~V4K|j7s<&2 z@(!7MxB92I4Y|sX>ge)|NdOF3_GeaD;gtwz2lXY%Z_8fb>DdVNN(Na?atFyLNIo^p zu?@iEB+qLQ05HD>e3K>Q_xS>JfxC&uR9Ur;-&V9Q18wE%;vKHRwc$QB1twS7k8@?z zjZaOd8zjt%CjWW@IB7dK-@Tob#9%u*9Vh%bOZg4WJRsoeRFg><@yPeJ+dy%tm^Urb zaN5vNVlnm}+Ofvmht-8P`^|w42}D}`jpVth5v<&A2#JV=&9ZjC9|{};(C=vDx2Oey z(PXPyU~7j2lte7_r1nXj5D=H^a}vt{TuimC4s=y0CJvOn^x@9Cc`dFGy@W#uv)en;^G>uwOu;Q?71ck+l(GCE2 zN-PwGtL(@ydKmwEHp#b1#tDUr-Fu7VY*}NDKmR;Qi!2%?z=?24Pz$vD2Z4QhvExd_Gd)ln7XHo8Fo>`zmYE{TqYz zP6yW`6g{DppHP-Fb-FmD_Yffs5?sBpEUlm7oo1YAZDu6 zDX1H%wU$JM$>W$&L2AZnoW}VrJFyD@b9~NrU#n=^yge}4my$LimyM*W8yel<+y*R znALF%w6TPKYO=2+wj(+SV3o|78ei+v?k%=~&y`rV%d?ZE*o^@0@veCCsC+Xn%MLa7 z?7tDTlj571yF`z6pSrD-jZga&I*LT5`1UmZvxhZdn*rGM8b8guB=__jvaTLM+GrHI jVfp?Dh>U2A7O4LLiqJ_QJp0o;00000NkvXXu0mjfRI`_~ literal 0 HcmV?d00001 diff --git a/build/tray/trayIconCheckingForUpdates@4x.png b/build/tray/trayIconCheckingForUpdates@4x.png new file mode 100644 index 0000000000000000000000000000000000000000..3d113af086c5a5933ea43e859fab73bd82ac9bfc GIT binary patch literal 2786 zcmV<83LW){P)pyR_r34INh;m9Z*^6j?<{rdRCSh(nM5Q5z-0hn62KIIiSS=h=)DQ6tMBE{ zUiO44GdlRG1Q`DRG=L=lmRng0K%b?+s|D;OCsYSEnUL~606qZV^8l^_uo1w+0R94C zJAfSko&fL=fI9(P3E(0C2P8mnZ7TKqa$$Txzh4jF(*SM(@C^Eq15f};8Z}6n(@Vkp zAPnSv0In60=K?b#A};`#1@Iz(xmZL*uRE>&=MuoK18}p5yp8&sh-R`_jAua=k2ck2 znzbTSaxfw|c2!`M9s#h2wL4{!Kgv+_cWwpnP9972Hwy-U?CQv+z6!ukNX#n9SrvC+ zI5HizLkNHqtdE>|EB9GN)ezMbryq%k`j~u7>U{NG2V<-xgs|P84B+3+I7zz=(nT{F;EW`hT66c%cX5T-QO+>swg$0lX5x->v=} z)$?2J+v!^ogpo7>>G{{u{kDzZc^XVx#u)&X?03nxxPQ5X>oD`dcewfd%3=y-zBFBq z!u){HbdS3Xz+*Njx5+L5NO<>20Iy-&7mG@>IdfndP6HrxwfrM01cp*skuMq<+> zefPL$kaVOc0M6j2NcFwX4b*-U!2Fy+SW3>ZJpfX5c0QQ1f_-Ya%R0ybr;p2wCh)mxj&1@vM@!xJq%zd0K|~1|AzwedfjYw9i%Sp z<{+3XF6}fkz@+XDL`04W&hFwE^NYxjTdFGm=XGx+3HjpbybkRp+YfQY$<}Uey0wca zR2|)`ZIQx*dCuZ|me_t2@6R=8LjIi0L{;^`(AFwjAbDF|0pR*>mfNh|W>Y|Qs{0`g zltH+f>iNLG5b9J09T->oMq=8#d{{eOK%h9`XVDbu9N&a#!r|0VQE1wFcaWT}?YA)U zi789T-~StcSA;g!2E1fM0HUusGOl3?N_flLQ<5O3bPv7b44gy&#K6b_^!Cn9Onb>b zN1*6$HpLmPpdkHs7_-ry{oWfqrwtPXgxlmjG>{~CV_+Vkf7gQda4b`2``1P$_)2E* zM1vZaOed&fG#_31{)zgOagz0&`vMWUzTymF4@@finx~J_D-aFy>^CXy_6YHc03hH0 zoT4+g#V=v;NXPL88*>gq40=966;rAh10Dt9AeN|ztP&BP%I4w}O3d$Pxxr@vJO$wC z1uU9-R63W(kcH^)Hml^$u8niKi4b+QK0mLx%jxObJqA%3ssEmq8J-c58NE_jAtEdE zI;OJH7IO1ZA?EF2Z%=Rxb3|lc4%9KO1!e}iczS?ddDNIJ*&mm>6#7DyVu6HtiM+o? z&6~8qJ^SVm%j@-6s(-47qb(SBfVA#jkxJ{^<2}Jc`0pL!2T0ALcX1h>g+S<)FRGI#3d5C93MDHVc zwwQr%-qfis&({Oi!3=G3^jV0+Jl_^uB6qU?8dGo(KL}vG$I6N~_` zn*GOO{oY!T2$+TkjHPp@p0FJV@4x_Bp zM9R@r?z@)wZe+CO`>w)gB+T+Ln-VXzvYrAtrc*>jouJ--G{s{U9xO988H)zc5_Tpg zJVZnT5$$XD1URm`z5(lWza56ilN#Z@W%eIWeN0~tKA~`esg&3b^#kMZ1vN#}U(brj zUwNtwl0P&^URSGZ)49ht^BM$G{*Jx#BF#v?p;KO)p#1QS9hSr6po?pqRTgZ19X+3F zFdL0$GE3R}p62tkWnP>iN_pIYU9YEYrC#yCkT}63MNNe-apxE^M#mBJ_uJfFnhu$X zFjbyj1NIIx$La6{LnILoN5Z2lkK3~KxSLYATK)VR<%1< z4?~Ls3!&d5$xQr&$F5C`AygNKB)xwF00V2}wRBja^-+};iBsJKEQW#7Q1xtXFc2jIhrgA42gx3Uv#JmWJ? z5KxZHw9{L{k&~eyB&NM$`;4Tz)xIn6=Pqeo)j1W@Aa9yPN~}NnpBYBgE;W7h+n@<7 z;%84kk$xa&xd`2hR=+2y4nE6!CdG-?RVR z*_}xYxYYFIc;jM-+T=Y5{r!V*1h=09MS7azQ`{wONF1ZlqwcS=!A((e!^r`BAV}6@ z|I;}LwO!~Fqhqw|a{DhXhu0*--@YKoyt*9^;Ge|!Y{K?Go^Wutg*tw{fR?jyaT9%w zI?rDMxJ*PYv-`(G9R>F^Hm%--5K)nb-P@d4AtX}k-zDt!L>in&*{&_RY<+X^_}TuW|-)g6`nT`(3??HPHrO48Mi^vu?8G4WVIo3|Gm6D?REs-Wy zMC2MfXJk}seD1Nt046o63%jyQ((q>1c_n$SU^ADd)@_hBg#eJ4YWiyCrakck@ zY|-{EJ98XYjSKVbkWyj_s(il}2B9B8cA@Qlu)@<_G?Ub>@D}~cQd9>J2k7?)h{#2@ z`La<&9yB%HVaz^myT5mc$T~}4dg{7~*$D?fwE|o;LUl@t1C7t7Z9~>So?cS(@$}*| olZ}zWX^&Q)&ztA3)Lkh0KX$c}FsJ?>dH?_b07*qoM6N<$g3Js`)Bpeg literal 0 HcmV?d00001 diff --git a/build/tray/trayIconCheckingForUpdatesTemplate.png b/build/tray/trayIconCheckingForUpdatesTemplate.png new file mode 100644 index 0000000000000000000000000000000000000000..de4fada91a449b8e03515c14acd8dfeca9a5bd71 GIT binary patch literal 442 zcmV;r0Y(0aP)g?t3p z#%0L|V3ga;kZ3k`E(;4^z>*DCY~8XDdg}k=c$;zR^ghpfo^#Is{LeZ3m638@k0UsP z%h=;zSunWk&KqzOU-7%>PF%%ftjybma|O5(hhO-S^CfI8!9HO75XmM?VjbR>#~-mA zPjmm0?>nrj2(HI)0EbF|qc}V$r|WDb>~n#)6tD3nrQN`D+{L}A|`M;-0YTCHOFuGiSO7L$3-Q`%Q?!JkVr$rt9g397Avq9Z__oqayT3KP0t5* z?e}rq!EGGGSbU9!keLuP6~dn3R-8}d|7xsB_9wNCv-7m-RO}B2eczliM*5FtY{OB9 zBx%EpyPbZ^1R}$2jhXz&1Ax*^(Nh6V(>wQ5I)M0)0yD$M7Iro%|n? kE^UQdpX)leH+Aj(0d2BscK8I-*8l(j07*qoM6N<$g8Dzo1^@s6 literal 0 HcmV?d00001 diff --git a/build/tray/trayIconCheckingForUpdatesTemplate@2x.png b/build/tray/trayIconCheckingForUpdatesTemplate@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..9ec465436712eb3e532d25bca762b409c4dbbc09 GIT binary patch literal 993 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 literal 0 HcmV?d00001 diff --git a/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap b/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap index 74307f3b53..2cc8acffca 100644 --- a/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap +++ b/src/behaviours/__snapshots__/extension-special-characters-in-page-registrations.test.tsx.snap @@ -187,17 +187,7 @@ exports[`extension special characters in page registrations renders 1`] = `
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
-
- Checking for updates... -
-
-
+ />
-
-
- Downloading version some-version... -
-
-
-
+ />
-
-
- Download of update failed -
-
-
+ />
-
-
- some-version is available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
-
- Checking for updates... -
-
-
+ />
-
-
- Downloading version some-version... -
-
-
-
+ />
-
-
- Download of update failed -
-
-
+ />
-
-
- some-version is available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
{ let applicationBuilder: ApplicationBuilder; let checkForPlatformUpdatesMock: AsyncFnMock; let downloadPlatformUpdateMock: AsyncFnMock; let showApplicationWindowMock: jest.Mock; - let trayIconPaths: TrayIconPaths; beforeEach(() => { applicationBuilder = getApplicationBuilder(); @@ -46,7 +43,6 @@ describe("installing update using tray", () => { mainDi.override(electronUpdaterIsActiveInjectable, () => true); mainDi.override(publishIsConfiguredInjectable, () => true); - trayIconPaths = mainDi.inject(trayIconPathsInjectable); }); }); @@ -61,10 +57,6 @@ describe("installing update using tray", () => { expect(rendered.baseElement).toMatchSnapshot(); }); - it("should use the normal tray icon", () => { - expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); - }); - it("user cannot install update yet", () => { expect(applicationBuilder.tray.get("install-update")).toBeNull(); }); @@ -80,10 +72,6 @@ describe("installing update using tray", () => { expect(showApplicationWindowMock).not.toHaveBeenCalled(); }); - it("should still use the normal tray icon", () => { - expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); - }); - it("user cannot check for updates again", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled, @@ -117,10 +105,6 @@ describe("installing update using tray", () => { expect(showApplicationWindowMock).toHaveBeenCalled(); }); - it("should still use the normal tray icon", () => { - expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); - }); - it("user cannot install update", () => { expect(applicationBuilder.tray.get("install-update")).toBeNull(); }); @@ -156,10 +140,6 @@ describe("installing update using tray", () => { expect(showApplicationWindowMock).toHaveBeenCalled(); }); - it("should use the update available icon", () => { - expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.updateAvailable); - }); - it("user cannot check for updates again yet", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled, @@ -199,10 +179,6 @@ describe("installing update using tray", () => { ).toBeNull(); }); - it("should revert to use the normal tray icon", () => { - expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.normal); - }); - it("user can check for updates again", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled, @@ -231,10 +207,6 @@ describe("installing update using tray", () => { ).toBe("Install update some-version"); }); - it("should use the update available icon", () => { - expect(applicationBuilder.tray.getIconPath()).toBe(trayIconPaths.updateAvailable); - }); - it("user can check for updates again", () => { expect( applicationBuilder.tray.get("check-for-updates")?.enabled, diff --git a/src/behaviours/application-update/installing-update.test.ts b/src/behaviours/application-update/installing-update.test.ts index 666dbc1e4c..2e10403ed8 100644 --- a/src/behaviours/application-update/installing-update.test.ts +++ b/src/behaviours/application-update/installing-update.test.ts @@ -16,7 +16,8 @@ import type { DownloadPlatformUpdate } from "../../main/application-update/downl import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable"; import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-update-on-quit.injectable"; import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable"; -import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time"; +import { useFakeTime } from "../../common/test-utils/use-fake-time"; +import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable"; describe("installing update", () => { let applicationBuilder: ApplicationBuilder; @@ -36,6 +37,8 @@ describe("installing update", () => { downloadPlatformUpdateMock = asyncFn(); setUpdateOnQuitMock = jest.fn(); + mainDi.override(staticFilesDirectoryInjectable, () => "/some-static-files-directory"); + mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock); mainDi.override( @@ -65,13 +68,21 @@ describe("installing update", () => { beforeEach(async () => { rendered = await applicationBuilder.render(); - processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); + processCheckingForUpdates = applicationBuilder.dis.mainDi.inject( + processCheckingForUpdatesInjectable, + ); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); + it("shows normal tray icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe( + "/some-static-files-directory/icons/trayIconTemplate.png", + ); + }); + describe("when user checks for updates", () => { let processCheckingForUpdatesPromise: Promise; @@ -86,8 +97,10 @@ describe("installing update", () => { ); }); - it("notifies the user that checking for updates is happening", () => { - expect(rendered.getByTestId("app-update-checking")).toBeInTheDocument(); + it("shows tray icon for checking for updates", () => { + expect(applicationBuilder.tray.getIconPath()).toBe( + "/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png", + ); }); it("renders", () => { @@ -103,8 +116,10 @@ describe("installing update", () => { await processCheckingForUpdatesPromise; }); - it("notifies the user", () => { - expect(rendered.getByTestId("app-update-not-available")).toBeInTheDocument(); + it("shows tray icon for normal", () => { + expect(applicationBuilder.tray.getIconPath()).toBe( + "/some-static-files-directory/icons/trayIconTemplate.png", + ); }); it("does not start downloading update", () => { @@ -114,12 +129,6 @@ describe("installing update", () => { it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); - - it("when 5 seconds elapses, clears the notification to the user", () => { - advanceFakeTime(6000); - - expect(rendered.getByTestId("app-update-idle")).toBeInTheDocument(); - }); }); describe("when new update is discovered", () => { @@ -136,8 +145,10 @@ describe("installing update", () => { expect(downloadPlatformUpdateMock).toHaveBeenCalled(); }); - it("notifies the user that download is happening", () => { - expect(rendered.getByTestId("app-update-downloading")).toBeInTheDocument(); + it("still shows tray icon for downloading", () => { + expect(applicationBuilder.tray.getIconPath()).toBe( + "/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png", + ); }); it("renders", () => { @@ -153,8 +164,10 @@ describe("installing update", () => { expect(quitAndInstallUpdateMock).not.toHaveBeenCalled(); }); - it("notifies the user about failed download", () => { - expect(rendered.getByTestId("app-update-download-failed")).toBeInTheDocument(); + it("still shows normal tray icon", () => { + expect(applicationBuilder.tray.getIconPath()).toBe( + "/some-static-files-directory/icons/trayIconTemplate.png", + ); }); it("renders", () => { @@ -171,8 +184,10 @@ describe("installing update", () => { expect(quitAndInstallUpdateMock).not.toHaveBeenCalled(); }); - it("notifies the user about successful download", () => { - expect(rendered.getByTestId("app-update-available")).toBeInTheDocument(); + it("shows tray icon for update being available", () => { + expect(applicationBuilder.tray.getIconPath()).toBe( + "/some-static-files-directory/icons/trayIconUpdateAvailableTemplate.png", + ); }); it("renders", () => { diff --git a/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap index 7abb5b3bf5..aafe097eb1 100644 --- a/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/src/behaviours/extensions/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -187,17 +187,7 @@ exports[`extensions - navigation using application menu renders 1`] = `
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
diff --git a/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap b/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap index d7575b76a7..43f0bf8522 100644 --- a/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap +++ b/src/behaviours/welcome/__snapshots__/navigation-using-application-menu.test.ts.snap @@ -187,17 +187,7 @@ exports[`welcome - navigation using application menu renders 1`] = `
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
-
-
- No new updates available -
-
-
+ />
{ const quitAndInstallUpdate = di.inject(quitAndInstallUpdateInjectable); const discoveredVersionState = di.inject(discoveredUpdateVersionInjectable); - const downloadingUpdateState = di.inject(updateIsBeingDownloadedInjectable); const withErrorLoggingFor = di.inject(withErrorLoggingInjectable); + const updateIsReadyToBeInstalled = di.inject(updateIsReadyToBeInstalledInjectable); return { id: "install-update", @@ -34,9 +34,7 @@ const installApplicationUpdateTrayItemInjectable = getInjectable({ enabled: computed(() => true), - visible: computed( - () => !!discoveredVersionState.value.get() && !downloadingUpdateState.value.get(), - ), + visible: updateIsReadyToBeInstalled, click: pipeline( quitAndInstallUpdate, diff --git a/src/main/application-update/tray-icons/checking-for-updates-tray-icon.injectable.ts b/src/main/application-update/tray-icons/checking-for-updates-tray-icon.injectable.ts new file mode 100644 index 0000000000..5d22c98bba --- /dev/null +++ b/src/main/application-update/tray-icons/checking-for-updates-tray-icon.injectable.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import getTrayIconPathInjectable from "../../tray/menu-icon/get-tray-icon-path.injectable"; +import { trayIconInjectionToken } from "../../tray/menu-icon/tray-icon-injection-token"; +import updatesAreBeingDiscoveredInjectable from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable"; +import updateIsBeingDownloadedInjectable from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable"; + +const checkingForUpdatesTrayIconInjectable = getInjectable({ + id: "checking-for-updates-tray-icon", + + instantiate: (di) => { + const getTrayIconPath = di.inject(getTrayIconPathInjectable); + const updatesAreBeingDiscovered = di.inject(updatesAreBeingDiscoveredInjectable); + const updateIsBeingDownloaded = di.inject(updateIsBeingDownloadedInjectable); + + return { + iconPath: getTrayIconPath("checking-for-updates"), + priority: 1, + shouldBeShown: computed( + () => + updatesAreBeingDiscovered.value.get() || + updateIsBeingDownloaded.value.get(), + ), + }; + }, + + injectionToken: trayIconInjectionToken, +}); + +export default checkingForUpdatesTrayIconInjectable; diff --git a/src/main/application-update/tray-icons/update-is-ready-to-be-installed-tray-icon.injectable.ts b/src/main/application-update/tray-icons/update-is-ready-to-be-installed-tray-icon.injectable.ts new file mode 100644 index 0000000000..7f097c0cbb --- /dev/null +++ b/src/main/application-update/tray-icons/update-is-ready-to-be-installed-tray-icon.injectable.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import getTrayIconPathInjectable from "../../tray/menu-icon/get-tray-icon-path.injectable"; +import { trayIconInjectionToken } from "../../tray/menu-icon/tray-icon-injection-token"; +import updateIsReadyToBeInstalledInjectable from "../update-is-ready-to-be-installed.injectable"; + +const updateIsReadyToBeInstalledTrayIconInjectable = getInjectable({ + id: "update-is-ready-to-be-installed-tray-icon", + + instantiate: (di) => { + const getTrayIconPath = di.inject(getTrayIconPathInjectable); + const updateIsReadyToBeInstalled = di.inject(updateIsReadyToBeInstalledInjectable); + + return { + iconPath: getTrayIconPath("update-available"), + priority: 1, + shouldBeShown: updateIsReadyToBeInstalled, + }; + }, + + injectionToken: trayIconInjectionToken, +}); + +export default updateIsReadyToBeInstalledTrayIconInjectable; diff --git a/src/main/application-update/update-is-ready-to-be-installed.injectable.ts b/src/main/application-update/update-is-ready-to-be-installed.injectable.ts new file mode 100644 index 0000000000..157d1bbd6c --- /dev/null +++ b/src/main/application-update/update-is-ready-to-be-installed.injectable.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import discoveredUpdateVersionInjectable from "../../common/application-update/discovered-update-version/discovered-update-version.injectable"; +import updateIsBeingDownloadedInjectable from "../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable"; + +const updateIsReadyToBeInstalledInjectable = getInjectable({ + id: "update-is-ready-to-be-installed", + + instantiate: (di) => { + const discoveredUpdateVersion = di.inject(discoveredUpdateVersionInjectable); + const updateIsBeingDownloaded = di.inject(updateIsBeingDownloadedInjectable); + + return computed( + () => + !!discoveredUpdateVersion.value.get() && + !updateIsBeingDownloaded.value.get(), + ); + }, +}); + +export default updateIsReadyToBeInstalledInjectable; diff --git a/src/main/tray/electron-tray/electron-tray.injectable.ts b/src/main/tray/electron-tray/electron-tray.injectable.ts index d7547ca57a..d8b264060a 100644 --- a/src/main/tray/electron-tray/electron-tray.injectable.ts +++ b/src/main/tray/electron-tray/electron-tray.injectable.ts @@ -8,8 +8,8 @@ import packageJsonInjectable from "../../../common/vars/package-json.injectable" import showApplicationWindowInjectable from "../../start-main-application/lens-window/show-application-window.injectable"; import isWindowsInjectable from "../../../common/vars/is-windows.injectable"; import loggerInjectable from "../../../common/logger.injectable"; -import trayIconPathsInjectable from "../tray-icon-path.injectable"; import { convertToElectronMenuTemplate } from "../reactive-tray-menu-items/converters"; +import trayIconInjectable from "../menu-icon/tray-icon.injectable"; const TRAY_LOG_PREFIX = "[TRAY]"; @@ -38,13 +38,13 @@ const electronTrayInjectable = getInjectable({ const showApplicationWindow = di.inject(showApplicationWindowInjectable); const isWindows = di.inject(isWindowsInjectable); const logger = di.inject(loggerInjectable); - const trayIconPaths = di.inject(trayIconPathsInjectable); + const trayIcon = di.inject(trayIconInjectable); let tray: Tray; return { start: () => { - tray = new Tray(trayIconPaths.normal); + tray = new Tray(trayIcon.get().iconPath); tray.setToolTip(packageJson.description); tray.setIgnoreDoubleClickEvents(true); diff --git a/src/main/tray/menu-icon/get-tray-icon-path.injectable.ts b/src/main/tray/menu-icon/get-tray-icon-path.injectable.ts new file mode 100644 index 0000000000..fe2746a2ab --- /dev/null +++ b/src/main/tray/menu-icon/get-tray-icon-path.injectable.ts @@ -0,0 +1,37 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import getAbsolutePathInjectable from "../../../common/path/get-absolute-path.injectable"; +import staticFilesDirectoryInjectable from "../../../common/vars/static-files-directory.injectable"; +import isDevelopmentInjectable from "../../../common/vars/is-development.injectable"; +import isMacInjectable from "../../../common/vars/is-mac.injectable"; +import { camelCase, flow, upperFirst } from "lodash/fp"; +const upperCamelCase = flow(camelCase, upperFirst); + +const getTrayIconPathInjectable = getInjectable({ + id: "get-tray-icon-path", + + instantiate: (di) => { + const getAbsolutePath = di.inject(getAbsolutePathInjectable); + const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable); + const isDevelopment = di.inject(isDevelopmentInjectable); + const isMac = di.inject(isMacInjectable); + + const baseIconDirectory = getAbsolutePath( + staticFilesDirectory, + isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras + ); + + const fileSuffix = isMac ? "Template.png" : ".png"; + + return (name: string) => + getAbsolutePath( + baseIconDirectory, + `trayIcon${upperCamelCase(name)}${fileSuffix}`, + ); + }, +}); + +export default getTrayIconPathInjectable; diff --git a/src/main/tray/menu-icon/normal-tray-icon.injectable.ts b/src/main/tray/menu-icon/normal-tray-icon.injectable.ts new file mode 100644 index 0000000000..53c9679b65 --- /dev/null +++ b/src/main/tray/menu-icon/normal-tray-icon.injectable.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import { trayIconInjectionToken } from "./tray-icon-injection-token"; +import getTrayIconPathInjectable from "./get-tray-icon-path.injectable"; + +const normalTrayIconInjectable = getInjectable({ + id: "normal-icon", + + instantiate: (di) => { + const getTrayIconPath = di.inject(getTrayIconPathInjectable); + + return { + iconPath: getTrayIconPath(""), + priority: 999, + shouldBeShown: computed(() => true), + }; + }, + + injectionToken: trayIconInjectionToken, +}); + +export default normalTrayIconInjectable; diff --git a/src/main/tray/menu-icon/reactive.injectable.ts b/src/main/tray/menu-icon/reactive.injectable.ts index 42622ff2a8..8c6d358477 100644 --- a/src/main/tray/menu-icon/reactive.injectable.ts +++ b/src/main/tray/menu-icon/reactive.injectable.ts @@ -4,27 +4,22 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; -import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable"; import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; import electronTrayInjectable from "../electron-tray/electron-tray.injectable"; -import trayIconPathsInjectable from "../tray-icon-path.injectable"; +import trayIconInjectable from "./tray-icon.injectable"; const reactiveTrayMenuIconInjectable = getInjectable({ id: "reactive-tray-menu-icon", + instantiate: (di) => { - const discoveredUpdateVersion = di.inject(discoveredUpdateVersionInjectable); + const trayMenuIcon = di.inject(trayIconInjectable); const electronTray = di.inject(electronTrayInjectable); - const trayIconPaths = di.inject(trayIconPathsInjectable); return getStartableStoppable("reactive-tray-menu-icon", () => ( reaction( - () => discoveredUpdateVersion.value.get(), - updateVersion => { - if (updateVersion) { - electronTray.setIconPath(trayIconPaths.updateAvailable); - } else { - electronTray.setIconPath(trayIconPaths.normal); - } + () => trayMenuIcon.get(), + icon => { + electronTray.setIconPath(icon.iconPath); }, { fireImmediately: true, diff --git a/src/main/tray/menu-icon/tray-icon-injection-token.ts b/src/main/tray/menu-icon/tray-icon-injection-token.ts new file mode 100644 index 0000000000..a1e678d107 --- /dev/null +++ b/src/main/tray/menu-icon/tray-icon-injection-token.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectionToken } from "@ogre-tools/injectable"; +import type { IComputedValue } from "mobx"; + +export interface TrayIcon { + iconPath: string; + priority: number; + shouldBeShown: IComputedValue; +} + +export const trayIconInjectionToken = getInjectionToken({ + id: "tray-icon-token", +}); diff --git a/src/main/tray/menu-icon/tray-icon.injectable.ts b/src/main/tray/menu-icon/tray-icon.injectable.ts new file mode 100644 index 0000000000..dd2cc7bcb3 --- /dev/null +++ b/src/main/tray/menu-icon/tray-icon.injectable.ts @@ -0,0 +1,33 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { pipeline } from "@ogre-tools/fp"; +import { find, sortBy } from "lodash/fp"; +import { getInjectable } from "@ogre-tools/injectable"; +import { computed } from "mobx"; +import { trayIconInjectionToken } from "./tray-icon-injection-token"; + +const trayIconInjectable = getInjectable({ + id: "tray-icon", + + instantiate: (di) => { + const availableIcons = di.injectMany(trayIconInjectionToken); + + return computed(() => { + const mostPrioritizedIcon = pipeline( + availableIcons, + sortBy((icon) => icon.priority), + find((icon) => icon.shouldBeShown.get()), + ); + + if (!mostPrioritizedIcon) { + throw new Error("There should always be tray icon which is shown."); + } + + return mostPrioritizedIcon; + }); + }, +}); + +export default trayIconInjectable; diff --git a/src/main/tray/tray-icon-path.injectable.ts b/src/main/tray/tray-icon-path.injectable.ts deleted file mode 100644 index df83a2e31c..0000000000 --- a/src/main/tray/tray-icon-path.injectable.ts +++ /dev/null @@ -1,37 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import getAbsolutePathInjectable from "../../common/path/get-absolute-path.injectable"; -import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable"; -import isDevelopmentInjectable from "../../common/vars/is-development.injectable"; -import isMacInjectable from "../../common/vars/is-mac.injectable"; - -export interface TrayIconPaths { - normal: string; - updateAvailable: string; -} - -const trayIconPathsInjectable = getInjectable({ - id: "tray-icon-paths", - - instantiate: (di): TrayIconPaths => { - const getAbsolutePath = di.inject(getAbsolutePathInjectable); - const staticFilesDirectory = di.inject(staticFilesDirectoryInjectable); - const isDevelopment = di.inject(isDevelopmentInjectable); - const isMac = di.inject(isMacInjectable); - const baseIconDirectory = getAbsolutePath( - staticFilesDirectory, - isDevelopment ? "../build/tray" : "icons", // copied within electron-builder extras - ); - const fileSuffix = isMac ? "Template.png" : ".png"; - - return { - normal: getAbsolutePath(baseIconDirectory, `trayIcon${fileSuffix}`), - updateAvailable: getAbsolutePath(baseIconDirectory, `trayIconUpdateAvailable${fileSuffix}`), - }; - }, -}); - -export default trayIconPathsInjectable; diff --git a/src/renderer/components/icon/arrow-spinner.svg b/src/renderer/components/icon/arrow-spinner.svg new file mode 100644 index 0000000000..413b93f3a2 --- /dev/null +++ b/src/renderer/components/icon/arrow-spinner.svg @@ -0,0 +1,6 @@ + + + + diff --git a/src/renderer/components/status-bar/auto-update-component.tsx b/src/renderer/components/status-bar/auto-update-component.tsx deleted file mode 100644 index 0f6e69c086..0000000000 --- a/src/renderer/components/status-bar/auto-update-component.tsx +++ /dev/null @@ -1,107 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { withInjectables } from "@ogre-tools/injectable-react"; -import { observer } from "mobx-react"; -import assert from "assert"; -import React, { useState } from "react"; -import { Spinner } from "../spinner"; -import type { ProgressOfUpdateDownload } from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable"; -import progressOfUpdateDownloadInjectable from "../../../common/application-update/progress-of-update-download/progress-of-update-download.injectable"; -import type { DiscoveredUpdateVersion } from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable"; -import discoveredUpdateVersionInjectable from "../../../common/application-update/discovered-update-version/discovered-update-version.injectable"; -import type { UpdateIsBeingDownloaded } from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable"; -import updateIsBeingDownloadedInjectable from "../../../common/application-update/update-is-being-downloaded/update-is-being-downloaded.injectable"; -import type { UpdatesAreBeingDiscovered } from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable"; -import updatesAreBeingDiscoveredInjectable from "../../../common/application-update/updates-are-being-discovered/updates-are-being-discovered.injectable"; -import { reactiveNow } from "../../../common/utils/reactive-now/reactive-now"; - -interface Dependencies { - progressOfUpdateDownload: ProgressOfUpdateDownload; - discoveredVersionState: DiscoveredUpdateVersion; - downloadingUpdateState: UpdateIsBeingDownloaded; - checkingForUpdatesState: UpdatesAreBeingDiscovered; -} - -interface EndNoteProps { - version?: string; - note: (version: string) => JSX.Element; -} - -const EndNote = observer(({ version, note }: EndNoteProps) => { - const [start] = useState(Date.now()); - - if (start + 5000 <= reactiveNow()) { - return idle(); - } - - return note(version ?? ""); -}); - -const checking = () => ( - <> - -
Checking for updates...
- -); - -const available = (version: string) =>
{`${version ?? "Update"} is available`}
; - -const notAvailable = () =>
No new updates available
; - -const downloading = (version: string) => { - return ( - <> -
{`Downloading version ${version}...`}
- - - ); -}; - -const downloadFailed = (errMsg: string) =>
{errMsg}
; - -const idle = () =>
; - - -export const NonInjectedAutoUpdateComponent = observer(({ - progressOfUpdateDownload, - discoveredVersionState, - downloadingUpdateState, - checkingForUpdatesState, -}: Dependencies) => { - const discoveredVersion = discoveredVersionState.value.get(); - - const { failed } = progressOfUpdateDownload.value.get(); - - if (downloadingUpdateState.value.get()) { - - assert(discoveredVersion); - - return downloading(discoveredVersion.version); - } - - if (checkingForUpdatesState.value.get()) { - return checking(); - } - - if ( discoveredVersion) { - return ; - } - - if ( failed ) { - return ; - } - - return ; -}); - -export const AutoUpdateComponent = withInjectables(NonInjectedAutoUpdateComponent, { - getProps: (di, props) => ({ - progressOfUpdateDownload: di.inject(progressOfUpdateDownloadInjectable), - discoveredVersionState: di.inject(discoveredUpdateVersionInjectable), - downloadingUpdateState: di.inject(updateIsBeingDownloadedInjectable), - checkingForUpdatesState: di.inject(updatesAreBeingDiscoveredInjectable), - ...props, - }), -}); diff --git a/src/renderer/components/status-bar/auto-update-status-bar-item.injectable.ts b/src/renderer/components/status-bar/auto-update-status-bar-item.injectable.ts deleted file mode 100644 index de8f1518e8..0000000000 --- a/src/renderer/components/status-bar/auto-update-status-bar-item.injectable.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { computed } from "mobx"; -import { AutoUpdateComponent } from "./auto-update-component"; -import { statusBarItemInjectionToken } from "./status-bar-item-injection-token"; - -const autoUpdateStatusBarItemInjectable = getInjectable({ - id: "auto-update-status-bar-item", - - instantiate: () => ({ - component: AutoUpdateComponent, - position: "left" as const, - visible: computed(() => true), - }), - - injectionToken: statusBarItemInjectionToken, -}); - -export default autoUpdateStatusBarItemInjectable; diff --git a/src/renderer/components/test-utils/get-application-builder.tsx b/src/renderer/components/test-utils/get-application-builder.tsx index 80a6627f50..e6fb639adc 100644 --- a/src/renderer/components/test-utils/get-application-builder.tsx +++ b/src/renderer/components/test-utils/get-application-builder.tsx @@ -43,7 +43,6 @@ import applicationWindowInjectable from "../../../main/start-main-application/le import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting"; import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting"; import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels"; -import trayIconPathsInjectable from "../../../main/tray/tray-icon-path.injectable"; import assert from "assert"; import { openMenu } from "react-select-event"; import userEvent from "@testing-library/user-event"; @@ -194,11 +193,7 @@ export const getApplicationBuilder = () => { const traySetMenuItemsMock = jest.fn(); mainDi.override(electronTrayInjectable, () => ({ - start: () => { - const iconPaths = mainDi.inject(trayIconPathsInjectable); - - trayMenuIconPath = iconPaths.normal; - }, + start: () => {}, stop: () => {}, setMenuItems: traySetMenuItemsMock, setIconPath: (path) => {