From 7b88e5bdaf38138dabe6687e64657b3a7f5d3178 Mon Sep 17 00:00:00 2001 From: Kanav Arora Date: Wed, 14 Feb 2024 03:41:05 +0530 Subject: [PATCH] 3865-Add-Integrations (#3870) * initial commit setup * ui done * added links * changed brand logos * Twenty logo fix * Windmill logo fix * Fix typo * Add feature flag --------- Co-authored-by: Charles Bochet --- .../public/images/integrations/Cal.png | Bin 0 -> 2619 bytes .../public/images/integrations/Github.png | Bin 0 -> 423 bytes .../public/images/integrations/MailChimp.png | Bin 0 -> 4145 bytes .../public/images/integrations/Slack.png | Bin 0 -> 14675 bytes .../public/images/integrations/Tally.png | Bin 0 -> 3899 bytes .../public/images/integrations/Twenty.svg | 35 ++++++ .../public/images/integrations/Windmill.png | Bin 0 -> 7953 bytes packages/twenty-front/src/App.tsx | 5 + .../SettingsNavigationDrawerItems.tsx | 15 +++ .../src/modules/types/SettingsPath.ts | 1 + .../src/modules/ui/display/icon/index.ts | 1 + .../modules/workspace/types/FeatureFlagKey.ts | 1 + .../SettingsIntegrationComponent.tsx | 104 ++++++++++++++++++ .../integrations/SettingsIntegrationGroup.tsx | 61 ++++++++++ .../integrations/SettingsIntegrations.tsx | 20 ++++ .../constants/IntegrationTypes.ts | 22 ++++ .../integrations/constants/Integrations.ts | 12 ++ .../integrations/constants/Request.ts | 19 ++++ .../integrations/constants/Windmill.ts | 19 ++++ .../settings/integrations/constants/Zapier.ts | 40 +++++++ .../core/feature-flag/feature-flag.entity.ts | 1 + 21 files changed, 356 insertions(+) create mode 100644 packages/twenty-front/public/images/integrations/Cal.png create mode 100644 packages/twenty-front/public/images/integrations/Github.png create mode 100644 packages/twenty-front/public/images/integrations/MailChimp.png create mode 100644 packages/twenty-front/public/images/integrations/Slack.png create mode 100644 packages/twenty-front/public/images/integrations/Tally.png create mode 100644 packages/twenty-front/public/images/integrations/Twenty.svg create mode 100644 packages/twenty-front/public/images/integrations/Windmill.png create mode 100644 packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationComponent.tsx create mode 100644 packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationGroup.tsx create mode 100644 packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx create mode 100644 packages/twenty-front/src/pages/settings/integrations/constants/IntegrationTypes.ts create mode 100644 packages/twenty-front/src/pages/settings/integrations/constants/Integrations.ts create mode 100644 packages/twenty-front/src/pages/settings/integrations/constants/Request.ts create mode 100644 packages/twenty-front/src/pages/settings/integrations/constants/Windmill.ts create mode 100644 packages/twenty-front/src/pages/settings/integrations/constants/Zapier.ts diff --git a/packages/twenty-front/public/images/integrations/Cal.png b/packages/twenty-front/public/images/integrations/Cal.png new file mode 100644 index 0000000000000000000000000000000000000000..7941af38e64bb1ae76395ceb25b484ba940e9cb1 GIT binary patch literal 2619 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 R12X^s002ovPDHLkV1nQ4rZfNm literal 0 HcmV?d00001 diff --git a/packages/twenty-front/public/images/integrations/MailChimp.png b/packages/twenty-front/public/images/integrations/MailChimp.png new file mode 100644 index 0000000000000000000000000000000000000000..67018e75e8af1703e193727b5d10f2936c96464e GIT binary patch literal 4145 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-front/public/images/integrations/Slack.png b/packages/twenty-front/public/images/integrations/Slack.png new file mode 100644 index 0000000000000000000000000000000000000000..8fe767eda642ed54b0cbefb412562eee44a8b284 GIT binary patch literal 14675 zcmbum_cvVM_Xj+B^yr-+h|v-?(TNr{+8BL^E^74NYY+rM^lk>Dmnee>A)@y-h)ztD z82y>NKi@y#S_u2cLefB+TpZ$8B_}AL1q(qEF004mWm70T4i~8lm+PqNureN6X27PBLxNOn*$n})Gc5f5hZOIfs|V9quuurg%9E$ zahN}(En*57!Z$9z>{&Ce)}A@jEN@-B3M|+O*7hE=(eu9gY#C}_AfA*#|AMoG${)Y; zi-=w@-(*U^WrR-bSeQ=u^|}N?O6yFbfj{sMGOC4^{HJ^e-6T$G2;*M1j|a-jtN^RP zTHq(!doMP>AJ)os9u(tnHTzzv=lwG>srf{fc;nKz zJ&Hb0SZax;noIO=MN$Kf1!7~@k2kwEJvmOQT@&Y+Y_QBWISZwgRZrJ(VAgkK^e|OCIS`%sfL00Q5$2 zQ?X~-F7{tY=+(T+eMl8zp=8Bb64;xIm@<5v#pst5Y2e}B!G&PwDALDDm3#PJ^AYdd z$HCsJpU2;wH;*4VUFSw*mEHBQCTzF04-I$jp9zfW2EQindxKgegotuMs@9D9~ z@#2d)1av*uAibU^1EB|pCq&j^f$s?Bbo!uJnckG*Ru8u-u=ygWL&n~BcOE>uv2^}( zN>p3dcYOHfEae#-yzr4u_xtvm-Sk@2!L_IG6$6wwze>SrBW~pVkC?8w1Fo<`ohOSiFPVZ%rhe1;$EEaPV@|nz68={;dZm z@lMN$j-_&jrZ95)yEy)Bo-{j?+8U5qAz>qQgO&8Ql~w?UxQ#-L07z4mhDvO}bYbRE#ySm^ zlE^DhxIeJaP)1i3oQgG)qTSM1_0Ake{jV_>1!%Rhlq)Pc@MB30B!-b|l ztbq-Y1_mp=ik?Al7crBxF=;L0u)K+COmFZKQ5TFY8geS5Va9vUrk$>0e8PC4bJ`nY z6;bOaNXzFT3{j>Mz9$Y*S9~M}Cz2{;I z0_pmZ%w;90)elXvfC)2lC{eU%kc_QW^@tOtUGUfe@_3y={FokgQ;v*5Nn!rF_JC9k z$-{n{u|L9-DOljfxA`Rl>It8bXVEpU+k3b;KBhW-MmVnYub!);pQ^fgaOT7weI$q7 zIH%H167%5!7YK!XAK3Wn3dv1$x;tr~KD_hoi>_mz4jb~@EX?8sBIazq9&WPD!+mxc7nZCXV zYjY(|ehEM5vmQK$Ec7cwtt@Al*yrrsVO&Ek<>aQU+1w>O{uzc_(m;<8ek}Jr_oj@B zC(igdi8P7Wc}M*vJs!Wd{p$P6BFBrpsP8(bVt)FH$vN7i?Gh9zrP8}>cbu!+P5VT) z-!|(=C(=|g-y`CVuwXkI`09_x)AnrJX~W9+pb4U~L~>^Krkk3^0?D<7-vi085`BTT z%7Qeu<9EAk(MF7>6oX`$WX5t!$AH~?2O4no3$(teplv)0kR`d{NtxZT3`#{DGpJ^2 z_%150pai>)tiU>58EUt_nYwsaQ2Fiw~Xr@%-Gd^c=LZ}z%Q(Soo5-|ZU(EuSziWTL1vmYzm( zRAj`x{MQUh=xx10EGIum$@500PB!fzq8lpN&9Hbfv=XV!lrjszkDZGn9Eiv41>@<-bOL0|yqNXG`T z1$opGOD-LJA`6#!_0Md0MyMp#!}w*V4_30OVA#-Cgf#@SpI1@fB!&+ltjkoiE6Mrj zNS^Y`r%aqsaTcLTCF7j@bm7hW>0@8Okk|l|+&7Ykn}%+0ng5^W$5XLyQRI_-Gu+Fypn~hw8n(u)x82JVJtoU z7kboi@o2e}?R8-F5QAjOhktUmuabKPe&ix|zPxSvuc7Q!@*00>@X9eZyu*4<7oQd< zF+-67QT&eZ)O~?MpSh#h7~@1p{UkRb4Cs>42`CJBg!RY@!nI7o4|*$H%zr{oVO66B z(4+?w{tK;KMMQDq)o%)_SB-Ke|La-#u<2(s)Sya4b|Cz}vFfrzj<&~ps~hx0;QMj^ znz-ayn_^Vg61}PxeabU+-T!lo=tx|{Hlknz3-rxq5~lD!Z<^yb(LU<9swb>|KRWiG zqaCxz`RmVrNXs8&#Wl>@x&Qj#L=_lK94Hfl*C>o-a1RplX&nC32~z`TL^_vt$W3D3 zG>B|?e;p)c{x|1=lP&a@w6qIsSV)9dS?!rqKFDMpGcZVf12@le)q``?#d?LJ=|m}o z$$u*V6)sd}y32cj*?GT5$q%bgFn}@s$lSt}+T5GoWg6EsE8^g%0yzTc{zbuX1I8;1 zf2dtp9`}j?TfiV5)Kj?dTg+06dHzWDBdpCvk)bI3?xoc3_lCBu01pYx)JFdq?@-o; zi{vkF4%ux;A;>ZW<7ZgPO8p@C_iIvVaXCi82 zFTb91mP%}#yO15Va|Qcqc9RSC4enmM{ZAN&C<4mZosV~n?>@mDeoxcrD3RdXC$)F& z`oHfbIrP@w;oXBO|Dw76|AHA4%l|ATW-$KqB|pgN|KrChz2$?ohV9QDdHB!ZlX(0c zV*xD*kyDc=BnLC48E@ymtRhkaKR4!H*r8$$B2Ci1BGg&o+%b9<=80aCoeZ5-Ub5&f z7CCc0Y!`2|VCM#(w2%Tw7XXyyUH^=Q+41(!=zel!imk*E6?6N{NbOIx3~|6R#j5s} zgv%=t8Arey2p106M>o=e`J-L0Y2VU@#SWHIaN8=LEI<}3b*A3uS*Y~n%AXFpdosB( zx0Hi+)HZq{#^(`H`n@WL0o!Y9ChF=ZBA%QxMx3|LHJ9%17~uhvRgL!TtIFvsg#$jr zA7fX^N;THMAQP#7_~;f8A2~>_Jm+~Pj*06HoJ@0xv|*jr2L=PZNvHq`G$*PI#p2H8 zey=Rod~;#cM~+BDHa@gEiu9to%H24Q;iv~Iu*A?9K9G0PF$+~T_`JR^T*`-%WpQj) zK{$aUtE+)bU%1Gxmw5W$piER**;RN>q>qQp70062>_i6#=rowEAp_+6D?$3Yv*B%b zjH_Q%d+qUVgga?#*{!iZpPc9S28FV$nkMx$6YVAX-HP6===`}z`5M^RKc1lMT?{SJ z^>D>4y$e4e>U0glo4QV`*s%FD{oGw`0Dh6Lja3f}W=-j9eJ*^m_%)t)5@QU9Uy6R~ zEt!1YgF^n^9n=#GxfCzW0t{FkBu_e5*D`d$-4TJ8 zgcdzZnViYh#*21-6s4YbA90X>EK}#Jva|9lbnyj(1o-B`?+Cf@`<(0haBuq z{5tH?7FFZj`r9g+QMt~|q`P>pH)uWTU7F%?o?}sKpOSIKDRZ49#7+loT~G9dujkDk z?-BHsI%bGiBNlIy??_zLW4Vn9g$r)W$X zOI1k^VrZSvWL7@C?_p{Gnh>5L56RZYMrIG`=j@z)B#fk!Eeh zpb#plIfZQ?zx~~Kwe9etcek26`b@&`j7{jR^dq@x<@K*na5YnW~|}btJyfg6Acf40N|ub) zavU^A0-F!By>`a4OggjPbh9Tm39-oF?cwkGIsQj#$(I1Go;*L5z{&4}2$)7;p&crs z?J!OhgD`ML#u_&@+GFQey`&8`2Fy5_g-(N(CO(b!Mtc^xTLkpyPm5X)Arc6|Ej?8I zbg*KhdJ#Hvf5C0X_z8iQ`2_A`tOGF=jlrY#`vjTr^N^c4NdZw}2Cx9O#!uIZQM7B^ zwK2yKpP2QNlf!dtu;&WIJCqtRSP41leRxO+3s;UcVcvQQx5mnJq7-b};`XbT(}{I) zy}963%6xZb5Oc8?@tuM;P$pzC)%1-BoC81e$j#Fiv^+*(9I_YONK0-(c3kXZLx1}j z_+D%^B~J#=a!0iNoCF7|4EfG}r(r0<`z6?@_l9HY$3<5aLO@9b)rV_F-8yy;D z|MZ{6!=7UOPoWf&N*s+K)tHHMPwCSl17vrEB03S*0N;m^U+43kNUh}vB7q*<@B%Gf z>ihMUnPPF7_dM7DDL6zr_3VVOlH`#3)75jRSJP5116UVFLkX<9>2|~Qdnbl#Mtt2MdNr0^1JvX1akK(uC&`K__hJWa}}zh((kbct5jUiG9j? zRTdwleVo z{D1`LUeTMlQTxxh&{Fjs%^s5p4k&~I_=o7tp7LLFB`-tj!Vnr9=V5<4vz;{!yx;n$ zl+8Mfv%qyCT~w>(3=rdxC}kdMU!8$;nq={kFZl3$z7};Wh*qzEp08IhHBDP2@|5Z| z!#pp1ar6!0(a8h}+)G(mednhPMQC)~xBal!i=ns7N~Dc0$?$Sl23whU;Zt#-JJXB) znUrem?}HPKJT1%I{&+XR73V9As}To1Rnaxsth}Nsidp@t#n?Y>AY%JBqiQbgo4fAk z$mOBk>Ulm~sXr<<%J!fT=2TEWjo<@VuW_{;4^{>{hda$Fjj7A|h*lr3@zH@`ts^^EQ`gtepS48zZecyf>Y=dU@w{7B`AlECAqGHa10-Lg6-&6%+)TFx?4 zG1@`MfT%`$UGZphrr!8j5{|*)& z?e-H7jV}OZD3Ax{hz;Dxx!-b|vOO3^m=ri$2mTs}bVjlv&s#D>e;66MWtc_HZO615 z50QZjG|(C!GrID`u{18Fq4e`a5~j0bhRio&;p$?TaMK55syhN7{T$+t^mcPk&oouQ#f@O;IgZlY`NZ6m+74py zs_2K%{#XEdDiWcm3)1!}CqraN;$^O^+&${7pNiQXhK7ZFRe0C%Ta?JciMWa#Ggpts{+G~P=EEK{{2qqi9*ZP=x`ek+pmg1<^Ihy2h=y}sATZZg_amupqosz=of&)>)U2(oqm{_KgV5{OEa zpx^VWjovef5tZtT;f?5t1>aG%EX0==EHN3Can-M@?}!-tWJxo+J_|d{bTV8INW0`U zcFD{TNz4QdbHklhAJhlcZlQw>;3=nC|!07ms8#UnXo@ zc$>6P+~I&sA9Yb$>LULmL2)nVm#hE+OgXRue7Cv2r3(YysZ%38D+>pS1l{%{?pKM>MyM}G zWJ(~5ZX0~?Wlnua6YlHaIgp0ip zz`zfxtpNN$w}%g!Z|x=UdAvpf{+^6Z-H&OLrR?UU^8f~UGn6xj$NV3?OI7r zV(D~y*dPISr7ZN@6FLqVz#engsT1`j?eDo_&q z03-O4-LMWLu0M9jV;&v5JAspH>nmnt-oQ?}_3LOF{8)jk^Fx9H9Qbk+(FsowRPF&% zI{w08R+^>0c`~yk$x1Gzpd@XJ?c4bZin6mCu(yt)?MPdwzNA|c8DY^FQ|y?|l=7Gj z%&gR;lF4EZrrqoLu$toamG<2Z{;AW1uTEPE&}m2q*eL9m@$zrtxcj9d`d#w#soDUX zN#_NZQ*V?G%OZuB&6!NHG+xypq1fdlSyezo!X~2ZTE&574GVa6#l8B4alHK}Ek*j@ zLUDnz7c3!kosnj7ELXYDBGffjMxLQkQ2Y|O1zgs21gTk(a^buiQXs9fJgtJ*Y~Q1K z5C-q72V2ct$JqNKzIjCzE;VL&nO^@y-jAenGf?KR*$*`KQxc z@w^0!LhA^d4X@xqDB&GzkjwjSLfzG!RM)&HhsVsf88>rFeFTW(Se=+t3<`bdUZR#nj(>55iB>-zEDkaTuV&-F|m9aY>w`*hZ?JcccQ?FA3r zQ<&Z3-tpI7s7T7(+?SeDiK_bGS0<~LwF3k*iDy>;)3<*2gu)g^9|U8KHg@>twb~$c zg*Pv|W%20QEo%mmJ?mXxK3r&g$WK~(!MNH03(JVx-axCV%O50FJ}-z68aQ{;^*6)D zvFPCdC{%TbuceH%6&$4gOko7G%ct%jRQoJn=JP8C(A}6JEe395j(dKJR0YKhqD}`< z49f`@p>bn72BqzK!<>REDb_*ho4I+9Z1YkM*wG4p#$}MMi0O9=LFRBAxi_sdV|^EW zbN%+~jW6i;?AC>{)Mz56y|Ajg?^22y%wrQy_<@8#?FTAdIL*)3MZ@coD8W`kID$)@ zGSqhguT=CX_j?21K3_vgMBK*!X6NJ*F5JEzq<{FGH1-CB4oQQl7cSVR?rdH;paW5y zli ze03G_YfL>h>N?*Bk)ieeSkl3IFj)60alxiahPH}nxGeC+$8Ppcp4FadDDGXWKchSi zA$-|giA$=#iYgcoQpgIH+|9WREo?`p1>6Ozt2C8K9iF}>*9QRTFaL1?(hC7FA`p4- z%My4f!(O`W{nBTw3RoqhC`eDN!ro<0tQc>KdNspC2t~7T#4`SJmAsm!K*r z^jHWomn3R?QaJRSuxky2U%mR?YVy6u0)Gv=XW+8}TPz9KB`G2pf3m_>;o?e(-eAvL zD>TG*K{r%rlBz1Sp)A>NZg)z)XcdpQ??Sv*D#`8WPmgYa6Kj;HVNnhq~|nX+c2zwm1G6Gi*jXI+VR_Gz8^Q_`_N#s}B3nNK{~ zUw2o=W*4KVT2N9tg@=YapAC4cXCRlE_ZubgLKOZQK7$FniX}Yh{`9~^HDSBRq*8W< zNHrfTbY*6(qsZ#d`!*MZ@M-Nd&+I8FQ-++_<#s6hxloBCUs*R2cS?K6G!O*0M-Z%E zRe3s;OG-_NUpKp|bhz09MK-%4cv}T8VH)~$H|*$XgO2Cnc(0FQ)bC2hr=!n)nb)mV zL~jcuvFg1*70wVEo)vFJbcximMGjKFj-O9mI0@(KsT2&~G2q6@WHMX1_d#pV6r|P? z(Q(439e{?YnKCccGBN-A>7Cj8D2<1|$D{Omj)xa%_gY6@W)kwblKEsgJH46_R$AG~ zkb%r(|9-^x*=Vo!CA&H26)bI0_wz$Yd#~M@qS0^lA}gAU(`I~u`<#}>>>Zy+!)bVW zqIizxkB&+U=Wv8!9ZSCb1fYFo3_fzJWJ-_`#b% zTH#>EX~bDhUET)HH)+@;qp9aZrG^7n_q<3LS+`|K)>O`xXSl53vp;Sn<6odI?W&=T zCoGmePGIrU3W+zKHk7{}bkh~*fVDq$DKd2%9O3`M1<9~Eb$Ew%yu9e(I2Pn@E;0tE zPRu-e^5LRtHz7Cj&_kuson&j10zJbG_lc#8$If1PQgn;hXZjR>_P{Ut@XN5xyVs_2 zOV*;KzAm)j4E8tSryqi?l$qZmCTId>1n1q#%1k?^(DKxZ6kH!Spbx9CGjr<12`+tQ zCk+YxG98weLgl2#CE-d1Unv)KdJ)zst*vX>?-4rR4g?&3&v+ShZ+e9v7T-b3!?&(V zB9{<7c)#Yjk;am)VwLj59X++Du!&A6nqt-!Wy!b9Y@^fbKsl*);))BCD1NkUSOl|m zz`&_E8h+h;z6UT{KgoVS_jA&lh;oUh2e3Emp#$a=^MtWzU>0t`Av!7)i3i#W4F`oqD?WdJ z;Jv*5(;}s-#vYkog;>!mPAx$5DFlRZal-tET8}G}ciRd$g`wS&|5cv$f|pV=DKS-@ zs)mdTY+vW9In$;k7gs#+*|Fe}EF}J;&nfz?K0*)rTNhAJv~biJ@?j;c=l_amwGW=P z(?HI9>3kPD#g2H8={Z=S0XIt7yf7k!cGlRw350iioQ(J%4kyL(+XBKnwd>$klJV0P z(o6+jer%&NV@}S$C}?Zytbu_4z%hU8r|UR2*yv-xb!b+Y`op5Gg`2gv+wOQ- z;WGhIT&+qLhRHpYaDC*-L(=hi9^LS3Akc*!E8~%q!$imTcN$uU`acm)7(SE7*<3## zrabq`9R9-}d@D+L;%Bg^LHU}nSo{c%iq@mzVHANcQd$L52@YDY&&Ri3>6sGyO-z0c zmq4s;*tbe$e)_=XzEy8V0`m(K3yVNIEN6u0VUKkGB;a%UbE@L%c27Ws(dIsSt`kwj zOByI{vQ7^^!UFjZHLPDx&kimB`C04i@jRZNQvy*pbuHP26JkOA?e_xtftg>T3Li5L z)CEy|u%y)c3+KuFxl2fD9+_JS-x@25)OGG~XH~~}BiSQYS~EO+CX<`}k}}NM5F3au zm0eqy(+#$a_F+ltv4&GQi4x59 zh9b@*68wMAO-l3%*|%ZmJS^Wv{!Idjas`Cghy#ZQ`&mjYXaQb%*_nVac{^!jgZ;MdEvGe@3G16I_FbK7BCBWxlo+EGVl? ztd0?abiEbZ!mxfvw?%Tzxg(Tp%m*4lio>T3x#W@SsS>ui)pPkZs7sp*OR2WRvovHl z8BXAr4rr0U5MIcxoXzU~0t0R`N=X0WQ)Tua$JmRRPWhBEEN$_l5MeI^nMi2v zQ5K$LsSR6OMX^;`S)uY^EnD*TYoeXFLaa z9pfigeXcEr`c%rtF>88%hKH08X$1UW)JnB`dAl*VMBx3zkFtKb9;}O|$puX43BlD= zEN5p?g%hH`?5r+~`}h6PhYh>J@SAQZT-_py3wR!nD%q!piYjU>H@4lchUc0sR_gR( z@SI1GDmNYA=eAYC@+q%x!<{x2&hLeI-Bj_<+b!|kjQ)Nh;jW3p2A6f;EwsrJ*H)_+ zWJXUk>mg;Y@1q_ZxEqlJMW5+3AF+(ofV4+rtm8&8}!qUew=E8_j?zesVQM+lBRMPQG)axa%d&GrkE?8Xa* z%rZyuYk;&qd7r2$Z<03pj>SDVk*{3paV=*z=)`_oE~Wfn$!u{4nly@#^zTRH%ql=$ zjYapwDc-g=&DdUk-(BzwfDP$$vkF zy$`~a#GQrUP12C~ZW3o&4%h|qeACuLPxK|iivQ9zm&WO#blY)Cog(~I&>i=q7&y1 zw-Z4s`bJ7WwX+if@umhp#^Ni<2J}!w-;MYkV{mE#J|&b5jgRMH5+L(dh|whC+(Q&^ zCtG)>txV!5?Lb+`qUqcp@rDrj=RJi-*W`AH;DoB-Nd;&;Zp#um^5^QPR>Gy|mNO## z7Z#4QiG6rk8F7<3@1i9Borf~3=EK8}J41YgWWVGPXAS5y-Z+Ji!9b_K9iRD^5!2Cj zTw%7!9DhlFyxV#_MSpYc>^rkVf)`$NlfbEWK z?Ix^!W$O`tN|X(MeVSKUr50GW7Bx4#@+2Wl9;K^ovL0!F_ua4?|YpqYuJUlhST>Ijw*xb+9(8P;jyP~YbwBX$1 zFAd*)**YJ{(zL8+1J=C$TwHI&!xYCbrTEMTkcn0?1*mFQt56X4%{y%H^Znv&&M)4v z-MD}!#9fHD1E{#@!as-6fIc;$e~~5orGs16A#@eA1=u&I7~^F=gC*hU0-;-9Hz$M zV?YpTyyU}un((bWF~I;XQRWunlWPW-_{IiuJ4!`(LL+2dCXZlN&%J3-8L;) zaU_Hx8u5HZI1$71lc_-7%#xLTn3Fg~=}!M~*fr8PJh-`SEiuFE8C;kU762eFXnDsM zL=6$Any}ItnE#qQpbn!4ui(H?j#7T+$^pU31^D_%771fQIvglp7)?ypG)EuA>J%-8!s`NnfK27YXP*~L}LvV{-rcyJJwtn#>8)2(36cxRB^va zV%YQ-pqH$5c!fNik{cg1hckkkmC$x5$9Yt@`xDLnA~ta#!5ovTWfBVXyjcaZ%aG(7 zKeHQY1lRv#?Gd#-q}K`}lLh2sa%wI`j2!6supR}ixqiW{CDMEt!ziQtN3n`F7cVpv zeBdy_IB-cK06P3fd*e=Qn!frf)+Wn>TI}c>w;tfd(Ab>&)S!@TkzZ_BZ4MncI`1F@ zJeXD}mL-Xs<+|=mklDYUvu@DxoS3uE6+@)h{zamE7!DQ&@@$F$QOubd5Os2q{$ES| z{ul>DCi%=j27{4XD+B*&dgdN~cClSs#t*Xjr-~8&xxf&v0hqnBHF<;~tSSE+1e7qP zZ>^3RwpV6YVpl&Hx$~@|HKzxl#XT8HcaEy|vwX2T4` zsWeQCts6GI#3muVfzm_UlCr~SZrJ;#r}|$_=9Jg(mk#yu$q%`xjFlCh%IsIe7+Q(nkyTndB=hR(KJLlExQarV;UB4$?>)OQvixEh;qT)nSJl{5 zdaaeY@nEce~qJ1#Xm2` z9tDH2_}=N#Dkl?xHITPU*!-e|BPVB{h?S^?KaM_uO8*ig#9RnqO|Avke-E40Mp+88 zSbaZZR?5_pAkf-NAin4)ud>shE#~*;E{e9R3(mawA+0!+@G|@f)D0Pm+-an?%}%$X zu)1a0>phCAZ33ROLEBLh%264;WPW%XxqQ~WBFZ17?-OX!6%hd}#UGXo@x~s&vBx|Z zI}HQFx0H=l4Q<$T4#W1s_)yu_1|M@HVQn-KAl6zNEED05lbkkkY>U8VD$rvbuxY&d zk>SbN*od%CQ5z*Z=NKyyBmJBPoA%uHc0S`YLywdn%ginB7b5n9>!d3rmBiu5IF&fk zyG)0#$zjb$M)yqDk6nhX;N_6|$4ZW@sOuEOc`%pUusUbknaosL2@}#qqw6S^<~v}P z8%3BAac-SZWO%y$k;Z|K;n~>RTp|fP<5%g)vViK*43ftq>bB-h-GVUd$^{B3ozWpK zIgXg4CoV}R5~$m&F1LN(VV$G$j`(w~uClk<2w~aZ)h+geeD&TmDs^JQ<0x{Kh^>U> zcx#pD+z43dh-CxkBunbuM22ZYXWD#MCu`&B?A~Pu}N4AGZ-fQF-Dm> zi;ez~CXMLDQRQWIV9;>AnpUyJS(vsMd8BdIQ*x@8_6{C;BBq1dr~@ zu98Fz7RdzN^m~!CKSxk^1!nE0PAN>i|D~>5zF+lw#+Onp2;}hUYW#BVjgRobT@RAW z1*HibZfP(6$a>2)yvrlcfY@sF+7+Wr%@>%Nls`7l&cqrIO>}sSw%X+cO>#t(qz-5O z@h!lHb?+xo{6OA5Hnx2ukdGU6Yawr~G&*Op**~ym1dZ1(+e*ucpg~LFswf#A7#Mgr zFz9+13=G4t!#><9$#A_$4AMd8!kON;xx7x}$CEPdxyH0@7vwVhVykHM|aJFLAc_LZbW9-HC+#oX14K2s`< z1S~{j@GuL5L9eG@XHb`@EI|1i^Y(>RCigC_@3|He1tu8q(>1ed;_E`&Dk*Y-Z7-BV zhGOppYAb9~44tRkR=dNu?p8?XPdOQl_H}!C72xN(kUI{XlRCi<`m=wJ^Fc=@~0drDELIAGL9O(c600d`2O+f$vv5yPV zKB73{h$D_Tu2&?`H3nv`E`OQ{8wzXVCt;be5KKr&xI)(ut_cB1qbJFq0m44Q9>T`L zTEfKgQ!WV42=@zD2>&izFTyxYad?L`d~M;ch5Ln<**UHV|0VoM`5P05TS&tV5FTa! z*epz^IGjNmD?#{_@GJ+1BH<4y4tq#LJ;&j}Y2i~8hZ@pAk8^lYEbL7&gqX2{q+!~~ zpU;F%ROej0c#%H;{Bz39&832Z0xB*pCb4uVIXRiq)6*#@Cxc6Rrsx{wO)GZ zB~D68(l&l5>({T(OP4Oy3E-5lHN{~<8e^fVrQUn*J+4`^rsKx1VD;+NS=5zI2xBM? zqw%W=k6X3Sp+kqbL4yXa8^40L-F6$FJ9kbcfP9L>5I`SQ3qAYnvz{Bjf^WR>25ZoQ zu6IZyOtEU2^XJcVc`!?chk|MN69bp^75#pq(pT% z>H~2s2q4w!M+hJYT)uqSm@_EQl%kAS5I~C6k9+s-rJ(T5H{YlZ-AGYJEC|5TU3~WJ zSqcg=o~RDhq$nfm0+5EbY#p)vDJaycRZDf~0!0~77l1TQk=5^w8a1MzaN~_iO;bcs zMl7hHLaQHdy6Gkg3MnZmszb#TWmF>{5IY)rq5+wM83N>&$qbOg?kf?G<9P?g9J2Z` zH8qujKw@H|PMC+u0pvO1UaehDj9Cc$ zz-~Dgw&ZHzQmJU6qDV^tG;P|H#GgYKF8EW^x88cIZamqgI>2TkK!&idFq6#ZgkHq& z5J0K$pqvMD?Ni}0c}AtVcSzyJa&&m!o_UHc@ry@`ylFeE4wR0(kxP z*Hy(IV^g)D4poHr3s(p)vOk<>Gu{x46;WQXlN>xYu=z&d%{pOq!fUU+=34+?eDQ_q z{-3egR%>(W?L+ee_X|0qhXgR<(0AMdQOm`3JHI+Hc#ojU@DE z{5^8y2vx0Gm6|tiPPg203-##HgTxg~5~n4vz_r=g+4Rmk?~oVVe*5hd1mH{hzojDD9w??H zKla#ThAOcMk}EN5)+|rG9|3x4F!lnxd3*Nk;a6XMl{<9kV3ei0k90VG`Q?}S+i$g+ z3`u79I~71r)>u1lzWFBCsZ+;QV~D$f`}OO`AAR(ZYe9Vd_1B&R(7JVN_JXgz`pU4r zP-mz2LPzY@tsC#$xl>m(tbs&wAb|O*5|%Gt&hol>*2#D%=;a+dcCb@GVDh@VzL$;t ze-*ZG-_D~(jq;QLP(jRFii?X?w}6#3(5~_83rnr87XLiUl-_gYLRq6m4I|zw5ifRv zhaY~}^*xp>S>mYdQ>RYx#EBD)RF)u~ZRE(2I?HR3odEi(uADr1av&89Wyg*kdF9HL zc5TEm2)in`UcGuO1E;o3==p^U7qS=(fj$$`VW7qoK&5Ky1n?WHtIEpCxLvz;feQe< z;f5P{^ytyLSC@C~+GU*Qv`maQXkZoaHuvw}pT$uZmS-9}cC6~wmxQf!0Xi zuUoh7J0|OzHESIAzEGPSJ#p^bxyHBphj3m6gS-SFbke;lvz;Wg~%po;`bZM02^GCQO*YM*HDnojrT@G-lTd zY!j*nR5_R^+^V`7;XR#a@Ome7zl{fWBH2Ms8mGD%v&*Sdr^ep|3ub0!>Rb>2rurSo zfdJ~T8Lw3Wi{K;>aor07+5iqp#I9}P0l+wN3N~W`+E_5&2AGHA$B*aK)KuHx%>N59 z&_mTc_~3)Qc=2LBbH-7~e4VhaRa+-01c2Y46HX%sIC=6UZP~JgHgDcc;szk`9Z_Ln zA&E=DcVbnvfUu*y;gpn=L`|ABG1ei&3uUCP^Oc^}=CA_&BVpCk_p zx}|3rvrn0j(Ek1V>G0vhbmGJbV`eMv0g_kNNE^rEYcX?;g%tQ7a}6BFUl8XZ-i&kH zpl;o|hAl2$RD+nufcPKjiXbxYFn6dpE)zFn9)YYp#J17M5CD#OjBO(uaDX)aM)CqS zts-m}bB-ej%sZe{Va~ny;)|Z##u*tIhCd0ebohgG?&&ZACTAP+3pSINdJDI61OWkz z7%{?^&t6mqfBf;s9AT6Rr?YOt(f8WjnKC4~S4;R*iTtxl}7i z4uh41fWF&nk^3`g(j+5BYy;@5v2?A0&HW#a=$;INB1}v-+t7q^$dDmMIq<)Dbr3%A zzymCE6gwec^q#=i%Kk!9(QLNa?GU#46Hh$h%d@&{+5h%;l9{RJa3 z=xJW`ePxarGv+(x9y@l-cO(pB3bH?JfI-7qmUAQ_m8!?4#h}E74I8*kn>M~1A1-ht zid6>E;Qf}3!Fkc5MRpn7c=b9{EI}&tM_rBc^74GGbP45Mcim+RIW{L$!MY^zNMvUGnUdccj2b?)`rsaJ~N=l4m-yrS*Az-6G8~mQ44L02pO4Wl^ zCM{aD2(0m;e)99xuBdV2#szw>4?p}+CjcZbbfRcND)3WP?U3IYRFACSJ@?$BYY-zR zG{`V161%XxN`oa7EwJgP-lVEo5F74Q=KT5dwE{pKA!wn)!8q@D6~59U3&JNPK6TQ>?460@s_+u~@{Ze(pyYIdmSY4VmYo=RD`y@pga#PDxV0<_si1oLyd=4Bqz#2SV zUJoP_Teb{VtlxX@y@3c|=+L3My7Zz*gB3ff;Gw&A?dto15pdT4{^+_Pb(yR>5vvvb zT14njxw*Nz`ZS?PgUt<{EP-q^KM#$S?wTAP=%mLh)g^_^J>V?ib<3LyVv#tu(^p_U zMFVVR$|&#u|47 zR1qE;E7!^4!)9k^^N}OkkTQ01NmtY*Nw{2jVQHyrAz&SVO{^G$RP=I%#z!0QCd>FbOX6wFv`<(2gg^0OrZV zT6kRH_CO#;v*%9*kfLb616H`fW?WzvI|O{|=;=r+agni%-Fh8a8s+stma=W($c%%R z6CD5vS`Oa83P4YGq*#GerY@UX6Ndv(ajw30#O4HT0fz^WQa_3{uxS+`VjkpPqkm(M zTL8;-RoNz6!vhM1Srn^aa}VZUuwrKF0#F}wg*C_r*i=X3Ihb_}Sh^dWb19sVinb8W zVZ{c38la*6A^aW%2sTs8@o`DpbZ84e-y<*7S7(R{q|)hZW){PkR+)#`)b!tM4&>b_ zOkh(bWeTyA#y-}+6_^QP!3lPGuSa1-L}Hocy$3-H45s*=2zFG$x>NY`_Xu}8{MtrP z^}$CdpiXWUHYW3<444C8S0{Xg0WR)c;)o-TIN}Hk{sTwgbh40Stpor7002ov JPDHLkV1iV8P9*>U literal 0 HcmV?d00001 diff --git a/packages/twenty-front/public/images/integrations/Twenty.svg b/packages/twenty-front/public/images/integrations/Twenty.svg new file mode 100644 index 0000000000..bb5819bc26 --- /dev/null +++ b/packages/twenty-front/public/images/integrations/Twenty.svg @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/twenty-front/public/images/integrations/Windmill.png b/packages/twenty-front/public/images/integrations/Windmill.png new file mode 100644 index 0000000000000000000000000000000000000000..4f10ae59f75ec4fce1033c50e24467f285dbbedf GIT binary patch literal 7953 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 literal 0 HcmV?d00001 diff --git a/packages/twenty-front/src/App.tsx b/packages/twenty-front/src/App.tsx index 801fd04c5c..bdf99f5bdf 100644 --- a/packages/twenty-front/src/App.tsx +++ b/packages/twenty-front/src/App.tsx @@ -35,6 +35,7 @@ import { SettingsDevelopersApiKeysNew } from '~/pages/settings/developers/api-ke import { SettingsDevelopers } from '~/pages/settings/developers/SettingsDevelopers'; import { SettingsDevelopersWebhooksDetail } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhookDetail'; import { SettingsDevelopersWebhooksNew } from '~/pages/settings/developers/webhooks/SettingsDevelopersWebhooksNew'; +import { SettingsIntegrations } from '~/pages/settings/integrations/SettingsIntegrations'; import { SettingsAppearance } from '~/pages/settings/SettingsAppearance'; import { SettingsProfile } from '~/pages/settings/SettingsProfile'; import { SettingsWorkspace } from '~/pages/settings/SettingsWorkspace'; @@ -153,6 +154,10 @@ export const App = () => { } /> + } + /> } diff --git a/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx b/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx index 99db28f34d..d5ae7b3a7a 100644 --- a/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx +++ b/packages/twenty-front/src/modules/settings/components/SettingsNavigationDrawerItems.tsx @@ -4,6 +4,7 @@ import { useMatch, useNavigate, useResolvedPath } from 'react-router-dom'; import { useAuth } from '@/auth/hooks/useAuth'; import { AppPath } from '@/types/AppPath'; import { + IconApps, IconAt, IconCalendarEvent, IconColorSwatch, @@ -31,6 +32,12 @@ export const SettingsNavigationDrawerItems = () => { }, [signOut, navigate]); const isMessagingEnabled = useIsFeatureEnabled('IS_MESSAGING_ENABLED'); + const isIntegrationsEnabled = useIsFeatureEnabled('IS_INTEGRATIONS_ENABLED'); + const isIntegrationsItemActive = !!useMatch({ + path: useResolvedPath('/settings/integrations').pathname, + end: true, + }); + const isAccountsItemActive = !!useMatch({ path: useResolvedPath('/settings/accounts').pathname, end: true, @@ -137,6 +144,14 @@ export const SettingsNavigationDrawerItems = () => { }) } /> + {isIntegrationsEnabled && ( + + )} diff --git a/packages/twenty-front/src/modules/types/SettingsPath.ts b/packages/twenty-front/src/modules/types/SettingsPath.ts index f2ffab8abd..24b7446d57 100644 --- a/packages/twenty-front/src/modules/types/SettingsPath.ts +++ b/packages/twenty-front/src/modules/types/SettingsPath.ts @@ -17,6 +17,7 @@ export enum SettingsPath { Developers = '', DevelopersNewApiKey = 'api-keys/new', DevelopersApiKeyDetail = 'api-keys/:apiKeyId', + Integrations = 'integrations', DevelopersNewWebhook = 'webhooks/new', DevelopersNewWebhookDetail = 'webhooks/:webhookId', } diff --git a/packages/twenty-front/src/modules/ui/display/icon/index.ts b/packages/twenty-front/src/modules/ui/display/icon/index.ts index 3508b027c2..96f35f00e3 100644 --- a/packages/twenty-front/src/modules/ui/display/icon/index.ts +++ b/packages/twenty-front/src/modules/ui/display/icon/index.ts @@ -16,6 +16,7 @@ export { IconAt, IconBaselineDensitySmall, IconBell, + IconBolt, IconBox, IconBrandGithub, IconBrandGoogle, diff --git a/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts b/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts index 1316f6e35f..ea63653e7b 100644 --- a/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts +++ b/packages/twenty-front/src/modules/workspace/types/FeatureFlagKey.ts @@ -1,4 +1,5 @@ export type FeatureFlagKey = | 'IS_MESSAGING_ENABLED' + | 'IS_INTEGRATIONS_ENABLED' | 'IS_QUICK_ACTIONS_ENABLED' | 'IS_NEW_RECORD_BOARD_ENABLED'; diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationComponent.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationComponent.tsx new file mode 100644 index 0000000000..19345b7020 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationComponent.tsx @@ -0,0 +1,104 @@ +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { SoonPill } from 'tsup.ui.index'; + +import { IconArrowUpRight, IconBolt } from '@/ui/display/icon'; + +import { Integration, IntegrationType } from './constants/IntegrationTypes'; +interface SettingsIntegrationComponentProps { + integration: Integration; +} + +const StyledContainer = styled.div` + align-items: center; + background: ${({ theme }) => theme.background.secondary}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-radius: ${({ theme }) => theme.border.radius.md}; + font-size: ${({ theme }) => theme.font.size.md}; + display: flex; + flex-direction: row; + justify-content: space-between; + padding: ${({ theme }) => theme.spacing(3)}; +`; + +const StyledSection = styled.div` + align-items: center; + display: flex; + flex-direction: row; + gap: ${({ theme }) => theme.spacing(3)}; +`; + +const StyledIntegrationLogo = styled.div` + align-items: center; + display: flex; + flex-direction: row; + gap: ${({ theme }) => theme.spacing(2)}; + color: ${({ theme }) => theme.border.color.strong}; +`; + +const StyledButton = styled.button` + align-items: center; + background: ${({ theme }) => theme.background.secondary}; + border: 1px solid ${({ theme }) => theme.border.color.light}; + border-radius: ${({ theme }) => theme.border.radius.sm}; + color: ${({ theme }) => theme.font.color.secondary}; + display: flex; + flex-direction: row; + font-size: ${({ theme }) => theme.font.size.md}; + gap: ${({ theme }) => theme.spacing(1)}; + padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)}; + cursor: pointer; +`; + +const StyledSoonPill = styled(SoonPill)` + padding: ${({ theme }) => theme.spacing(1)} ${({ theme }) => theme.spacing(2)}; +`; + +const StyledLogo = styled.img` + height: 24px; + width: 24px; +`; + +export const SettingsIntegrationComponent = ({ + integration, +}: SettingsIntegrationComponentProps) => { + const theme = useTheme(); + const openLinkInTab = (link: string) => { + window.open(link); + }; + + return ( + + + + + {integration.to ? ( + <> +
+ + + ) : ( + <> + )} +
+ {integration.text} +
+ {integration.type === IntegrationType.Soon ? ( + + ) : ( + openLinkInTab(integration.link)}> + {integration.type === IntegrationType.Use ? ( + + ) : ( + + )} + {integration.type === IntegrationType.Goto ? ( +
{integration.linkText}
+ ) : ( +
Use
+ )} +
+ )} +
+ ); +}; diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationGroup.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationGroup.tsx new file mode 100644 index 0000000000..f742d7d69b --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrationGroup.tsx @@ -0,0 +1,61 @@ +import styled from '@emotion/styled'; + +import { H2Title } from '@/ui/display/typography/components/H2Title'; +import { Section } from '@/ui/layout/section/components/Section'; +import { SettingsIntegrationComponent } from '~/pages/settings/integrations/SettingsIntegrationComponent'; + +import { IntegrationCategory } from './constants/IntegrationTypes'; + +interface SettingsIntegrationGroupProps { + integrationGroup: IntegrationCategory; +} + +const StyledIntegrationGroupHeader = styled.div` + align-items: start; + display: flex; + flex-direction: row; + justify-content: space-between; +`; + +const StyledGroupLink = styled.div` + align-items: start; + display: flex; + flex-direction: row; + font-size: ${({ theme }) => theme.font.size.md}; + gap: ${({ theme }) => theme.spacing(1)}; + cursor: pointer; +`; + +const StyledIntegrationsSection = styled.div` + display: flex; + flex-direction: column; + gap: ${({ theme }) => theme.spacing(4)}; +`; + +export const SettingsIntegrationGroup = ({ + integrationGroup, +}: SettingsIntegrationGroupProps) => { + const openLinkInTab = (link: string) => { + window.open(link); + }; + return ( +
+ + + {integrationGroup.hyperlink && ( + openLinkInTab(integrationGroup.hyperlink ?? '')} + > +
{integrationGroup.hyperlinkText}
+
+
+ )} +
+ + {integrationGroup.integrations.map((integration) => { + return ; + })} + +
+ ); +}; diff --git a/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx new file mode 100644 index 0000000000..c488bf1796 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/SettingsIntegrations.tsx @@ -0,0 +1,20 @@ +import { SettingsPageContainer } from '@/settings/components/SettingsPageContainer'; +import { IconSettings } from '@/ui/display/icon'; +import { SubMenuTopBarContainer } from '@/ui/layout/page/SubMenuTopBarContainer'; +import { Breadcrumb } from '@/ui/navigation/bread-crumb/components/Breadcrumb'; +import { SettingsIntegrationGroup } from '~/pages/settings/integrations/SettingsIntegrationGroup'; + +import integrationCategories from './constants/Integrations'; + +export const SettingsIntegrations = () => { + return ( + + + + {integrationCategories.map((group) => { + return ; + })} + + + ); +}; diff --git a/packages/twenty-front/src/pages/settings/integrations/constants/IntegrationTypes.ts b/packages/twenty-front/src/pages/settings/integrations/constants/IntegrationTypes.ts new file mode 100644 index 0000000000..37eca610da --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/constants/IntegrationTypes.ts @@ -0,0 +1,22 @@ +export enum IntegrationType { + Use = 'Use', + Goto = 'Goto', + Soon = 'Soon', +} + +export interface Integration { + from: { key: string; image: string }; + to: { key: string; image: string } | null; + type: IntegrationType; + linkText?: string; + link: string; + text: string; +} + +export interface IntegrationCategory { + key: string; + title: string; + hyperlinkText?: string; + hyperlink: string | null; + integrations: Integration[]; +} diff --git a/packages/twenty-front/src/pages/settings/integrations/constants/Integrations.ts b/packages/twenty-front/src/pages/settings/integrations/constants/Integrations.ts new file mode 100644 index 0000000000..cf1f1ae785 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/constants/Integrations.ts @@ -0,0 +1,12 @@ +import { IntegrationCategory } from './IntegrationTypes'; +import requestIntegrations from './Request'; +import windmillIntegrations from './Windmill'; +import zapierIntegrations from './Zapier'; + +const integrationCategories: IntegrationCategory[] = [ + zapierIntegrations, + windmillIntegrations, + requestIntegrations, +]; + +export default integrationCategories; diff --git a/packages/twenty-front/src/pages/settings/integrations/constants/Request.ts b/packages/twenty-front/src/pages/settings/integrations/constants/Request.ts new file mode 100644 index 0000000000..92a15fef48 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/constants/Request.ts @@ -0,0 +1,19 @@ +import { IntegrationCategory, IntegrationType } from './IntegrationTypes'; + +const requestIntegrations: IntegrationCategory = { + key: 'request', + title: 'Request an integration', + hyperlink: null, + integrations: [ + { + from: { key: 'github', image: '/images/integrations/Github.png' }, + to: null, + type: IntegrationType.Goto, + text: 'Request an integration on Github conversations', + link: 'https://github.com/twentyhq/twenty/issues/new/choose', + linkText: 'Go to GitHub', + }, + ], +}; + +export default requestIntegrations; diff --git a/packages/twenty-front/src/pages/settings/integrations/constants/Windmill.ts b/packages/twenty-front/src/pages/settings/integrations/constants/Windmill.ts new file mode 100644 index 0000000000..4711837db1 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/constants/Windmill.ts @@ -0,0 +1,19 @@ +import { IntegrationCategory, IntegrationType } from './IntegrationTypes'; + +const windmillIntegrations: IntegrationCategory = { + key: 'windmill', + title: 'With Windmill', + hyperlink: null, + integrations: [ + { + from: { key: 'windmill', image: '/images/integrations/Windmill.png' }, + to: null, + type: IntegrationType.Goto, + text: 'Create a workflow with Windmill', + link: 'https://www.windmill.dev', + linkText: 'Go to Windmill', + }, + ], +}; + +export default windmillIntegrations; diff --git a/packages/twenty-front/src/pages/settings/integrations/constants/Zapier.ts b/packages/twenty-front/src/pages/settings/integrations/constants/Zapier.ts new file mode 100644 index 0000000000..75b0a50643 --- /dev/null +++ b/packages/twenty-front/src/pages/settings/integrations/constants/Zapier.ts @@ -0,0 +1,40 @@ +import { IntegrationCategory, IntegrationType } from './IntegrationTypes'; + +const zapierIntegrations: IntegrationCategory = { + key: 'zapier', + title: 'With Zapier', + hyperlinkText: 'See all zaps', + hyperlink: 'https://zapier.com/apps/twenty/integrations', + integrations: [ + { + from: { key: 'twenty', image: '/images/integrations/Twenty.svg' }, + to: { key: 'slack', image: '/images/integrations/Slack.png' }, + type: IntegrationType.Use, + text: 'Post to Slack when a company is updated', + link: 'https://zapier.com/apps/twenty/integrations/slack', + }, + { + from: { key: 'cal', image: '/images/integrations/Cal.png' }, + to: { key: 'twenty', image: '/images/integrations/Twenty.svg' }, + type: IntegrationType.Use, + text: 'Create a person when Cal.com event is created', + link: 'https://zapier.com/apps/twenty/integrations/calcom', + }, + { + from: { key: 'mailchimp', image: '/images/integrations/MailChimp.png' }, + to: { key: 'twenty', image: '/images/integrations/Twenty.svg' }, + type: IntegrationType.Use, + text: 'Create a person when a MailChimp sub is created', + link: 'https://zapier.com/apps/twenty/integrations/mailchimp', + }, + { + from: { key: 'tally', image: '/images/integrations/Tally.png' }, + to: { key: 'twenty', image: '/images/integrations/Twenty.svg' }, + type: IntegrationType.Use, + text: 'Create a company when a Tally form is sent', + link: 'https://zapier.com/apps/twenty/integrations/tally', + }, + ], +}; + +export default zapierIntegrations; diff --git a/packages/twenty-server/src/core/feature-flag/feature-flag.entity.ts b/packages/twenty-server/src/core/feature-flag/feature-flag.entity.ts index 5e579a452a..ad226e8290 100644 --- a/packages/twenty-server/src/core/feature-flag/feature-flag.entity.ts +++ b/packages/twenty-server/src/core/feature-flag/feature-flag.entity.ts @@ -14,6 +14,7 @@ import { IDField } from '@ptc-org/nestjs-query-graphql'; import { Workspace } from 'src/core/workspace/workspace.entity'; export enum FeatureFlagKeys { + IsIntegrationsEnabled = 'IS_INTEGRATIONS_ENABLED', IsMessagingEnabled = 'IS_MESSAGING_ENABLED', IsWorkspaceCleanable = 'IS_WORKSPACE_CLEANABLE', IsNewRecordBoardEnabled = 'IS_NEW_RECORD_BOARD_ENABLED',