From 0654172fa2fd4aa7cbf93a59b360b7eb4dbe3daf Mon Sep 17 00:00:00 2001 From: Eric Date: Wed, 27 Nov 2024 13:43:23 -0600 Subject: [PATCH] Website: Add app library & app details page (#24205) Related to: #23792 Changes: - Added /app-library, a page that displays information about Fleet-maintained apps - Added the app details page (/app-library/{app identifier}), a page that gives users detailed information about a single Fleet-maintained app - Updated the build-static-content script to add information about Fleet-maintained apps to the website's configuration. --- website/api/controllers/view-app-details.js | 60 +++ website/api/controllers/view-app-library.js | 33 ++ .../images/app-icon-1password-60x60@2x.png | Bin 0 -> 3863 bytes ...app-icon-adobe-acrobat-reader-60x60@2x.png | Bin 0 -> 1206 bytes .../images/app-icon-box-drive-60x60@2x.png | Bin 0 -> 1117 bytes .../app-icon-brave-browser-60x60@2x.png | Bin 0 -> 1966 bytes .../app-icon-cloudflare-warp-60x60@2x.png | Bin 0 -> 1016 bytes .../images/app-icon-docker-60x60@2x.png | Bin 0 -> 977 bytes .../assets/images/app-icon-figma-60x60@2x.png | Bin 0 -> 1372 bytes .../images/app-icon-firefox-60x60@2x.png | Bin 0 -> 3915 bytes .../app-icon-google-chrome-60x60@2x.png | Bin 0 -> 3144 bytes .../app-icon-microsoft-edge-60x60@2x.png | Bin 0 -> 3365 bytes .../app-icon-microsoft-excel-60x60@2x.png | Bin 0 -> 1629 bytes .../app-icon-microsoft-teams-60x60@2x.png | Bin 0 -> 1924 bytes .../app-icon-microsoft-word-60x60@2x.png | Bin 0 -> 2788 bytes .../images/app-icon-notion-60x60@2x.png | Bin 0 -> 1232 bytes .../images/app-icon-postman-60x60@2x.png | Bin 0 -> 1068 bytes .../assets/images/app-icon-slack-60x60@2x.png | Bin 0 -> 1472 bytes .../images/app-icon-teamviewer-60x60@2x.png | Bin 0 -> 2338 bytes .../app-icon-visual-studio-code-60x60@2x.png | Bin 0 -> 1306 bytes .../images/app-icon-whatsapp-60x60@2x.png | Bin 0 -> 1538 bytes .../assets/images/app-icon-zoom-60x60@2x.png | Bin 0 -> 3531 bytes website/assets/js/pages/app-details.page.js | 47 ++ website/assets/js/pages/app-library.page.js | 25 ++ website/assets/styles/importer.less | 2 + website/assets/styles/pages/app-details.less | 418 ++++++++++++++++++ website/assets/styles/pages/app-library.less | 205 +++++++++ website/config/policies.js | 2 + website/config/routes.js | 14 +- website/scripts/build-static-content.js | 41 ++ website/views/layouts/layout.ejs | 2 + website/views/pages/app-details.ejs | 88 ++++ website/views/pages/app-library.ejs | 64 +++ 33 files changed, 1000 insertions(+), 1 deletion(-) create mode 100644 website/api/controllers/view-app-details.js create mode 100644 website/api/controllers/view-app-library.js create mode 100644 website/assets/images/app-icon-1password-60x60@2x.png create mode 100644 website/assets/images/app-icon-adobe-acrobat-reader-60x60@2x.png create mode 100644 website/assets/images/app-icon-box-drive-60x60@2x.png create mode 100644 website/assets/images/app-icon-brave-browser-60x60@2x.png create mode 100644 website/assets/images/app-icon-cloudflare-warp-60x60@2x.png create mode 100644 website/assets/images/app-icon-docker-60x60@2x.png create mode 100644 website/assets/images/app-icon-figma-60x60@2x.png create mode 100644 website/assets/images/app-icon-firefox-60x60@2x.png create mode 100644 website/assets/images/app-icon-google-chrome-60x60@2x.png create mode 100644 website/assets/images/app-icon-microsoft-edge-60x60@2x.png create mode 100644 website/assets/images/app-icon-microsoft-excel-60x60@2x.png create mode 100644 website/assets/images/app-icon-microsoft-teams-60x60@2x.png create mode 100644 website/assets/images/app-icon-microsoft-word-60x60@2x.png create mode 100644 website/assets/images/app-icon-notion-60x60@2x.png create mode 100644 website/assets/images/app-icon-postman-60x60@2x.png create mode 100644 website/assets/images/app-icon-slack-60x60@2x.png create mode 100644 website/assets/images/app-icon-teamviewer-60x60@2x.png create mode 100644 website/assets/images/app-icon-visual-studio-code-60x60@2x.png create mode 100644 website/assets/images/app-icon-whatsapp-60x60@2x.png create mode 100644 website/assets/images/app-icon-zoom-60x60@2x.png create mode 100644 website/assets/js/pages/app-details.page.js create mode 100644 website/assets/js/pages/app-library.page.js create mode 100644 website/assets/styles/pages/app-details.less create mode 100644 website/assets/styles/pages/app-library.less create mode 100644 website/views/pages/app-details.ejs create mode 100644 website/views/pages/app-library.ejs diff --git a/website/api/controllers/view-app-details.js b/website/api/controllers/view-app-details.js new file mode 100644 index 0000000000..e757164e3c --- /dev/null +++ b/website/api/controllers/view-app-details.js @@ -0,0 +1,60 @@ +module.exports = { + + + friendlyName: 'View app details', + + + description: 'Display "App details" page.', + + + inputs: { + appIdentifier: { + type: 'string', + required: true, + description: 'the identifier of an app in Fleet\'s maintained app library.', + example: '1password' + }, + }, + + exits: { + + success: { + viewTemplatePath: 'pages/app-details' + }, + + badConfig: { + responseType: 'badConfig' + }, + + notFound: { + responseType: 'notFound' + }, + + }, + + + fn: async function ({appIdentifier}) { + + if (!_.isObject(sails.config.builtStaticContent) || !_.isArray(sails.config.builtStaticContent.appLibrary) || !sails.config.builtStaticContent.appLibrary) { + throw {badConfig: 'builtStaticContent.appLibrary'}; + } + + let thisApp = _.find(sails.config.builtStaticContent.appLibrary, { identifier: appIdentifier }); + if (!thisApp) { + throw 'notFound'; + } + // FUTURE: make these better. + let pageTitleForMeta = thisApp.name + ' | Fleet app library'; + // let pageDescriptionForMeta = 'TODO' + + // Respond with view. + return { + thisApp, + // pageDescriptionForMeta, + pageTitleForMeta, + }; + + } + + +}; diff --git a/website/api/controllers/view-app-library.js b/website/api/controllers/view-app-library.js new file mode 100644 index 0000000000..1ea01f1e25 --- /dev/null +++ b/website/api/controllers/view-app-library.js @@ -0,0 +1,33 @@ +module.exports = { + + + friendlyName: 'View app library', + + + description: 'Display "App library" page.', + + + exits: { + + success: { + viewTemplatePath: 'pages/app-library' + }, + badConfig: { responseType: 'badConfig' }, + }, + + + fn: async function () { + + if (!_.isObject(sails.config.builtStaticContent) || !_.isArray(sails.config.builtStaticContent.appLibrary) || !sails.config.builtStaticContent.appLibrary) { + throw {badConfig: 'builtStaticContent.appLibrary'}; + } + + let allApps = sails.config.builtStaticContent.appLibrary; + allApps = _.sortBy(allApps, 'name'); + // Respond with view. + return {allApps}; + + } + + +}; diff --git a/website/assets/images/app-icon-1password-60x60@2x.png b/website/assets/images/app-icon-1password-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..99bf1fe9ba4f885b46c4b5882dfe87289fdf5428 GIT binary patch literal 3863 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

Mxws_#xkY<-5?kMHr1UF8D z07ranbVJPQr|H9FcF*=CVqe%8ULHJ!j`&V351q$Hd@KC%Vtvx`Ijj*bGCJ-9re^cx zc?g|{n(eMb&7|v4vmeeoxS>@r5$qUOagy&Y!8$6M!rz^0uWP`^xJ~H;&STtWxHRYF z&XS7u182-MlZnJ6AL@q5*UJ5Z%1s?Ixz^NcB{&xJsD3TS9Y_+pgP_v|xP)!y8!85- zK|FYK!kHX*I%kUR^GBzfA(6|S6E+HM5h7S5(wS0yCd9`jAjlQKfm&c0nrV+n zW<P($5BOq_j{}1BZF4TFvAZq5 zjqcpocu|erWse8#-LC;C)+X}=HvkL&S3jnhV0J97Lvv%HB6 zL>*R7>v#coW-(hot)eSDEEm8=Jb$3HFTl*}MfDS7wZ7_}HhG31yms3hLm*~JI4^BZ zVhG5y7xRuYz0Pw8%*rotSmFd59h&97UgOgyVL-Pk`Iy8^b zGfcudieVDs2qxmUiB(-IxB-K>F4C65z!f;epXrebNI1kIJy8Myi@0o!nbA9E)<7^$ zOc!hbRPNRp2pGgo>&vlnqGT3vg@so1e6ff>THOX(WJ>m$MO>h`OtI;GxWv_=bO#Y& zoD~;)u>bQyacQ>zpwhstwl25;Kp(_Fz!M;@PMZdvYHH z@&yPz)&*{k8z5j1Teq~TIfx|?a2*76c@Q^1z#xV%*W&CTu7Q9&Cs@RpPmhAyC^*FWY%3Ny zvCJIe(&sdOimZ1vGl)fs2%p+J=)fSBojXn2OF6rrC* zTFT%^ogYT+EA5c)%pJv9=Ln!`vrS1dIYLYqteOg?v|5njVFg=di>_o_nWh$dYTcCH zJYKAQC6}tJ!Q&VI9%5Hye}-fu;2USVe=^hK#il3SSnQ<4qI>@?$BTdVx3KkvZx^NT zf4P%bm*=ILZa!m_q=ivGemCR9P2sgWt**!E&KgtYctjZ?Rx(dLB~XYm?IB^P*lT?W zv|4s9v~L(JHW^U@fj-N#+`>??F0jEqEN`N;b-R?+gEt9v41ruKnGU$yGE`h2yId&{ z)MRmpKaXiETzC+f&mhJW)c)sw8gPgucDY3m-_bb4)`@bB>38uQ%OMu$E4m}1gG0PK zdHn+S(ttrM&Tg$(DzZ4l#$U3ZWa@H=U3WElsXIIzVvBbfBzpS;%_7#W)k>YVh}{J* zix|*&EjU=jBJ*D0=;^gY$f+?;;pFP)=kMg?>f_|= zS#B5bHZ8WxP2df+UM=ALTK?)`gB1XrFV~#BO}V<90bmtq;ralFBYC@y2LQhl^lu+d zS7JrS6ZjvUcn>+Tr2O8-9Qbf27Igss+0QFD<;0@$6RfI4100D}T>*ZQy@Ug?tiw;p z0S0VMM_2^j2F}E~&aio8`a-Ph0!!}`6tS)=Y`q2K#JX}=cmQMu0XXou9N2*!*nu6` zfnUmj9r$m8#aEi(lSObzDc$3vH87(OMFI_0!8B|h9oT^#*ny3}LM2JT1Q{qSl7xkC z0*kMhJ{2c=gEV^Dxop@Or(ADTlr#>F!25`zI&TeQ+R+moR-dyj7bpCQU`{o)?iZ16 z=j>rjX~j|K9Y%O}c5xh!Gg8GOGh({0U0*o}{-&jF@+#C?$rxOV)R^;SZM~}{`Yp2jwP@ztEiKx2>mkxOWi1<=Dh@k z1scjz>NeUs!?a^w%)otX_97C2!$@!(hvxh0zBR$|qAS9VVK~cK0Cy|m zRyQh$2{^>{c%-b;L2I;TIOI&gVl=XLZ63`;hC{0!%?4n?5ugV)R_<|Y3^_$f6L31x zPZA4uBw*gSfZ7{?*|4AXW3R+0Wv2PpL-yhS(-s&>4@QgWOwaBT{^eoqIBk`DEaBUMwRa5WCK z@w}e~#-h==0_PEp%ldmA%ov*tCPGqOvf^qnV+oe}l7xl{;8qFmzP@;|p-%%O+cD?)4t58NIgYYJ;CZV#4(~6k>k8J& z3j{uyIO`p jFX8=KtT5cUt`GhJz|!rci$Qd+00000NkvXXu0mjfyAmR7 literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-brave-browser-60x60@2x.png b/website/assets/images/app-icon-brave-browser-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..53fe7548c40aa1b0009270985b9813df89bf42fe GIT binary patch literal 1966 zcmV;f2T}NmP)gDI{;^pe%f+?;;^gb%fh(*Ez_^|NsC0RRH4T z>ifirW0{`{!|7#%ss(}As5dVNc|CM0>qLlx&kpD(1|G%LBpK$-xzxw<9 z|8+6{-_QR=Dedp_>g@3U%CG;RaQ|u||4bSGQ49ak%Ky~A^7HopP&faVhyQe6|LEoa zt)l;ndjDKR|GBUKi%{n0?d9j~|J>LA%CP^7QU8ii|3@YN#k~K3Z2xFd|5hsW_4oh4 zp#Q+1%Lx3S0000GbW%=J01%KMpWokL@9)nbFwdYc5CE%C000JcNkl1T~7T!cha_d{RL#e{EXQzLLe9+e?w5xJ-cyABNq z7bSp>?cljEua%7!E=B81M zbx6&27xeqg}M-vMo?6#Wl>=y@T-d~oF?}_Q^yR= z7-wTg{0kmq51;3Od?8TAW3)VP2ET3xcb+XGz@i_1+jdY+F+P{p zL?+MU#w~T6Ru?t9g`e(8um~PV3{m>t&XEtoH5D1GCckD}Jp~q@4anNbP*9q#&eBNY z>G@=B1Cl$y#I2GVYZiGmM4{-AXwp2{rb?3A!Neui*64^`mJ~ZGSKQmWBFVkr$R$}i zng;Llob$M}xu@I*mUWfucF!wz+8CUGytrXZy$oa2EhUM_d%&_<=_p=YA6kzT9~`|4 zY%H&b8*~8K=|Xzx1wG{lhZ z4B~N*g=&3FMs2FDN5Lyq3Ty@Q#pcy=oa&X2$*duuweQShS^F!ULA zxm;vn>7>)sfB8XhR$JAf?06ZwXcWkO`o9l?8BM1zsoL2S6?ohJc+}%VtxzE&p{f#; zW80|57(jkcU47Ihgu6@&MvzhP@=c>Y>fcHfr=Ak7r(v+CJ{kMUmr`8bUlV@3Wp3}t z94 zG*2LXGP{(B_eRSxtuV~aHOE7yWiyu7ZH)?en3({eC>F_SYtwt8C)hGoA_783y}wpuWD zluEhj1m@A}K_#XmnBpkn>cQ=qE8yzD_#Y1Oyn&KhnC@Uyr-!w&MhI5!XYL@+17l=n zIe}db7^WHLsBLuybGzr9g5sTdG8mn=WwCkw)Pq?EZ=~`3r#CPU(0JU{Cm7X)?e+e|r} z*N!UBqg=GY)v_NWl>TZNOwX46>vamdV_hHo1$-#Qpopjbi~s-t07*qoM6N<$f@*r` Aw*UYD literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-cloudflare-warp-60x60@2x.png b/website/assets/images/app-icon-cloudflare-warp-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..3c38697db8ce0a5804bf9597c3ea0fec61900350 GIT binary patch literal 1016 zcmV*D0<;^pe%f+?<;^gY%=kMd^=j7z<;o|B4|NrxVAmZfe`mR9z@8kaU z=k<_0`}_R--^csUtM;H+`M;0!h%Wy3@$K*O>g@3QxLEl3`v3a#{_D^8uXE<-?fvJ~ z`p2F4xPtq_aQCQY`?E~)^Y;Js=ls^6{_xxV;kW$CgZHp>{L+*8z>xKrO8eKj{oJej zy=3z9_5S9=_orqONHhfi000eiQchC<5buzm-`~$*ARsWH>(6&40008-NkluBX4v=#l=qCbQN=DOuZvZ~!Um`hEdvn>2vNhA)3Am$tYHmnn45;bqW-Y8%lATs zaOh70a_VI?Py^G^QDwF-9}Y+4Qm!u<_FTegO=ZF@!q27h;5E5cFpvW?moLkKMo`E0zL-446?VG3jC*lKno zJjm}p0XT`~x4~Y1*n`+f)|sh+UjW{m@A5*)Qu}b&V%Bt#8K$1d+oQuww%X}%IGh9| zZ!TqUqH#JLZg;Af3mfOGw={U*5`mf&_ASogY41Ahi?G2E4!xbra}F%%2Cn<`8p5f^ z)%%n)GK1597+U_mSMSh(9)qj(9^?39d3@61E3nIZB?#1eKfo&voc4$8So7HA>CmXP z@0BLCc(WRhJG zkNkfA*INy1Si>5I^fatt4Qp7#8s?_q9}O3E1h%+CzrPDQ=3LytZqq8_C_9>lQ7Yo_ zzHJyr9hHsD2Cf%*LBlXBY8N{?UP&?P6^zu)+{SV}dF@D%+-28}_SIEhw5ngaS_Tqh mSIfRtw^4ppiH%#-^}&ChAp8v|zU@~40000*D0=;^gY$f`JER*La*o%F}p z`#E>-j!iHv$<*rA;{4R&{D7zQPH&r)0000CbW%=J0N)_*pO6q>&oB_r0W>-` z0008;Nkl`y!-i#PGdq4Re}frs?*M_<@5K*aT`SO8fT`_&o|gYb`bUBqk#YhUvk630KCZxeR_Hr#xCiSgaN>Bl1nXI%=O984K^)-v4DbLC z@OOk`cFEK-%%V%;0UqE1{#Rjrfo%VmE0Y?YUXufq`hx`6=>iQLRnAbNKk(||8sJ`G z-V-b%CVPO-#kA}J7UzPn569<1I=2nWONA)|Sn2>M{j92mnw7p}XZfz)M%SpP;JLU) z0qAG`rBGH1@>bAWd`|KVT;0lsdn~GjN-1J?;pi4+6;5w3SCR|Cxw5>}5z`Nwk{;eh zwfP~b;XJC(J2lMjz=9fvxYlJr4%fFVAHkAeqX6{tykX&P%L(~it@3)85|(q3$7v0l z=I|KavX+VNB~2RLTyfN8()X#*tSwl=ElrlXD>sJc;7wPscoI%Jav3}c3z~)>!2%?-4IbK`}U?O>IXoUF$%?9AL9w1uVF zLaR2g`Hylcp*<`OcDV!t7=E^P6EK1yHgJt#nHsnzFmMXD9yb47kwZJ!@Q<&QLkrlv z=U75lFi6(C-MrI(l*>(vc8y>i!J4p~;(I5-TChg2PPx6WrU|F~rcH?rt3hL}62LmL z%%^e8*l&=rc)AnwZ~5KgB?COb1Ka@a?-kfLEWmp9IO***=l)*o4!u5JWyjEQf<9i} z_s`=B_Kufsc=S1-aaw}KEKV3)MpEo9_7UAzJ%n?#*7G7mcT^cWI$1i}#R=V){s*n} zXxW}}w5<3XEqnbsOy?tgyg;{G$t(T%V5Qq%BtpIBhE5{+00000NkvXXu0mjflD+oC literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-figma-60x60@2x.png b/website/assets/images/app-icon-figma-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..a30d4e902425c37c2c51753701d39a6a9a87ce03 GIT binary patch literal 1372 zcmV-i1*7_jP)*D0<;^*q$-|yn(>f+?<;^gY&Y`cy|8ipTP96%+ zgBra4%wkr;M&LBRpljs zr6_NUTt$Hwo@y^mS*BM_Fhop@Pe@ojIOa_thEU9TOS5=Ovy7LpfPsX6fP*Vub4WT_ z%wt!xT2LosOo2WsopW)z9NynX=b%^kE&>cnvjN)%fx9=SPV_80(-GD3JQyMqPKFP z5#yk=EaJ_@_G1hb7rPnRVgoBHjvmWs!7fl<7q%FFdY4ag7Tv1 zF%UsRh!2KKtJi

uRg(*G|7|ICp&zb{2BBa8Z;Ak2BT*JL-@I=l(Lw2|HUX%7Jr} zVGhiZiExRz9Jo#{Nq{H9&BLMJboeSP0*Cs^@T3^rMuk_yVsNOR2v3N@J4AR=6kepk zrLZU*Dv{uQad@8uuZqL{j}y-6y3`;J0}XB$h0lrbxG20wgiE4ukqEU#ICmfd zFBHizT#3MYK!;(xdAI|pFkj}l1ehc9;e|br1w(G);qZA8D6o^BdajVcN$?pL&hX$R65PjyZC<^P6J8d-)Y~L@g$ob4 zcXPoS;qRp90g|V|{JSfiaqp1{ha4CZw3meN$k2G?C6^Zhr<_*=6^5zimp(%v174YG zcCj~pXAEVL3B0Xi%q&kaa`1>_Ot5@EhvsAW?>lQ|-l` zMzi(q5YDu^LpU)sebvW~;-I7~J9eb}pq0;gv}|VH&7)=6naa_!R--nbAKlO6W#h71 e-9J89HSIsfpg+`TKZ1q;0000CzCV) literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-firefox-60x60@2x.png b/website/assets/images/app-icon-firefox-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..1ff3b7c35dec0ca605b7e65c2011ed7bd56b3270 GIT binary patch literal 3915 zcmV-R547-!P)*3?;;^gY$fh(<;pFP)=kMp|=j7z-z^t0RJ>60EPeR z97O-;L;p}4NfmVesQ~}60RN@{0BP>#8cF}G0sn>r|GxnNc=-Q-2LNyK-WF2--2wn~ z_0JAt)e&6(#R321K>xY{|Fr-XNyXU{SK=5=|K2+PqW}Pq`TyEB|5q6QEh+(E=o&@8 z|APhzR@wj70s>v+5>3nhd+SL)J+me`tpS(wGA)|_)iEtGp}+=n|IjKy9D>>+L-h6d0Hg0l7<>QA zBmc%9GZt+B>=*yD13e*$|F;kS_T2x!7y04s0-EFnX4)nre(h`||NQU-gy8@3jpidj z|L!d1O(pV1B>wUA%qV{U??dWZHvC#D^~>Dff3Wh1p4By5%^pejb`$^exy?Y9BPx&H zO-z=|{q3p80#C#Fw7=draEGO8lZ9b!EnSj4PU$`@-_;xc*vA}r#Rf#Q6Fj9GGMn;V zbyzTI{po1jLMi{?B=LP6_LC3elEXGoSu+>RRJw-jNk^fi*W`l_Q)s-s(a zkA;eHUP)&Ex+}_WDBsH*@V5=a)AT^Es@qD6|JQ}RBW!k9NX)M!-`^emsRJ>r^@geH zZI9iNp4gh($4s=pZQvlx(@t=@j zAkQEmFwZbb)5gyL01NL)L_t(&-p$(yR8&d8QRJf5d(SdWwOZ%0p@=+%RnIB_(P zlRX^jo&?s*1p$4Ms`S}#QPw4ae5UN{in_A2(%HjRu9W#XW3Rki8f+LFw2NJ=_c`a# zustzo7iTn8_HcP&8g_4wUZ=ReFjYPUlXl4!tUYDVUT3)nKCM@8Hykk?a<6XOtx{($ z(x z;ij7s;_dDOk3RU|li!-EyoJnG`_+{v2G`DYyv6=daNn@I0Vl)@_|7|-`<@9$EK)`C z23zroz;pWnmSuk&`Owh&-~wio=7r%t`8$qS%F`R353{X20k~p!zgl^+zYMtt@GuFB z6DIgu3A1s3loo5u>pI+eO}|zzk)K8kNdk;X+mE;ppETU5CJxKe>9M|lb{U>~4InmefWmntA6b3qp5-6M8p-|OriA_~cq(9%mPInMin{<; z%$hX|?6j*c=^Joy@PMFDf4}+{ZLDzfmW2Ke@Cv}^Yh0u%qrD68%vs2^E3Ulcg1#4D zmogv(aM-|Dz=3ZSY>BsTHDnG?*Rsg984b?Evr+h>a|Z(s02~woH_b+qHoQL^*Ri}~ z0^SNZTgxIBj=IBnxMtRb^Ul3uuzk|9@GySolDF!qQ~#z}YgNh%rB1`!CtL*h%BwEu z8*p7Pn{*mrI^nxj_i6#ZL9+&{bs-l!3%6bhSR64X9m*#S_!9@1%b%N&Dv8S6TIwWR zd+Fr@#-st$q;2FznwzxGV^sc&PFc$$*IqlS*eN)_AA_|=4A^S+Y0^}FbZW^8A7r{< zrAjGv3f>Kv@0Rw66U{z8oA&K%TJcT^Dhs(}>mrh`b!^LXYq1k>?KObKZe6UvHlq=@ zX-le)l0{pk{GJb!JE%yhemH+OU}dT0Rc!QSu-PuJuy-yg*(YVNic7&M>xFA?2P~Ib zy<3Jj75rWwMSg&WO}P~+T%i&>YE*-6c%Fn+OC76)7bP%Qbl$qj$80wH+$vRKkvrP; z!m|h6cuham)igj2Cju7kVq8;pdUMG;o6M9KWLd@{#X8}6fce#=z@ZY3$`J6r#arV0 z3mH+#jx18D51x68XpGCaBb?0OO-;)Sh9|@enbVs~7JtI!QDVj-ceU$-Yh>dNu)z?4 zS#N5>OVDuKzaWFQ+gwgfHQyoGyC}uF;4l6gj!bPz8aZ?rUauWxq))-(Pg7Z5kSwJ^ z4?J`BEfVfH>WJvIbLQZ^{%$T4Eo>yA;Da0~L*yA(st2x6!B_qp+?<4;WYjWfVfRPn z$P9urQsD}A+_-jqqrPR(?ecQ!04J|a8mY*V7THqJ6m7`NU=b?iE?w}=5|%GMDtPaZ zdlZ>UgN7~ego4H9@IWDtQ{2ZN&wEYB857*`mRVo4apT5yd-q2q?;MfDWnNm)uqg!v z`{H~dXCfJbMfSYXIXwI3TW;$BhnB5hU$${wOH0d+y-P8l1T0^4+g*MrlC{8!4FczR40{NGI1~nZ(&i zld5$z-gYnG8|is`p8Z8&*)q6g!G{4u9wTIw7Bp;;f;r1g=IG>zL<&tdv2iTPV<6)vDJm^!vKc>o*qk{gQ(|Ovw1o#Ohx0mzD*=lO`3imq zS-5Orc{z%=-9J{!qBPO4l>lC3%1n=mv_g%Gi_3zVm6cV!q4UPuDsSdb3AtSh;nI$+ zzaO%gwkVC(uz`!*w`9p8lQ}9XJth$>0v73eK*v^BI&2r<0J!LlH?P$inbWX=^9&`} z$C?wB9>rniPPrhfQ#d~#u-LA1`5~8=W4GDW9LD9xNLFZWLuVPeWC@;{agd`>IWaMD z3fL)As>gK(Bb8WdY?r)S_q~AbU$}Alr5P1j(!z#LNm{xTu*C}53YKK#z=l;iU|MU3 zL+&ene)9JlX!L!nO_6u*TD!J+=NQ<8i!52X6R%#GR;v}25v!Hp4Y^--4&y>r4*4R$ zm^ENptx*54fkxb~*L}ES$BtcV4_K`jrsa4uY6Is%;az5eY1USj+$p)ahTH}naLsse z$jT#`;NX-HOjLOz5| z<7sK!MQ|Lz^z?N0OHOW1PR^>%VdQmo$f~_&u=;<4FgZq%Kiz><<7sR>o`EEi7!!lP z@kguARdcLii(O}L|&p8_7_rcd5JV0KAuT|#mq>A{;*0Hj6=p=i+hN= za!AOGXA!Q0U)NSxct2&VNMqqzizO2e2gXvOqoe7!JUuY-jI4Z~IAvBj#DC-b1$A|G z#2;DEHhJ&ftWU`e^-fvChi2;hh<;l|z&m6B*mbWiu*naEUfJ$57ZExYK<`FDh11@;O zZ(jOgte3j7eb`(sLTQbC{eHS#M6pPg#kgHJEGyqGEA!1x2_o6AXx)6ZJ%9g8(R9HA zk4cXN3YNKn$eLRHFtSZlR?7iW4oj>5c=dw$$b!`$zhuA$p(b!7LIf%jK4Z|UPQm%F zvujxlTWmI8Fd^efWuzxYcpz@ww7nc>CQD#=c(`xTpc#4kVR9c)hSpzY?~zFjn=F-;ez)IrG%`k zIKfXv)CjpB$uw?~sWj%zX=YP#=7)wLL3>d5gka=lO=nq}wdS_K(G-6kK^N#;e<4l$J6tEn2hM42OQ* z#S7~yE4O=fBaD-tcN^V3Y20kbI4x?knFk!J`|7K@HG3+$6-Mdpn$m3GG;xkEJa%kh zc|bMJw|ik^_B<}DX=Ve5P1%#*GoR<0Id}U!N%J)mHt;uJ!&TH1u)u3u`Mjw$Xl@UN zio@+GST?V1ZQaf6H{blD^|g2B3RFMrwvWKN?L)tA`kArg`$~$NzJ!B8^PG8->!wX#J95((t3y=S>#na4 Z{sXBAQ^B4b*D0=;^gYz-|yn&>fz+-;^gb$tR{2FuU;^gZ8|Nq=F zC*U_L-83j7lS1S>F5WdM{J#(4IxYOY2mHPY{J#t(mPP!lcM=6_0=Rh+2z!N5zM*P7Q{J;?)kU;#x87rMiE}~BS!51i+Nc_erET2sK z!yWs)1uULR<~}jzKQZY+GukmGDx66!piTY9EHI-_{KFso!W;a<9WkU({Kzl;#wRhQ zQ7xcNGNw`=k3aBz9r*eC`^GBre;oGr`t|ns>+JF9>hM#R?#boR{_n%;LNzFS>EG_= z`t#tL!u5^0^yTO5_sz=t<)`LoU;EQt-$6F0)wYt%qx{cJJeNJ=?fl~H{8N_g_1D&e z!5_Tl35zr6FbuWIm%?9Xs1aQxS8PO)iAr)4jeNvgCqimNoMvM%Aj zE8)H)`0wxe_U-%T4y;g|d1l54qv?}vZrbZbejW$R*B zLXk&Pl|k!HK^~7jrB*ZH!7#-@E73YB&^Rb!p6^DD?bGPm>D<@g+0FXw!`9=!)wGBFS!m{(dkM9cZ%K|qpFEAaNDW3Wi^ufr#U*h8fv&Ghs4NgC=b$mG!!*e;g}t0 zYOHY=iBQy7!ADu>YOb?LU{`Zbf;^~duCj_JtGSF9&_8&wPxmMY!vGY=uOMwPWUNr| z2(5=H9g9$hehS_}#7U5@y@HG4Jv@ys&qyLJLZg#^vj2D_nN0rhN7dbWldk$mO4+Z{ zVb|n8fa}vG^HGEVPapL|TYVEQ*XazXaSa`Y*HiT+c$?0UuVvEHCmf%O%^Cv*jLQ#$Hl=) zp3jTc30y7%l|Xd$VyPEfE`qDtm*e63;CXb>%VLRRV9I(jDyp$?e)JS97+oFNx5#$za)HacjoF-JR2VX>B43!#MsChN&P!n~mT`%px1RFr+~O z?I7tUnzSjgL`$Wlr4g}eZ6UpE+Eqh>rKFLdRP3@|R^kPV)OuNof-Xe-Ccfu6=gd3p zkmgMO6kNFY@tkuyv9nsoGHu~444Oe$b3*0IZ1O!2E$li!4czr|$?^J4U9YoS)H)_(lF9Bg=)e!Mn9!Mh*f z@)cvTe$=zog6(y6aUc?j^oe@=dUgH%^n=P_;2rnZAz*fS@wism-c&Ndz#;24LcqJO z+a#7>HQ(_T*Z`f@GF+DFpRzf8#dY1vfnLloxh1-Mudh&R6(w05F2w#_QLq9G7 zi;B{{sad8crF;RK70h(+v?2VE)IsVWVE#j3&KBi!RT@S} z4Zq4!C(5>x(+2R27#ve_B9Ul_$!~4yODA~Urk+Jbo-Az>7;_a%4GpzuG2WKdsT@9= z=NRVECNQPc|JB>cYg0iS2k?V>5GDA)2VRVVAwlC7HF(hwLxKo`O2ouN38oPV6>M%= zY}~0UQe0|9>W;fbP;t2^DxTaB^q`2Se~91r9cSk0P~SAQ34TdVJ$(57W|}<6%zVO6 zUQV98m2hCVt!Gl!v@NWsOm_LAMQ4TyLpEp&n5t~MbP=-SyBPI4yHUp>%hoD3n+vR1 z-KA*De3{Ho>H|UW1qUh7C9LVB&A$^|HD%I^7oR=lAp3*h^Zc5Kqq2yUXHT)&)m@l0 z(4}yNik#*L$oe37kAuX${8_r)0`BFmf~wtl^PYPjnLC5vjowFQg0iwn&n{WOWlq`8 zB2V60d`WC_kd8z`!g1Ytn+1Fcuyn~XANg4OcbJd4wS*Vd8MKFAwtx%lOIEr|mdv~U zij@Nkubr!5%A)n*0GR2MDqX_Jdp`QC3s_<2Bw&+{glyo)s;y>Yu~^%sMd4tLllV?S@?9}eC~X5bR`(TVs& zOSp$BVd)~#XmqoXo!z7ryUP*ohfET3(vagt8L)E?0Z6^+TP8_bsrDq*0vo zVQZM_6)IsYtw6QQOk-T85~ix?jBI@+G(5Pc?%Pzt#Y?D!L27pT^l#yCI0BrmkFFK% zV4Zt{C5pFEma;45fv|||tYq#iYnZ9RHQS1iRdtcu5>_$-xg#`uxMwp_)|ITexWc_j z)ucP`*uy%7I%H#4(PgMIl^;1%hTU0g><6zyb-@}_R%L&|w{p2$IA_q=!;SvLw*jn* zkCik`7G4Ngx!P_EH3U=Etbc9kLS*L5xxH|qNz-i%rrfVsM7U5H=?=g(=`7qvVXkwZ z@vqCpb%}cJClvk_-%@vCeH(_ELZ5UQRhRA@~tbD@#KTmZrW73p?fX)8A2u;8J454uitUtjU;Mz+2EWXHqH#sBGe zWUG$Aw(QVv%Z@p>?qK)0F|9btJ_#2VCbr`6{#agDXzuo6Vcrdy*!&9`lAg;pl5eP1@S4ylY3Tzi5SZp6FdI+c&yb%l54SGG45&uk_eSqn|P3 iQP;?X(Z4?EYx@%n6t9_oGub@=0000*D0<-{0@zfz+-;^gY#Hq)#;^gWAd({Mf z*A7yd27uQz!R-!In+{Qx4^NaU!_x?Y*bP;kF2ddqjodE6+X;l(3y0bPdDJY!)(wi= z3`~qM!s9E$&ka_d4^EOa!S5}@*b7RC6O!H#O^^(T+6`8p4pEmCmETg`fiS}05Rcs~ z#LQgebuGi$4@{0==W;T^=L}Dh3`T-g-+fNohFRiyGr{Xa)0PZQk2%b&KhU8(&Zk1s zn>5F7EW^qA`}|DViY&v%N!O26-*PR*zB9*yGsb&R+i^9=W%2a)6L6wW+ITd_bvMhh zJE0W2_Bkn+?aJ-yw_JDX!JJ?$1(ts2F{th~%7J&gpTq=Gyk-V65X7lG>%d*o36UfZf5S z>a&*Tt_oY8J8GPP+?06Wj%nw9%kcNh@bRL|>VUlJF_Ybvve2*ay&RCePtCeYezP!w zu_ULgLUyaL*7BX=?@_7cwd&+8y54ix)l#6*XxFq^)t_nDe#PbYXVLSJ#O=Y{>9ok* zE1B4{#MUUZ$e-%KTZXkBk+B+sue8YAHm1r?o5WVDy&L)SUH||94|GyaQve|EkPx5W z-(b%$5YM2X{W32a000TdNklCmk=2S9vPTn=zR13-AgXqT{sc9sF9*YkQ|l>(IQ24 z1EWs(h(H~lNa0niTSWZrc&~~&2d1Lecpwqo6m_FW(m2Pd!X76{kxfcRk0PyiEGy{s zQsn3+eaGpXmhr~UZc(K1IwxkF6j@&9h|+qUQ?p)*$ObJ*SYKzRq9oC9xo|UxR}nLG|f6%xCoNY1(70zlUxH!|6$GX^}USv z_^xvv>>KL;Bq)8pd=)BG?$DuSwc)p(Jb2{mXn5Tv|IBI9Btg=1x@F61)#kNob?eEa zb&i8C`R6H+IWuHIR|d`G0Rsj+d*m26^l%EKKml$;2F**)WAx-(r+n=WhXy5Mfz4_2 z(vwGwXbRe%@TJ4)^5n^rEE!%@TMV3)=JJ5GfScAk`5dxIMgTKeOq)7a>j=1P(=r5i ze!lw8VgCdP5|n^FhqvaP0rSp)AroA;blI|H>XifBxy#2tgx9@-i;xVO%W`MMu#IrJ zawVH}uF?gv?J(TK2{M7DVBWuzmkwue8G<_#TT&8l_eAa51mYBP_i{7veegKrq zqH*DLidjQuvj%L~TWr$IEn4)bEwHcBrR^mei$zw$G-(uOZt;tL*2C+9)Gj}k0Yhf4 z7&V7!iFskL$RTTCvA}9qH0E#EZ~^0JGKcf$&%fGQ*cV&bn8N#lZ+@Ag*H4}DRs{Rvir9r~aH+%3!{?MBze(3f-^{4mGg* zrT|^3?`4c$zn~M@3b%ssXhLBI%PxY-*1$m}SoZ0m_Ug5B=guaEOqn{hmmbAC1#?%x zd{b94f!nk}Wh>y&IdhsfZ~l17=9MdqlO_?a*Mt6GJpZZO5|g$7w?R-@ zI~-IP30?`7)Sf*zZr!@IKg-rNYk+h5Gj}Th7Mq&wEddu=tsTCU4q3B#<$SQqHg4Ry zWXZ&d6I)R5Cve!HAs-Q%e%cg+V&D!_h}HhJ>ASy^&Xprbg^RJv1Tc4j>f=RF3vi-6_q z*9wOwOLkMPyJT34>|hZAGn=)Z)CBTD`HY^O>D7~Awz=v<=JaW;uzw1;s5=*I+T;|H z&1f!vHl9=iX6IX7#5*SB{0%N>g@g8yJ9o*j?Ag--R>?f?_8fcqloqxOVN@fU8z*P!(CN4L;1=l&KJc)uoq&;7645T?S8^#^J6U zX0jFVw{7I6im?B^Uy$kNIV6bpoS0|U!n*x;L zrwtB^8#k_yO*Z#1Z%@xG9u`Oaj97B3&q8E)Nbey)kqbI)uuohei-ktvv)*t^t*`{k zD#GDDeTJ~KBYU+*IFMYt04uiGFmgSLB(iWRVZVW`QKJUnJ_vKWQ&3n7jAVxlm?foH zXt{8aL=$vodCpa&PMtb^D18yAh@WP7uL*3@Ig9MZJ853ns3PUdbC<)Xb(-OaU?~Eo zY@@<(6PhiuUuU6G+P81d+_4l4S~Glv!^+Kl7KaiQcF&-m^=P5WY^_?g8a4!qyqIkT zd|wIk(jGKvxH)p%)+utdj#>rVa1je!E8xI5aa1zkVcx88LiZdQRF!AX;;2DIdh}rK zAuIn6WG}%yDY1z@jq?!8B>s*nNeCx38o7PoFtY zIdpn8skXpJ1WYl3Ge8FHe$UGx7rbcJ3Y%cIskuwC{b6K}62@o74uW$snB;^BSL}8G ztgej4+gM`(L!RIO7?oA@2EN8J3>i7;0C;g~^)hE6I3C|zaFKW`PS_hpWymtj>3Al` zF+wi#JKF2ypmWy4VSp8#HxZ28B}NUI(Uy1Fgn$rFPj4?PVdQFRCA|%>VUgkT%9Nb9 zuZO9+ehmmIIB1ZkXMoOnIB>5@PRJJ7UELUP&P0hqZhty?;_ZY9Z%|;Og2D%Mw!?wfQVUw%*pOLYcev^` zM!1W@=e%r(h0L>w%YZ2sVJ0)zMp#T+$QZWhEMTRZk=z4tZGuIvn#voB$THMluQA*J zdtA7Fozz60>w)iWB%?8SK4~RfFyy+OF4gZ9a_YH7Jg9Tdcos(u7H*i%J}|~@Htocq zQCYpYsBeIm&R#G|<5SXD`fL^tP9q8!?12e(z5(URUQv2S5f9KAGbT=yC?~>T!P*%H zjn)dfAnc4{PjS}%Fa~~XFNbl~>7IpbBwIn41wBFnz&Z#<79YFD<+vMmoXv?7G3Kve zsv}|QegEpiYsQn$B@>?>x#Hu*Tjv6O!WJ(M^9lTSZWjD|VOQM(>$;nMW4q`!XV=}> z?H0imx3Wuacv`^~H}6Ms+2abXd_V(_q&Rojco-&z;UOGn?(A`R2**{A9l8ENE2lnM v#@APrjwLxh5h9AZA~B-Ia`fYaCT)KL-r<<4jswzu00000NkvXXu0mjfV-%r3 literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-microsoft-excel-60x60@2x.png b/website/assets/images/app-icon-microsoft-excel-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..8401843239d73190befb341d5a5bd8329c166ab6 GIT binary patch literal 1629 zcmV-j2BP_iP)*D0<;^pe%*D0=;^gY#Ez_^|Ns9OTsI-3 zX5!@P5PU&1#DNomMiPHS6oW_+enJ(5N)UNJ6@^O=cRu3l<_&N-4s|>YaXJrnJrYAG zkkPUihD;7~JDK6Y6;Ln`dqE6pG!1Sy4stpjnOzKQHW!CZhrXaJw|E|tT>Sn07E>|~ zH6Rm8EF6zl4KN-HDjF4JIt@c52}mX;t8EQyImO}A3uiKmt(#f8jPdvM;qT}9`upwg z^6KpHrqH=Bk6TiNX$w{@^7HoQ=j}|IZwp~CEQC`GWHH0u&`OnSA&62PeMk#bET_@C zrOmf$t%w_xSQ2zUJeOuIh*m6uQXhg$&*$4rqINBYRSQ)u<@fKV<;bww#jwY_lgX}& z!=`w$kw;G!E90000GbW%=J0N)UhpI{*G@6RA0FwdYcSmVak000Dh zNkl~hTMRK#v^2-`gfKSBdG(Jg<#K&y(-39L!%D(12@Z=1 z&*tTAhiTD5fa_&NA#m9dQL;R)gd>}t4$R9IYt2v(oLQb%7Co@(am(|@MI^LI6fMsy zigls2ULRsU$RQyt9}*&fTNl9pJv_g^UGEMq-@^ypz?ZhQ?cDZu9qb%_w5>Ckd(bg_ zsXO?gU+}>I4&VR|-~iSSe>$;D{c7R-g(WSVZqd|flvTp-2e<>&E@-FI4yRZQUa?na zzXPohe#$JXm{iH-Uj6zpFmMO!Ki;+#!ZU6c<;H38gL^%4WN#GPwXJRYR|d-^yQYN? zo|fG>ysnI#R}C|JfZc{A6N{;a<&x!=nbixsw%p>ZVl}1#X0`b(Bw;F{0YfOQp+fTlg|2;5 zEzByzv3VNV8Td9ITwuXf4NH|;aL(l_4$KFaR9!H$d{X5bZ=q-SRiU<*PvkW6VurwfbA=23B*{ zd<;?!lj^z*L1{dxaLb4S3-ca6tQcmu;c}3MTn88DJ**r?)@GJnP$kQ*dN|YICW(be zrE}^CvKnApvP-rsS!z@@OsX6gS%?oV#O$bQcoJP^<+glT!>g_wr1uhH`JT!$U2~{eH7gH~f6xGJ)$0 zd}^y^_}i)0ZPg8bJ=7}Lvu^lu>;Eu-12}+J5&We)_;JVZ+pgRfUEFf>_(kXLosuwS>p`ghasW}j|z_V31S(}#mRD1-@5EBJBqegvKx*dV+-y?EeW z-yYDwOvBq{m-&$tShgX`-aUj<5=L)`+h};U?V^0_h-UWkL95<>;n6Z2IwJJ9CM?JG b>+!)qKgNn_<2Q1p00000NkvXXu0mjfO}P_` literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-microsoft-teams-60x60@2x.png b/website/assets/images/app-icon-microsoft-teams-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..08c254d1018d64943cf726a55147c71e72166d5f GIT binary patch literal 1924 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 u6*yY*D0<-{0@zfz+-;^gb%i_@$|F)a|eo+7I z=Kpm=|Mv6$qk{jDY5&^I|G%jJhg|>U+W)MM|H!oMx2O4qUHf}Y|C)CHq=M03R|I0A)pm12Cdpm7?}*Dah-bY-oZS@t@s5WTsAPS> z*~d-2O9G|P@mh28jz>_;5@$&dPw+sX7&_pjA85oisAh%O4fYh5pqyn_a>50xWsT!x zw7?ChXM>B=NN+(sTbz#OxB~U8a6TF%fqDqXBSd&Y5MS`$^MYUSV<>pvmg+ENF70By zE*xBXNv;XE={44nQG<=Ub*o$rZf;y-(=;f-=D|&KCD`A&T}THm?p#NCTI#?*_w|-O z4T=@>IGb7v_Pyr@cn7)Ge@u5n?RIKUHRKNuwU>uOowYo3aT^Q6zUsLWe9H3aM;H#a z#|i>~)?VeE0a2KWGnGMTb{@NE|)a2>g>?e21rg|o=D zWxxI~Lh$ddq5O0yKopMMicHncI-;Q9oEV0R%UoLx)LN{cF*#~ZLTBVf*j0~1r4_ul*23P z8$@7sZBv&7K-JmxDZ65@&x@9ZmNHav8%3_%l-a)$N+@DiddhSKuQ1sahC|^E&m`qv@*>xU34QAJ61e$Ob zu{v*cmpgE?fP z`T0NIfbxQ0@C*JmFZdt8Pul|fyiLDfPuk}Eyp7$-_!(Q-F&T{}&)B>_?T;&{JziY! z+xdXTofhh*;^pe%f+?<;^gY$g43?=jZR=-{0Zl>Hq)#M84nbvMw&R zec&Ei;^gZ6_2uaI`{nlU`{V1D+P?6Ptor->{r&!;-|zJM{p)g=^85Gw@%8QR^6KpH z(C_#D`tn=G<4?lj`s~X{zm4QNZ|%1`e9^8uyM^K`W%k&X^7Hn&=kw<0?fBxcbI#{t z$erj`gYm^;t>f{r zKoG!jb2OKx2WF8WB3=*;N}xg#6wF%_C<%d<(#!e&ALXF5nYgv<26RKA|F`&%ALAx6 zs8RaF7~f!T-HeTiu6^y#fYAOj{&K87K*VV2xX@ef{W3ztfnFPTgcv%|drpWrJRACU zgzJ7;qSrXQJ)1XlK~ZjWnpq!V1PTjrs8{d+*Dff`UE`p-(TENx%|R@0wt*oiE-XjZ z6%I@zPjzjA5hyRhiDuvul($4f8{<7F&%v=aMHiIk;#5O~D}?w93!Cq^2}`mS)C-Pz zYMO7aR!^|MXCK8idY76Xy#{^24>6-Wx^A1)!s-DoUFtOR#ysz>d)Q;O5+ACpg;~q) z9FAE%j|M(3?HZmlt_-T)O|C=7aKZSX%H%tC410{PI^^IBZ1)b&s^3=c@YA(mKT!)) z-nC#qRtr;)v09j##fo8Sm8piQ$N6WV7N&mT9}oMp=KRax;3C*BvV?tGwtA3*5C6)& zDBoDJ@RLBL^|lSR^3(3Qk%K+fo+pO+Ezp*MS4^hjdzf5mCxB^hmnreZ@Ex~&2CeXl z$>j;)hU>>xIFp38LU_kt&RgMxNhXAC{&Lz1GueC*d}s1?JTb_^X~$;_3trd}eAyX$ zlJFiH4>Jv#;Y};-Cvxx%s)Do*yg(zouv%d#r2ocM&vhVZhBsY2tHrM(2$p?TQ$^gu zCIvu~oLkTYr_UeS+979;- z{7?iZRf?HgRx~(5^b{6&65v{Eaacf%{LHHW4(5iYE7(hWyk51JS;WraBv7R@8fsQrA!kpb>=#kmfw z3~-&SSz(#zx7Y~BisUXr8>~M#b76*|qAi&Gu141Y_w%mC%Hvxz7hr`U zTUc221T+{#nSZQyx&5N3rzEvgvoFeU*rz_u+2qEr~{FsVQI*Tb_zkHf+t!-{NR z7+Zz|!ze!v45Pg91hdo^tTvut_T&prox>8hw=UtDx}mRnhPS%Aho(Y@XFb5ijegm^ z<61!9aKt-zpRscE9Ao=03vSA^1@{TlKSeA;2QbL#flXG>q;GF`v7--cV*2{7=Cy=& zS)rI(?`FT_%bvF*uvfti4BkU9eEnG8h4DAJ-8e#yZIa~o9M%I7lHf!o#Aq^iTm-v a32JY3GOP4=##{LS0000 literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-teamviewer-60x60@2x.png b/website/assets/images/app-icon-teamviewer-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..298113cfb141405a333fc521681fba39f2ad301a GIT binary patch literal 2338 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 literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-visual-studio-code-60x60@2x.png b/website/assets/images/app-icon-visual-studio-code-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..b9fe5290acd83691b0eff744c100e9956f8b73b8 GIT binary patch literal 1306 zcmV+#1?BpQP)*D0=;^gY#;pFP%eoy_WkyWCBm)MlyD*6H=H z)a#_nVTW$l>xvnafO*#yyL{Tc_7~uhd$c%Pow>9)ZJ~q-h9 z1y_wKmbD=SM<0V9wJLw*9?hKK%6@=`sp|^OqkArJr4{_%C|bI%Q2!N?3k(2*FQdbgA4r5P@IEzzulGNF!FB^Lfmikk z?8-j+UD;>OtNXCq&#&TBcJ@85xQdVW3!dk#v)Yky;L`UC8ppa9G>*CW<4TI|u$w=x zqhKDYe#%sCzU$KxONn`u6ohxU$|Npw_afR@*D0<;^*q$-|yn(>f+?;;pFP%S*u)yd-3q~Ntp+H0Mg@HPMd01k9gPE!Ei?~ou6pJ2~0AP~=>KH47;000Fg zNklKS$WzmQwok+;Va=@z>|4H^_E3Fn3Mq`9N;2!Hgyux9f6(gg&+2CqKRoBKhV(XdU zW?)AZEmS!`pXPwM@pC2{UGvFcUiX}=v)Ym_qhtW*at+JvG{z&N!OlySEa~2GCxIJq zv%<~v5NV45`vVt@;KYDjp}{Q3#gi2h%mjiP%S*v=U>o7$Y<4KHyyO*dk>nDbjR0T9 z+mWeK;Ou;`#?>$4B>;{FNQ@>Rt2M#}<}+M86AWWzfqYZ=FzY-p7~F*N+~A#E@;tDF zN(wblmS4?aat0VuT6%+lw;)Z<0;^DF2>_QIZ?Z~*A(*G3!JrCnvdICLfmpgexF%?m zOP&UI&}03I$mEAm4O&T=WRfm-z%2!1gH$tt2?7@!FyCw?&m z&MH&jD=Tq_Oe}v|<8d&%QZNcxN`AJoJaFa39ydAp>CxtaCAn(yX&P8z!Tu6NEeqxX zo7Z@7IE9qA;YRh$77zBFZKh;3zK;FOE-b!|Ndhb)%Ns7Pdb^U>0&g-qR}IhkVx`xy z!Jn4JdbLS`ZFG^LdaK;Z%iIu}7n!qD71^Hx0yslQ7hO5V|-Rp3MAgZd@@^7w8K$Nr1sORqVq`R4m}1CJk2U?!@XCw+#7D zA@)ux*$2aN0Z$8(0dBmuh;z3LbOnppAHz}uXS4`yecB8##N{;UH!u}2xF%WP4$>2k z)**vs9+(J7>?B$YGkSoq;Qc(X#C%Xxz%DfpzDDMPiNGyoRppFvjpXs~gK01%Hkly@ z24{oYyddY5TTSx8u$!K&4q7(?Y~X(;sx6_u^1&RkVm8;1Y%sXV&gTk-0o$3s3&;x> znl!3&@#*;ts|f^{%_=5l`i&a}mfmn#<#H>lD*Id<*bU;tD*N%SI;Xaj@g^z+xV#h- zm;KqtBBn`?i&%lw%_kJlDrIdfuhMI-h(yzdsag!5YY7@$7jX$Ihi`4AEl1B7PS9Xh z3N`O#0)CX%xI<#C8yiK|olFm-@g~1N4g8PPitP z4PAf}Is*HPwq$X=(udXWZ#w4ueFwXDo9{TvPIvFO6^>+K9qIn#y24`V1qR=J=LL<` zZoRCtU+DVratY^UF`N03uJ8KSjuuMo_Vd~iT(mkafIb{4*xSEa_Ig8)^Y;JMvd8gd ox;?$UHd`t<807*qoM6N<$f&=#Z=Kufz literal 0 HcmV?d00001 diff --git a/website/assets/images/app-icon-zoom-60x60@2x.png b/website/assets/images/app-icon-zoom-60x60@2x.png new file mode 100644 index 0000000000000000000000000000000000000000..069259362d4fcd57072227e0c96ad1ee2f8c736f GIT binary patch literal 3531 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 FV1iGN>zM!m literal 0 HcmV?d00001 diff --git a/website/assets/js/pages/app-details.page.js b/website/assets/js/pages/app-details.page.js new file mode 100644 index 0000000000..bba7bb6ac1 --- /dev/null +++ b/website/assets/js/pages/app-details.page.js @@ -0,0 +1,47 @@ +parasails.registerPage('app-details', { + // ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗ + // ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣ + // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝ + data: { + //… + }, + + // ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗ + // ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣ + // ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝ + beforeMount: function() { + //… + }, + mounted: async function() { + + if(this.algoliaPublicKey) { // Note: Docsearch will only be enabled if sails.config.custom.algoliaPublicKey is set. If the value is undefined, the documentation search will be disabled. + docsearch({ + appId: 'NZXAYZXDGH', + apiKey: this.algoliaPublicKey, + indexName: 'fleetdm', + container: '#docsearch-query', + placeholder: 'Search', + debug: false, + searchParameters: { + 'facetFilters': ['section:queries'] + }, + }); + } + + $('[purpose="copy-button"]').on('click', async function() { + let code = $(this).siblings('pre').find('code').text(); + $(this).addClass('copied'); + await setTimeout(()=>{ + $(this).removeClass('copied'); + }, 2000); + navigator.clipboard.writeText(code); + }); + }, + + // ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ + // ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗ + // ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝ + methods: { + //… + } +}); diff --git a/website/assets/js/pages/app-library.page.js b/website/assets/js/pages/app-library.page.js new file mode 100644 index 0000000000..595a8ad10e --- /dev/null +++ b/website/assets/js/pages/app-library.page.js @@ -0,0 +1,25 @@ +parasails.registerPage('app-library', { + // ╦╔╗╔╦╔╦╗╦╔═╗╦ ╔═╗╔╦╗╔═╗╔╦╗╔═╗ + // ║║║║║ ║ ║╠═╣║ ╚═╗ ║ ╠═╣ ║ ║╣ + // ╩╝╚╝╩ ╩ ╩╩ ╩╩═╝ ╚═╝ ╩ ╩ ╩ ╩ ╚═╝ + data: { + //… + }, + + // ╦ ╦╔═╗╔═╗╔═╗╦ ╦╔═╗╦ ╔═╗ + // ║ ║╠╣ ║╣ ║ ╚╦╝║ ║ ║╣ + // ╩═╝╩╚ ╚═╝╚═╝ ╩ ╚═╝╩═╝╚═╝ + beforeMount: function() { + //… + }, + mounted: async function() { + //… + }, + + // ╦╔╗╔╔╦╗╔═╗╦═╗╔═╗╔═╗╔╦╗╦╔═╗╔╗╔╔═╗ + // ║║║║ ║ ║╣ ╠╦╝╠═╣║ ║ ║║ ║║║║╚═╗ + // ╩╝╚╝ ╩ ╚═╝╩╚═╩ ╩╚═╝ ╩ ╩╚═╝╝╚╝╚═╝ + methods: { + //… + } +}); diff --git a/website/assets/styles/importer.less b/website/assets/styles/importer.less index 33420eb3ae..8fc197e4c2 100644 --- a/website/assets/styles/importer.less +++ b/website/assets/styles/importer.less @@ -78,4 +78,6 @@ @import 'pages/start.less'; @import 'pages/deals.less'; @import 'pages/testimonials.less'; +@import 'pages/app-library.less'; +@import 'pages/app-details.less'; diff --git a/website/assets/styles/pages/app-details.less b/website/assets/styles/pages/app-details.less new file mode 100644 index 0000000000..b4e52a0343 --- /dev/null +++ b/website/assets/styles/pages/app-details.less @@ -0,0 +1,418 @@ +#app-details { + + h3 { + padding-top: 32px; + color: #192147; + font-size: 24px; + font-weight: 800; + line-height: 120%; + margin-bottom: 0px; + } + + p { + color: #515774; + font-size: 16px; + font-weight: 400; + line-height: 150%; + } + + [purpose='page-container'] { + padding: 64px 64px 32px 64px; + } + [purpose='page-content'] { + margin-left: auto; + margin-right: auto; + max-width: 1072px; + } + + [purpose='breadcrumbs-and-search'] { + margin-bottom: 64px; + max-width: 1072px; + font-size: 14px; + [purpose='breadcrumbs'] { + margin-right: 24px; + } + [purpose='search'] { + // Note: We're using classes here to override the default Docsearch styles; + button { + width: 100%; + cursor: text; + margin: 0; + } + .DocSearch-Button { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border: 1px solid @core-fleet-black-25; + background-color: #FFF; + padding: 6px; + height: 36px; + margin: 0; + width: 256px; + } + .DocSearch-Button:hover { + box-shadow: none; + border: 1px solid @core-fleet-black-25; + color: @core-fleet-black-50; + } + .DocSearch-Search-Icon { + margin-left: 10px; + height: 16px; + width: 16px; + color: @core-fleet-black-50; + stroke-width: 3px; + } + .DocSearch-Button-Keys { + display: none; + } + .input-group:focus-within { + border: 1px solid @core-vibrant-blue; + } + .DocSearch-Button-Placeholder { + font-size: 16px; + font-weight: 400; + padding-left: 12px; + } + [purpose='disabled-search'] { + input { + padding-top: 6px; + padding-bottom: 6px; + border: none; + } &::placeholder { + font-size: 16px; + line-height: 24px; + color: #8B8FA2; + } + .input-group { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border: 1px solid @core-fleet-black-25; + background: #FFF; + } + .input-group:focus-within { + border: 1px solid @core-vibrant-blue; + } + .form-control { + border-radius: 6px; + padding: 6px; + height: 36px; + margin: 0; + width: 212px; + } + .docsearch-input:focus-visible { + outline: none; + } + .ds-input:focus { + outline: rgba(0, 0, 0, 0); + } + .input-group-text { + color: @core-fleet-black-50; + } + .form-control { + height: 36px; + padding: 0px; + font-size: 16px; + } &:focus { + border: none; + } + } + } + + [purpose='breadcrumbs-category'] { + color: #8B8FA2; + margin-right: 8px; + font-size: 14px; + font-weight: 400; + line-height: 150%; /* */ + &:hover { + color: #192147; + text-decoration: none; + } + } + [purpose='breadcrumbs-title'] { + margin-left: 8px; + } + } + [purpose='icon-and-name'] { + flex-direction: row; + align-items: center; + + } + [purpose='app-icon'] { + img { + height: 80px; + } + margin-right: 24px; + } + [purpose='app-name'] { + color: #192147; + font-size: 32px; + font-style: normal; + font-weight: 800; + line-height: 150%; + margin-bottom: 0px; + } + + [purpose='app-description'] { + color: #515774; + font-size: 16px; + font-style: normal; + font-weight: 400; + line-height: 150%; + margin-bottom: 0px; + padding: 16px 0px 32px 0px; + } + [purpose='app-details'] { + padding-right: 64px; + max-width: 800px; + width: 100%; + p { + margin-bottom: 24px; + margin-top: 16px; + color: #515774; + font-size: 16px; + font-weight: 400; + line-height: 150%; + } + a { + color: #515774; + text-decoration: underline; + text-underline-offset: 1px; + &:hover { + color: #515774; + } + } + [purpose='platform-and-version'] { + p { + color: #8B8FA2; + font-size: 16px; + font-weight: 400; + line-height: 150%; + margin-bottom: 0px; + margin-top: 0px; + } + } + + } + [purpose='app-uninstall'] { + pre { + height: 141px; + } + } + [purpose='app-install'] { + ol { + counter-reset: custom-counter; + list-style-type: none; + padding-inline-start: 0px; + padding: 0; + margin-top: 16px; + margin-bottom: 32px; + ul > li { + text-indent: 0px; + margin-left: 0px; + } + > li { + counter-increment: custom-counter; + margin-left: 36px; + text-indent: -36px; + padding-left: 0px; + margin-bottom: 16px; + code:not(.nohighlight):not(.mermaid) { + display: inline; + } + p { + display: inline; + margin-bottom: 0px; + } + blockquote { + text-indent: 0px; + } + } + > li::before { + content: counter(custom-counter); + background-color: #E2E4EA; + width: 24px; + font-size: 13px; + display: inline-block; + border-radius: 50%; + margin-right: 10px; + padding: 2px 4px; + text-align: center; + line-height: 20px; + text-indent: 0px; + } + } + } + [purpose='app-check'] { + padding-bottom: 24px; + } + + [purpose='right-sidebar'] { + width: 256px; + margin-left: 16px; + font-size: 14px; + transition-property: transform; + transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1); + transition-duration: 500ms; + a:not([purpose='edit-button']) { + margin-bottom: 8px; + display: block; + color: #515774; + &:hover { + text-decoration: none; + color: @core-fleet-black; + } + } + } + [purpose='docs-links'] { + a { + display: block; + } + } + [purpose='social-share-buttons'] { + padding-bottom: 24px; + margin-bottom: 24px; + border-bottom: 1px solid #E2E4EA; + a { + margin-right: 16px; + } + img { + height: 20px; + width: 20px; + } + } + [purpose='edit-button'] { + margin-top: 24px; + img { + width: 16px; + height: 16px; + display: inline; + margin-right: 8px; + } + padding: 6px 8px; + display: block; + color: @core-fleet-black-75; + text-decoration: none; + font-size: 14px; + line-height: 21px; + border-radius: 6px; + width: 102px; + background: rgba(25, 33, 71, 0.05); + &:hover { + background-color: rgba(25, 33, 71, 0.1); + } + &:active { + background-color: rgba(25, 33, 71, 0.1); + } + } + + [purpose='codeblock'] { + padding: 0; + position: relative; + [purpose='copy-button'] { + position: absolute; + top: 11px; + right: 10px; + border-radius: 8px; + height: 32px; + width: 32px; + background: url('/images/icon-copy-16x16@2x.png'); + background-color: #F9FAFC; + background-size: 14px 14px; + background-position: center; + background-repeat: no-repeat; + cursor: pointer; + &:hover { + background-color: #F2F2F5; + } + &.copied { + background: url('/images/icon-copy-clicked-checkmark-32x32@2x.png'); + background-size: 32px 32px; + background-repeat: no-repeat; + background-position: center; + } + } + } + + pre { + width: 100%; + max-width: 100%; + padding: 16px 44px 16px 24px; + border: 1px solid #E2E4EA; + background: #F9FAFC; + border-radius: 4px; + margin-top: 32px; + margin-bottom: 24px; + white-space: pre-wrap; + word-wrap: break-word; + overflow: auto; + code { + color: #515774; + font-family: 'Source Code Pro'; + font-size: 14px; + font-weight: 400; + line-height: 150%; + background-color: @ui-off-white; + border: none; + padding: 0; + dispaly: block; + } + } + + @media (max-width: 1200px) { + + + } + @media (max-width: 991px) { + [purpose='page-container'] { + padding: 32px; + } + [purpose='app-details'] { + padding-right: 0px; + max-width: 100%; + } + [purpose='right-sidebar'] { + width: 100%; + margin-left: 0px; + } + [purpose='breadcrumbs-and-search'] { + margin-bottom: 32px; + } + } + + @media (max-width: 768px) { + [purpose='breadcrumbs-and-search'] { + max-width: 1072px; + font-size: 14px; + [purpose='breadcrumbs'] { + margin-bottom: 24px; + } + [purpose='search'] { + width: 100%; + .DocSearch-Button { + width: 100%; + } + } + } + } + + @media (max-width: 575px) { + [purpose='page-container'] { + padding: 32px 24px; + } + + } + @media (max-width: 375px) { + [purpose='icon-and-name'] { + flex-direction: column; + align-items: flex-start; + + } + + } + + + } diff --git a/website/assets/styles/pages/app-library.less b/website/assets/styles/pages/app-library.less new file mode 100644 index 0000000000..5b2f66861d --- /dev/null +++ b/website/assets/styles/pages/app-library.less @@ -0,0 +1,205 @@ +#app-library { + + [purpose='page-container'] { + padding: 64px; + } + [purpose='page-content'] { + max-width: 1072px; + margin-left: auto; + margin-right: auto; + } + [purpose='search-and-headline'] { + margin-bottom: 64px; + } + [purpose='page-title'] { + max-width: 662px; + margin-right: 16px; + } + [purpose='app-search'] { + + // Note: We're using classes here to override the default Docsearch styles; + button { + width: 100%; + cursor: text; + margin: 0; + } + .DocSearch-Button { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border: 1px solid @core-fleet-black-25; + background-color: #FFF; + padding: 8px 15px; + height: 36px; + margin: 0; + width: 221px; + } + .DocSearch-Button:hover { + box-shadow: none; + border: 1px solid @core-fleet-black-25; + color: @core-fleet-black-50; + } + .DocSearch-Search-Icon { + margin-left: 0px; + margin-right: 8px; + height: 16px; + width: 16px; + color: @core-fleet-black-50; + stroke-width: 3px; + } + .DocSearch-Button-Keys { + display: none; + } + .input-group:focus-within { + border: 1px solid @core-vibrant-blue; + } + .DocSearch-Button-Placeholder { + font-size: 16px; + line-height: 16px; + font-weight: 400; + padding-left: 0px; + } + [purpose='disabled-search'] { + input { + padding-top: 6px; + padding-bottom: 6px; + border: none; + } &::placeholder { + font-size: 16px; + line-height: 24px; + color: #8B8FA2; + } + .input-group { + border-top-left-radius: 6px; + border-bottom-left-radius: 6px; + border-top-right-radius: 6px; + border-bottom-right-radius: 6px; + border: 1px solid @core-fleet-black-25; + background: #FFF; + } + .input-group:focus-within { + border: 1px solid @core-vibrant-blue; + } + .form-control { + border-radius: 6px; + padding: 6px; + height: 36px; + margin: 0; + width: 212px; + } + .docsearch-input:focus-visible { + outline: none; + } + .ds-input:focus { + outline: rgba(0, 0, 0, 0); + } + .input-group-text { + color: @core-fleet-black-50; + } + .form-control { + height: 36px; + padding: 0px; + font-size: 16px; + } &:focus { + border: none; + } + } + img { + height: 16px; + margin-right: 8px; + } + background: #FFF; + &::placeholder { + font-size: 16px; + color: @core-fleet-black-50; + } + } + [purpose='app-cards'] { + column-count: 3; + margin-right: -8px; + margin-left: -8px; + margin-bottom: -8px; + margin-top: -8px; + } + + [purpose='app-card'] { + margin-right: 8px; + margin-left: 8px; + margin-bottom: 8px; + margin-top: 8px; + display: flex; + height: 92px; + min-width: 30%; + padding: 16px; + align-items: flex-start; + gap: 16px; + // flex: 1 0 0; + border-radius: 8px; + border: 1px solid #E2E4EA; + background: #FFF; + box-shadow: none; + &:hover { + text-decoration: none; + color: unset; + box-shadow: 0px 0px 0px 2px rgba(0, 0, 0, 0.03); + } + h4 { + color: var(--text-text-brand, #192147); + + /* Title XS */ + font-family: Inter; + font-size: 16px; + font-style: normal; + font-weight: 800; + line-height: 19.2px; /* 120% */ + margin-bottom: 0px; + } + p { + color: var(--text-text-primary, #515774); + + /* Body SM (FKA Card text) */ + font-family: Inter; + font-size: 14px; + font-style: normal; + font-weight: 400; + line-height: 21px; /* 150% */ + } + } + [purpose='app-icon'] { + margin-right: 16px; + img { + height: 60px; + } + } + + @media (max-width: 991px) { + [purpose='page-container'] { + padding: 64px 32px; + } + [purpose='app-card'] { + min-width: 40%; + } + } + + @media (max-width: 768px) { + [purpose='page-container'] { + padding: 48px 24px; + } + [purpose='app-search'] { + margin-top: 32px; + width: 100%; + .input-group { + width: 100%; + } + } + } + + @media (max-width: 575px) { + [purpose='page-container'] { + padding: 32px 24px; + } + + } + +} diff --git a/website/config/policies.js b/website/config/policies.js index becc2c3931..00c0dbecbb 100644 --- a/website/config/policies.js +++ b/website/config/policies.js @@ -58,4 +58,6 @@ module.exports.policies = { 'deliver-deal-registration-submission': true, 'get-est-device-certificate': true, 'view-testimonials': true, + 'view-app-library': true, + 'view-app-details': true, }; diff --git a/website/config/routes.js b/website/config/routes.js index f02a813ae5..be8f24a69c 100644 --- a/website/config/routes.js +++ b/website/config/routes.js @@ -297,10 +297,22 @@ module.exports.routes = { action: 'view-testimonials', locals: { pageTitleForMeta: 'Customer stories', - pageDescriptionForMeta: 'See what people are saying about Fleet' + pageDescriptionForMeta: 'See what people are saying about Fleet.' } }, + 'GET /app-library': { + action: 'view-app-library', + locals: { + pageTitleForMeta: 'App library', + pageDescriptionForMeta: 'Discover what is available for install in Fleet\'s maintained app library.', + } + }, + + 'GET /app-library/:appIdentifier': { + action: 'view-app-details',// Meta title and description set in view action + }, + // ╦ ╔═╗╔═╗╔═╗╔═╗╦ ╦ ╦═╗╔═╗╔╦╗╦╦═╗╔═╗╔═╗╔╦╗╔═╗ // ║ ║╣ ║ ╦╠═╣║ ╚╦╝ ╠╦╝║╣ ║║║╠╦╝║╣ ║ ║ ╚═╗ // ╩═╝╚═╝╚═╝╩ ╩╚═╝ ╩ ╩╚═╚═╝═╩╝╩╩╚═╚═╝╚═╝ ╩ ╚═╝ diff --git a/website/scripts/build-static-content.js b/website/scripts/build-static-content.js index 75d0d64043..d14d4f8e8b 100644 --- a/website/scripts/build-static-content.js +++ b/website/scripts/build-static-content.js @@ -1116,7 +1116,48 @@ module.exports = { // Add the rituals dictionary to builtStaticContent.rituals builtStaticContent.rituals = rituals; }, + // + // █████╗ ██████╗ ██████╗ ██╗ ██╗██████╗ ██████╗ █████╗ ██████╗ ██╗ ██╗ + // ██╔══██╗██╔══██╗██╔══██╗ ██║ ██║██╔══██╗██╔══██╗██╔══██╗██╔══██╗╚██╗ ██╔╝ + // ███████║██████╔╝██████╔╝ ██║ ██║██████╔╝██████╔╝███████║██████╔╝ ╚████╔╝ + // ██╔══██║██╔═══╝ ██╔═══╝ ██║ ██║██╔══██╗██╔══██╗██╔══██║██╔══██╗ ╚██╔╝ + // ██║ ██║██║ ██║ ███████╗██║██████╔╝██║ ██║██║ ██║██║ ██║ ██║ + // ╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═╝╚═╝ ╚═╝ ╚═╝ + // + async()=>{ + let appLibrary = []; + // Get app library json + let appsJsonData = await sails.helpers.fs.readJson(path.join(topLvlRepoPath, '/server/mdm/maintainedapps/apps.json')); + // Then for each item in the json, build a configuration object to add to the sails.builtStaticContent.appLibrary array. + await sails.helpers.flow.simultaneouslyForEach(appsJsonData, async(app)=>{ + let appInformation = { + identifier: app.identifier, + bundleIdentifier: app.bundle_identifier, + installerFormat: app.installer_format, + }; + // Note: This method of getting information about the apps will be out of date until the JSON files in the /server/mdm/maintainedapps/testdata/ folder are updated. + let detailedInformationAboutThisApp = await sails.helpers.fs.readJson(path.join(topLvlRepoPath, '/server/mdm/maintainedapps/testdata/'+app.identifier+'.json')) + .intercept('doesNotExist', ()=>{ + return new Error(`Could not build app library configuration from testdata folder. When attempting to read a JSON configuration file for ${app.identifier}, no file was found at ${path.join(topLvlRepoPath, '/server/mdm/maintainedapps/testdata/'+app.identifier+'.json. Was it moved?')}.`); + }); + // Grab the latest information about these apps from the Homebrew API. + // let detailedInformationAboutThisApp = await sails.helpers.http.get(`https://formulae.brew.sh/api/cask/${app.identifier}.json`) + // .intercept((error)=>{ + // return new Error(`Could not build app library configuration. When attempting to send a request to the homebrew API to get the latest information about ${app.identifier}, an error occured. Full error: ${util.inspect(error, {depth: null})}`); + // }); + // let scriptToUninstallThisApp = await sails.helpers.fs.read(path.join(topLvlRepoPath, `/server/mdm/maintainedapps/testdata/scripts/${app.identifier}_uninstall.golden.sh`)) + // .intercept('doesNotExist', ()=>{ + // return new Error(`Could not build app library configuration from testdata folder. When attempting to read an uninstall script for ${app.identifier}, no file was found at ${path.join(topLvlRepoPath, '/server/mdm/maintainedapps/testdata/scripts/'+app.identifier+'_uninstall.golden.sh. Was it moved?')}.`); + // }); + // appInformation.uninstallScript = scriptToUninstallThisApp; + appInformation.version = detailedInformationAboutThisApp.version.split(',')[0]; + appInformation.description = detailedInformationAboutThisApp.desc; + appInformation.name = detailedInformationAboutThisApp.name[0]; + appLibrary.push(appInformation); + }); + builtStaticContent.appLibrary = appLibrary; + }, ]); // ██████╗ ███████╗██████╗ ██╗ █████╗ ██████╗███████╗ ███████╗ █████╗ ██╗██╗ ███████╗██████╗ ██████╗ // ██╔══██╗██╔════╝██╔══██╗██║ ██╔══██╗██╔════╝██╔════╝ ██╔════╝██╔══██╗██║██║ ██╔════╝██╔══██╗██╔════╝██╗ diff --git a/website/views/layouts/layout.ejs b/website/views/layouts/layout.ejs index 3134e14af1..7aefb13152 100644 --- a/website/views/layouts/layout.ejs +++ b/website/views/layouts/layout.ejs @@ -467,6 +467,8 @@ + + diff --git a/website/views/pages/app-details.ejs b/website/views/pages/app-details.ejs new file mode 100644 index 0000000000..c5e384b948 --- /dev/null +++ b/website/views/pages/app-details.ejs @@ -0,0 +1,88 @@ +

+
+
+
+
+ +
+ <%- thisApp.name %> +
+
+ +
+
+
+
+
<%- thisApp.name %> icon
+
+

<%- thisApp.name %>

+
+

macOS | <%- thisApp.version %>

+
+
+
+

<%- thisApp.description %>

+
+

Self-service install

+

To install <%- thisApp.name %> on your work computer:

+
    +
  1. Navigate to the Fleet Desktop icon in the OS menu bar and select My device.
  2. +
  3. From the Self-service tab, navigate to <%- thisApp.name %> and click Install.
  4. +
+

Don’t see <%- thisApp.name %> or the Fleet Desktop icon? Send a link to this page to your IT team.

+
+ +
+

Is <%- thisApp.name %> up to date?

+

Run this query in Fleet to find old versions of 1Password across all your computers:

+
+
+
SELECT 1 FROM apps WHERE bundle_identifier = '<%= thisApp.bundleIdentifier %>';
+
+
+
+
+
+

Share

+
+ Share this article on Hacker News + Share this article on LinkedIn + Share this article on Twitter +
+
+
+ Docs + REST API + Guides + +
+
+
+
+
+
+<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %> diff --git a/website/views/pages/app-library.ejs b/website/views/pages/app-library.ejs new file mode 100644 index 0000000000..8ea942f115 --- /dev/null +++ b/website/views/pages/app-library.ejs @@ -0,0 +1,64 @@ +
+
+
+
+
+

App library

+ +
+ +
+
+ <% for(let app of allApps) { %> + + +
+
+ <%- app.name %> icon +
+
+

<%- app.name %>

+

+ <%- app.version %> +

+
+
+
+ <% } %> + + + + +
+
+
+
+<%- /* Expose server-rendered data as window.SAILS_LOCALS :: */ exposeLocalsToBrowser() %>