From a52d4069b76e07fcf4036483feca0f34fa9486c3 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 10 Sep 2026 13:13:57 -0700 Subject: [PATCH 1/5] fix(search): streamline Atlassian source setup --- apps/docs/content/docs/search/confluence.mdx | 26 +- apps/docs/content/docs/search/jira.mdx | 26 +- .../search/confluence-personal-setup.png | Bin 0 -> 68304 bytes .../public/static/search/confluence-setup.png | Bin 45456 -> 0 bytes .../static/search/jira-personal-setup.png | Bin 0 -> 66883 bytes apps/docs/public/static/search/jira-setup.png | Bin 58681 -> 0 bytes .../sim-search/personal-source-setup/route.ts | 70 ++++ .../integrations/connect-account-options.tsx | 1 + .../integrations/integrations.test.tsx | 5 +- .../search-integration-connection.tsx | 13 +- .../atlassian-source-setup-modal.test.tsx | 172 ++++++++++ .../atlassian-source-setup-modal.tsx | 241 ++++++++++++++ .../search-sources/source-setup-modal.tsx | 24 +- .../add-connector-modal.test.tsx | 51 ++- .../add-connector-modal.tsx | 4 + .../connector-selector-field.queries.test.tsx | 176 +++++++++- .../connector-selector-field.test.tsx | 64 +++- .../connector-selector-field.tsx | 164 ++++++++-- .../use-connector-config-fields.test.tsx | 34 ++ .../[id]/hooks/use-connector-config-fields.ts | 34 +- .../connectors/confluence/bulk-spaces.test.ts | 234 ++++++++++++++ apps/sim/connectors/confluence/confluence.ts | 189 +++++++++-- apps/sim/connectors/confluence/meta.ts | 2 + apps/sim/connectors/jira/meta.ts | 2 + apps/sim/connectors/types.ts | 4 + .../hooks/queries/personal-source-setup.ts | 69 ++++ apps/sim/hooks/queries/selectors.test.tsx | 287 ++++++++++++++++- apps/sim/hooks/queries/selectors.ts | 236 +++++++++----- .../use-personal-source-account.test.tsx | 153 +++++++++ apps/sim/hooks/use-personal-source-account.ts | 135 ++++++++ ...use-search-integration-connection.test.tsx | 14 + .../use-search-integration-connection.ts | 14 + .../knowledge/personal-source-setup.test.ts | 47 +++ .../knowledge/personal-source-setup.ts | 86 +++++ .../knowledge/application/operations.test.ts | 16 + .../lib/knowledge/application/operations.ts | 18 ++ .../personal-search-account.test.ts | 133 ++++++++ .../application/personal-search-account.ts | 68 ++++ .../application/personal-source-setup.test.ts | 300 ++++++++++++++++++ .../application/personal-source-setup.ts | 263 +++++++++++++++ .../knowledge/application/sim-search.test.ts | 48 +++ .../lib/knowledge/application/sim-search.ts | 32 +- .../application/execute-selector.test.ts | 108 +++++++ .../selectors/application/execute-selector.ts | 41 ++- .../lib/selectors/server/credentials.test.ts | 86 +++++ apps/sim/lib/selectors/server/credentials.ts | 54 ++++ .../providers/credential-bundle.test.ts | 45 +++ .../server/providers/credential-bundle.ts | 15 +- apps/sim/lib/selectors/server/types.ts | 5 + apps/sim/lib/selectors/types.ts | 7 + .../lib/sim-search/personal-source-setup.ts | 2 + .../components/combobox/combobox.dom.test.tsx | 22 ++ .../emcn/src/components/combobox/combobox.tsx | 15 + packages/emcn/src/components/index.ts | 1 + 54 files changed, 3650 insertions(+), 206 deletions(-) create mode 100644 apps/docs/public/static/search/confluence-personal-setup.png delete mode 100644 apps/docs/public/static/search/confluence-setup.png create mode 100644 apps/docs/public/static/search/jira-personal-setup.png delete mode 100644 apps/docs/public/static/search/jira-setup.png create mode 100644 apps/sim/app/api/knowledge/sim-search/personal-source-setup/route.ts create mode 100644 apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.test.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx create mode 100644 apps/sim/connectors/confluence/bulk-spaces.test.ts create mode 100644 apps/sim/hooks/queries/personal-source-setup.ts create mode 100644 apps/sim/hooks/use-personal-source-account.test.tsx create mode 100644 apps/sim/hooks/use-personal-source-account.ts create mode 100644 apps/sim/lib/api/contracts/knowledge/personal-source-setup.test.ts create mode 100644 apps/sim/lib/api/contracts/knowledge/personal-source-setup.ts create mode 100644 apps/sim/lib/knowledge/application/personal-search-account.test.ts create mode 100644 apps/sim/lib/knowledge/application/personal-search-account.ts create mode 100644 apps/sim/lib/knowledge/application/personal-source-setup.test.ts create mode 100644 apps/sim/lib/knowledge/application/personal-source-setup.ts create mode 100644 apps/sim/lib/sim-search/personal-source-setup.ts diff --git a/apps/docs/content/docs/search/confluence.mdx b/apps/docs/content/docs/search/confluence.mdx index f818dcba9de..d332940b739 100644 --- a/apps/docs/content/docs/search/confluence.mdx +++ b/apps/docs/content/docs/search/confluence.mdx @@ -38,14 +38,9 @@ Open your organization's **Settings → Sources**, turn on **Confluence**, then ### Choose the account and spaces -Under **Indexing account**, select a service account or [add one](#using-a-service-account). Enter the same **Confluence Domain** as the credential, then choose **Spaces**. To enter comma-separated keys such as `ENG, PRODUCT`, use the switch beside the Spaces field. +Under **Indexing account**, select a service account or [add one](#using-a-service-account). Enter the same **Confluence Domain** as the credential, then choose **Spaces**. **Select all** selects every space the account can currently browse; newly created spaces are not added automatically. Clear the picker search before selecting all. -Confluence source setup with a service account, site domain, and spaces +To enter comma-separated keys such as `ENG, PRODUCT`, use the switch beside **Spaces**. Switching between the picker and manual entry keeps your selection. Open **More options** for content type, labels, and metadata tags. The default is **Pages only**; choose **All content** to include blog posts. @@ -65,9 +60,22 @@ For workspace Search, start from **Search → Add source**. Available methods de ## Connect member accounts -After an admin allows Confluence, open **Integrations → Connect**. If no source exists, enter **Confluence Domain** and **Space Keys**, then connect your account. To use another site or space scope, choose the row labeled **Connect a different site or content scope**. +After an admin allows Confluence, open **Integrations → Connect**. For an existing source, authorize your account; you do not choose its spaces again. + +If no source exists, or you choose **Connect a different site or content scope**: + +1. Under **Your account**, select a saved account or choose **Connect account**. Authorize using the Atlassian email matching your verified Sim email. +2. Enter the hostname under **Atlassian site**, then choose **Spaces**. Use **Select all** for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 spaces in this form. +3. Select **Connect & Sync**. Sim saves the selected scope and starts indexing with your account. + +Confluence personal source setup with a saved account, Atlassian site, and selected spaces -Admins manage these sources under **Settings → Sources → Confluence → Manage**. An **Account for browsing** populates the space picker; it does not enroll that account for Search. Manual space keys work without a browsing account. +Admins manage these sources under **Settings → Sources → Confluence → Manage**. In **Add source**, an **Account for browsing** populates the space picker; a saved personal Search account can be reused here. Choosing a browsing account does not enroll it for Search. Manual space keys work without a browsing account. ## Using a service account diff --git a/apps/docs/content/docs/search/jira.mdx b/apps/docs/content/docs/search/jira.mdx index b793135c408..83cf654726b 100644 --- a/apps/docs/content/docs/search/jira.mdx +++ b/apps/docs/content/docs/search/jira.mdx @@ -37,16 +37,11 @@ Open your organization's **Settings → Sources**, turn on **Jira**, then select ### Choose the projects -Enter **Jira Domain**. Under **Account for browsing**, select an account or choose **Connect Jira account**, then select **Projects**. To enter keys such as `ENG, SUPPORT` manually, use the switch beside Projects; this works without a browsing account. +Under **Account for browsing**, select a saved account (including your personal Search account) or choose **Connect Jira account**. Enter **Jira Domain**, then choose **Projects**. **Select all** selects every project the account can currently browse; newly created projects are not added automatically. Clear the picker search before selecting all. -**Account for browsing** only loads the project picker, using OAuth or **Add service account**. It does not enroll anyone for Search. A service account needs Jira access and the [Jira read scopes](/integrations/atlassian-service-account#jira-and-jira-service-management); Confluence-only tokens do not work here. +To enter keys such as `ENG, SUPPORT` manually, use the switch beside **Projects**; this works without a browsing account. Switching between the picker and manual entry keeps your selection. -Jira source setup with an account for browsing, site domain, and projects +**Account for browsing** only loads the project picker, using OAuth or **Add service account**. It does not enroll anyone for Search. A service account needs Jira access and the [Jira read scopes](/integrations/atlassian-service-account#jira-and-jira-service-management); Confluence-only tokens do not work here. @@ -71,6 +66,21 @@ Each teammate follows this step. Existing authorized accounts may already be con For workspace Search, start from **Search → Add source**; its source-creation button is **Create & Invite**. Search manages the sync schedule and hides item limits. +## Connect before a source exists + +After an admin approves Jira, a teammate can start from **Integrations → Connect**. The same setup opens when you choose **Connect a different site or content scope**: + +1. Under **Your account**, select a saved account or choose **Connect account**. Authorize using the Atlassian email matching your verified Sim email. +2. Enter the hostname under **Atlassian site**, then choose **Projects**. Use **Select all** for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 projects in this form. +3. Select **Connect & Sync**. Sim saves the selected scope and starts indexing with your account. + +Jira personal source setup with a saved account, Atlassian site, and selected projects + ## Manage the source Admins open **Settings → Sources → Jira → Manage**, then a source's **Documents**, **Settings**, or **Sync history**. Metadata tags include issue type, status, priority, labels, assignee, and last updated. diff --git a/apps/docs/public/static/search/confluence-personal-setup.png b/apps/docs/public/static/search/confluence-personal-setup.png new file mode 100644 index 0000000000000000000000000000000000000000..2d196b8937962dde2c4a2861148ae99b89296ed1 GIT binary patch literal 68304 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

88J&%dbW>b~1$Q!94{o3aw` z`o7Bk`%CzlB>+kJDU&iExH@qJf z&T5$-8nCZGLgj3Ss}+{pRO;D{b3d>xuiP=jm>_k@274f@$*Sa&c(PEPT>Y1`qLcE3 zP#UONsC7YYkbkRz?8#z3n%72%qLW_x`_rRy73B6f+uXzUJ=`9rGHvfo z{PQA7w;(&a_$Ti`X&6emO$&nDJt3TNbUH2ihw6ly(Wv5N6vzM@}F4dEYAd6e;sxzkTGOW2#kLbT7|^Df}}W&hKC3J zcLh~S^DXNlGg-LnQ}_%B&;Vas>LoRAM; z^=hLu9kHP;!0D~eguYvSeQnR_i_7T*3y!TTAtCbK5-W+A5z{lM;%QqU*jR@~O+02| z4s16OkdbZdzn;i#)G+l}!)aqIjsu}b3VtKIOZ%oTf+|0INk`*(m&Zn9e&EB7to+m>q zr6Q9+W%tRZOs&8&&Sa?}0urdZxBKDU!>SD9$o%-eRZ#l&5%na+f8E7TTYN~2aFP8M zA-02&=I*l6x~s*;l;gZLKO#iWe=e@Engi2t({s%Gkp*AwK9;iqDxW3VXlH&AA+}eB zQF3n;Px}=fW7l_3qoM(N1y458JmtK&N%_@DTdHXuKDJt=uSnA3Fsiw5Y36R{8OIs2h!;6`!oZRS?oagL{B`RRPniA%2ywD zU=$uWpw`*m5VJm`UxWX2jb7tn<)aOcebxeYQd)Q?C2nLD-`@DIVD~|VL3hoQj4FQG zqhbCIF2z?=*iW4kO}>zlttmQ^ z7Wo_Qj9`ln&RtC`%9%eRMjaMe17@%DHiQ2kCk6xFYZQ@`KZk|AZ0nR{G)+~ar_l*b zxgWx%XNx08Q%DN}b?+zOd{zBHa7b5)*wd7{RogabnrM z<8ZBDppy`Fz!BU!jkvcgXkCUR3ZF3ANRz0Fy%rl-_cv4Oh7_`xSzb{O1g#6t%G4^N z&ymf6?;%Ac(U)CgYY}R+7IhDK@vJ8uPvoTrW>}(TG;0Fup5>;NTw)5EFCk|$Om|RS zpvzI`&bh}~Uo}P6tt17R_0I@lQo4bw#JH9nBfCgbv44lZW0+j>%kin1Cj4NP_K#kQ>EU6v`9Eof?}y zvC?gzQB+htUeB|FPpP>>viPoduh}j2FF9e5UuN~#^hfhBe$*`)53|fXWmLNTJNFLs zJ8D~-gy)CODozlC#d8=&z(%er5X!3LYThiK51L1A*5?saB);=}d~*VGCv~zCz-rwH z^;li_?f!W>BQ4ZqxovF1(?|}bV%RbLXUc%NR>^#&_?k$^ z3u(SuG()uNLHiby>DZk=oVinsU{_*tSxommI`)AF1?81RUOxz0__SFqWP`;}uufnm z&1VZ1t*yhkhM)7lnN0e9o_yYv+$L9>;cuE zIf+>+M-_%?F&<6m{F%g?m&hwnOP4AC{ryIBKFj?P4ZolI)=@$ zjVUGSChQ8~+a$chNcZ{lr7Zta+5}+{^?$PaC5G40lmy(LM{JH@^q(I*Dn9I4m_DTT zL%D!&R@b7yy_GgtFmKctUzIbj`kD07HhQgJ1>Iui#;kKvxiCMP~8Yh~FUeCDb zn>0i0=mk%boPV5qxVFiyI&1H>07skU=b?J#!eyop5|1jGGwjDXCD25{__C)AT1V9_ z^)rpGxa|&x5|LZsx94t$;kPDNpE@lCBk4gx_g6Blw7}b{oH)5K_=)@;4?`7ZAZmw7 zT9xvVm>hn;z$4}Jpbm>R13Q42pJet((~^I43Bw?7xebqba*@WxH{-W^)0^HIjog=5 z)Zx9eX>5-`3oWaCi?Q9C1H` zKFd+6eE4K<>XYSX`X|k^!d<5a{A{brP>OuznEt)hc5kAx{{CHU?z`qpoFN+wno{up z^@pQvCE&}QR-54Sm_1~-m+2NN5g(D5$^(V1>u9vSB=fwZDJwip{sOu!@?FD`^j0Ce z0ec?SNIy(;d@Xi^-y|ykd~cDGe_$o`&ouY-c-eq*BOXW5q@_;dbnWHW6IJ&X{9FA3 zvi9^AkQH;Hl?2`4mc>E3|E%?m^2aLjDP`S~{K=cv;=A}3&yQq0kn6LzQxE5zTuGn$ zA+zQmKC_OdX;+dpIdUH7H&2STRX4hB9y6GQL~?Ex9x2T}OS$%#`MbYdz){ZFGcHAQ zjt0Q|W7!@N>SB>`-iBd`)QEA8aZWO+X;LefVXOx*Req``ckCJn_{s@FMooX;!N6(FsxtC8$H$e4p`v2B+#t{E?2F;wT76b+8TK_NOuUb8zQz6D zSOBPhKO4!)v%OpPRj%Sh(#0T%dGh>ETAC|ZJe|B zf2rz7EeN|LkfLfYP}c-E}UonGfk$VBXr@m6Eat8c*_n~Jou*_Qq*puOOd z%^`F0)7;u@IC=T5$~oFO|K5hB$C~B4B;T9+=%4T`ihp@@%R`Q8jW}8-K}Pc21{&`+ zz^p`Fg_b~HJOQPwdB~DK>$VaD)!U!Gy-OFPni3sltQE!y369?O@^28b{wAQCXCQJ90?C2CYA}= zfS1n(39#%hN#rG1ZJoD23pwqx=afM`RQ}xyXz1?%;%!|f#)h@#V@BeU&Q0gggHZPr z*bmx5>Pt-2oD6;MqV>CFU1#p;*FlND!Pw3hOE&k#aU zEA_l6Ymb?FjYJ*qVo42tK4Y7;T)jR>LA{*<&gh=5|qrz}b01u7rD} z6BVV}Pm6a@f?E`UI@j zBdC&vN@GJrN%x*}i0fHNB?>M#g_GJJ(Z%0ESpy+&TC8-nX23WUB&1`fH#f0G^-TYk zt#6TO5o=K-g2~X24K<`DGck8ZFMcLwQC5(}l|=Qt2Kvfg2drA~sMl#+@jx-$Egmdr z9_Yi_43manB<`yhuuLSr-w(XbD6waITWYO^Y#!UfA^9D$O4s6htjCRL7tuACL%j8f zwN2N0C2|+(%$4>N+dUfgvUJO+va74V3yo_)cPIBjJXsDF3WXHyoSzmBq~qMiyidGB zMP006+km6J14S>(8k0D^LABoQwE5)M`$)9p?d(>0d0m&X{r>Iv4Ry7)B7Fn@`dR;u z%$?berfw1>J&I!*TdMW=cwzr4=6-eLNpBNFIo=@2t&;G(-SUTcvil0=GDu%~Th|~4 zvHh~cTuk;ljOw_%@rt!|OaI`hJXh60MGX?lCHRweZ@o{+hRr z+?yPAxsc+i)_+$!92l=UI2Aq%cWk+mx`QR!!dP}=&oMQS?x7RmYV>L$XW~=c2}?hE zC*E6L8fw)GDCF1RmFV$|aZo3(!e&4DSt|cPl{iL0qMy(7yd>l|)Q_ozhPZb=v;KQj zCwBrG^Wv`i3~rHO6OjY7L@pcJ7KMfL%a`o65eD}=!PORwGV9AHy0_>t-TNKM55MdSkf_W zlw>QFK9OvBq0AY_PjFkLGK*8ey*iw3&$3NZ50QS;GjsRGhVpG~^^wN}1&Yx)M=_i& zw{Pqc4Xr&sq#dlqhU?`bdOm-twZ-9M;@6G#3VTc+Q8%5_{gIRFuj|yV2Ho5hdA1J+ z%Y%-kyQgkTY2bZ*A|q>4MalzNtLWpFcL{9M=+3QSqu#Jr=RQj$#4aYyoYZ)j4-3mD zmNDE*MBAT$8qrnbjepv&jVIS$ORo!}_2(fF2UcbsmWuj`2?ZVrt)QK(&;56<@+F@z ze`f-tro^E8r2~J&gE_48qT?T0wTC?g%JG}>?b$9ru5XaPt9pPLfV>d>fbL!YLChVI zSv%5_(NHF3N5Fv_H;oM@1)f9D#%p=uvKXV<3(k*GflH@tmu|yR>kO9zK(B_yT$!(G zI?%6z^ynF19+K49CzG}WeN9s!%jDTH$3m@$V*#!7VpyuMlcCRS)t4N)U$4$`2Z`S< zyeA#$df>Wn{!?*g4J*3aqXUqp9A(@ei+z?Lp2z=6@lDJF}D5XfAPqZjs~WObJC982L9O(L4Z2Lr6UKp2|3JxWbP=m z>k`yoAdYim)TckTTYgB3afM^}?+XeNlh1E`e(8jll;(ef#2$YPUxg&%FG5QqFyYf` z7YH6+$iG!LaHCVWJMgBjAlrduD>&k_T<}ZQe3uY2i0`DPQ_$AD+`DV+{&@(0%xg_I z)RR@bR>$xWxObvrqX6%TcciTw$x|@R-iYa3#9;t~v0A>pnMDdj(Sb*UrIYbD@Ajku zB=(NtJs8BJaw%H1+8&Ebz}!f~z?D!ZBq{&}a={kkr6pw4LQ#pCiFx?2cMUIGDKv_@ z9R+MvV7IU_W*#;lU%e?MG<#VSA_kE1YWC?U@AB>v=q`P5IfkDTF&bq}#*s%yWz&2F zk443};*_kT;bn>X1Fb3zz4y$Z;!}5Eb-?Mg-x@ypZrJRxb-?@YU&yv#{yY5qe=p_m zzsyzq&weo@{Aw-|nnp4D8YqiH-l9mRFiARO!jrXCugGaw; z8B(M8r!e(t@%6qMdB`MR_00fMAB=$v+CX#Q{2@$3&*XqXktb5wuwXDDR16+QBHMvW z1rvoq$&jC7nR8~Hqu`K|}VK%{Nr%U#(g;Kfw?qeka8FJbHy z{)GG0yxz$hOldC%ofWmEBYmN2ERek6bA6?89nDL@oqO6)751nsVNDX40kG9Ujcgz> zfIKtkhXL80g4P4x+iI?t-YbE-rxUU#!Ng4Af-Y=#Tyu(|ER#uN0DSfe-6qsNFpz#* z-vAq)625uVT8$Q`vO7Io!woZ^yeHN3hMQ8bB|!Cn_vnCTl<-I51W2357g`+w?`lZMF(MT|Ep2$HT%lpk*|+aD6(R^o|l@foVc_nILYk)YPd{T_KN#(-5Kc>|s= zzJ8HCX;;8I)QRA3zlo=FYJsUD!H!mIjPd-)OWVg--8_#MBmSX8G;Hdlj7wm}s(KTX z@Eqt5R{vh4u0kXKP7c1bS~04t_aGklD2}kxy5P-#ebyQu%_&gOw#{jGtX)Q3uOH{+ zo!D-)^qnIHh`Bh1VqtatruX+A#&J>e1)E}5(Oy@Ks&8;G0tRcJ7wy!iU>+BJ<~qa; zr2+p0*9z4|nw))?Z6LoAdooeM>2YJy!{Y0>a^=gCbC)<)!M((dbWryHA&egD_-dif z5StpoAXbXhKE{nMY+RqPN%Efacj6`RIz#@B*S$^^-df&XR3%ZNr`V-`ht=&veU$R|hFRZRdhobm zxcN-c?SH}*YPS>}3m$bTtRr}DeW@3?HFZW$gj#?$6Ml#wsGVzH6*;BshORxTAb-BH z&k_9~pxTkw@4M1;(&&?4<$2tC5Ag{x#ex$d%8*z43d~MebDTyqHClu0<=S*@D5LGJBq05 ztQ*=+=2D%QCho{rMc-=?aaF(3R$|P4Pig&_io34#%6wY&GSC)G6L)k@xl$YoW-8G- z_;>mAF8{!gv>%7I={~HT{YRuKuyu2qwu}t&r_2|Dh>CMlT zbpQ7kw!96S zB;jP7-naXoU_7U^M0h)TtU^c_Zu51IP-80wLu)L~<_g$5?@B=Lt zIqlQzCO_Wz-Qo$UP+o$V(|^igRc7mB+(o2Ql#lz_&niD7*sP-{-Up61II8eTj-Kf^ zb2qA!#Toi;)>nuuCYH@1zC3Y}b^ivBr#O`pM=Q{lsn`v*J&7r9kg!s;>Ld7qQ^OWo zBn`gH-`>b`n(iA)mHwHA(vb^y3iLj$$PO5OnXhmm@lyahGo=U{zW>2|N;XDJBMEY3*1I0 zL)jr*!QFCOYfxf`gq4(EK8_E1U;1gWyAj|acD2n^I$K5hPYa|JCBN?<50A@TL!gle z@Q)UCN`X1&A=Br3<1dPf+Vn_iY_}~~Vm6|->r}1v0k)VZ6jTi$0PmTUUyVgeFhTTu zryn1ajQ@Jkxl2+|B&#z(y>>02p-qdG;2_Y&Br*?s#PVAOZQU(x#P-!iXS_vn7J_57 zwK1dfqNG99G*%0a?um z1&no2d=iP$H{ouf>ihFyVu~brQ$x_}tG5_QN#+ms+gC{tr@ZpW@^gj|0fDnhu{pQW zV^7hzI0@USjd-omL6>q+fiC%%6E4X`=KlLC-Mq!&fPhf7s_YemcaPH~U(M{DQEc%H zx!nyOjdFo8&qCeWV_FMMhy7PM8)b>kJ`e`$*=_9LQ?n1#3lPMFvxngE4kUR5+~XH; zde#A~Wis&kvIAEtJ&Meosj6AkFh!@fsI4%3)SCWb9NaJ+)1+r-?HESGk9G&>IZ3ZWf?pJQuvNF825Ne=Jq z)6RV!)E^Gcl{cojYayj<^&xIK^=LfP7_#XNach4*q3a;^h(Fv8_fM;P*ZHoy8*WRM zyq`}V{D`5KxlzJrQHY%WKGSZXX7gMmz9;h2JxYewo|Q(I@%gkumuBb1Wv34;3D$AX zbh1MFZ<|Kl4`^)U#@wS2Acvmqv zY%N@zevRV}TjUZh>c;7-(>$X{o_HcYtS@73SXOx~Cra2gF0p^8eNfjQ_B_?7iL@6- zZ`1n;MO)}8hPz>JJon|2ZWWzvy6CFXZ&8t5k{Y7&l7EXw9CN&Osv{(R_L(uL6oqSF zt+HREoHkG99Uhib+ia>uHKE>gr<=2WcPR11wScai-EDldJ*S#j-a4wirEavhEbo7y zZx}-L`LX9*P|tm)^?z@|kuJ*--iwF@(NL9FiEbB=tMv@XI;#9o=7szzJ*nK)pjXF) z6FBTY>9_r|Q&{x)u#m_?)X0RMK|_aIo;+>7LvyCZKT+0}FQ=fAmUBI^?l+UxxP7&c zajKQ)?7lEV-XreuKBQogiA&em{E>5bY0VOK^`=Ku1jv_fbe_nY3{m&4`~sEYlfIjy z_bb+QM(Xizch^(?we({l{!6+>HgzUZ){Q|TU><$%rIJR1# z2!HOtfFjn%=f^11b3?gufsN|3t%lp^Rwi2AN&jrwy`6*i%Qo84rB=uRSn|381N|Zj zXomqk{vqp9hX}YD5{0W92=}w3Oc^048kJEiU^tZf+i{L+)!Ff46Jj1u?sL&$YM~SW z!Ho7|AM(D8@)I#Ir#x4eoht=ANe4eix3Pr(rn`ijCWQ#w;VT$!*R*bY=TgioKV0i) z+cY!n7ReOoIq;v@*`|_)CRJMC z&c{ONa2s6Jn$dbZSF~0#vj)mzD{+L*RZ;pQbSSw|cFRyuc1_7nmb{9rpU*j4eC(3t zTPAt21=nqbpwU4tU76<*_m%BQ3NU6pLY!te7%b)AkxOhLVJPUjL=hf+`HR-BV9DRm zLh=+59=lwJ(WpJ%zI$WTHZUELf4=2F?~8?L2~Ev5u^sdSt1QfpM5e^I&s-+b2BDh# z3I#>Ari0~k0=ZI$5}%}mrHU(E(f(GfRnpz@NBG}_Y_HiTR+qJZslSs*)iD=(gY!dk zE*m#^y}qFNvG~kFb;0+vZYmNcW(QOE4p*f=_@XBj@3a!Vs#77E8k+tk`O%F|Xlji@ z`(O_2bltapD(0C$xmg5YispyPPvqwBbu0U(#6 zH*<-I%euFrRM9&8vaJ7&kYD%MA3CHN6fy_j!8v9p{cY~OFghhDt6YZ{Vl%T^tc1Qq zw3?VNT^TB9^-RVIaJ72L4Ga0c#-wF5R)FCC!^fBM&!}XpeuYg zV?{|j7OR?v&HouawxV)%%bZJQ^_Yd!oz&2X8c&B1%V(WfLCjD4)Y>{-$3-8ptb7?d zGmrK+qc!~@Pt}rTCO$=|+?G8j`@q4gGb*0WgHI9Y>JIVZon_E^nS@^<`lT}+&YTrB zEYDK+Cg#Q({?^cU?~ha-afM9u=%04r{*Dg4Xw<5x<{JDO)!h)}6pd!LE-!nFX>mQ% z@$)#~VJ&PNOQgM8l$8hYu{2Ye3q!^mtYFqxPd;&^I_~byHw=~!z>gfL3OUNuR5ArE3gErUW<)-cm4_nWGH@}B9M ztXne4OzNcIBx_=FWz)YVR-OOY&)E@BWqLyV!0y?^1JAP;&?@+QNN9Q2ywlp`u%SCK zE229lx8oBYWAd($gRb8%INzccex`M0`DqcO)CDwcHs`&XdGpsdIe|~xnHwUMuZoG( z#1AdDjGrIPQo&=!r?+0qCBf9W7a~BJse|qCCM7CFTB`M-q~(COXmPZ0TSm>}a-YSw zIn~2D+n3y|)`>15-$fT9If32IOQ5?|)z#ywtg^i=)EP7^cZ0QDj5pUT_if12RH_Lq zGOa!s9@O|cZ0pz;R-{+; zDQSIATEQ6Q$pT8TIF20(3?PY%^b`kG(uEAaY>E#C6vid$DS{lH78{bQ=>|R9GA?2^ z^Hi`6Yh3!f6}#jFtK+TRL^3>2gq)Vj{E=nNgX59s{U~!v~eKvUV_&1KI=L zuWWsjawLD&!?|iYjGKPAFqttm>UO9S$2zVq^i~Vz%07B3p&By&>(i{*2P7;COS{H+ zSf@c3C2ddZt@RX|$*W3KFu8oN-bL_8-PeYq48DuccSY}V?%R1?t&J*6snGt;>qdR6 z-iuySgG+C8Bei>!$9;pTjj-!>%`1hPsn>G%B(T(asd5xfYaHJ|lQF}Uxy!XubPmIS zD!%rqA0OTR1J~WEB{J9inwKVwXMmHxwo|Ss?+}+O!wDwKhtGq1G0iEx3XF@6Et5s-fOv)Evr=pO|UI#TNCe~prBpfDtYnu_&UMM)52OhA$s%W zW2DdM8(voRjJOkOMbrUDUzfgmRdWSMo;WbA(sZh)BPQ_5exAHB2_zlYATtAs zW@0MCC6~)f)#rLju1YUQU-Y`f-nd-efMbEmq0y?cL#bI*Cp0Ul{^|M(4h|mWnG%?q zo1OkCeYlsG^h1jB3X}=X zz2a$K8*Img6@*hoX z?Y==9XqpF9GUT{{q+94W^7W)MNz88+!Z~Mpc#jaEb?W`pJNu$iFVxopn@fZTq~*Db zIVDj({{NC!Z2HNi2pkc-&ufnesJ0QUUc;rowz>iZZzfs+ zWW1F|?*@FXjd1?xr$Eb~yscm#sUz2(`yCehl)x@Wb2OGCsZvzS2t~a#Z}Z0$s7Jy9&k;O` zcY$H6+Tj@40Nz%B7=SfLz3Tx>!^)5k3=2})H&D^SX8Y+>azol4x5}GpZRT}J(NBSB z{{<<_L-1>k=2cN20qm`!)B=HIl(`-d++m&>VODuKQ`v*(F}ZVL-ErGA^*5`P61>AYK+82#6vz6tpPU#TZZ}g@Jw%k+7WGg z=UmlRq5kB4gMgF%k)rU@dcU^d$|WFR*)s3PC;*ml>X=KkVa{DQbcYL22&`}-)7;3p zE~IvS$Zjz=V&ugLhekG$asoIt(%RF7w*S9S*zabv?8q5OeNa4oyz*ljH0*?0jgYse zIK}O{oYpV|kJ(v(0lHP~1GtyHi&r5FFy1GTF66oD=9&Qu5%i_cxU{U`Xd=KkO!n6K zXW22A&=gJ&MDHJugmPO7oJ7DYRIqM^g1~1Upg9-?iMw2%r7wTBdn0w@GADg)ON5I} zVgE!Jk^T>I?l8!kFg#8{ic^W<+&7tb+GxU zhyF*cL!Ia1omLfiIp&+Qp$bfL#|`<3tn2?4gW`V>(I(AGtyal$_?WkzdNFHS zBqhK$g15iCO*R-6;}T@@pP!xm_2%a79!QfWwmA;glqjcU6Iy2Sn)cdSKq{WiB&WRin)Cfc2B+h|JU@#-l%?q#Vnc}TX_Sa*d zW!_IiQ=*jlpx~2X?oIn92n|mlqG`U@TLL^u>WmpXXs2QXL&BmFt$Jb4_f@05QoqG< z$Wd?mDb0*r=B)`+pV+0Q9I)PE5#N})!SzbsE{d&N35&)TjSCfzwJr0w66-q-f(@2n zZ8MOS9xi)*)LSpK9{;mChTUK1m@$ZSBiV83>gLsR$8Xd|damBVGpQ4*vWIeW*@Xzt%6_cn zMbKmHb-pUEQ&5tHsB4P$+fpBc;0---^Ra%GJnMDG#ywA$H_nNq*X-&iDZm5LgA=p8 zJd20S9(FR9FaA-wlju`l35{Z7S~KGPc}Ax{neUFY#1 z;daG5wmW^~y3)^DWQ$l<2n*t7K28K{YgP$3h9M8Ucqyg0SFKOD8Y%3$&fSj$=00gK z)#>eXk4p`(=X<0mX4q`7p5ZO`zpxwkLn7^Z* zuke3(*OaDN8wJfpHTo?QNZzL8cml;z#QN?vQ38pmHS zgBY^%K-VC@=ftXTo-Ut73?x_iQNP`RIW7MvntMcPUzO;LBP+!|-YZVXLo4~y{C{$? zWfHv(6Qt!%(78DS7!10Ezv}Vw#`Svj$8FckXc~eX_sTe_h4H|6IG%J6s+yo=}6fVt!eWRA;)kw9l}7 ziv{RU$Jt-h+7ejB}rrMAU$1 zy0YvGGvPZ6x#{g5Tyox0MuO}k{C%%E?i}vuyz=cqao7#>H08&x^ngk!Ig#rr25P;Rm>_$c{qiWT+$C@I}jaj=Z9!DQ;^Z08$j=Vq3Fg<9RV zoXA<)B>kPh~~(>O>Mr2V1cgJ|$&#p7-o)W)2#Y`c#7G1VG%uGiLm zn8Cs&$2|GkY0ia)#QtbS`& zR6mc~I@Ns2cU`{_!`KuYdi98Lvy{n4x1A&VmI#1+lz;#@6kTyOp@C4SI(bHuIvQmE zRWs}8tSB$f-$B~&9ECSlafs#4P2vSGr1G~|NQ1-mYuO?&kh@c?FlsIrr1Sbce!3>R z>(r|QkLu=U`9xVUSHXSDK7N79qR#XB?~+TFattW@Z=IyNoSzBHPjPjV*e@_amLYzv3X889OB{om- z=y%c<8b=_ewRD$u#*L5Ad5i{yMygF&om;*gGJ4}=GjVWU=QW6z@MJnzxwzr@jYkZY zO`5Q7!_vu{RnqIv-uZ9T0YT$(|F#bAq?dh;sVD~@0)Hy#qSp}ITvLf2fJ}%Fx%zH9 z7h`$V-MNc1P%iB3iORVgSp~YgyOcnfZ)Q5&S2xv6O7>4CzM@wpE@%4uf9zqj{Z6=w zOCxIEc~70%AQ0L|N@c#LaIT*@lu#!FbEbT1u8q+~bA%iY9fO*6FO&aWV6Y0XEg;Sm z8%gWV1fYVJfX)dqk*a)yH~}EXWL}&#zzs`te@TenEtTRut-Y{b#mJX<=}lwv>1Z(k zNwju;+N}8u|LlX%v#uh!0tA*p_Ju2dzxbQYnM}mK+1{3826E8x^7>h3gy{F3B{XLr zvLFA=E&Bh>{QZAP7yAD)xL1FaoBJQIfd7-9_eR0A0=88L(O7bmRR0e+@c-)}WW)DD z^JpAHK#4$L!tO1q2#+=$GZo#?F~(~VA`3wAi9Dh2hQzNZJ|RqYfc=~xgFkv7y zCEG$f;o2TLBT?EeT+$9>ZG;N;=GW)Vh!kthhobS9t^BXQFFye@{xr_JaOjNfpGx!$ zM2P}vb3)4vS%f3XPfI>oj<&qBNS$TQ0I{)k|Je+H2aK0fAa`Kgef$HdP4hmnoavRJ z+)^{Iq~vbslS4U22$z9I<&OMCUTAL>jApx{H3cbeLdVP?>|R&w>B-h4z(AxUT)3Av z5c3TGmV=I&6D?ah0Xg%nB{IjRIV21p|94dEi>(@1*{ zTn7bZIoB7!8+b5+cE7HThNE{P1yS+$@Yoq?WyPzAa3oTVV+Z`eL?AgWZ;;jEX~Oyp zIZ8;wcisrIBf`vK8|mgYAV43>hrvlm7&N%fM6f4hb@oSv`zi^UVqMx()Ng=*Y(bj` zFRS4|J^k+RbPm>#rXgUK^BD8y)MVgQ+6(XP5L%pOjDU>ShFFqcTV1~t-L2!5417yO zU^o<9P(K^@k?rglK2) z%S9St=7({P0fd7EV*DQepiSIo_3SDH*XF;8>l6{;u$BJ+GV0G3CDLV{BGAIB5MeuM1=Ys?+u)Y4EJ8)jgVhEqnktezWR}` zx&jpuqDuf>=E#KrOogfueM;*TbOgol*|FT-9t$I^ej znusk+*wE3hP<)bRb)bWRJbCjHpMmagh7sU?R*j z)}@hB|IA@1=a0j6dLykl>Ekb=)!U&e8_(_aC9JY*z#3J=9-O~KyPxLJYwu%_uSLi~ zx08?Fqug`068AeXNfF|r-*BK2!fO^&fBq>&)Xt(fM|W|l9dm`8cCP8>HrMx{ZD4Ed z+G7%C17V9++3Zkqy88B`FFTrAQ_yOc9|qYcHk=nl-;S5YC>M>tR$254KPravkWW-| zI4gA8EK@#PU?9>FyJ>EyemL)UM6Ec%N8Wc`Vr93PjMp5@SE>#MC7usRvz;X}#Q) zgDnpA?!q}fHA);uBHEV3_dAo(WGtrtR6;{6u=1cghdk4`V9fH1IF&pCWoEOukkMl< zIXIo`QSld3nI*T^3XOCYuR*Ynb|SHplgl-ruQxsRaj;McM7jQ}YN?H1ujHMzFj!$6 znrqiTO=g+LvOis%T^xSvMHOTHF{)#dNArxr%Fm%A3dQ5)JGEX`l6lM?QPmgYftZ9C zK3$tlQcRZg&LfuGtx447+wOANDCuaD2^R_;_@O#ja6(*3+X$ zL&>ya7<*C3FiJa2^7}e+H#i}(#2g|&Eg z|C|hw(XUdHtH#ODNVY5fVga8b@tbaffx|E`Z{0jCv+hV$A$3c#lUBxzF3Cq$pv)xba(Y^ z9uD`FcW9%l_cg|-sd>NmXY3~e2xvL~5IpK^7sPTghjR}zr*k-W-7Aeu8hHzuvzK_x zqB^mKb${07SN-!etPxHbzm}dw13MbUD&js4od+b?OK$(M>AHfx`&F6y1(X+y^_%oN z$sDXK?$fEe^CIetoCAn`%O1X@rdA>z&#^aP-;C=H{ruIwa=!GsMzi^t3+_sMMTC=T zazQZkmq!0dkz(ba5Qj_vCCuMAm5l5)6F~>%pRs3LVNTYyua*u$)b!;;xqMHDg02>) zcGJ~o5F&t?n{0P@!d2h)6guXw$_Cd&KD3e8v52VYr#ejuv6qXhz4qHanSJ8H_qm-q z!;}KSDTkZ2TR2snm$L|vXg3{I3_Wmxtk>ki48tn8Q|=EB8)e2N6Q6$?pTim~0xG;B z?vUH^!Q~{b)1Y-!`5Eo>ctWSK>uS~jAr^>$hBx5*)-|50gv)!P>f6|W`m~&Dc^des zKDR~~5jOe6)RReZrGd-``ggtxYjRJU7nn(YTYytb@M7*;7kpDgn#n$wOzq6*9?>1G zc43F|WAUNoi7}JJKHV^ij%B_6sE2!SLYPda6Ja9+F35Uk`OQt=Y7OhYSL%hnjBVC| za&}i7-W!BxlEYUe+)wDD&-LTH{wh>92TnJNYFX6#>L{% zVC6L*$xR*Bm14Jo;23sMyA~HM1FA_+;pB8{Li$Zh|E*CUkXB${?$$M^I{N1xs?O8P zxd(Ger~Q;Pr}-1pGvS})Hl9%}=2^65OmuXeAgBW%3%!3jU4~Q3ANg6y^V^_$QE5G( zcTvr{uF=ZKBY;1ENSPeoIRHHS?dB5l>32k~DF>Y;O2Ua=QWkgVCFO!7_Bj3e(~VLD zPSG;n?SGVa^OCae!*c6M*0571zCVY)q;FJF%)?XUBvze3DUZYfy2C4yr7RaY+)d9JUzfy;~78X z-@vf0Q(UTZ)9mGYIyIIowA2!ZC&>@f8?*jNE_yPvHNt>Nk>k|)io}aONPG24UGKLr%!)JB$AVKcIz|W)^O-R(h3w9} zhuQAyjQG{~EF?Q$!$x%ZRASHf%6qU^EYfW|+eOpaPE0Uf3>n2WP5H&^Rd66ZZhz4= zePehxisnJU5xMe>^V8?E9} zN7dbqH}x#dbP9{#T5Tzub@)e|Wcbqhust4>;r z$JRj)H(u#0AulSD)ky8T<`@UeCsEJs#TZ$!BRu;uDcnmTi(t^kLw^ZhBoa?qBz3IC zRO#*&(M~^_M_ZT|Wf$jOHqTGPG z3NGjRXnDFPhM~zys~X@OZ53ZsZDRFd*!ywuXT1rJai~Oc7TU&wuI2QO+)>U#8}~Eh zuTh=iD|KYeu>Ys0GY^Dvf5W~dDN9a^R8AD97(|DYBPFS1H?}c$3CYO5h9TmRB@s!; zzRcM7Wh_z2R(7&yOJm78VHoq?Prvtl|7D)>^~^Kh<-R}Hb*3jo)j~2Ff zY!<{A;-Dp$NK@Wssz5IL6%GNtcx~<$Do!NWAaGJV_4VAMKWy@fpR5Dp@| zvT8JhuWzE?lGrTa5m`yEuPO@yee#PoUg?+Cz?y~l0>%H?fSFnU=Vm(uj09DN?Ek-7 zfW-wT+C^gIEZXhIfn7eIB@4pOKz8wN=_sX}7}|-@<*GIo$~E&v8nj!)CKUe!T`i8= zz@KaR2#fym(M4R=#T0&`iO-#D{VYnMXDmGwlXM!0bzw1V=W)zG=DR$fXj4A3YGEo6 zcb&u=5c;C0Tsfnqc)wygR;6D|Z)r^~fbxohj#nGG2)J9REw8_>jf-2WVX2PB=aE~m z7up&X;=FJ#>*6ALLNt|Hd*+mP#|RPSQ!MN~9CX7l`X`BaaO4Akh%qkCxY-{Rdn0~< zf;3azLasLpHNUEX^jN04ZHIrUxPjxbeNX&Z=*}na=j+gQ`9#ef{V~i@Y=HFj{yftQ zgs2a&isv85kJA6^#sWhrdSq{BLr|!{e%<@Q<0}L!5 zS-0v;4-~OQi)4VF16c3eKkb~Qa!NGxDmlz8vLs~vDP}NWF1uW!Zl+J|$UzWR4Rs}* zob`Y0i#~?mP!bQ-S^HY6V{ljf1(@y+2ld+UIV4Pn=Og{zOrMyrpMy=Ni9KPHN1;=! z_E#L0G1TRZ_$_&ZsXQ#kVPnd8;5NNFkfb3T9I_SqeXEf&HR&*EsGK*eOVVyK3qZU{ z*{-s5V5W|k8o-9`$=K*whn%9B}hQd zH}-qMq1>nzI8N=&;I0k3KW)FY&lGo=n*u&B2r{N&@M=T!p0y9REE4I~nvUVKKdwBz zTBK6X__86mLdeZP9mp3K$8*WX{ixS)#{Ac}_S06rYR${Nr_`Y8=A0-`uVS8zu4nij zoArvtM(PZ0+ts@`bzAzWpY62Vvd&v#A2#kvbw$qfsQG-+@}riMMHQ@1Ox7l~Sw?-d zFle8qScyD|S|@*ADZ4?j#6$i)JCdJYoWDI?l(Ffr@eca~&-wMs;Sh2%QEV>oWqN|S zXdLHyncZfFZSWKv=CkXF1E2b08QoyU3cEh7wvRIQ#<9Yw^LaEYZSWVqq+EY+VD#Yi zXPre6c0#!3yv#CcH1`qR;O+670b{;;LZ@L0bF*XK?vw&WG2j6mT{Eox5U1$ypG4kP z)|LL~d_if+N8zt>Hx5D{Qt7XPodqwMtJ{8(pruiH{OChp-5Z@sm1V(uzVtlEG?AUy zQTk{ynt5YWNLhf??v=qjQh|H65E1d^bw5 zovAx^eikqP2VH0%tDYBMdOWdV=CYO@7^G>ks9%G5y!RH*sY!%fmh!k`_6MCB) z_ZZ4{6_U~oN#-eDw=c-CJgm<*yOSeUemiakV(+CE`PX2vuKo7krr!hZI_|X!rl|?Z z8z1IR5Of^`*cJDwraWwGEWIObA}R&dA>=+ui{=BoBFZ7*^50^|@f2C#Da*D~^!~w` zoZFf_l8aK0j-yC}!C4Z5b5rdxojbh5U^M%GAJG?s(B`kyKguVLt{h@ee$S(TKi9#X z6#zRm$mDUao&5PUx~t zYp&Y9IMG&E{ppffT{YAIJbFslTMiUIf4Xny43#OA9j^x^N?tA&P41%2xyex13@)PI zF7@g>H8cNg6sCFfgUy%QAt{|`{e=VR1BII<>NRioMP=$L{YJL-*f-+ME>QUd7)m1> z6@pk|$9}mrLTx^unsGf%=Oe&3u?N90hX>}ay;#qMwm9gw8d%=MjH-*LRP2~K$(d&k z1+d?LF{rC(H<@w+21ZSS1xtgCTog!D-P;Df0JU;#{LtrEg6^egcw(pd>&O+ zx9@Z9{av;~qtTP`l#k0rOsGFl67kPNhKiG9&lzbbn}0UmbMFawcqI->GGcGvRy^z7 zvv2Q8Yq(Iqz&X&`C1d^9iQT&IsB(N=Miv z7LqfSQnR<-VcOkcXmiWtM_>SK@v`=g+Y2YQ8qdi%`U)yoKO#NuK56LWsnB-Gn$ zR-QEXgD6R-GQUC0kt%Hy2q8S`(``;noPZq^E?zYSv6k}bICVvXGF582l&JFnvY-Z< zin6mQuhwSTw*R(S?_6;n!0Ar#iPppnVeWHtKUIM0x1FlzAn0{o_ArXebci~?K#BzkLgFs z_GlX!J?+ctO;f4kOx3l7^PTR8FVD$+c9DgL@HVzHJY~{IA9cwtip4Y5ALV6| zoV)Uhz{WCh&`i-Dhl;XJDZl0uI%0j^=?C}Rb>Pc5@h*@q76FhyZ5wh^KY8#KBb1Z0wc<%~nQpR(O46~f%kG+H9 zuf=h;3(-<}9#Vhoo>w!ZbUqkiq1qPP(q8OLvO5ADB~mi_y*H|wbN%5SUQsV1ieq6F z;Ez#T3z~{oW^=*2qBy@{!GZ=bkY9)hcoXcwe0t`6M5*I!UAZRXI23Bx8bo;h+a0Dh zCxmU19mT(s&uxt=*q*wwzCJfuwb0D(!SWnHfm+!rU+19adZJG?!hTU;h zroq?Gd{3@t1B^4cya2!3%FyJ+ce!z&?+7 ztJ32gNXX~9lF1!k{O@h%-{A6ir9mnKOdsdG;A1$+g9|kdFkxK-gVyE_qdKpWWKEq^ zY%Rv!YV})_G)GN?(xzpqPQ4$;W^no^?r@6xFl02Sx47zk-US4ENcKk&(2t&Yqx`YL z(tsoQct*Sutp3JvJ_YZNFw$eCLp6OqN_^|y3dTPuXMv5&5#DfBwIOnN=Wcc0fK`>N zYm<0@*p|;}gV!%F-pfcH|+d*Men_OnQsc)%Ya#!A8+MS3eekbxPB>y`YMcU6x(Ob@5oB7lT)v0|K7VzrJx%SUIva~>Et?d`Y zfdH}ypcY?I*#^75r51JZ9}oFXFXk5$-sG9&zE|0u{_tdBnD`ilx&f5~Y4mnwvg#}> zs!NC#*_MWFtAO&wNSX-8uH|}|XyKu)FTDzR8QQ337FK9DtZ~(c?u*dEY_A!w8IRui z^$d`rlkl4VFvh2#2MYz1jC;7Jw zKZ_`eRkY`u8fg`X+4I*c)t5dOPFB%c&|<#bqfPn-XOwcaAj;C{e7uKistOt?G z;+y|e-z@{KvB@%28)vsFQV7Gw* zp=ykv|sMHE*aIJjY*{lX7dIg7X7&pu8A6!FLd<6=giq> zzB$A#xY$p~Fh9WKRu{3EplvPG>!Z*^gpQiW%YJIWYMIgBw9x7UI@`P8P~gTi+`i0= z+=mQ8Aa?dcb>-8rPa?hKDm2B2Ca$!vN-kLSj-0<^mo-TOKj%EAf|Q}w&uog9+LTQV zgXc-i;xZzC?d5CU`Eac;2_`V;r6sa6MVUrlM+%Uy?sp;RWmn*lI7j9+s9LpGocvG` zBg_29PW^LTlvd-Cha(}18D&10f_btgGwsbRAo`_Mcc=9TcMwyaqy)ObUb1YH!e^)j?VO!tiV@lTN~vZeX4yAQ2v>T~@?6XO|>{Pg79 z>htI*NfP-%lqR$spKvgG53av==fbwx@^rWpRyU2c-`3p+C;X2pcNFx}xB0I2NQ2B4 zz9S!Pq(>y$f3p3ErllX}F`5tB|H_~o1a_T@lYS^i-!uuij%JBd{@q>t{`!Wx=FQP5QkV25OOU|CqgBm%``Dg;Bpc1lHx^C5R;ZhO zx70m(HO`2_j2M8mkf_3?d9U`M5Di7hlGa=%4=aO1+zucDq-@Wn*|r?tlut$}IV+zQ zrag_8*FJ6B*a73K&>@@J_A+?}t(UVs_mDV`E;zF6JRmwF#HlBNeH1!&*DYMnPS>~h zS432LT2488`4`#MeABeLOxH8}#KELoUqF*R7y9+B<{~v)7xPJG(m7UOaTu~4*Jiuz z(Kw{@^9HF<&`%^E);G4GDg7#Trg}~DAITT(zUdVOB^x|5&%Q^KlO#KumIHp@4FM$A z^kW;{CoaEabjCPi0}T14u5`Pe!N{q9WVobkUOkAucuT1h3a;7cB1z|2HL0Z-HSv-~ zOSc1~pEWRmgBo2hP3BkMX}{XTKk`hEhS_U4Hge`yRx1DNB&L$*SbIiVfnUk`-si%u zs4t%hs+j}b#;vGQrH8l4MPTdrw)e~fnJ0fU%%*$^7PP_iuvFgk2c6?dcIau>|$4T1)J#TYpQ3MA4S~Q0Kb@L}FC~voPREVmP8rCX(f*yI4Q-&W=;M1S z7Cob#^e2g^Q6ZLA2hLZzl4xHi^b0Sit}>81zb|~=tDXChuc6nZ1TkK$+|^U6vVcSw z;YTdT#!3om09G*fnqtv_04a%_Fdu!?$Tzbwhj-_S`RnL5s>8{$#}O(J<-Q|pt)!#kURn~lcc?xvHyl~gIn+b?w0i2IO zjes}>9#cBN%24qC}tmTOKwOf1v8#LVh{;p%-HA%g) z2O9A=qm8E=@NRKHRj|Bsm_2;L^8Z5>t@FyCZvGNo*RK2@RDm>BOj5$`tA|t_alvN( z58}v&aYNnyH^l*}iwSNN5{@B!3TT)+0UVDxta#6U1<2Z6G4eOx(E@S=a3IiNJ#h`} zgVw>|!bDpTqBfo|ZNOOsB2Fh5KemEK5Rn`IU#R3A{E2Ds`g;qSMdq+zXuq0+!qBjn zHRAU>#_0Hf6I9%{voD-LNL>p(AxMK*DrNpnjubW(7vy(r36VPw&tLBhr23QE5r$lM)Sl-ok4_gs%N+h|YUl4aP>m*m z@`vhpz1mm{`%t0=pqkG|Ax<^_oO$VAib!-ysurfuWSC{`nje|KR5M+BYuA6by2z+P z)%8R8Pgwj1)WJ?8^T!c*>4{^(%b;Wc+isP$YwNKBwSl$MwQp&TX?VDER7VK1n3gDU z7?-u)17hR_lKJt3$%Zh_GWW}CwlcKPg;aJeN8GH=;Ha7N4ZmkZ9XberV2^+s@Il7P zqNq~uax?mxnFCe^dk3op2FlOMzBPcK79^42(!up=ExxS1ZiLZWapCvP4=C<0d~J^( znvp_?89G?#Hqkl1IYf;#sol_*$> zJ-0JLLt#&R-NxGkXfNsvXh`x5Q%~!dtpSP1a86Ef5h#S^;`c|w2H{gvP8dOWv-VK{ z%{HWB*E8e_;lB3)sHuGu`%l!oOR#$dhibfd0b<$Y&igTB7o7xG45whXji=uhZd zRdpx#E6W zu40=;36j7I)xvlKh`3?zszjZsT~RV7b`d5T3%T+48^L7f3%jeP$^ByIJ|R~*Co+e1 zw|D7VccC7T?(Hd&E+S@zdLCTz70K+F6??ZWP_qLIYVM!vpG_b+a>&3%3_IEChy^5X zH6FgAplZ`U!^KLW>yN4JMag9*^q(na$6&mp{=y@#WhsQ)0iejTef>^Nmhe>6u5ap2SX7F#8%mzx?^L!1ZaKXb5#yY59d|2Q5jOEA7- z)+bUf0s8KehE2NgzEmiZfup5$Vvu{-ek>k7Np+Bl!I82dB%*7cj>RJd**9ux6fXcQ z;4xj6z+$ewYYBEk#^q8331@>PA8nSvK4f(AA?nLCl`i$CmF8iyqTD63JpD`b&sdbm>%gJ=037N7zXg<3Fb|k( zGMsZ22}BkPFmj|i`X;r+mh91sszXRUR=0-7YiA6i<$E2Ff!y literal 0 HcmV?d00001 diff --git a/apps/docs/public/static/search/confluence-setup.png b/apps/docs/public/static/search/confluence-setup.png deleted file mode 100644 index 8ce6c182f59e8913ccdc3a645981a30df32bf865..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 45456 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 z z)q(20cxUhu`D6&w> z?&XeXqG)HxJ3rRbdpEsMKHBem;eJa%#4nX#{V8kSaciA)u9ywGrUHR{dw*(qUtUC_ z?0hFtLo)Suu_07aTQ=zum(T&#R@7YqE@B&`zbq%sQ+1v+kBOmgmR9&V{h~-;B}C7! za-ik9zG?D`H>?2yKED3DLd=9QX-E5 z!$b7e42?D`h`k)hI%yml|I$TBHP{!tdnV+C76h*ca5I|2x*zb8ebmD}P)F*Znnv)d zNmQbBrDSxB6ZQ+}EXY6t32nYE>LN9(C9C(|vgfuj!H3wH>3A%WR3JOn+?lqIu=p8X zK7%nfS1}x-%fU4J!ouH7nIG22WLMvv;C-n}W<}5d-e;)kU%yFcjTq=r_@0Zw&P$V@QaX0$hE9=Yb}wiU*qAVTo|}B@ zSGsmzHjl7uB9`4@o7Y&LW8WB<)|&oqdbG!F=A;vPP@*K8VSzd5YUs)*f9S)0l(*ru zI$DCUSy1SU=foe7KlUsW)lL$xE-Io;PUt8bO7_mUTS?^(40sJH8dkfphq#2aPukRo z{cZ|y`NXH7Uc!yc$kkIjM&}rjVRCY_ovw~Wt|l|(IyN`fhf}Y=C^5%W%YrI#L47^o z#U_anM@nPPlinaA;AI&F^QEpUEn96HJrYdT7tDz|t+Bflp2@rU81TIR_9MAt!E065 zQ(+fLw2=K`g*{)9caW$y%X&L=^LyBb_QZu}Do*9wTK{yn9M@KPKWzyR#loDVaCGeV zF{yTR93)0MQVsolg&IXrcQ%rb*9!mp90bipP$+sdK%6Tgycfi93k}B&@um9j0rtkmv(6sH(*7tZRfx!7_m@VDe-Bdkeg2qmr zaz>#%l%V3QR4aUd07SoDRx|llIkvI|j#$M(X=Q8dTi6Rw0w}TFliqI}vzDZmjLZJ_ zZv^eM&5RYle7~IE+al`^4znAmLN~A<;g@{n8|Vcgw`j;L0E$BhY5B|86|_r0QTZ*9 zm-9OhLTWK;@)68|5c>gsNpIw(2s6C*k(d4;BHv+7^77Qx$Stu6pi`;>RY=+Me<%uI zDIk-0KsN)w?{YE6i9O-Or}R*VQ70H z-?pNtRXI&?zAHP5?FG2%lRQ9z@;Qk26>v_ILy&nD1g~f%m#!?`EU-%Amvn*Bn$1C| zajk&;4yal}7Fl5QvOC33ZuAqfNzGxd?P7T|6M(g#j+|eXaqTWdp|+kyas+@BdJ~ES zAh2uTpQx3jh85EI8Z@58!BsIff!)WcXgL8vgenu_om?hVs?q>}9cN`CBo6fQwEPvM za`(#whx~p%{5i%>WoU3jMArD#UF4q$ozj6eJ9Zam(O`kkA--?gQmJYOX#>c&iDeF^ z#_y~9D4oxNL^+T+6-s*zx^Ew5zTC-#Gm_hh1Og@$3RFm$5#Debqo~||(f^IZiRe1C zOp)u@xzZ44;){IIiWzuG+3u;CNXft?NKvFpIOXx{Afcbps+vK}X4^q!SBQlh6LntA z_%p?>nguHeff@mUO8H2Z)>vyo@K zmS@}yru<*3&m35Rp~ukE6Dj!^rWc?Iz+ahHBgc_ok=Q4-RiI*G%0Jpi)0dkGtk5~$ zpWs|(2TaB>@M78JJl7dQ$?~xXl>D6g z`Qa%vTwfHb$D~BYB)1JnSb|G6T(!gk9Ej<8Rn@n~)Ug+NutO8bdB=hG8Mm+IYM_jT zrA2EN;AJg8A)Vsg)nm*URlUc^ZyOJdM{~PQ-PH7_hWbL)Z#is1vE~X@u0nhr*vZX_ z1{i5moNVt9C;&2Jcm52{CM83%itAL!Q)SpZ0fz}Cie<B9Lh;r*$*Q=Yf+L<0;h%%MQ*d20 zL|eW@9t?GUkz8iz zydOR;)_KAUi8vvo5`)!X-@tm+N3C(phH?4ND$OPo$m;8e5#_udJAND+^=EhlXR~jLdWBS_El_e)dfzH3P>MOE$-1_~VF+ zT=oyok=vwZQCB7844tBtSFov&Vh?Rul7-H{%EuDf9M~s^L*Nv&yX#sV43dv Ty9bKmkZp7{4Kyg~4w3%@3Zg6Z literal 0 HcmV?d00001 diff --git a/apps/docs/public/static/search/jira-setup.png b/apps/docs/public/static/search/jira-setup.png deleted file mode 100644 index 393b062c6414bdd2b65c08cf64e5ec3a16a2060f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 58681 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 diff --git a/apps/sim/app/api/knowledge/sim-search/personal-source-setup/route.ts b/apps/sim/app/api/knowledge/sim-search/personal-source-setup/route.ts new file mode 100644 index 00000000000..8fff7a8ff6e --- /dev/null +++ b/apps/sim/app/api/knowledge/sim-search/personal-source-setup/route.ts @@ -0,0 +1,70 @@ +import { + listPersonalSourceSetupAccountsContract, + personalSourceSetupContract, +} from '@/lib/api/contracts/knowledge/personal-source-setup' +import { + defineInternalJsonRoute, + extendInternalErrorPolicy, + internalErrorResponse, + internalRateLimits, + internalSessionAuth, +} from '@/lib/api/server/routes' +import { internalKnowledgeErrorPolicies } from '@/lib/knowledge/api/route-policies' +import { knowledgeOperations } from '@/lib/knowledge/application/operations' +import { + listPersonalSourceSetupAccounts, + personalSourceSetup, +} from '@/lib/knowledge/application/personal-source-setup' +import { + SelectorConnectionUnavailableError, + SelectorContextUnavailableError, + SelectorOptionsUnavailableError, +} from '@/lib/selectors/server/errors' +import { IntegrationNotAllowedError } from '@/ee/access-control/utils/permission-check' + +const errorPolicy = extendInternalErrorPolicy( + internalKnowledgeErrorPolicies.connectAccount, + (error) => { + if (error instanceof SelectorConnectionUnavailableError) + return internalErrorResponse(error.status, { + error: 'Reconnect your account to choose projects or spaces', + }) + if (error instanceof SelectorContextUnavailableError) + return internalErrorResponse(400, { + error: 'Enter your Atlassian site to choose projects or spaces', + }) + if (error instanceof SelectorOptionsUnavailableError) + return internalErrorResponse(error.status, { + error: + 'Could not load projects or spaces. Check the site and account access, then try again.', + }) + if (error instanceof IntegrationNotAllowedError) + return internalErrorResponse(403, { error: error.message }) + return null + } +) + +export const GET = defineInternalJsonRoute({ + contract: listPersonalSourceSetupAccountsContract, + auth: internalSessionAuth, + operation: knowledgeOperations.listPersonalSourceSetupAccounts, + rateLimit: internalRateLimits.user({ bucketName: 'knowledge.search.personal-setup.accounts' }), + errorPolicy, + mapInput: ({ query }) => query, + useCase: listPersonalSourceSetupAccounts, + present: (data) => ({ success: true as const, data }), + staticResponseHeaders: { 'Cache-Control': 'private, no-store' }, +}) + +export const POST = defineInternalJsonRoute({ + contract: personalSourceSetupContract, + auth: internalSessionAuth, + operation: knowledgeOperations.personalSourceSetup, + rateLimit: internalRateLimits.user({ bucketName: 'knowledge.search.personal-setup' }), + errorPolicy, + parseOptions: { maxBodyBytes: 384 * 1024 }, + mapInput: ({ body }) => body, + useCase: personalSourceSetup, + present: (data) => ({ success: true as const, data }), + staticResponseHeaders: { 'Cache-Control': 'private, no-store' }, +}) diff --git a/apps/sim/app/o/[organizationId]/integrations/connect-account-options.tsx b/apps/sim/app/o/[organizationId]/integrations/connect-account-options.tsx index c5e75a3a749..fe091b7cc4f 100644 --- a/apps/sim/app/o/[organizationId]/integrations/connect-account-options.tsx +++ b/apps/sim/app/o/[organizationId]/integrations/connect-account-options.tsx @@ -210,6 +210,7 @@ export function ConnectAccountOptions({ {enrollment.setupConnector && ( { } ) - it('keeps source setup fields after a failure without duplicating the toast inside the modal', async () => { + it('keeps manual source setup fields after a failure without duplicating the toast inside the modal', async () => { const message = 'Connection unavailable' mocks.enrollmentError = message - mocks.setupConnector = SEARCH_CONNECTORS.find((connector) => connector.type === 'jira') ?? null + mocks.setupConnector = + SEARCH_CONNECTORS.find((connector) => connector.type === 'github') ?? null await render() expect(document.querySelector('[role="dialog"]')).not.toBeNull() expect(document.body.textContent).not.toContain(message) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/search-integration-connection.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/search-integration-connection.tsx index e1df655f9ce..5428ce8551d 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/search-integration-connection.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/message-content/components/special-tags/search-integration-connection.tsx @@ -53,7 +53,8 @@ function SearchIntegrationConnectionControl({ }) const name = connector?.meta.name ?? target.provider const action = target.credentialId ? 'Reconnect' : 'Connect' - const label = connection.connected + const connected = connection.connected + const label = connected ? `Connected ${name}` : connection.isLoading ? `Checking ${name} connections…` @@ -76,18 +77,14 @@ function SearchIntegrationConnectionControl({ !connector || connection.isLoading || connection.isStarting || - connection.connected || + connected || (!connection.available && !connection.pending) } onClick={handleConnect} leading={ connector && } - trailing={ - connection.connected ? ( - - ) : undefined - } + trailing={connected ? : undefined} /> {connection.pending && Cancel} {connection.error && ( @@ -100,6 +97,8 @@ function SearchIntegrationConnectionControl({ )} {setupOpen && connector && ( setSetupOpen(false)} isPending={connection.isStarting} diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.test.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.test.tsx new file mode 100644 index 00000000000..44e7fe18616 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.test.tsx @@ -0,0 +1,172 @@ +/** @vitest-environment jsdom */ +import { act } from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { PersonalSourceSetupAccounts } from '@/lib/api/contracts/knowledge/personal-source-setup' +import type { ConnectorConfigField } from '@/connectors/types' + +const m = vi.hoisted(() => ({ + connect: vi.fn(), + authorize: vi.fn(), + close: vi.fn(), + complete: vi.fn(), + accounts: [] as PersonalSourceSetupAccounts['accounts'], + pending: false, +})) +vi.mock('@/hooks/use-personal-source-account', () => ({ + usePersonalSourceAccount: () => ({ + accounts: { + data: { accounts: m.accounts, completedCredentialId: null }, + isPending: false, + isError: false, + }, + connect: m.authorize, + cancel: vi.fn(), + pending: m.pending, + }), +})) +vi.mock('@/hooks/queries/personal-source-setup', () => ({ + useConnectPersonalSourceSetup: () => ({ mutateAsync: m.connect, isPending: false }), +})) +vi.mock( + '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field', + () => ({ + ConnectorSelectorField: (props: { + field: ConnectorConfigField + value: string[] + onChange: (value: string[]) => void + credentialId: string + selectorSurface: { kind: string } + }) => ( + + ), + }) +) + +import { SEARCH_CONNECTORS } from '@/lib/sim-search/connectors' +import { AtlassianSourceSetupModal } from '@/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal' + +let root: Root +let container: HTMLDivElement +function button(label: string) { + const found = Array.from(document.querySelectorAll('button')).find( + (node) => node.textContent?.trim() === label + ) + if (!found) throw new Error(`Missing button: ${label}`) + return found +} +function input(placeholder: string) { + const found = document.querySelector(`input[placeholder="${placeholder}"]`) + if (!found) throw new Error(`Missing input: ${placeholder}`) + return found +} +function fill(field: HTMLInputElement, value: string) { + act(() => { + Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')!.set!.call(field, value) + field.dispatchEvent(new Event('input', { bubbles: true })) + }) +} +function render(type: 'jira' | 'confluence' = 'jira') { + const connector = SEARCH_CONNECTORS.find((item) => item.type === type)! + act(() => + root.render( + + ) + ) +} +beforeEach(() => { + vi.clearAllMocks() + m.accounts = [] + m.pending = false + m.connect.mockResolvedValue({ + kind: 'connected', + connectorId: 'source-1', + knowledgeBaseId: 'kb-1', + }) + ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true + vi.stubGlobal( + 'ResizeObserver', + class { + observe() {} + unobserve() {} + disconnect() {} + } + ) + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) +}) +afterEach(() => { + act(() => root.unmount()) + container.remove() + vi.unstubAllGlobals() +}) +describe('Atlassian personal source setup', () => { + it('starts with account authorization and hides content fields until an account exists', () => { + render() + expect(document.querySelector('[data-testid="picker"]')).toBeNull() + expect(button('Connect & Sync')).toBeDisabled() + act(() => button('Connect account').click()) + expect(m.authorize).toHaveBeenCalledOnce() + expect(m.connect).not.toHaveBeenCalled() + }) + it.each(['jira', 'confluence'] as const)( + 'reuses an account and preserves selected %s keys through manual mode and submission', + async (type) => { + m.accounts = [ + { id: 'my-account', name: 'My account', provider: type, type: 'managed_oauth', scopes: [] }, + ] + render(type) + fill(input('yoursite.atlassian.net'), 'team.atlassian.net') + const picker = document.querySelector('[data-testid="picker"]')! + expect(picker.dataset.credential).toBe('my-account') + expect(picker.dataset.surface).toBe('personal-search-setup') + act(() => picker.click()) + act(() => button('Enter keys manually').click()) + const manual = document.querySelector( + `input[aria-label="${type === 'jira' ? 'Project Keys' : 'Space Keys'}"]` + )! + expect(manual.value).toBe('ENG, SUPPORT') + fill(manual, 'ENG, PRODUCT') + act(() => button(`Choose ${type === 'jira' ? 'projects' : 'spaces'} from list`).click()) + expect(document.querySelector('[data-testid="picker"]')?.textContent).toBe('ENG,PRODUCT') + await act(async () => button('Connect & Sync').click()) + expect(m.connect).toHaveBeenCalledWith({ + action: 'connect', + organizationId: 'org-1', + connectorType: type, + credentialId: 'my-account', + domain: 'team.atlassian.net', + keys: ['ENG', 'PRODUCT'], + }) + expect(m.authorize).not.toHaveBeenCalled() + expect(m.complete).toHaveBeenCalledWith({ + connectorId: 'source-1', + credentialId: 'my-account', + }) + } + ) + it('clears the selection when the site changes', () => { + m.accounts = [ + { id: 'my-account', name: 'My account', provider: 'jira', type: 'managed_oauth', scopes: [] }, + ] + render() + fill(input('yoursite.atlassian.net'), 'team.atlassian.net') + act(() => document.querySelector('[data-testid="picker"]')!.click()) + fill(input('yoursite.atlassian.net'), 'other.atlassian.net') + expect(button('Connect & Sync')).toBeDisabled() + }) +}) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx new file mode 100644 index 00000000000..c4009ea5405 --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx @@ -0,0 +1,241 @@ +'use client' + +import { useState } from 'react' +import { + Chip, + ChipCombobox, + ChipInput, + ChipModal, + ChipModalBody, + ChipModalField, + ChipModalFooter, + ChipModalHeader, + toast, +} from '@sim/emcn' +import { getErrorMessage } from '@sim/utils/errors' +import type { PersonalSourceSetupQuery } from '@/lib/api/contracts/knowledge/personal-source-setup' +import type { SearchConnector } from '@/lib/sim-search/connectors' +import { MAX_PERSONAL_SOURCE_SETUP_KEYS } from '@/lib/sim-search/personal-source-setup' +import { ConnectorSelectorField } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field' +import { useConnectorConfigFields } from '@/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields' +import { useConnectPersonalSourceSetup } from '@/hooks/queries/personal-source-setup' +import { usePersonalSourceAccount } from '@/hooks/use-personal-source-account' + +interface AtlassianSourceSetupModalProps { + organizationId: string + connector: SearchConnector + connectorType: PersonalSourceSetupQuery['connectorType'] + onClose: () => void + onConnected?: (connection: { connectorId: string; credentialId: string }) => void +} + +export function AtlassianSourceSetupModal({ + organizationId, + connector, + connectorType, + onClose, + onConnected, +}: AtlassianSourceSetupModalProps) { + const [selectedAccount, setSelectedAccount] = useState() + const account = usePersonalSourceAccount({ + organizationId, + connectorType, + onConnected: (id) => { + setSelectedAccount(id) + config.setSourceConfig((previous) => ({ domain: previous.domain ?? '' })) + }, + }) + const { mutateAsync: connect, isPending } = useConnectPersonalSourceSetup() + const config = useConnectorConfigFields({ + connectorConfig: connector.meta, + accessMode: 'members', + }) + const accounts = account.accounts.data?.accounts ?? [] + const requestedAccount = + selectedAccount ?? + account.accounts.data?.completedCredentialId ?? + (accounts.length === 1 ? accounts[0].id : undefined) + const credentialId = accounts.find((item) => item.id === requestedAccount)?.id ?? null + const canonicalId = connectorType === 'jira' ? 'projectKey' : 'spaceKey' + const picker = connector.meta.configFields.find( + (field) => field.canonicalParamId === canonicalId && field.type === 'selector' + )! + const manual = connector.meta.configFields.find((field) => field.id === canonicalId)! + const advanced = config.canonicalModes[canonicalId] === 'advanced' + const domain = typeof config.sourceConfig.domain === 'string' ? config.sourceConfig.domain : '' + const resolved = config.resolveSourceConfig()[canonicalId] + const manualValue = config.sourceConfig[canonicalId] + const keys = Array.isArray(resolved) + ? resolved + .filter((key): key is string => typeof key === 'string' && Boolean(key.trim())) + .map((key) => key.trim()) + : [] + const pending = isPending || account.pending + const close = () => { + if (!isPending) onClose() + } + const chooseAccount = (id: string) => { + if (id === credentialId) return + setSelectedAccount(id) + config.setSourceConfig({ domain }) + } + const addAccount = () => { + void account.connect() + } + const submit = async () => { + if (!credentialId || !domain.trim() || !keys.length || pending) return + if (keys.length > MAX_PERSONAL_SOURCE_SETUP_KEYS) { + toast.error('Choose no more than 1,000 projects or spaces per source.') + return + } + try { + const result = await connect({ + action: 'connect', + organizationId, + connectorType, + credentialId, + domain: domain.trim(), + keys, + }) + onConnected?.({ connectorId: result.connectorId, credentialId }) + onClose() + } catch (error) { + toast.error(getErrorMessage(error, 'Could not connect the source')) + } + } + + return ( + { + if (!open) close() + }} + srTitle={`Connect ${connector.meta.name}`} + > + Connect {connector.meta.name} + + + {(aria) => ( + <> + {accounts.length > 0 && ( + ({ value: item.id, label: item.name }))} + placeholder='Select your account' + disabled={pending} + /> + )} +

+ {account.accounts.isPending && ( +

Loading accounts…

+ )} + {account.accounts.isError && ( + void account.accounts.refetch()}>Retry loading accounts + )} + + )} + + {credentialId && !account.pending && ( + <> + config.handleFieldChange('domain', value)} + placeholder='yoursite.atlassian.net' + autoComplete='off' + required + disabled={isPending} + /> + + {(aria) => ( + <> + {advanced ? ( + + config.handleFieldChange(canonicalId, event.target.value) + } + placeholder={manual.placeholder} + disabled={isPending} + /> + ) : picker.selectorKey ? ( + + config.handleFieldChange(picker.id, value, labels) + } + credentialId={credentialId} + sourceConfig={config.sourceConfig} + configFields={connector.meta.configFields} + canonicalModes={config.canonicalModes} + selectedLabels={config.selectionLabels[canonicalId]} + disabled={isPending} + /> + ) : null} + config.toggleCanonicalMode(canonicalId)} + disabled={isPending} + > + {advanced + ? `Choose ${connectorType === 'jira' ? 'projects' : 'spaces'} from list` + : 'Enter keys manually'} + + + )} + + + )} + + + window.open(connector.meta.searchDocsUrl, '_blank', 'noopener,noreferrer'), + }, + ] + : undefined + } + primaryAction={{ + label: isPending ? 'Connecting…' : 'Connect & Sync', + onClick: () => void submit(), + disabled: !credentialId || !domain.trim() || !keys.length || pending, + }} + /> + + ) +} diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/source-setup-modal.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/source-setup-modal.tsx index 4b73d5b989c..eb6f15699a4 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/source-setup-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/source-setup-modal.tsx @@ -9,8 +9,11 @@ import { ChipModalHeader, } from '@sim/emcn' import type { SearchConnector } from '@/lib/sim-search/connectors' +import { AtlassianSourceSetupModal } from '@/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal' interface SourceSetupModalProps { + organizationId?: string + onConnected?: (connection: { connectorId: string; credentialId: string }) => void connector: SearchConnector onClose: () => void isPending?: boolean @@ -23,7 +26,26 @@ interface SourceSetupModalProps { * The few fields a source needs before its first connect, such as a site and * a space. Everyone after the first person clicks straight through. */ -export function SourceSetupModal({ +export function SourceSetupModal(props: SourceSetupModalProps) { + if ( + props.organizationId && + (props.connector.type === 'jira' || props.connector.type === 'confluence') + ) { + return ( + + ) + } + return +} + +function ManualSourceSetupModal({ connector, onClose, onConnect, diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx index 2dbccfee687..9e5cc037fe9 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx @@ -13,6 +13,7 @@ import type { ConfigFieldMap } from '@/app/workspace/[workspaceId]/knowledge/[id const mocks = vi.hoisted(() => ({ create: vi.fn(), accountsQuery: vi.fn(), + oauthQuery: vi.fn(), configFields: vi.fn(), resolveSourceConfig: vi.fn((): Record => ({})), sourceConfig: {} as ConfigFieldMap, @@ -130,14 +131,17 @@ vi.mock('@/hooks/queries/source-accounts', () => ({ }, })) vi.mock('@/hooks/queries/oauth/oauth-credentials', () => ({ - useOAuthCredentials: () => ({ - data: mocks.credentials, - isLoading: mocks.credentialsState === 'loading', - isSuccess: mocks.credentialsState === 'ready', - isFetching: mocks.credentialsState === 'loading', - error: mocks.credentialsState === 'error' ? new Error('Could not load accounts') : null, - refetch: mocks.refetchCredentials, - }), + useOAuthCredentials: (...args: unknown[]) => { + mocks.oauthQuery(...args) + return { + data: mocks.credentials, + isLoading: mocks.credentialsState === 'loading', + isSuccess: mocks.credentialsState === 'ready', + isFetching: mocks.credentialsState === 'loading', + error: mocks.credentialsState === 'error' ? new Error('Could not load accounts') : null, + refetch: mocks.refetchCredentials, + } + }, })) vi.mock('@/hooks/use-oauth-return', () => ({ useOAuthReturnForKBConnectors: vi.fn() })) vi.mock('@/hooks/use-credential-refresh-triggers', () => ({ @@ -809,6 +813,32 @@ describe('Search setup options', () => { }) describe('Account connection dropdown', () => { + it.each(['jira', 'confluence'])( + 'reuses the caller’s managed %s account for browsing member sources', + async (connectorType) => { + mocks.credentials = [ + { id: 'managed-account', name: 'My Search account', type: 'managed_oauth' }, + ] + await render({ + initialConnectorType: connectorType, + lockedAccessMode: 'members', + scope: { kind: 'organization', organizationId: 'org-1' }, + }) + expect(mocks.oauthQuery).toHaveBeenLastCalledWith( + expect.any(String), + expect.objectContaining({ purpose: 'browsing', organizationId: 'org-1' }) + ) + await act(async () => combobox('My Search account').click()) + const option = Array.from(document.querySelectorAll('[role="option"]')).find( + (node) => node.textContent?.trim() === 'My Search account' + ) + expect(option).toBeDefined() + await act(async () => option!.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))) + expect(mocks.configFields).toHaveBeenLastCalledWith( + expect.objectContaining({ credentialId: 'managed-account' }) + ) + } + ) it.each(['google_drive', 'gmail', 'google_calendar'])( 'opens only service-account creation for a central %s source and submits that credential', async (connectorType) => { @@ -858,7 +888,10 @@ describe('Account connection dropdown', () => { ) it('only offers service accounts when creating a central Confluence source', async () => { - mocks.credentials = [{ id: 'personal-account', name: 'Personal Confluence', type: 'oauth' }] + mocks.credentials = [ + { id: 'personal-account', name: 'Personal Confluence', type: 'oauth' }, + { id: 'managed-account', name: 'My Search account', type: 'managed_oauth' }, + ] mocks.serviceAccountTarget = { serviceAccountProviderId: 'atlassian-service-account', serviceName: 'Atlassian', diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx index 846081bd5bf..1992813ba0c 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.tsx @@ -243,6 +243,8 @@ export function AddConnectorModal({ !serviceAccountTarget.hidden && (deploymentState === 'ready' || deploymentState === 'limited') + const browsePersonalAccounts = + isMembersMode && (selectedType === 'jira' || selectedType === 'confluence') const { data: rawCredentials = [], isLoading: credentialsLoading, @@ -251,6 +253,7 @@ export function AddConnectorModal({ refetch: refetchCredentials, } = useOAuthCredentials(connectorProviderId ?? undefined, { enabled: Boolean(connectorConfig) && !isApiKeyMode, + purpose: browsePersonalAccounts ? 'browsing' : undefined, ...owner, }) @@ -258,6 +261,7 @@ export function AddConnectorModal({ const credentials = rawCredentials.filter( (credential) => + (browsePersonalAccounts && credential.type === 'managed_oauth') || !connectorConfig || isConnectorCredentialTypeAllowed(connectorConfig.auth, access.accessMode, credential.type) ) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.queries.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.queries.test.tsx index d4bb2cd6abf..471a40eb07b 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.queries.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.queries.test.tsx @@ -1,5 +1,5 @@ /** @vitest-environment jsdom */ -import { act, useState } from 'react' +import { act, type ComponentProps, useState } from 'react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { createRoot } from 'react-dom/client' import { beforeEach, expect, it, vi } from 'vitest' @@ -11,6 +11,7 @@ interface ComboboxProps { isLoading: boolean onChange: (value: string) => void onMultiSelectChange?: (value: string[]) => void + onSearchChange?: (value: string) => void } const mocks = vi.hoisted(() => ({ @@ -18,7 +19,12 @@ const mocks = vi.hoisted(() => ({ combobox: vi.fn((_props: ComboboxProps) => null), })) -vi.mock('@sim/emcn', () => ({ ChipCombobox: mocks.combobox })) +vi.mock('@sim/emcn', () => ({ + ChipCombobox: mocks.combobox, + Chip: ({ children, ...props }: ComponentProps<'button'>) => ( + + ), +})) vi.mock('next/navigation', () => ({ useParams: () => ({ workspaceId: 'workspace-1' }) })) vi.mock('@/hooks/use-debounce', () => ({ useDebounce: (value: string) => value })) vi.mock('@/lib/selectors/client/execute-selector', () => ({ @@ -161,3 +167,169 @@ it('keeps the loaded list visible while resolving a saved selection on another p client.clear() } }) + +async function renderBulkSelector() { + const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }) + const container = document.createElement('div') + document.body.appendChild(container) + const root = createRoot(container) + const change = vi.fn() + await act(async () => + root.render( + + + + ) + ) + const button = (label: string) => { + const element = Array.from(container.querySelectorAll('button')).find( + (item) => item.textContent === label + ) + if (!element) throw new Error(`Missing ${label} button`) + return element + } + await act(async () => + vi.waitFor(() => expect(button('Select all').disabled).toBe(false), { interval: 1 }) + ) + return { + container, + change, + button, + dispose: async () => { + await act(async () => root.unmount()) + client.clear() + container.remove() + }, + } +} + +it('selects every complete page, exposes the count, and clears explicitly', async () => { + mocks.execute.mockImplementation(async ({ request }: { request: SelectorRequest }) => + request.kind === 'detail' + ? { kind: 'detail', item: null } + : request.cursor + ? { kind: 'list', items: [options[1], options[0]] } + : { kind: 'list', items: [options[0]], nextCursor: 'next' } + ) + const view = await renderBulkSelector() + try { + expect(view.container.textContent).toContain('1 selected') + await act(async () => view.button('Select all').click()) + await act(async () => + vi.waitFor(() => expect(view.change).toHaveBeenCalledWith(['ENG', 'OPS'], options), { + interval: 1, + }) + ) + expect(mocks.execute.mock.calls.filter(([args]) => args.request.kind === 'list')).toHaveLength( + 2 + ) + await act(async () => view.button('Clear').click()) + expect(view.change).toHaveBeenLastCalledWith([], []) + } finally { + await view.dispose() + } +}) + +it.each(['partial', 'error'] as const)('preserves the selection on %s results', async (failure) => { + mocks.execute.mockImplementation(async ({ request }: { request: SelectorRequest }) => { + if (request.kind === 'detail') return { kind: 'detail', item: null } + if (request.cursor) { + if (failure === 'error') throw new Error('Provider is unavailable') + return { kind: 'list', items: [options[1]], truncated: true } + } + return { kind: 'list', items: [options[0]], nextCursor: 'next' } + }) + const view = await renderBulkSelector() + try { + await act(async () => view.button('Select all').click()) + await act(async () => + vi.waitFor(() => expect(view.container.querySelector('[role="alert"]')).not.toBeNull(), { + interval: 1, + }) + ) + expect(view.change).not.toHaveBeenCalled() + expect(view.container.textContent).toContain('1 selected') + expect(view.container.textContent).toContain( + failure === 'error' ? 'Could not load all options' : 'too many results' + ) + } finally { + await view.dispose() + } +}) + +it('disables bulk selection while searching and ignores a completion after the user edits selection', async () => { + let resolvePage!: (result: SelectorResult) => void + const pending = new Promise((resolve) => { + resolvePage = resolve + }) + mocks.execute.mockImplementation(({ request }: { request: SelectorRequest }) => + request.kind === 'detail' + ? Promise.resolve({ kind: 'detail', item: null }) + : request.cursor + ? pending + : Promise.resolve({ kind: 'list', items: [options[0]], nextCursor: 'next' }) + ) + const view = await renderBulkSelector() + try { + await act(async () => mocks.combobox.mock.lastCall![0].onSearchChange?.('Eng')) + expect(view.button('Select all').disabled).toBe(true) + expect(view.container.textContent).toContain('Clear search to select all') + await act(async () => mocks.combobox.mock.lastCall![0].onSearchChange?.('')) + await act(async () => view.button('Select all').click()) + await act(async () => view.button('Clear').click()) + expect(view.change).toHaveBeenCalledTimes(1) + await act(async () => resolvePage({ kind: 'list', items: [options[1]] })) + await act(async () => + vi.waitFor(() => expect(view.container.textContent).not.toContain('Selecting…'), { + interval: 1, + }) + ) + expect(view.change).toHaveBeenCalledTimes(1) + expect(view.change).toHaveBeenLastCalledWith([], []) + } finally { + await view.dispose() + } +}) + +it('hydrates only the trigger-visible labels for large saved selections', async () => { + const client = new QueryClient({ defaultOptions: { queries: { retry: false } } }) + const root = createRoot(document.createElement('div')) + try { + await act(async () => + root.render( + + `SAVED-${index}`)} + onChange={vi.fn()} + credentialId='credential-1' + sourceConfig={{ domain: 'example.atlassian.net' }} + configFields={[domainField, field]} + canonicalModes={{}} + /> + + ) + ) + await act(async () => + vi.waitFor(() => expect(mocks.combobox.mock.lastCall![0].isLoading).toBe(false), { + interval: 1, + }) + ) + expect( + mocks.execute.mock.calls + .filter(([args]) => args.request.kind === 'detail') + .map(([args]) => args.request.id) + ).toEqual(['SAVED-0', 'SAVED-1']) + } finally { + await act(async () => root.unmount()) + client.clear() + } +}) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx index a9746766ade..708cf3c5db0 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx @@ -1,5 +1,5 @@ /** @vitest-environment jsdom */ -import { act } from 'react' +import { act, type ComponentProps } from 'react' import { createRoot } from 'react-dom/client' import { beforeEach, expect, it, vi } from 'vitest' import type { ConnectorConfigField } from '@/connectors/types' @@ -8,9 +8,15 @@ const mocks = vi.hoisted(() => ({ combobox: vi.fn((_props: ComboboxCallbacks) => null), change: vi.fn(), projectContext: vi.fn((_key: string, context: Record) => context), + loadAll: vi.fn(), })) -vi.mock('@sim/emcn', () => ({ ChipCombobox: mocks.combobox })) +vi.mock('@sim/emcn', () => ({ + ChipCombobox: mocks.combobox, + Chip: ({ children, ...props }: ComponentProps<'button'>) => ( + + ), +})) vi.mock('next/navigation', () => ({ useParams: () => ({ workspaceId: 'workspace-1' }) })) vi.mock('@/lib/selectors/context', () => ({ projectSelectorContext: mocks.projectContext })) vi.mock('@/lib/selectors/manifest', () => ({ @@ -22,6 +28,7 @@ vi.mock('@/hooks/queries/selectors', () => ({ data: [{ id: 'folder-b', label: 'Company docs', secret: 'not display metadata' }], error: null, truncated: false, + loadAll: mocks.loadAll, }), useSelectorOptionDetails: () => ({ data: [{ id: 'folder-a', label: 'Engineering' }] }), useSelectorOptionDetail: () => ({}), @@ -173,3 +180,56 @@ it('uses saved labels only for selected values and prefers live provider names', vi.clearAllMocks() } }) + +it('keeps the prior selection when all personal setup options exceed its source limit', async () => { + mocks.loadAll.mockResolvedValue({ + status: 'complete', + options: Array.from({ length: 1001 }, (_, index) => ({ + id: `P${index}`, + label: `Project ${index}`, + })), + }) + const field: ConnectorConfigField & { selectorKey: 'jira.projectKeys' } = { + id: 'projects', + title: 'Projects', + type: 'selector', + selectorKey: 'jira.projectKeys', + multi: true, + allowSelectAll: true, + } + const container = document.createElement('div') + const root = createRoot(container) + try { + await act(async () => + root.render( + + ) + ) + const button = Array.from(container.querySelectorAll('button')).find( + (item) => item.textContent === 'Select all' + ) + await act(async () => button?.click()) + expect(mocks.loadAll).toHaveBeenCalledTimes(1) + expect(mocks.change).not.toHaveBeenCalled() + expect(container.querySelector('[role="alert"]')?.textContent).toContain( + 'Select up to 1,000 items' + ) + } finally { + await act(async () => root.unmount()) + vi.clearAllMocks() + } +}) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx index 8a02e6a09d1..88595e6e428 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx @@ -1,12 +1,13 @@ 'use client' -import { useMemo, useState } from 'react' -import { ChipCombobox, type ComboboxOption } from '@sim/emcn' +import { useEffect, useMemo, useRef, useState } from 'react' +import { Chip, ChipCombobox, type ChipModalFieldAria, type ComboboxOption } from '@sim/emcn' import { useParams } from 'next/navigation' import { type ResourceScope, resourceScopeFromOwner } from '@/lib/core/resource-scope' import { projectSelectorContext } from '@/lib/selectors/context' import { getSelectorManifestEntry, type SelectorKey } from '@/lib/selectors/manifest' -import type { SelectorContext } from '@/lib/selectors/types' +import type { SelectorContext, SelectorSurface } from '@/lib/selectors/types' +import { MAX_PERSONAL_SOURCE_SETUP_KEYS } from '@/lib/sim-search/personal-source-setup' import type { SourceSelectionLabel } from '@/lib/sim-search/source-identity' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' import { getDependsOnFields } from '@/lib/workflows/subblocks/dependencies' @@ -23,7 +24,9 @@ import { import { useDebounce } from '@/hooks/use-debounce' interface ConnectorSelectorFieldProps { + controlAria?: ChipModalFieldAria scope?: ResourceScope + selectorSurface?: SelectorSurface field: ConnectorConfigField & { selectorKey: SelectorKey } value: ConfigFieldValue onChange: (value: ConfigFieldValue, selectedOptions?: SourceSelectionLabel[]) => void @@ -37,7 +40,9 @@ interface ConnectorSelectorFieldProps { } export function ConnectorSelectorField({ + controlAria, scope: explicitScope, + selectorSurface, field, value, onChange, @@ -53,6 +58,17 @@ export function ConnectorSelectorField({ const scope = explicitScope ?? resourceScopeFromOwner(params) const isMulti = Boolean(field.multi) const [searchTerm, setSearchTerm] = useState('') + const [bulkError, setBulkError] = useState<{ context: SelectorContext; message: string } | null>( + null + ) + const bulkGenerationRef = useRef(0) + + useEffect( + () => () => { + bulkGenerationRef.current += 1 + }, + [] + ) const context = useMemo(() => { const candidate: Record = {} @@ -95,10 +111,14 @@ export function ConnectorSelectorField({ }, [field.dependsOn, sourceConfig, configFields, canonicalModes]) const isEnabled = !disabled && !!credentialId && depsResolved + const missingDependencyMessage = selectorSurface + ? 'Enter your Atlassian site first' + : `Select ${getDependencyLabel(field, configFields)} first` const debouncedSearch = useDebounce(searchTerm.trim(), SEARCH_DEBOUNCE_MS) const { data: options = [], isLoading, + isFetching, hasMore, isFetchingMore, isLoadingAll, @@ -109,6 +129,7 @@ export function ConnectorSelectorField({ } = useSelectorOptions(field.selectorKey, { context, scope, + surface: selectorSurface, search: debouncedSearch, enabled: isEnabled, surfaceId: `connector:${field.id}`, @@ -121,13 +142,15 @@ export function ConnectorSelectorField({ ) const missingSelectedIds = useMemo(() => { const loadedIds = new Set(options.map((option) => option.id)) - return selectedIds.filter((id) => !loadedIds.has(id)) + /** The trigger displays at most two labels; additional selections are counted. */ + return selectedIds.slice(0, 2).filter((id) => !loadedIds.has(id)) }, [options, selectedIds]) const { data: selectedOptions, isLoading: isLoadingSelectedOptions } = useSelectorOptionDetails( field.selectorKey, { context, scope, + surface: selectorSurface, detailIds: isEnabled ? missingSelectedIds : [], surfaceId: `connector:${field.id}`, } @@ -143,6 +166,7 @@ export function ConnectorSelectorField({ const { data: searchedOption } = useSelectorOptionDetail(field.selectorKey, { context, scope, + surface: selectorSurface, detailId: resolvesUnknownIds && isEnabled && debouncedSearch.length > 0 ? debouncedSearch : undefined, surfaceId: `connector:${field.id}`, @@ -171,6 +195,8 @@ export function ConnectorSelectorField({ }, [options, selectedOptions, searchedOption, selectedLabels, selectedIds]) const handleChange = (nextValue: ConfigFieldValue) => { + bulkGenerationRef.current += 1 + setBulkError(null) const ids = new Set(Array.isArray(nextValue) ? nextValue : nextValue ? [nextValue] : []) const selected = comboboxOptions .filter((option) => ids.has(option.value)) @@ -178,50 +204,126 @@ export function ConnectorSelectorField({ onChange(nextValue, selected) } + const handleSearchChange = (nextSearch: string) => { + bulkGenerationRef.current += 1 + setBulkError(null) + setSearchTerm(nextSearch) + } + + const hasSearch = searchTerm.trim().length > 0 || debouncedSearch.length > 0 + const selectAll = async () => { + if (!isEnabled || hasSearch || isFetching || isLoadingAll) return + const generation = ++bulkGenerationRef.current + setBulkError(null) + const result = await loadAll() + if (bulkGenerationRef.current !== generation || result.status === 'cancelled') return + if (result.status !== 'complete') { + setBulkError({ + context, + message: + result.status === 'partial' + ? 'There are too many results to select all. Select items individually or enter keys.' + : 'Could not load all options. Try again.', + }) + return + } + if ( + selectorSurface?.kind === 'personal-search-setup' && + result.options.length > MAX_PERSONAL_SOURCE_SETUP_KEYS + ) { + setBulkError({ + context, + message: `Select up to ${MAX_PERSONAL_SOURCE_SETUP_KEYS.toLocaleString()} items. Choose a smaller set to continue.`, + }) + return + } + onChange( + result.options.map((option) => option.id), + result.options.map((option) => ({ id: option.id, label: option.label })) + ) + } + if (isMulti) { const multiValues = Array.isArray(value) ? value : value ? [value] : [] return ( - +
+ + {field.allowSelectAll && ( + <> +
+ void selectAll()} + > + {isLoadingAll ? 'Selecting…' : 'Select all'} + + handleChange([])} + > + Clear + + + {multiValues.length} selected + +
+ {hasSearch && ( +

Clear search to select all.

+ )} + {bulkError?.context === context && ( +

+ {bulkError.message} +

+ )} + + )} +
) } return ( ({ GmailIcon: () => null, GoogleCalendarIcon: () => null, GoogleDriveIcon: () => null, + JiraIcon: () => null, + ConfluenceIcon: () => null, })) import { describeSearchSource, SOURCE_LABELS_KEY } from '@/lib/sim-search/source-identity' @@ -17,9 +19,11 @@ import { type UseConnectorConfigFieldsResult, useConnectorConfigFields, } from '@/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields' +import { confluenceConnectorMeta } from '@/connectors/confluence/meta' import { gmailConnectorMeta } from '@/connectors/gmail/meta' import { googleCalendarConnectorMeta } from '@/connectors/google-calendar/meta' import { googleDriveConnectorMeta } from '@/connectors/google-drive/meta' +import { jiraConnectorMeta } from '@/connectors/jira/meta' import type { ConnectorMeta } from '@/connectors/types' describe('useConnectorConfigFields member configuration', () => { @@ -277,6 +281,36 @@ describe('useConnectorConfigFields member configuration', () => { expect(current.selectionLabels).toEqual({}) }) + it.each([ + [jiraConnectorMeta, 'projectKey', 'projectSelector'], + [confluenceConnectorMeta, 'spaceKey', 'spaceSelector'], + ] as const)( + 'carries the current $0.name keys between picker and manual entry', + (meta, canonicalId, selectorId) => { + render({ connectorConfig: meta, accessMode: 'members' }) + act(() => current.handleFieldChange('domain', 'team.atlassian.net')) + act(() => + current.handleFieldChange( + selectorId, + ['ENG', 'SUPPORT'], + [{ id: 'ENG', label: 'Engineering' }] + ) + ) + act(() => current.toggleCanonicalMode(canonicalId)) + expect(current.resolveSourceConfig()[canonicalId]).toEqual(['ENG', 'SUPPORT']) + expect(current.selectionLabels[canonicalId]).toEqual([{ id: 'ENG', label: 'Engineering' }]) + act(() => current.handleFieldChange(canonicalId, 'ENG, PRODUCT')) + act(() => current.toggleCanonicalMode(canonicalId)) + expect(current.sourceConfig[selectorId]).toEqual(['ENG', 'PRODUCT']) + expect(current.resolveSourceConfig()[canonicalId]).toEqual(['ENG', 'PRODUCT']) + expect(current.selectionLabels).toEqual({}) + act(() => current.handleFieldChange('domain', 'other.atlassian.net')) + expect(current.resolveSourceConfig()[canonicalId]).toEqual([]) + act(() => current.toggleCanonicalMode(canonicalId)) + expect(current.resolveSourceConfig()[canonicalId]).toEqual([]) + } + ) + it('clears dependent selector labels together with their values', () => { const meta: ConnectorMeta = { ...googleDriveConnectorMeta, diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields.ts b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields.ts index 6d8619ec5fa..1308e9c7e2c 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields.ts +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/hooks/use-connector-config-fields.ts @@ -219,17 +219,29 @@ export function useConnectorConfigFields({ [dependentFieldIds, fieldsById] ) - const toggleCanonicalMode = useCallback((canonicalId: string) => { - setSelectionLabels((prev) => { - const next = { ...prev } - delete next[canonicalId] - return next - }) - setCanonicalModes((prev) => ({ - ...prev, - [canonicalId]: prev[canonicalId] === 'advanced' ? 'basic' : 'advanced', - })) - }, []) + const toggleCanonicalMode = useCallback( + (canonicalId: string) => { + const group = canonicalGroups.get(canonicalId) ?? [] + const currentMode = canonicalModes[canonicalId] ?? 'basic' + const nextMode = currentMode === 'basic' ? 'advanced' : 'basic' + const currentField = group.find((field) => field.mode === currentMode) + const nextField = group.find((field) => field.mode === nextMode) + if (currentField && nextField && group.some((field) => field.preserveValueOnModeChange)) { + setFieldValues((prev) => ({ + ...prev, + [nextField.id]: coerceForField(nextField, prev[currentField.id]), + })) + } else { + setSelectionLabels((prev) => { + const next = { ...prev } + delete next[canonicalId] + return next + }) + } + setCanonicalModes((prev) => ({ ...prev, [canonicalId]: nextMode })) + }, + [canonicalGroups, canonicalModes] + ) const resolveSourceConfig = useCallback((): Record => { const resolved: Record = {} diff --git a/apps/sim/connectors/confluence/bulk-spaces.test.ts b/apps/sim/connectors/confluence/bulk-spaces.test.ts new file mode 100644 index 00000000000..f2e670030a6 --- /dev/null +++ b/apps/sim/connectors/confluence/bulk-spaces.test.ts @@ -0,0 +1,234 @@ +/** + * @vitest-environment node + */ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { confluenceConnector } from '@/connectors/confluence/confluence' + +const fetchMock = vi.fn() +const config = { domain: 'example.atlassian.net', spaceKey: [] as string[] } +const keys = Array.from({ length: 120 }, (_, index) => `SPACE_${index}`) + +function requestUrl(input: string | URL | Request): URL { + return new URL(input instanceof Request ? input.url : String(input)) +} + +beforeEach(() => { + fetchMock.mockReset() + vi.stubGlobal('fetch', fetchMock) +}) + +afterEach(() => vi.unstubAllGlobals()) + +describe('Confluence bulk space validation', () => { + it('validates every selected space with bounded query sizes and follows partial pages', async () => { + const verifiedKeys: string[] = [] + fetchMock.mockImplementation(async (input) => { + const url = requestUrl(input) + const batch = url.searchParams.getAll('keys') + expect(batch.length).toBeLessThanOrEqual(50) + expect(Number(url.searchParams.get('limit'))).toBeLessThanOrEqual(50) + const page = url.searchParams.has('cursor') ? batch.slice(25) : batch.slice(0, 25) + verifiedKeys.push(...page) + return Response.json({ + results: page.map((key) => ({ key, id: key })), + _links: + batch.length > 25 && !url.searchParams.has('cursor') + ? { next: '/wiki/api/v2/spaces?cursor=second-page' } + : {}, + }) + }) + + await expect( + confluenceConnector.validateConfig( + 'token', + { ...config, spaceKey: [...keys, keys[0]] }, + { cloudId: 'cloud' } + ) + ).resolves.toEqual({ valid: true }) + expect(verifiedKeys).toEqual(keys) + expect(fetchMock).toHaveBeenCalledTimes(5) + }) + + it('bounds encoded URLs for long space keys', async () => { + const longKeys = Array.from({ length: 20 }, (_, index) => `SPACE_${index}_${'x'.repeat(240)}`) + const verifiedKeys: string[] = [] + fetchMock.mockImplementation(async (input) => { + const url = requestUrl(input) + expect(url.toString().length).toBeLessThan(2_100) + const batch = url.searchParams.getAll('keys') + verifiedKeys.push(...batch) + return Response.json({ results: batch.map((key) => ({ key, id: key })) }) + }) + await expect( + confluenceConnector.validateConfig( + 'token', + { ...config, spaceKey: longKeys }, + { cloudId: 'cloud' } + ) + ).resolves.toEqual({ valid: true }) + expect(verifiedKeys).toEqual(longKeys) + expect(fetchMock.mock.calls.length).toBeGreaterThan(1) + }) + + it('rejects an unavailable space in a later batch', async () => { + fetchMock.mockImplementation(async (input) => { + const batch = requestUrl(input).searchParams.getAll('keys') + return Response.json({ + results: batch.filter((key) => key !== 'SPACE_110').map((key) => ({ key })), + }) + }) + await expect( + confluenceConnector.validateConfig( + 'token', + { ...config, spaceKey: keys }, + { cloudId: 'cloud' } + ) + ).resolves.toEqual({ valid: false, error: 'Space not found: SPACE_110' }) + }) + + it('rejects repeated pagination instead of accepting a partial space set', async () => { + fetchMock.mockImplementation(async () => + Response.json({ + results: [], + _links: { next: '/wiki/api/v2/spaces?cursor=repeated' }, + }) + ) + await expect( + confluenceConnector.validateConfig( + 'token', + { ...config, spaceKey: keys }, + { cloudId: 'cloud' } + ) + ).resolves.toEqual({ + valid: false, + error: 'Confluence returned an incomplete space list. Try again.', + }) + expect(fetchMock).toHaveBeenCalledTimes(2) + }) + + it('does not accept a later failed batch', async () => { + fetchMock.mockImplementation(async (input) => { + const batch = requestUrl(input).searchParams.getAll('keys') + return batch.includes('SPACE_50') + ? Response.json({}, { status: 403 }) + : Response.json({ results: batch.map((key) => ({ key })) }) + }) + await expect( + confluenceConnector.validateConfig( + 'token', + { ...config, spaceKey: keys }, + { cloudId: 'cloud' } + ) + ).resolves.toEqual({ valid: false, error: 'Failed to validate spaces: 403' }) + }) +}) + +describe('Confluence bulk space listing', () => { + const sourceConfig = { ...config, spaceKey: keys.slice(0, 52) } + + function page(id: string, next?: string): Response { + return Response.json({ + results: [{ id, title: id, type: 'page', status: 'current', space: { key: 'SPACE_0' } }], + _links: next ? { next: `/wiki/rest/api/content/search?cursor=${next}` } : {}, + }) + } + + it('exhausts each provider cursor before moving to the next explicit space batch', async () => { + fetchMock + .mockResolvedValueOnce(page('1', 'provider-page-2')) + .mockResolvedValueOnce(page('2')) + .mockResolvedValueOnce(page('3')) + const context: Record = { cloudId: 'cloud' } + const first = await confluenceConnector.listDocuments('token', sourceConfig, undefined, context) + const second = await confluenceConnector.listDocuments( + 'token', + sourceConfig, + first.nextCursor, + context + ) + const third = await confluenceConnector.listDocuments( + 'token', + sourceConfig, + second.nextCursor, + context + ) + expect( + [first, second, third].flatMap((result) => result.documents.map((doc) => doc.externalId)) + ).toEqual(['1', '2', '3']) + expect([first.hasMore, second.hasMore, third.hasMore]).toEqual([true, true, false]) + const requests = fetchMock.mock.calls.map(([input]) => requestUrl(input)) + expect(requests[0].searchParams.get('cql')).toBe(requests[1].searchParams.get('cql')) + expect(requests[1].searchParams.get('cursor')).toBe('provider-page-2') + expect(requests[2].searchParams.has('cursor')).toBe(false) + expect(requests[2].searchParams.get('cql')).toContain('space in ("SPACE_50","SPACE_51")') + expect(context.listingCapped).toBeUndefined() + }) + + it('marks a limit reached before later batches as incomplete for deletion reconciliation', async () => { + fetchMock.mockResolvedValueOnce(page('1')) + const context: Record = { cloudId: 'cloud' } + const result = await confluenceConnector.listDocuments( + 'token', + { ...sourceConfig, maxPages: '1' }, + undefined, + context + ) + expect(result.hasMore).toBe(false) + expect(result.nextCursor).toBeUndefined() + expect(context.listingCapped).toBe(true) + }) + + it('continues through an empty batch without widening the query', async () => { + fetchMock.mockResolvedValueOnce(Response.json({ results: [] })).mockResolvedValueOnce(page('1')) + const context: Record = { cloudId: 'cloud' } + const first = await confluenceConnector.listDocuments('token', sourceConfig, undefined, context) + const last = await confluenceConnector.listDocuments( + 'token', + sourceConfig, + first.nextCursor, + context + ) + expect(first.documents).toEqual([]) + expect(first.hasMore).toBe(true) + expect(last.documents.map((doc) => doc.externalId)).toEqual(['1']) + expect(last.hasMore).toBe(false) + }) + + it('rejects an invalid batch continuation before requesting any content', async () => { + await expect( + confluenceConnector.listDocuments('token', sourceConfig, 'space-batches:{"batch":-1}', { + cloudId: 'cloud', + }) + ).rejects.toThrow('Invalid Confluence space continuation') + expect(fetchMock).not.toHaveBeenCalled() + }) + + it('bounds CQL requests for long space keys while retaining filters', async () => { + const longKeys = Array.from({ length: 20 }, (_, index) => `SPACE_${index}_${'x'.repeat(240)}`) + fetchMock.mockImplementation(async () => Response.json({ results: [] })) + const context: Record = { cloudId: 'cloud' } + let cursor: string | undefined + do { + const result = await confluenceConnector.listDocuments( + 'token', + { ...sourceConfig, spaceKey: longKeys, labelFilter: 'published', contentType: 'all' }, + cursor, + context + ) + cursor = result.nextCursor + } while (cursor) + const queries = fetchMock.mock.calls.map(([input]) => requestUrl(input)) + expect(queries.length).toBeGreaterThan(1) + for (const url of queries) { + expect(url.toString().length).toBeLessThan(2_300) + expect(url.searchParams.get('cql')).toContain( + 'type in ("page","blogpost") AND label="published"' + ) + } + for (const key of longKeys) { + expect( + queries.filter((url) => url.searchParams.get('cql')?.includes(`"${key}"`)) + ).toHaveLength(1) + } + }) +}) diff --git a/apps/sim/connectors/confluence/confluence.ts b/apps/sim/connectors/confluence/confluence.ts index 1b4bb94e446..eb2f62f068f 100644 --- a/apps/sim/connectors/confluence/confluence.ts +++ b/apps/sim/connectors/confluence/confluence.ts @@ -39,6 +39,34 @@ import { getConfluenceCloudId, normalizeConfluenceDomainHost } from '@/tools/con const logger = createLogger('ConfluenceConnector') const PERMISSION_VALIDATION_TIMEOUT_MS = 10_000 +const SPACE_BATCH_SIZE = 50 +const SPACE_BATCH_QUERY_LENGTH = 1_800 +const SPACE_BATCH_CURSOR_PREFIX = 'space-batches:' + +/** Bounds both space lookups and CQL URLs when a source includes many spaces. */ +function spaceKeyBatches(spaceKeys: string[]): string[][] { + const batches: string[][] = [] + let batch: string[] = [] + let queryLength = 0 + for (const key of new Set(spaceKeys)) { + const encodedLength = encodeURIComponent(escapeCql(key)).length + 15 + if (encodedLength > SPACE_BATCH_QUERY_LENGTH) { + throw new Error('A Confluence space key is too long. Check the selected spaces.') + } + if ( + batch.length === SPACE_BATCH_SIZE || + queryLength + encodedLength > SPACE_BATCH_QUERY_LENGTH + ) { + batches.push(batch) + batch = [] + queryLength = 0 + } + batch.push(key) + queryLength += encodedLength + } + if (batch.length > 0) batches.push(batch) + return batches +} /** * The configured space does not exist for the caller. Confluence answers a @@ -595,7 +623,7 @@ export const confluenceConnector: ConnectorConfig = { * `lastModified`. */ if (labelFilter.trim() || spaceKeys.length > 1 || lastSyncAt) { - return listDocumentsViaCql( + return listSpaceBatchesViaCql( cloudId, accessToken, domain, @@ -746,43 +774,64 @@ export const confluenceConnector: ConnectorConfig = { } : VALIDATE_RETRY_OPTIONS const cloudId = await resolveCloudId(accessToken, sourceConfig, syncContext, retryOptions) - const params = new URLSearchParams() - for (const key of spaceKeys) params.append('keys', key) - params.append('limit', String(Math.max(spaceKeys.length, 1))) - const spaceUrl = `https://api.atlassian.com/ex/confluence/${cloudId}/wiki/api/v2/spaces?${params.toString()}` - const response = await fetchWithRetry( - spaceUrl, - { - method: 'GET', - headers: { - Accept: 'application/json', - Authorization: `Bearer ${accessToken}`, - }, - }, - retryOptions - ) - if (!response.ok) { - return { valid: false, error: `Failed to validate spaces: ${response.status}` } - } - const data = await response.json() - const results = (data.results as Array> | undefined) ?? [] - const foundKeys = new Set(results.map((r) => String(r.key))) - const missing = spaceKeys.filter((k) => !foundKeys.has(k)) - if (missing.length > 0) { - return { - valid: false, - error: `Space${missing.length > 1 ? 's' : ''} not found: ${missing.join(', ')}`, + let permissionSpaceId: string | undefined + for (const batch of spaceKeyBatches(spaceKeys)) { + const remainingKeys = new Set(batch) + const seenCursors = new Set() + let cursor: string | undefined + do { + const params = new URLSearchParams() + for (const key of batch) params.append('keys', key) + params.set('limit', String(batch.length)) + if (cursor) params.set('cursor', cursor) + const response = await fetchWithRetry( + `https://api.atlassian.com/ex/confluence/${cloudId}/wiki/api/v2/spaces?${params}`, + { + method: 'GET', + headers: { Accept: 'application/json', Authorization: `Bearer ${accessToken}` }, + }, + retryOptions + ) + if (!response.ok) { + return { valid: false, error: `Failed to validate spaces: ${response.status}` } + } + const data = await response.json() + if (!Array.isArray(data.results)) { + throw new Error('Confluence returned an invalid space list. Try again.') + } + for (const space of data.results) { + if ( + remainingKeys.delete(space.key) && + !permissionSpaceId && + typeof space.id === 'string' + ) { + permissionSpaceId = space.id + } + } + if (remainingKeys.size === 0) break + const next = data._links?.next + cursor = extractCursor(next) + if (next && (!cursor || seenCursors.has(cursor) || seenCursors.size >= batch.length)) { + throw new Error('Confluence returned an incomplete space list. Try again.') + } + if (cursor) seenCursors.add(cursor) + } while (cursor) + if (remainingKeys.size > 0) { + const missing = [...remainingKeys] + return { + valid: false, + error: `Space${missing.length > 1 ? 's' : ''} not found: ${missing.join(', ')}`, + } } } if (syncContext?.mirrorsSourceAcls === true) { - const spaceId = results[0]?.id - if (typeof spaceId !== 'string' || !spaceId) { + if (!permissionSpaceId) { return { valid: false, error: 'Confluence returned a space without an ID. Try again.' } } await validateConfluencePermissionAccess({ cloudId, accessToken, - spaceId, + spaceId: permissionSpaceId, contentType: (sourceConfig.contentType as string) || 'page', retryOptions, }) @@ -1037,6 +1086,86 @@ export function resolveLastModifiedClause( */ const CQL_PAGE_SIZE = 50 +/** Walks one bounded space batch at a time without discarding a provider continuation. */ +async function listSpaceBatchesViaCql( + cloudId: string, + accessToken: string, + domain: string, + spaceKeys: string[], + contentType: string, + labelFilter: string, + maxPages: number, + cursor?: string, + syncContext: Record = {}, + lastSyncAt?: Date +): Promise { + const batches = spaceKeyBatches(spaceKeys) + if (batches.length === 1) { + return listDocumentsViaCql( + cloudId, + accessToken, + domain, + batches[0], + contentType, + labelFilter, + maxPages, + cursor, + syncContext, + lastSyncAt + ) + } + + let batchIndex = 0 + let providerCursor: string | undefined + if (cursor) { + const invalidCursor = new Error('Invalid Confluence space continuation. Restart the sync.') + if (!cursor.startsWith(SPACE_BATCH_CURSOR_PREFIX)) throw invalidCursor + const state: unknown = JSON.parse(cursor.slice(SPACE_BATCH_CURSOR_PREFIX.length)) + if ( + typeof state !== 'object' || + state === null || + !('batch' in state) || + typeof state.batch !== 'number' || + !Number.isSafeInteger(state.batch) || + state.batch < 0 || + state.batch >= batches.length || + ('cursor' in state && typeof state.cursor !== 'string') + ) + throw invalidCursor + batchIndex = state.batch + providerCursor = 'cursor' in state ? (state.cursor as string) : undefined + } + + const result = await listDocumentsViaCql( + cloudId, + accessToken, + domain, + batches[batchIndex], + contentType, + labelFilter, + maxPages, + providerCursor, + syncContext, + lastSyncAt + ) + const hasMoreBatches = batchIndex + 1 < batches.length + if (maxPages > 0 && Number(syncContext.totalDocsFetched) >= maxPages) { + if (hasMoreBatches) syncContext.listingCapped = true + return { ...result, hasMore: false, nextCursor: undefined } + } + if (!result.hasMore && !hasMoreBatches) return result + return { + ...result, + hasMore: true, + nextCursor: + SPACE_BATCH_CURSOR_PREFIX + + JSON.stringify({ + batch: result.hasMore ? batchIndex : batchIndex + 1, + ...(result.hasMore ? { cursor: result.nextCursor } : {}), + }), + } +} + /** * Lists documents using CQL search via the v1 API (used when label filtering is enabled). */ diff --git a/apps/sim/connectors/confluence/meta.ts b/apps/sim/connectors/confluence/meta.ts index 76076f8e608..8113c1eace1 100644 --- a/apps/sim/connectors/confluence/meta.ts +++ b/apps/sim/connectors/confluence/meta.ts @@ -77,6 +77,8 @@ export const confluenceConnectorMeta: ConnectorMeta = { canonicalParamId: 'spaceKey', mode: 'basic', multi: true, + allowSelectAll: true, + preserveValueOnModeChange: true, dependsOn: ['domain'], placeholder: 'Select one or more spaces', required: true, diff --git a/apps/sim/connectors/jira/meta.ts b/apps/sim/connectors/jira/meta.ts index 43f05f39fa3..5afcf1f44ff 100644 --- a/apps/sim/connectors/jira/meta.ts +++ b/apps/sim/connectors/jira/meta.ts @@ -29,6 +29,8 @@ export const jiraConnectorMeta: ConnectorMeta = { canonicalParamId: 'projectKey', mode: 'basic', multi: true, + allowSelectAll: true, + preserveValueOnModeChange: true, dependsOn: ['domain'], placeholder: 'Select one or more projects', required: true, diff --git a/apps/sim/connectors/types.ts b/apps/sim/connectors/types.ts index d6392a19b1f..323325dc743 100644 --- a/apps/sim/connectors/types.ts +++ b/apps/sim/connectors/types.ts @@ -301,6 +301,8 @@ export interface ConnectorConfigField { mode?: 'basic' | 'advanced' /** Links selector + manual input fields that resolve to the same config key */ canonicalParamId?: string + /** Both modes use the same provider identifiers, so switching carries the current selection. */ + preserveValueOnModeChange?: boolean /** * When true, the field accepts multiple values. @@ -309,6 +311,8 @@ export interface ConnectorConfigField { * Connector handlers receive `string | string[]` and should normalize via `parseMultiValue`. */ multi?: boolean + /** Offers explicit bulk selection of the complete, bounded provider list. */ + allowSelectAll?: boolean } /** diff --git a/apps/sim/hooks/queries/personal-source-setup.ts b/apps/sim/hooks/queries/personal-source-setup.ts new file mode 100644 index 00000000000..25a3e0598a6 --- /dev/null +++ b/apps/sim/hooks/queries/personal-source-setup.ts @@ -0,0 +1,69 @@ +'use client' + +import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' +import { requestJson } from '@/lib/api/client/request' +import { + listPersonalSourceSetupAccountsContract, + type PersonalSourceSetupBody, + type PersonalSourceSetupQuery, + personalSourceSetupContract, +} from '@/lib/api/contracts/knowledge/personal-source-setup' +import { memberConnectorKeys } from '@/hooks/queries/kb/connectors' +import { organizationAccountsKeys } from '@/hooks/queries/organization-accounts' +import { personalSearchIntegrationKeys } from '@/hooks/queries/personal-search-integrations' +import { searchSourceKeys } from '@/hooks/queries/utils/search-source-keys' + +export const PERSONAL_SOURCE_SETUP_STALE_TIME = 15_000 + +export const personalSourceSetupKeys = { + all: ['personal-source-setup'] as const, + lists: () => [...personalSourceSetupKeys.all, 'list'] as const, + list: (query: PersonalSourceSetupQuery) => [...personalSourceSetupKeys.lists(), query] as const, +} + +export function usePersonalSourceSetupAccounts(query: PersonalSourceSetupQuery) { + return useQuery({ + queryKey: personalSourceSetupKeys.list(query), + queryFn: async ({ signal }) => + (await requestJson(listPersonalSourceSetupAccountsContract, { query, signal })).data, + staleTime: PERSONAL_SOURCE_SETUP_STALE_TIME, + refetchInterval: (state) => + query.completionId && !state.state.data?.completedCredentialId ? 1_500 : false, + }) +} + +export function useAuthorizePersonalSourceSetup() { + return useMutation({ + mutationFn: async (body: Extract) => { + const { data } = await requestJson(personalSourceSetupContract, { body }) + if (data.kind !== 'authorization') throw new Error('Could not start account authorization') + return data + }, + }) +} + +export function useConnectPersonalSourceSetup() { + const client = useQueryClient() + return useMutation({ + mutationFn: async (body: Extract) => { + const { data } = await requestJson(personalSourceSetupContract, { body }) + if (data.kind !== 'connected') throw new Error('Could not connect the source') + return data + }, + onSuccess: (_data, body) => + Promise.all([ + client.invalidateQueries({ queryKey: personalSourceSetupKeys.lists() }), + client.invalidateQueries({ queryKey: personalSearchIntegrationKeys.lists() }), + client.invalidateQueries({ queryKey: memberConnectorKeys.lists() }), + client.invalidateQueries({ + queryKey: searchSourceKeys.list({ + kind: 'organization', + organizationId: body.organizationId, + }), + }), + client.invalidateQueries({ + queryKey: organizationAccountsKeys.detail(body.organizationId), + }), + ]), + }) +} diff --git a/apps/sim/hooks/queries/selectors.test.tsx b/apps/sim/hooks/queries/selectors.test.tsx index 21ac2bdc2d5..67cf3275117 100644 --- a/apps/sim/hooks/queries/selectors.test.tsx +++ b/apps/sim/hooks/queries/selectors.test.tsx @@ -7,15 +7,22 @@ import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { createRoot, type Root } from 'react-dom/client' import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' -const { mockExecuteSelectorRequest } = vi.hoisted(() => ({ +const { mockExecuteSelectorRequest, mockRequestJson } = vi.hoisted(() => ({ mockExecuteSelectorRequest: vi.fn(), + mockRequestJson: vi.fn(), })) vi.mock('@/lib/selectors/client/execute-selector', () => ({ executeSelectorRequest: mockExecuteSelectorRequest, })) -import { useSelectorOptionDetail, useSelectorOptions } from '@/hooks/queries/selectors' +vi.mock('@/lib/api/client/request', () => ({ requestJson: mockRequestJson })) + +import { + type SelectorLoadAllResult, + useSelectorOptionDetail, + useSelectorOptions, +} from '@/hooks/queries/selectors' interface HookHarness { getResult: () => T @@ -100,6 +107,276 @@ afterEach(() => { }) describe('generic selector queries', () => { + it('uses the dedicated personal setup contract and isolates it from ordinary browsing', async () => { + const personalItems = [{ id: 'PERSONAL', label: 'Personal project' }] + mockRequestJson.mockResolvedValue({ + success: true, + data: { kind: 'list', items: personalItems }, + }) + mockExecuteSelectorRequest.mockResolvedValue({ + kind: 'list', + items: [{ id: 'ADMIN', label: 'Admin project' }], + }) + const hook = renderHookWithClient(() => + useSelectorOptions('jira.projectKeys', { + context: { oauthCredential: 'credential-1', domain: 'example.atlassian.net' }, + scope: { kind: 'organization', organizationId: 'org-1' }, + surface: { kind: 'personal-search-setup', organizationId: 'org-1', connectorType: 'jira' }, + surfaceId: 'projects', + }) + ) + await waitFor(() => expect(hook.getResult().data).toEqual(personalItems)) + expect(mockExecuteSelectorRequest).not.toHaveBeenCalled() + expect(mockRequestJson).toHaveBeenCalledWith( + expect.objectContaining({ path: '/api/knowledge/sim-search/personal-source-setup' }), + expect.objectContaining({ + body: { + action: 'options', + organizationId: 'org-1', + connectorType: 'jira', + credentialId: 'credential-1', + domain: 'example.atlassian.net', + request: { kind: 'list' }, + }, + signal: expect.any(AbortSignal), + }) + ) + hook.rerender(() => + useSelectorOptions('jira.projectKeys', { + context: { oauthCredential: 'credential-1', domain: 'example.atlassian.net' }, + scope: { kind: 'organization', organizationId: 'org-1' }, + surfaceId: 'projects', + }) + ) + await waitFor(() => + expect(hook.getResult().data).toEqual([{ id: 'ADMIN', label: 'Admin project' }]) + ) + expect(mockExecuteSelectorRequest).toHaveBeenCalledTimes(1) + }) + + it('hydrates personal setup labels through the same dedicated contract', async () => { + mockRequestJson.mockResolvedValue({ + success: true, + data: { kind: 'detail', item: { id: 'ENG', label: 'Engineering' } }, + }) + const hook = renderHookWithClient(() => + useSelectorOptionDetail('confluence.spaces', { + context: { oauthCredential: 'credential-1', domain: 'example.atlassian.net' }, + scope: { kind: 'organization', organizationId: 'org-1' }, + surface: { + kind: 'personal-search-setup', + organizationId: 'org-1', + connectorType: 'confluence', + }, + detailId: 'ENG', + }) + ) + await waitFor(() => expect(hook.getResult().data?.id).toBe('ENG')) + expect(mockRequestJson).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + body: expect.objectContaining({ + connectorType: 'confluence', + request: { kind: 'detail', id: 'ENG' }, + }), + }) + ) + expect(mockExecuteSelectorRequest).not.toHaveBeenCalled() + }) + + it.each(['selector', 'organization'] as const)( + 'rejects a mismatched personal setup %s before sending a request', + async (mismatch) => { + const hook = renderHookWithClient(() => + useSelectorOptions(mismatch === 'selector' ? 'confluence.spaces' : 'jira.projectKeys', { + context: { oauthCredential: 'credential-1', domain: 'example.atlassian.net' }, + scope: { + kind: 'organization', + organizationId: mismatch === 'organization' ? 'org-2' : 'org-1', + }, + surface: { + kind: 'personal-search-setup', + organizationId: 'org-1', + connectorType: 'jira', + }, + }) + ) + await waitFor(() => expect(hook.getResult().error).not.toBeNull()) + expect(mockRequestJson).not.toHaveBeenCalled() + expect(mockExecuteSelectorRequest).not.toHaveBeenCalled() + } + ) + + it.each(['flat', 'paged'] as const)('returns a complete already-loaded %s list', async (mode) => { + const items = [{ id: 'ENG', label: 'Engineering' }] + mockExecuteSelectorRequest.mockResolvedValue({ kind: 'list', items }) + const hook = renderHookWithClient(() => + useSelectorOptions(mode === 'paged' ? 'jira.projectKeys' : 'jira.issues', { + context: { + workspaceId: 'workspace-1', + oauthCredential: 'credential-1', + domain: 'example.atlassian.net', + }, + }) + ) + await waitFor(() => expect(hook.getResult().isSuccess).toBe(true)) + let result: SelectorLoadAllResult | undefined + await act(async () => { + result = await hook.getResult().loadAll() + }) + expect(result).toEqual({ status: 'complete', options: items }) + expect(mockExecuteSelectorRequest).toHaveBeenCalledTimes(1) + }) + + it.each(['provider', 'options', 'pages'] as const)( + 'reports %s truncation without a complete selection', + async (kind) => { + mockExecuteSelectorRequest.mockImplementation( + async ({ request }: { request: { cursor?: string } }) => ({ + kind: 'list', + items: + kind === 'options' + ? Array.from({ length: 10_001 }, (_, index) => ({ + id: String(index), + label: String(index), + })) + : [{ id: request.cursor ?? '0', label: 'Project' }], + ...(kind === 'pages' ? { nextCursor: String(Number(request.cursor ?? '0') + 1) } : {}), + ...(kind === 'provider' ? { truncated: true } : {}), + }) + ) + const hook = renderHookWithClient(() => + useSelectorOptions('jira.projectKeys', { + context: { + workspaceId: 'workspace-1', + oauthCredential: 'credential-1', + domain: 'example.atlassian.net', + }, + }) + ) + await waitFor(() => expect(hook.getResult().isSuccess).toBe(true)) + let result: SelectorLoadAllResult | undefined + await act(async () => { + result = await hook.getResult().loadAll() + }) + expect(result).toEqual({ status: 'partial' }) + expect(mockExecuteSelectorRequest).toHaveBeenCalledTimes(kind === 'pages' ? 200 : 1) + } + ) + + it('reports a failed continuation and retries from the first page', async () => { + let fail = true + mockExecuteSelectorRequest.mockImplementation( + async ({ request }: { request: { cursor?: string } }) => { + if (request.cursor && fail) throw new Error('Provider is unavailable') + return request.cursor + ? { kind: 'list', items: [{ id: 'OPS', label: 'Operations' }] } + : { kind: 'list', items: [{ id: 'ENG', label: 'Engineering' }], nextCursor: 'next' } + } + ) + const hook = renderHookWithClient(() => + useSelectorOptions('jira.projectKeys', { + context: { + workspaceId: 'workspace-1', + oauthCredential: 'credential-1', + domain: 'example.atlassian.net', + }, + }) + ) + await waitFor(() => expect(hook.getResult().hasMore).toBe(true)) + let result: SelectorLoadAllResult | undefined + await act(async () => { + result = await hook.getResult().loadAll() + }) + expect(result).toEqual({ status: 'error' }) + await waitFor(() => expect(hook.getResult().error).toBeTruthy()) + fail = false + await act(async () => { + result = await hook.getResult().loadAll() + }) + expect(result).toEqual({ + status: 'complete', + options: [ + { id: 'ENG', label: 'Engineering' }, + { id: 'OPS', label: 'Operations' }, + ], + }) + expect(mockExecuteSelectorRequest.mock.calls.map(([args]) => args.request.cursor)).toEqual([ + undefined, + 'next', + undefined, + 'next', + ]) + }) + + it.each(['scope', 'surface', 'credential', 'site', 'search', 'disabled', 'unmount'] as const)( + 'cancels bulk selection when its %s changes', + async (change) => { + let resolvePage!: (result: { + kind: 'list' + items: { id: string; label: string }[] + nextCursor?: string + }) => void + const pending = new Promise<{ + kind: 'list' + items: { id: string; label: string }[] + nextCursor?: string + }>((resolve) => { + resolvePage = resolve + }) + mockExecuteSelectorRequest.mockImplementation( + ({ request }: { request: { cursor?: string } }) => + request.cursor + ? pending + : Promise.resolve({ + kind: 'list', + items: [{ id: 'ENG', label: 'Engineering' }], + nextCursor: 'next', + }) + ) + let workspaceId = 'workspace-1' + let surfaceId = 'field-1' + let credentialId = 'credential-1' + let domain = 'example.atlassian.net' + let search = '' + let enabled = true + const useHook = () => + useSelectorOptions('jira.projectKeys', { + context: { workspaceId, oauthCredential: credentialId, domain }, + surfaceId, + search, + enabled, + }) + const hook = renderHookWithClient(useHook) + await waitFor(() => expect(hook.getResult().hasMore).toBe(true)) + let result!: Promise + act(() => { + result = hook.getResult().loadAll() + }) + await waitFor(() => expect(mockExecuteSelectorRequest).toHaveBeenCalledTimes(2)) + if (change === 'scope') workspaceId = 'workspace-2' + if (change === 'surface') surfaceId = 'field-2' + if (change === 'credential') credentialId = 'credential-2' + if (change === 'site') domain = 'another.atlassian.net' + if (change === 'search') search = 'Operations' + if (change === 'disabled') enabled = false + if (change === 'unmount') hook.unmount() + else hook.rerender(useHook) + await act(async () => { + resolvePage({ + kind: 'list', + items: [{ id: 'OPS', label: 'Operations' }], + nextCursor: 'unused', + }) + expect(await result).toEqual({ status: 'cancelled' }) + }) + expect( + mockExecuteSelectorRequest.mock.calls.filter(([args]) => args.request.cursor) + ).toHaveLength(1) + if (change !== 'unmount') expect(hook.getResult().isLoadingAll).toBe(false) + } + ) + it('transports supported search and keeps context and request plaintext out of query keys', async () => { const credentialReference = '{{SHARED_GOOGLE_CREDENTIAL}}' const search = 'private search phrase' @@ -365,7 +642,10 @@ describe('generic selector queries', () => { await waitFor(() => expect(hook.getResult().hasMore).toBe(true)) expect(mockExecuteSelectorRequest).toHaveBeenCalledTimes(1) - act(() => hook.getResult().loadAll()) + let result: SelectorLoadAllResult | undefined + await act(async () => { + result = await hook.getResult().loadAll() + }) await waitFor(() => expect(hook.getResult().isLoadingAll).toBe(false)) expect(mockExecuteSelectorRequest).toHaveBeenCalledTimes(3) @@ -375,6 +655,7 @@ describe('generic selector queries', () => { { id: 'workspace-2', label: 'Workspace 2' }, ]) expect(hook.getResult()).toMatchObject({ hasMore: false, truncated: false }) + expect(result).toEqual({ status: 'complete', options: hook.getResult().data }) }) it('refreshes from the first page before retrying a failed continuation cursor', async () => { diff --git a/apps/sim/hooks/queries/selectors.ts b/apps/sim/hooks/queries/selectors.ts index c30671f41b5..a92dcf537c1 100644 --- a/apps/sim/hooks/queries/selectors.ts +++ b/apps/sim/hooks/queries/selectors.ts @@ -2,7 +2,12 @@ import { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react' import { useInfiniteQuery, useQueries, useQuery } from '@tanstack/react-query' -import { executeSelectorRequest } from '@/lib/selectors/client/execute-selector' +import { requestJson } from '@/lib/api/client/request' +import { personalSourceSetupContract } from '@/lib/api/contracts/knowledge/personal-source-setup' +import { + type ExecuteSelectorClientInput, + executeSelectorRequest, +} from '@/lib/selectors/client/execute-selector' import { projectSelectorContext } from '@/lib/selectors/context' import { MAX_SELECTOR_OPTIONS, MAX_SELECTOR_PAGES } from '@/lib/selectors/limits' import { @@ -16,12 +21,12 @@ import type { SelectorOption, SelectorPage, SelectorScope, + SelectorSurface, } from '@/lib/selectors/types' import { selectorKeys } from '@/hooks/queries/utils/selector-keys' type SelectorListResult = Extract -const EMPTY_PAGE: SelectorListResult = { kind: 'list', items: [] } let nextOpaqueRevision = 1 export type SelectorClientContext = SelectorContext & { @@ -35,6 +40,38 @@ interface SelectorHookArgs { search?: string enabled?: boolean surfaceId?: string + surface?: SelectorSurface +} + +async function executeForSurface( + input: ExecuteSelectorClientInput, + surface?: SelectorSurface +): Promise { + if (!surface) return executeSelectorRequest(input) + const expectedKey = surface.connectorType === 'jira' ? 'jira.projectKeys' : 'confluence.spaces' + if ( + input.selectorKey !== expectedKey || + input.scope?.kind !== 'organization' || + input.scope.organizationId !== surface.organizationId || + !input.context.oauthCredential || + !input.context.domain + ) + throw new Error('This selector is not available during personal source setup') + const result = await requestJson(personalSourceSetupContract, { + body: { + action: 'options', + organizationId: surface.organizationId, + connectorType: surface.connectorType, + credentialId: input.context.oauthCredential, + domain: input.context.domain, + request: input.request, + }, + signal: input.signal, + }) + if (result.data.kind !== 'list' && result.data.kind !== 'detail') { + throw new Error('Personal source setup returned an unexpected selector result') + } + return result.data } export interface SelectorOptionsResult { @@ -48,10 +85,14 @@ export interface SelectorOptionsResult { error: Error | null isSuccess: boolean loadMore(): void - loadAll(): void + loadAll(): Promise refetch(): void } +export type SelectorLoadAllResult = + | { status: 'complete'; options: SelectorOption[] } + | { status: 'partial' | 'error' | 'cancelled' } + interface CollectedSelectorOptions { options: SelectorOption[] overflowed: boolean @@ -140,7 +181,13 @@ function usePreparedSelector( const context = projectSelectorContext(key, args.context) const scope = selectorScopeFromContext(args.context, args.scope) const contextValues = manifest.context.allowed.map((field) => context[field]) - const revision = useOpaqueRevision([...contextValues, ...requestValues]) + const revision = useOpaqueRevision([ + ...contextValues, + ...requestValues, + args.surface?.kind, + args.surface?.organizationId, + args.surface?.connectorType, + ]) const ready = args.enabled !== false && isSelectorReady(key, context) && @@ -152,6 +199,7 @@ function usePreparedSelector( revision, ready, surfaceId: args.surfaceId ?? generatedSurfaceId, + surface: args.surface, } } @@ -174,16 +222,19 @@ export function useSelectorOptions( // rq-lint-allow: context and search are represented by an opaque privacy revision. queryKey: baseKey, queryFn: async ({ signal }) => { - const result = await executeSelectorRequest({ - selectorKey: key, - scope: prepared.scope, - context: prepared.context, - request: { - kind: 'list', - ...(effectiveSearch !== undefined ? { search: effectiveSearch } : {}), + const result = await executeForSurface( + { + selectorKey: key, + scope: prepared.scope, + context: prepared.context, + request: { + kind: 'list', + ...(effectiveSearch !== undefined ? { search: effectiveSearch } : {}), + }, + signal, }, - signal, - }) + prepared.surface + ) if (result.kind !== 'list') throw new Error('Selector returned an unexpected detail result') return result }, @@ -196,18 +247,21 @@ export function useSelectorOptions( // rq-lint-allow: context and search are represented by an opaque privacy revision. queryKey: [...baseKey, 'paged'], queryFn: async ({ pageParam, signal }) => { - const result = await executeSelectorRequest({ - selectorKey: key, - scope: prepared.scope, - context: prepared.context, - request: { - kind: 'list', - ...(effectiveSearch !== undefined ? { search: effectiveSearch } : {}), - ...(typeof pageParam === 'string' ? { cursor: pageParam } : {}), + const result = await executeForSurface( + { + selectorKey: key, + scope: prepared.scope, + context: prepared.context, + request: { + kind: 'list', + ...(effectiveSearch !== undefined ? { search: effectiveSearch } : {}), + ...(typeof pageParam === 'string' ? { cursor: pageParam } : {}), + }, + signal, }, - signal, - }) - if (result.kind !== 'list') return EMPTY_PAGE + prepared.surface + ) + if (result.kind !== 'list') throw new Error('Selector returned an unexpected detail result') return result }, getNextPageParam: (last) => last.nextCursor, @@ -231,73 +285,88 @@ export function useSelectorOptions( const loadGenerationRef = useRef(0) const pageFetchInFlightRef = useRef(false) const [isLoadingAll, setIsLoadingAll] = useState(false) + const requestIdentity = JSON.stringify(baseKey) useEffect(() => { loadGenerationRef.current += 1 pageFetchInFlightRef.current = false setIsLoadingAll(false) - }, [key, prepared.revision]) + return () => { + loadGenerationRef.current += 1 + pageFetchInFlightRef.current = false + } + }, [requestIdentity, prepared.ready]) const loadMore = useCallback(() => { if (!canLoadMore || pageFetchInFlightRef.current) return + const generation = ++loadGenerationRef.current pageFetchInFlightRef.current = true void (async () => { if (pagedQuery.isFetchNextPageError) { const refreshed = await pagedQuery.refetch() + if (loadGenerationRef.current !== generation) return const refreshedPages = refreshed.data?.pages const refreshedLastPage = refreshedPages?.[refreshedPages.length - 1] if (refreshed.isError || !refreshedLastPage?.nextCursor) return } await pagedQuery.fetchNextPage() })().finally(() => { - pageFetchInFlightRef.current = false + if (loadGenerationRef.current === generation) pageFetchInFlightRef.current = false }) }, [canLoadMore, pagedQuery.fetchNextPage, pagedQuery.isFetchNextPageError, pagedQuery.refetch]) - const loadAll = useCallback(() => { - if (!canLoadMore || pageFetchInFlightRef.current) return - const generation = loadGenerationRef.current + 1 - loadGenerationRef.current = generation + const loadAll = useCallback(async (): Promise => { + if (!prepared.ready || pageFetchInFlightRef.current || pagedQuery.isFetching) { + return { status: 'cancelled' } + } + const generation = ++loadGenerationRef.current pageFetchInFlightRef.current = true setIsLoadingAll(true) - void (async () => { - let hasNextPage = Boolean(pagedQuery.hasNextPage) - let pages = pagedQuery.data?.pages - try { - if (pagedQuery.isFetchNextPageError) { - const refreshed = await pagedQuery.refetch() - if (loadGenerationRef.current !== generation || refreshed.isError) return - pages = refreshed.data?.pages - const refreshedLastPage = pages?.[pages.length - 1] - hasNextPage = Boolean(refreshedLastPage?.nextCursor) - } - while (hasNextPage) { - if ( - (pages?.length ?? 0) >= MAX_SELECTOR_PAGES || - collectSelectorOptions(pages).options.length >= MAX_SELECTOR_OPTIONS - ) { - break - } - const result = await pagedQuery.fetchNextPage() - if (loadGenerationRef.current !== generation) return - if (result.isError) break - hasNextPage = Boolean(result.hasNextPage) - pages = result.data?.pages - } - } finally { - if (loadGenerationRef.current === generation) { - pageFetchInFlightRef.current = false - setIsLoadingAll(false) - } + let hasNextPage = Boolean(pagedQuery.hasNextPage) + let pages = pagedQuery.data?.pages + try { + if (pagedQuery.isError || !pages) { + const refreshed = await pagedQuery.refetch() + if (loadGenerationRef.current !== generation) return { status: 'cancelled' } + if (refreshed.isError) return { status: 'error' } + pages = refreshed.data?.pages + const refreshedLastPage = pages?.[pages.length - 1] + hasNextPage = Boolean(refreshedLastPage?.nextCursor) } - })() + while (hasNextPage) { + const collected = collectSelectorOptions(pages) + if ( + (pages?.length ?? 0) >= MAX_SELECTOR_PAGES || + collected.options.length >= MAX_SELECTOR_OPTIONS || + pages?.some((page) => page.truncated) + ) + return { status: 'partial' } + const result = await pagedQuery.fetchNextPage() + if (loadGenerationRef.current !== generation) return { status: 'cancelled' } + if (result.isError) return { status: 'error' } + hasNextPage = Boolean(result.hasNextPage) + pages = result.data?.pages + } + const collected = collectSelectorOptions(pages) + return collected.overflowed || pages?.some((page) => page.truncated) + ? { status: 'partial' } + : { status: 'complete', options: collected.options } + } catch { + return { status: loadGenerationRef.current === generation ? 'error' : 'cancelled' } + } finally { + if (loadGenerationRef.current === generation) { + pageFetchInFlightRef.current = false + setIsLoadingAll(false) + } + } }, [ - canLoadMore, + prepared.ready, pagedQuery.data?.pages, pagedQuery.fetchNextPage, pagedQuery.hasNextPage, - pagedQuery.isFetchNextPageError, + pagedQuery.isError, + pagedQuery.isFetching, pagedQuery.refetch, ]) @@ -337,7 +406,14 @@ export function useSelectorOptions( error: (flatQuery.error as Error | null) ?? null, isSuccess: flatQuery.isSuccess, loadMore: () => undefined, - loadAll: () => undefined, + loadAll: async () => { + if (!prepared.ready || flatQuery.isFetching) return { status: 'cancelled' } + if (flatQuery.isError || !flatQuery.data) return { status: 'error' } + const collected = collectSelectorOptions([flatQuery.data]) + return flatQuery.data.truncated || collected.overflowed + ? { status: 'partial' } + : { status: 'complete', options: collected.options } + }, refetch: () => { if (!prepared.ready) return void flatQuery.refetch() @@ -365,13 +441,16 @@ export function useSelectorOptionDetail( prepared.revision ), queryFn: async ({ signal }) => { - const result = await executeSelectorRequest({ - selectorKey: key, - scope: prepared.scope, - context: prepared.context, - request: { kind: 'detail', id: args.detailId! }, - signal, - }) + const result = await executeForSurface( + { + selectorKey: key, + scope: prepared.scope, + context: prepared.context, + request: { kind: 'detail', id: args.detailId! }, + signal, + }, + prepared.surface + ) if (result.kind !== 'detail') throw new Error('Selector returned an unexpected list result') return result.item }, @@ -399,13 +478,16 @@ export function useSelectorOptionDetails( ordinal ), queryFn: async ({ signal }: { signal: AbortSignal }) => { - const result = await executeSelectorRequest({ - selectorKey: key, - scope: prepared.scope, - context: prepared.context, - request: { kind: 'detail', id: detailId }, - signal, - }) + const result = await executeForSurface( + { + selectorKey: key, + scope: prepared.scope, + context: prepared.context, + request: { kind: 'detail', id: detailId }, + signal, + }, + prepared.surface + ) if (result.kind !== 'detail') throw new Error('Selector returned an unexpected list result') return result.item }, diff --git a/apps/sim/hooks/use-personal-source-account.test.tsx b/apps/sim/hooks/use-personal-source-account.test.tsx new file mode 100644 index 00000000000..cccfe0e977f --- /dev/null +++ b/apps/sim/hooks/use-personal-source-account.test.tsx @@ -0,0 +1,153 @@ +/** + * @vitest-environment jsdom + */ +import { act } from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + authorize: vi.fn(), + refetch: vi.fn(), + error: vi.fn(), + completed: null as string | null, + cache: vi.fn(), + connected: vi.fn(), +})) +vi.mock('@tanstack/react-query', () => ({ useQueryClient: () => ({ setQueryData: mocks.cache }) })) +vi.mock('@sim/emcn', () => ({ toast: { error: mocks.error } })) +vi.mock('@/hooks/queries/personal-source-setup', () => ({ + personalSourceSetupKeys: { list: (query: unknown) => ['personal-source-setup', query] }, + useAuthorizePersonalSourceSetup: () => ({ mutateAsync: mocks.authorize, isPending: false }), + usePersonalSourceSetupAccounts: () => ({ + data: { accounts: [], completedCredentialId: mocks.completed }, + refetch: mocks.refetch, + }), +})) + +import { usePersonalSourceAccount } from '@/hooks/use-personal-source-account' + +describe('personal source account authorization', () => { + let root: Root + let container: HTMLDivElement + let current: ReturnType + let channels: Array<{ + onmessage: ((event: MessageEvent) => void) | null + close: ReturnType + }> + let tab: { + opener: unknown + location: { href: string } + focus: ReturnType + close: ReturnType + } + function Probe() { + current = usePersonalSourceAccount({ + organizationId: 'org-1', + connectorType: 'jira', + onConnected: mocks.connected, + }) + return null + } + beforeEach(() => { + vi.clearAllMocks() + vi.useFakeTimers() + mocks.completed = null + mocks.authorize.mockResolvedValue({ + kind: 'authorization', + url: 'https://auth.atlassian.com/authorize', + }) + channels = [] + vi.stubGlobal( + 'BroadcastChannel', + class { + onmessage = null + close = vi.fn() + constructor() { + channels.push(this) + } + } + ) + tab = { opener: {}, location: { href: 'about:blank' }, focus: vi.fn(), close: vi.fn() } + vi.spyOn(window, 'open').mockReturnValue(tab as unknown as Window) + ;(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) + act(() => root.render()) + }) + afterEach(() => { + act(() => root.unmount()) + container.remove() + vi.useRealTimers() + vi.restoreAllMocks() + vi.unstubAllGlobals() + }) + it('authorizes before a source exists and requires server confirmation of completion', async () => { + await act(async () => current.connect()) + expect(tab.opener).toBeNull() + expect(tab.location.href).toBe('https://auth.atlassian.com/authorize') + expect(mocks.authorize).toHaveBeenCalledWith( + expect.objectContaining({ + action: 'authorize', + organizationId: 'org-1', + connectorType: 'jira', + oauthCompletionId: expect.any(String), + }) + ) + expect(current.pending).toBe(true) + act(() => channels[0].onmessage?.({ data: 'connected' } as MessageEvent)) + expect(mocks.refetch).toHaveBeenCalledOnce() + expect(current.pending).toBe(true) + expect(tab.close).not.toHaveBeenCalled() + mocks.completed = 'my-account' + act(() => root.render()) + expect(current.pending).toBe(false) + expect(tab.close).toHaveBeenCalledOnce() + expect(mocks.connected).toHaveBeenCalledWith('my-account') + mocks.completed = null + act(() => root.render()) + expect(current.pending).toBe(false) + }) + it('shows an account mismatch as a toast and allows a fresh attempt', async () => { + await act(async () => current.connect()) + act(() => channels[0].onmessage?.({ data: 'account_mismatch' } as MessageEvent)) + expect(mocks.error).toHaveBeenCalledWith('Choose the account matching your Sim email address.') + expect(current.pending).toBe(false) + await act(async () => current.connect()) + expect(mocks.authorize).toHaveBeenCalledTimes(2) + }) + it('ignores a late authorization response after cancellation', async () => { + let resolve!: (value: { kind: string; url: string }) => void + mocks.authorize.mockReturnValue( + new Promise((done) => { + resolve = done + }) + ) + let connecting!: Promise + act(() => { + connecting = current.connect() + }) + act(() => current.cancel()) + await act(async () => { + resolve({ kind: 'authorization', url: 'https://auth.atlassian.com/authorize' }) + await connecting + }) + expect(tab.location.href).toBe('about:blank') + expect(current.pending).toBe(false) + }) + it('times out pending authorization and closes its channel on unmount', async () => { + await act(async () => current.connect()) + act(() => vi.advanceTimersByTime(10 * 60_000)) + expect(current.pending).toBe(false) + expect(mocks.error).toHaveBeenCalledWith( + 'This connection attempt expired. Try connecting your account again.' + ) + expect(channels[0].close).toHaveBeenCalledOnce() + }) + it('reports popup blocking without starting enrollment', async () => { + vi.mocked(window.open).mockReturnValue(null) + await act(async () => current.connect()) + expect(mocks.authorize).not.toHaveBeenCalled() + expect(mocks.error).toHaveBeenCalledWith('Allow pop-ups for this site to connect your account.') + }) +}) diff --git a/apps/sim/hooks/use-personal-source-account.ts b/apps/sim/hooks/use-personal-source-account.ts new file mode 100644 index 00000000000..3ac8447127d --- /dev/null +++ b/apps/sim/hooks/use-personal-source-account.ts @@ -0,0 +1,135 @@ +'use client' + +import { useCallback, useEffect, useRef, useState } from 'react' +import { toast } from '@sim/emcn' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { useQueryClient } from '@tanstack/react-query' +import type { PersonalSourceSetupQuery } from '@/lib/api/contracts/knowledge/personal-source-setup' +import { + CREDENTIAL_GROUP_OAUTH_FAILURE_MESSAGES, + credentialGroupOAuthCompletionChannel, + isCredentialGroupOAuthFailure, +} from '@/lib/credential-groups/oauth-completion' +import { + personalSourceSetupKeys, + useAuthorizePersonalSourceSetup, + usePersonalSourceSetupAccounts, +} from '@/hooks/queries/personal-source-setup' + +interface PersonalSourceAccountProps { + organizationId: string + connectorType: PersonalSourceSetupQuery['connectorType'] + onConnected?: (credentialId: string) => void +} + +/** A popup message only refreshes the account inventory; the server proves completion. */ +export function usePersonalSourceAccount({ + organizationId, + connectorType, + onConnected, +}: PersonalSourceAccountProps) { + const [completionId, setCompletionId] = useState() + const attempt = useRef<{ id: string; tab: Window } | null>(null) + const accounts = usePersonalSourceSetupAccounts({ organizationId, connectorType, completionId }) + const { mutateAsync: authorize } = useAuthorizePersonalSourceSetup() + const queryClient = useQueryClient() + const onConnectedRef = useRef(onConnected) + const completed = accounts.data?.completedCredentialId + const { refetch } = accounts + + useEffect(() => { + onConnectedRef.current = onConnected + }, [onConnected]) + + useEffect(() => { + return () => { + attempt.current?.tab.close() + attempt.current = null + } + }, []) + + useEffect(() => { + if (!completionId || completed) return + const fail = (message: string) => { + if (attempt.current?.id !== completionId) return + attempt.current.tab.close() + attempt.current = null + setCompletionId(undefined) + toast.error(message) + } + const channel = new BroadcastChannel(credentialGroupOAuthCompletionChannel(completionId)) + channel.onmessage = ({ data }: MessageEvent) => { + if (isCredentialGroupOAuthFailure(data)) fail(CREDENTIAL_GROUP_OAUTH_FAILURE_MESSAGES[data]) + else if (data === 'connected') void refetch() + } + const timer = window.setTimeout( + () => fail(CREDENTIAL_GROUP_OAUTH_FAILURE_MESSAGES.expired), + 10 * 60_000 + ) + return () => { + channel.close() + window.clearTimeout(timer) + } + }, [completionId, completed, refetch]) + + useEffect(() => { + if (completed && attempt.current && attempt.current.id === completionId) { + attempt.current.tab.close() + attempt.current = null + setCompletionId(undefined) + queryClient.setQueryData(personalSourceSetupKeys.list({ organizationId, connectorType }), { + ...accounts.data, + completedCredentialId: null, + }) + onConnectedRef.current?.(completed) + } + }, [completed, completionId, accounts.data, queryClient, organizationId, connectorType]) + + const connect = useCallback(async () => { + if (attempt.current) { + attempt.current.tab.focus() + return + } + const tab = window.open('about:blank', '_blank', 'width=600,height=700') + if (!tab) { + toast.error('Allow pop-ups for this site to connect your account.') + return + } + tab.opener = null + const id = generateId() + attempt.current = { id, tab } + setCompletionId(id) + try { + const result = await authorize({ + action: 'authorize', + organizationId, + connectorType, + oauthCompletionId: id, + }) + if (attempt.current?.id !== id) return + const url = new URL(result.url) + if ( + url.protocol !== 'https:' && + !(url.protocol === 'http:' && url.origin === window.location.origin) + ) { + throw new Error('The provider authorization URL is invalid') + } + tab.location.href = url.href + } catch (error) { + if (attempt.current?.id !== id) return + tab.close() + attempt.current = null + setCompletionId(undefined) + toast.error(getErrorMessage(error, 'Could not connect your account')) + } + }, [authorize, organizationId, connectorType]) + + const cancel = useCallback(() => { + attempt.current?.tab.close() + attempt.current = null + setCompletionId(undefined) + }, []) + + return { accounts, connect, cancel, pending: Boolean(completionId) } +} diff --git a/apps/sim/hooks/use-search-integration-connection.test.tsx b/apps/sim/hooks/use-search-integration-connection.test.tsx index 421180cab62..504e94bd0e9 100644 --- a/apps/sim/hooks/use-search-integration-connection.test.tsx +++ b/apps/sim/hooks/use-search-integration-connection.test.tsx @@ -134,6 +134,20 @@ afterEach(() => { }) describe('Search connection card lifecycle', () => { + it('confirms account-first setup against inventory and reflects later revocation', () => { + m.requestedTarget = { type: 'link', provider: 'jira', connectorType: 'jira' } + render() + act(() => connection().completeSetup({ connectorId: 'new-source', credentialId: 'mine' })) + expect(connection().connectorId).toBe('new-source') + expect(connection().connected).toBe(false) + expect(m.mutate).not.toHaveBeenCalled() + m.accounts = [{ credentialId: 'mine', status: 'connected' }] + render() + expect(connection().connected).toBe(true) + m.accounts = [{ credentialId: 'mine', status: 'reconnect_needed' }] + render() + expect(connection().connected).toBe(false) + }) it('starts OAuth only on click and completes only when its receipt and current account agree', async () => { render() expect(m.mutate).not.toHaveBeenCalled() diff --git a/apps/sim/hooks/use-search-integration-connection.ts b/apps/sim/hooks/use-search-integration-connection.ts index 96c455ac16f..3f0cd7873cd 100644 --- a/apps/sim/hooks/use-search-integration-connection.ts +++ b/apps/sim/hooks/use-search-integration-connection.ts @@ -213,7 +213,21 @@ export function useSearchIntegrationConnection({ error: 'Connection canceled. You can try again.', }) }, [attempt, key]) + const completeSetup = useCallback( + (result: { connectorId: string; credentialId: string }) => { + writeSearchConnectionAttempt(key, { + completionId: generateId(), + requestedAt: Date.now(), + connectorId: result.connectorId, + credentialId: result.credentialId, + status: 'connected', + error: null, + }) + }, + [key] + ) return { + completeSetup, connect, cancel, inventoryError: query.error?.message, diff --git a/apps/sim/lib/api/contracts/knowledge/personal-source-setup.test.ts b/apps/sim/lib/api/contracts/knowledge/personal-source-setup.test.ts new file mode 100644 index 00000000000..58e8fa013b5 --- /dev/null +++ b/apps/sim/lib/api/contracts/knowledge/personal-source-setup.test.ts @@ -0,0 +1,47 @@ +/** @vitest-environment node */ +import { describe, expect, it } from 'vitest' +import { personalSourceSetupBodySchema } from '@/lib/api/contracts/knowledge/personal-source-setup' +import { executeSelectorBodySchema } from '@/lib/api/contracts/selectors/execute' + +const source = { + action: 'connect', + organizationId: 'organization-1', + connectorType: 'jira', + credentialId: 'account-1', + domain: 'example.atlassian.net', + keys: ['PROJECT'], +} + +describe('personal Search setup contracts', () => { + it('accepts a bounded bulk selection larger than the legacy joined-string limit', () => { + const keys = Array.from({ length: 1000 }, (_, index) => `PROJECT${index}`) + expect(personalSourceSetupBodySchema.parse({ ...source, keys })).toMatchObject({ keys }) + }) + it.each([[], Array.from({ length: 1001 }, (_, index) => `P${index}`), [''], ['x'.repeat(256)]])( + 'rejects empty, oversized, or unbounded selections %#', + (keys) => { + expect(personalSourceSetupBodySchema.safeParse({ ...source, keys }).success).toBe(false) + } + ) + it('rejects arbitrary credential kinds, scope overrides and provider keys', () => { + for (const extra of [ + { workspaceId: 'workspace-1' }, + { selectorKey: 'jira.issues' }, + { accessMode: 'admin' }, + { connectorType: 'slack' }, + ]) { + expect(personalSourceSetupBodySchema.safeParse({ ...source, ...extra }).success).toBe(false) + } + }) + it('does not expose the trusted personal browsing marker through the generic selector API', () => { + expect( + executeSelectorBodySchema.safeParse({ + selectorKey: 'jira.projectKeys', + scope: { kind: 'organization', organizationId: 'organization-1' }, + context: { oauthCredential: 'account-1', domain: 'example.atlassian.net' }, + request: { kind: 'list' }, + personalSearchSetup: 'jira', + }).success + ).toBe(false) + }) +}) diff --git a/apps/sim/lib/api/contracts/knowledge/personal-source-setup.ts b/apps/sim/lib/api/contracts/knowledge/personal-source-setup.ts new file mode 100644 index 00000000000..c3e64253078 --- /dev/null +++ b/apps/sim/lib/api/contracts/knowledge/personal-source-setup.ts @@ -0,0 +1,86 @@ +import { z } from 'zod' +import { defineRouteContract } from '@/lib/api/contracts' +import { successResponseSchema } from '@/lib/api/contracts/knowledge/shared' +import { organizationIdSchema } from '@/lib/api/contracts/primitives' +import { + executeSelectorResponseSchema, + selectorRequestSchema, +} from '@/lib/api/contracts/selectors/execute' +import { MAX_PERSONAL_SOURCE_SETUP_KEYS } from '@/lib/sim-search/personal-source-setup' + +const setupOwnerSchema = z.object({ + organizationId: organizationIdSchema, + connectorType: z.enum(['jira', 'confluence']), +}) +const setupCredentialSchema = setupOwnerSchema.extend({ + credentialId: z.string().min(1).max(128), + domain: z.string().trim().min(1, 'Enter your Atlassian site').max(253), +}) + +export const personalSourceSetupQuerySchema = setupOwnerSchema.extend({ + completionId: z.string().uuid().optional(), +}) +export type PersonalSourceSetupQuery = z.input + +export const personalSourceSetupAccountsSchema = z.object({ + accounts: z + .array( + z.object({ + id: z.string().min(1).max(128), + name: z.string().max(512), + provider: z.enum(['jira', 'confluence']), + type: z.literal('managed_oauth'), + scopes: z.array(z.string().max(200)).max(200), + }) + ) + .max(1000), + completedCredentialId: z.string().min(1).max(128).nullable(), +}) +export type PersonalSourceSetupAccounts = z.output + +export const personalSourceSetupBodySchema = z.discriminatedUnion('action', [ + setupOwnerSchema + .extend({ action: z.literal('authorize'), oauthCompletionId: z.string().uuid() }) + .strict(), + setupCredentialSchema + .extend({ + action: z.literal('connect'), + keys: z + .array(z.string().trim().min(1).max(255)) + .min(1, 'Select at least one project or space') + .max( + MAX_PERSONAL_SOURCE_SETUP_KEYS, + 'Choose no more than 1,000 projects or spaces per source' + ), + }) + .strict(), + setupCredentialSchema + .extend({ action: z.literal('options'), request: selectorRequestSchema }) + .strict(), +]) +export type PersonalSourceSetupBody = z.input + +export const personalSourceSetupResultSchema = z.discriminatedUnion('kind', [ + z.object({ kind: z.literal('authorization'), url: z.string().url() }), + z.object({ + kind: z.literal('connected'), + knowledgeBaseId: z.string().min(1).max(200), + connectorId: z.string().min(1).max(200), + }), + ...executeSelectorResponseSchema.options, +]) +export type PersonalSourceSetupResult = z.output + +export const listPersonalSourceSetupAccountsContract = defineRouteContract({ + method: 'GET', + path: '/api/knowledge/sim-search/personal-source-setup', + query: personalSourceSetupQuerySchema, + response: { mode: 'json', schema: successResponseSchema(personalSourceSetupAccountsSchema) }, +}) + +export const personalSourceSetupContract = defineRouteContract({ + method: 'POST', + path: '/api/knowledge/sim-search/personal-source-setup', + body: personalSourceSetupBodySchema, + response: { mode: 'json', schema: successResponseSchema(personalSourceSetupResultSchema) }, +}) diff --git a/apps/sim/lib/knowledge/application/operations.test.ts b/apps/sim/lib/knowledge/application/operations.test.ts index 1dc78ba611f..3662a56b263 100644 --- a/apps/sim/lib/knowledge/application/operations.test.ts +++ b/apps/sim/lib/knowledge/application/operations.test.ts @@ -82,6 +82,8 @@ describe('knowledge operation registry', () => { 'knowledge.connectors.members.list', 'knowledge.connectors.members.enroll', 'knowledge.simSearch.connect', + 'knowledge.search.personalSetup.accounts.list', + 'knowledge.search.personalSetup', 'knowledge.search.sources.connectApproved', 'knowledge.search.index.read', 'knowledge.search.sources.prepare', @@ -143,11 +145,25 @@ describe('knowledge operation registry', () => { knowledgeOperations.readSearchIndex, knowledgeOperations.enrollConnectorMember, knowledgeOperations.simSearchConnect, + knowledgeOperations.listPersonalSourceSetupAccounts, + knowledgeOperations.personalSourceSetup, ]) { expect(operation.organizationOperation.minimumRole).toBe('member') } }) + it('limits personal source setup to the signed-in member without delegating credential discovery', () => { + for (const operation of [ + knowledgeOperations.listPersonalSourceSetupAccounts, + knowledgeOperations.personalSourceSetup, + ]) { + expect(operation.principalKinds).toEqual(['session']) + expect(operation.organizationOperation.principalKinds).not.toContain('organization_delegated') + expect(operation.workspaceApiKey).toBe('deny') + expect(operation.capability).toBe('knowledge.use') + } + }) + it('permits organization delegation only for Copilot reads', () => { for (const operation of Object.values(knowledgeOperations)) { if (!operation.organizationOperation.principalKinds.includes('organization_delegated')) diff --git a/apps/sim/lib/knowledge/application/operations.ts b/apps/sim/lib/knowledge/application/operations.ts index e9a7e1cb9a7..0669abe2c14 100644 --- a/apps/sim/lib/knowledge/application/operations.ts +++ b/apps/sim/lib/knowledge/application/operations.ts @@ -805,6 +805,24 @@ export const knowledgeOperations = { principalKinds: ['session'], }) ), + listPersonalSourceSetupAccounts: defineKnowledgeOperation( + defineWorkspaceOperation({ + id: 'knowledge.search.personalSetup.accounts.list', + minimumRole: 'read', + workspaceApiKey: 'deny', + capability: 'knowledge.use', + principalKinds: ['session'], + }) + ), + personalSourceSetup: defineKnowledgeOperation( + defineWorkspaceOperation({ + id: 'knowledge.search.personalSetup', + minimumRole: 'read', + workspaceApiKey: 'deny', + capability: 'knowledge.use', + principalKinds: ['session'], + }) + ), createApprovedSearchSource: defineKnowledgeOperation( defineWorkspaceOperation({ id: 'knowledge.search.sources.connectApproved', diff --git a/apps/sim/lib/knowledge/application/personal-search-account.test.ts b/apps/sim/lib/knowledge/application/personal-search-account.test.ts new file mode 100644 index 00000000000..a927fb31bfc --- /dev/null +++ b/apps/sim/lib/knowledge/application/personal-search-account.test.ts @@ -0,0 +1,133 @@ +/** @vitest-environment node */ +import { user } from '@sim/db/schema' +import { dbChainMockFns, queueTableRows, resetDbChainMock } from '@sim/testing' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + membership: vi.fn(), + approval: vi.fn(), + available: vi.fn(), + deployed: vi.fn(), + accounts: vi.fn(), +})) +vi.mock('@/lib/core/application/organization-authorization', () => ({ + requireOrganizationMembership: mocks.membership, +})) +vi.mock('@/lib/knowledge/search/integration-policy', () => ({ + requireOrganizationSearchApproval: mocks.approval, +})) +vi.mock('@/lib/knowledge/access/availability', () => ({ + requireKnowledgeMemberAccessAvailable: mocks.available, +})) +vi.mock('@/lib/integrations/availability.server', () => ({ + isOAuthServiceDeploymentAvailable: mocks.deployed, +})) +vi.mock('@/lib/credentials/organization-managed', () => ({ + getOwnOrganizationManagedOAuthCredentials: mocks.accounts, +})) + +import { + authorizePersonalSearchSetup, + authorizePersonalSearchSetupCredential, +} from '@/lib/knowledge/application/personal-search-account' + +const principal = { kind: 'session', userId: 'member-1', sessionId: 'session-1' } as const +const input = { + organizationId: 'organization-1', + connectorType: 'jira', + credentialId: 'own-account', +} as const + +describe('personal Search setup authorization', () => { + beforeEach(() => { + vi.resetAllMocks() + resetDbChainMock() + queueTableRows(user, [{ emailVerified: true }]) + mocks.deployed.mockReturnValue(true) + mocks.accounts.mockResolvedValue([ + { + id: 'own-account', + providerId: 'jira', + displayName: 'Work account', + scopes: ['read:jira-work'], + }, + ]) + }) + + it('permits a verified member and scopes the account lookup to that person and provider', async () => { + await expect(authorizePersonalSearchSetupCredential(principal, input)).resolves.toMatchObject({ + id: 'own-account', + }) + expect(mocks.membership).toHaveBeenCalledWith( + principal, + input.organizationId, + 'member', + 'knowledge.use' + ) + expect(mocks.approval).toHaveBeenCalledWith(input.organizationId, 'jira') + expect(mocks.accounts).toHaveBeenCalledWith({ + organizationId: input.organizationId, + userId: principal.userId, + providerId: 'jira', + credentialId: input.credentialId, + }) + }) + + it('rejects non-session callers before membership or protected account reads', async () => { + await expect( + authorizePersonalSearchSetup( + { kind: 'personal_api_key', userId: 'member-1', keyId: 'key-1' }, + input + ) + ).rejects.toThrow('Sign in') + expect(mocks.membership).not.toHaveBeenCalled() + expect(dbChainMockFns.select).not.toHaveBeenCalled() + }) + + it('rejects non-members before looking up credentials', async () => { + mocks.membership.mockRejectedValue(new Error('Membership ended')) + await expect(authorizePersonalSearchSetupCredential(principal, input)).rejects.toThrow( + 'Membership ended' + ) + expect(mocks.accounts).not.toHaveBeenCalled() + }) + + it('requires a verified email before approving or provisioning setup', async () => { + resetDbChainMock() + queueTableRows(user, [{ emailVerified: false }]) + await expect(authorizePersonalSearchSetup(principal, input)).rejects.toThrow( + 'Verify your email' + ) + expect(mocks.approval).not.toHaveBeenCalled() + }) + + it.each(['approval', 'available'] as const)( + 'propagates the %s refusal before account discovery', + async (gate) => { + mocks[gate].mockRejectedValue(new Error('Source disabled')) + await expect(authorizePersonalSearchSetupCredential(principal, input)).rejects.toThrow( + 'Source disabled' + ) + expect(mocks.accounts).not.toHaveBeenCalled() + } + ) + + it('rejects an unavailable OAuth deployment', async () => { + mocks.deployed.mockReturnValue(false) + await expect(authorizePersonalSearchSetupCredential(principal, input)).rejects.toThrow( + 'unavailable' + ) + expect(mocks.accounts).not.toHaveBeenCalled() + }) + + it.each([ + { accounts: [] }, + { accounts: [{ id: 'another-account', providerId: 'jira' }] }, + { accounts: [{ id: 'own-account', providerId: 'confluence' }] }, + ])('rejects revoked, foreign or mismatched grants %#', async ({ accounts }) => { + mocks.accounts.mockResolvedValue(accounts) + await expect(authorizePersonalSearchSetupCredential(principal, input)).rejects.toThrow( + 'Connect your account again' + ) + }) +}) diff --git a/apps/sim/lib/knowledge/application/personal-search-account.ts b/apps/sim/lib/knowledge/application/personal-search-account.ts new file mode 100644 index 00000000000..04a25443acb --- /dev/null +++ b/apps/sim/lib/knowledge/application/personal-search-account.ts @@ -0,0 +1,68 @@ +import type { Principal } from '@sim/auth/principal' +import { db } from '@sim/db' +import { user } from '@sim/db/schema' +import { eq } from 'drizzle-orm' +import { requireOrganizationMembership } from '@/lib/core/application/organization-authorization' +import { OrchestrationError } from '@/lib/core/orchestration/types' +import { getOwnOrganizationManagedOAuthCredentials } from '@/lib/credentials/organization-managed' +import { isOAuthServiceDeploymentAvailable } from '@/lib/integrations/availability.server' +import { requireKnowledgeMemberAccessAvailable } from '@/lib/knowledge/access/availability' +import { requireOrganizationSearchApproval } from '@/lib/knowledge/search/integration-policy' + +export type PersonalSearchSetupConnector = 'jira' | 'confluence' + +/** Rechecks the caller's organization and approved integration before personal account discovery. */ +export async function authorizePersonalSearchSetup( + principal: Principal, + input: { organizationId: string; connectorType: PersonalSearchSetupConnector } +) { + if ( + principal.kind !== 'session' || + (input.connectorType !== 'jira' && input.connectorType !== 'confluence') + ) { + throw new OrchestrationError('forbidden', 'Sign in to connect this Search source') + } + await requireOrganizationMembership(principal, input.organizationId, 'member', 'knowledge.use') + const [viewer] = await db + .select({ emailVerified: user.emailVerified }) + .from(user) + .where(eq(user.id, principal.userId)) + .limit(1) + if (!viewer?.emailVerified) { + throw new OrchestrationError( + 'validation', + 'Verify your email address before connecting an account' + ) + } + await requireOrganizationSearchApproval(input.organizationId, input.connectorType) + await requireKnowledgeMemberAccessAvailable({ organizationId: input.organizationId }) + if (!isOAuthServiceDeploymentAvailable(input.connectorType)) { + throw new OrchestrationError('validation', 'This account connection is unavailable') + } + return principal.userId +} + +/** Personal setup can browse only a currently live grant owned by the signed-in member. */ +export async function authorizePersonalSearchSetupCredential( + principal: Principal, + input: { + organizationId: string + connectorType: PersonalSearchSetupConnector + credentialId: string + } +) { + const userId = await authorizePersonalSearchSetup(principal, input) + const accounts = await getOwnOrganizationManagedOAuthCredentials({ + organizationId: input.organizationId, + userId, + providerId: input.connectorType, + credentialId: input.credentialId, + }) + const account = accounts.find( + (entry) => entry.id === input.credentialId && entry.providerId === input.connectorType + ) + if (!account) { + throw new OrchestrationError('not_found', 'Connect your account again before choosing sources') + } + return account +} diff --git a/apps/sim/lib/knowledge/application/personal-source-setup.test.ts b/apps/sim/lib/knowledge/application/personal-source-setup.test.ts new file mode 100644 index 00000000000..b8463118228 --- /dev/null +++ b/apps/sim/lib/knowledge/application/personal-source-setup.test.ts @@ -0,0 +1,300 @@ +/** @vitest-environment node */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + authorizeOperation: vi.fn(), + authorize: vi.fn(), + ownAccount: vi.fn(), + listAccounts: vi.fn(), + completion: vi.fn(), + provision: vi.fn(), + enrollment: vi.fn(), + oauthContext: vi.fn(), + oauth: vi.fn(), + selector: vi.fn(), + configure: vi.fn(), + binding: vi.fn(), + group: vi.fn(), + dispatch: vi.fn(), + billing: vi.fn(), +})) +vi.mock('@/lib/core/application/organization-authorization', () => ({ + authorizeOrganizationOperation: mocks.authorizeOperation, +})) +vi.mock('@/lib/knowledge/application/contexts', () => ({ + resolveKnowledgeOrganizationContext: async ({ organizationId }: { organizationId: string }) => ({ + organizationId, + workspaceId: undefined, + }), +})) +vi.mock('@/lib/knowledge/application/personal-search-account', () => ({ + authorizePersonalSearchSetup: mocks.authorize, + authorizePersonalSearchSetupCredential: mocks.ownAccount, +})) +vi.mock('@/lib/credentials/organization-managed', () => ({ + getOwnOrganizationManagedOAuthCredentials: mocks.listAccounts, +})) +vi.mock('@/lib/credential-groups/search-connection-completion', () => ({ + readSearchConnectionCompletion: mocks.completion, +})) +vi.mock('@/lib/knowledge/connectors/member-provisioning', () => ({ + provisionKnowledgeConnectorMembersBinding: mocks.provision, +})) +vi.mock('@/lib/credential-groups/self-enrollment', () => ({ + createViewerCredentialGroupEnrollment: mocks.enrollment, +})) +vi.mock('@/lib/credential-groups/enrollments', () => ({ + getCredentialGroupOAuthContextForEnrollment: mocks.oauthContext, +})) +vi.mock('@/lib/credential-groups/oauth', () => ({ startCredentialGroupOAuth: mocks.oauth })) +vi.mock('@/lib/selectors/application/execute-selector', () => ({ + executeSelector: { execute: mocks.selector }, +})) +vi.mock('@/lib/knowledge/application/sim-search', () => ({ + configureSimSearchConnector: { execute: mocks.configure }, +})) +vi.mock('@/lib/credential-groups/credentials', () => ({ + loadManagedCredentialGroupBinding: mocks.binding, + loadScopedAccountsCredentialListContext: mocks.group, +})) +vi.mock('@/lib/knowledge/connectors/member-queue', () => ({ dispatchMemberSync: mocks.dispatch })) +vi.mock('@/lib/knowledge/application/billing', () => ({ + resolveKnowledgeBillingAttribution: mocks.billing, +})) +vi.mock('@/connectors/registry', () => ({ + CONNECTOR_META_REGISTRY: { jira: { name: 'Jira' }, confluence: { name: 'Confluence' } }, +})) + +import { + listPersonalSourceSetupAccounts, + personalSourceSetup, +} from '@/lib/knowledge/application/personal-source-setup' + +const principal = { kind: 'session', userId: 'member-1', sessionId: 'session-1' } as const +const owner = { organizationId: 'organization-1', connectorType: 'jira' } as const +const credential = { credentialId: 'own-account', domain: 'example.atlassian.net' } +const connect = { ...owner, ...credential, action: 'connect', keys: ['PROJECT'] } as const +const account = { + id: 'own-account', + displayName: 'Work account', + providerId: 'jira', + scopes: ['read:jira-work'], +} +const runConnect = (changes = {}) => + personalSourceSetup.execute({ principal, input: { ...connect, keys: ['PROJECT'], ...changes } }) + +describe('personal source setup', () => { + beforeEach(() => { + vi.resetAllMocks() + mocks.authorize.mockResolvedValue(principal.userId) + mocks.ownAccount.mockResolvedValue(account) + mocks.listAccounts.mockResolvedValue([account]) + mocks.completion.mockResolvedValue(account.id) + mocks.provision.mockResolvedValue({ + credentialGroupId: 'group-1', + credentialGroupOptionId: 'option-1', + }) + mocks.enrollment.mockResolvedValue({ + enrollment: { id: 'enrollment-1', email: 'member@example.com' }, + invitationLink: 'https://example.com/credential-groups/enroll/invitation-token', + }) + mocks.oauthContext.mockResolvedValue({ option: { id: 'option-1' } }) + mocks.oauth.mockResolvedValue('https://auth.atlassian.com/authorize') + mocks.selector.mockResolvedValue({ kind: 'list', items: [{ id: 'PROJECT', label: 'Project' }] }) + mocks.configure.mockResolvedValue({ knowledgeBaseId: 'kb-1', connectorId: 'source-1' }) + mocks.binding.mockResolvedValue({ + organizationId: owner.organizationId, + credentialGroupId: 'group-1', + credentialGroupOptionId: 'option-1', + }) + mocks.group.mockResolvedValue({ credentialGroupId: 'group-1' }) + mocks.billing.mockResolvedValue({ actorUserId: principal.userId }) + mocks.dispatch.mockResolvedValue({ queued: true }) + }) + + it('lists owned accounts before a source exists and scopes completion receipts to the viewer', async () => { + const result = await listPersonalSourceSetupAccounts.execute({ + principal, + input: { ...owner, completionId: 'completion-1' }, + }) + expect(result).toEqual({ + accounts: [ + { + id: 'own-account', + name: 'Work account', + provider: 'jira', + type: 'managed_oauth', + scopes: ['read:jira-work'], + }, + ], + completedCredentialId: 'own-account', + }) + expect(mocks.completion).toHaveBeenCalledWith({ + organizationId: owner.organizationId, + userId: principal.userId, + completionId: 'completion-1', + }) + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('does not return a receipt for a foreign or no longer active credential', async () => { + mocks.completion.mockResolvedValue('another-account') + expect( + ( + await listPersonalSourceSetupAccounts.execute({ + principal, + input: { ...owner, completionId: 'completion-1' }, + }) + ).completedCredentialId + ).toBeNull() + }) + + it('starts verified personal enrollment without creating an index or requiring project keys', async () => { + const result = await personalSourceSetup.execute({ + principal, + input: { ...owner, action: 'authorize', oauthCompletionId: 'completion-1' }, + }) + expect(result).toEqual({ kind: 'authorization', url: 'https://auth.atlassian.com/authorize' }) + expect(mocks.enrollment).toHaveBeenCalledWith({ + organizationId: owner.organizationId, + userId: principal.userId, + credentialGroupId: 'group-1', + }) + expect(mocks.oauth).toHaveBeenCalledWith({ option: { id: 'option-1' } }, 'invitation-token', { + completionRedirect: true, + returnTo: 'search', + completionId: 'completion-1', + connectionIntent: { kind: 'create' }, + }) + expect(mocks.configure).not.toHaveBeenCalled() + expect(mocks.selector).not.toHaveBeenCalled() + }) + + it('does not start OAuth if enrollment was revoked', async () => { + mocks.enrollment.mockRejectedValue(new Error('An admin removed your access')) + await expect( + personalSourceSetup.execute({ + principal, + input: { ...owner, action: 'authorize', oauthCompletionId: 'completion-1' }, + }) + ).rejects.toThrow('admin removed') + expect(mocks.oauth).not.toHaveBeenCalled() + }) + + it.each(['jira', 'confluence'] as const)( + 'dispatches %s discovery through its fixed shared selector', + async (connectorType) => { + await personalSourceSetup.execute({ + principal, + input: { + ...owner, + ...credential, + connectorType, + action: 'options', + request: { kind: 'list', cursor: 'page-2' }, + }, + }) + expect(mocks.selector).toHaveBeenCalledWith({ + principal, + request: undefined, + input: { + selectorKey: connectorType === 'jira' ? 'jira.projectKeys' : 'confluence.spaces', + scope: { kind: 'organization', organizationId: owner.organizationId }, + context: { oauthCredential: credential.credentialId, domain: credential.domain }, + personalSearchSetup: connectorType, + request: { kind: 'list', cursor: 'page-2' }, + }, + }) + } + ) + + it('reuses a prepared account, validates all selected keys, and creates the source without another OAuth attempt', async () => { + mocks.selector + .mockResolvedValueOnce({ + kind: 'list', + items: [{ id: 'PROJECT', label: 'Project' }], + nextCursor: '50', + }) + .mockResolvedValueOnce({ kind: 'list', items: [{ id: 'SECOND', label: 'Second' }] }) + await expect(runConnect({ keys: ['PROJECT', 'SECOND', 'PROJECT'] })).resolves.toEqual({ + kind: 'connected', + knowledgeBaseId: 'kb-1', + connectorId: 'source-1', + }) + expect(mocks.selector).toHaveBeenCalledTimes(2) + expect(mocks.configure).toHaveBeenCalledWith({ + principal, + request: undefined, + input: { + organizationId: owner.organizationId, + connectorType: 'jira', + memberCredentialBinding: { + credentialGroupId: 'group-1', + credentialGroupOptionId: 'option-1', + }, + sourceConfig: { domain: credential.domain, projectKey: 'PROJECT,SECOND' }, + }, + }) + expect(mocks.dispatch).toHaveBeenCalledWith('source-1', { + billingAttribution: { actorUserId: principal.userId }, + }) + expect(mocks.oauth).not.toHaveBeenCalled() + }) + + it.each([ + { kind: 'list', items: [], truncated: true, nextCursor: '50' }, + { kind: 'list', items: [] }, + ])('rejects unavailable manually entered keys before source creation %#', async (page) => { + mocks.selector.mockResolvedValue(page) + await expect(runConnect({ keys: ['MISSING'] })).rejects.toThrow('could not be found') + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('rejects a repeated pagination cursor without looping or creating a source', async () => { + mocks.selector.mockResolvedValue({ kind: 'list', items: [], nextCursor: '50' }) + await expect(runConnect()).rejects.toThrow('could not be found') + expect(mocks.selector).toHaveBeenCalledTimes(2) + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('rejects stale or wrong-user credentials before provider calls', async () => { + mocks.ownAccount.mockRejectedValue(new Error('Account unavailable')) + await expect(runConnect()).rejects.toThrow('Account unavailable') + expect(mocks.selector).not.toHaveBeenCalled() + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('rejects an account whose enrollment group differs from the organization setup', async () => { + mocks.binding.mockResolvedValue({ + organizationId: owner.organizationId, + credentialGroupId: 'other-group', + credentialGroupOptionId: 'option-1', + }) + await expect(runConnect()).rejects.toThrow('Connect your account again') + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('rejects a current operation authorization denial before any setup effects', async () => { + mocks.authorizeOperation.mockRejectedValue(new Error('Membership ended')) + await expect(runConnect()).rejects.toThrow('Membership ended') + expect(mocks.authorize).not.toHaveBeenCalled() + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it.each([ + 'example.atlassian.net/wiki/spaces', + 'user:password@example.atlassian.net', + 'example.atlassian.net?site=other', + ])('rejects an invalid site value before discovery: %s', async (domain) => { + await expect(runConnect({ domain })).rejects.toThrow('hostname') + expect(mocks.selector).not.toHaveBeenCalled() + }) + + it('keeps the configured source available if the best-effort initial dispatch fails', async () => { + mocks.dispatch.mockRejectedValue(new Error('Queue temporarily unavailable')) + await expect(runConnect()).resolves.toMatchObject({ + kind: 'connected', + connectorId: 'source-1', + }) + }) +}) diff --git a/apps/sim/lib/knowledge/application/personal-source-setup.ts b/apps/sim/lib/knowledge/application/personal-source-setup.ts new file mode 100644 index 00000000000..e17a73c3792 --- /dev/null +++ b/apps/sim/lib/knowledge/application/personal-source-setup.ts @@ -0,0 +1,263 @@ +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { normalizeAtlassianSiteUrl } from '@/lib/atlassian/discovery' +import { OrchestrationError } from '@/lib/core/orchestration/types' +import { + loadManagedCredentialGroupBinding, + loadScopedAccountsCredentialListContext, +} from '@/lib/credential-groups/credentials' +import { getCredentialGroupOAuthContextForEnrollment } from '@/lib/credential-groups/enrollments' +import { startCredentialGroupOAuth } from '@/lib/credential-groups/oauth' +import { readSearchConnectionCompletion } from '@/lib/credential-groups/search-connection-completion' +import { createViewerCredentialGroupEnrollment } from '@/lib/credential-groups/self-enrollment' +import { getOwnOrganizationManagedOAuthCredentials } from '@/lib/credentials/organization-managed' +import { defineAuthorizedKnowledgeUseCase } from '@/lib/knowledge/application/authorized-knowledge-use-case' +import { resolveKnowledgeBillingAttribution } from '@/lib/knowledge/application/billing' +import { resolveKnowledgeOrganizationContext } from '@/lib/knowledge/application/contexts' +import { knowledgeOperations } from '@/lib/knowledge/application/operations' +import { + authorizePersonalSearchSetup, + authorizePersonalSearchSetupCredential, + type PersonalSearchSetupConnector, +} from '@/lib/knowledge/application/personal-search-account' +import { configureSimSearchConnector } from '@/lib/knowledge/application/sim-search' +import { provisionKnowledgeConnectorMembersBinding } from '@/lib/knowledge/connectors/member-provisioning' +import { executeSelector } from '@/lib/selectors/application/execute-selector' +import { MAX_SELECTOR_PAGES } from '@/lib/selectors/limits' +import type { SelectorExecutionResult, SelectorRequest } from '@/lib/selectors/types' +import { MAX_PERSONAL_SOURCE_SETUP_KEYS } from '@/lib/sim-search/personal-source-setup' +import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' + +const logger = createLogger('PersonalSourceSetup') + +interface PersonalSourceSetupOwner { + organizationId: string + connectorType: PersonalSearchSetupConnector +} + +type PersonalSourceSetupInput = PersonalSourceSetupOwner & + ( + | { action: 'authorize'; oauthCompletionId: string } + | { action: 'options'; credentialId: string; domain: string; request: SelectorRequest } + | { action: 'connect'; credentialId: string; domain: string; keys: string[] } + ) + +type PersonalSourceSetupResult = + | { kind: 'authorization'; url: string } + | { kind: 'connected'; knowledgeBaseId: string; connectorId: string } + | SelectorExecutionResult + +function normalizeSetupDomain(value: string) { + let url: URL + try { + url = new URL(normalizeAtlassianSiteUrl(value)) + } catch { + throw new OrchestrationError('validation', 'Enter your Atlassian site hostname') + } + if ( + url.username || + url.password || + url.port || + url.pathname !== '/' || + url.search || + url.hash || + !url.hostname.includes('.') + ) { + throw new OrchestrationError( + 'validation', + 'Enter your Atlassian site hostname without a page path' + ) + } + return url.hostname +} + +/** Lists the viewer's live accounts independently of whether any source exists yet. */ +export const listPersonalSourceSetupAccounts = defineAuthorizedKnowledgeUseCase({ + operation: knowledgeOperations.listPersonalSourceSetupAccounts, + resolveContext: ({ input }: { input: PersonalSourceSetupOwner & { completionId?: string } }) => + resolveKnowledgeOrganizationContext(input), + async execute({ principal, input }) { + const userId = await authorizePersonalSearchSetup(principal, input) + const accounts = await getOwnOrganizationManagedOAuthCredentials({ + organizationId: input.organizationId, + userId, + providerId: input.connectorType, + }) + const completedCredentialId = input.completionId + ? await readSearchConnectionCompletion({ + organizationId: input.organizationId, + userId, + completionId: input.completionId, + }) + : null + return { + accounts: accounts.map((account) => ({ + id: account.id, + name: account.displayName, + provider: input.connectorType, + type: 'managed_oauth' as const, + scopes: account.scopes, + })), + completedCredentialId: accounts.some((account) => account.id === completedCredentialId) + ? completedCredentialId + : null, + } + }, +}) + +/** Connects the viewer first, then configures only an approved personal-account Search source. */ +export const personalSourceSetup = defineAuthorizedKnowledgeUseCase({ + operation: knowledgeOperations.personalSourceSetup, + resolveContext: ({ input }: { input: PersonalSourceSetupInput }) => + resolveKnowledgeOrganizationContext(input), + async execute({ principal, input, context, request }): Promise { + const userId = await authorizePersonalSearchSetup(principal, input) + if (input.action === 'authorize') { + const binding = await provisionKnowledgeConnectorMembersBinding({ + organizationId: input.organizationId, + connectorMeta: CONNECTOR_META_REGISTRY[input.connectorType]!, + userId, + }) + const { enrollment, invitationLink } = await createViewerCredentialGroupEnrollment({ + organizationId: input.organizationId, + userId, + credentialGroupId: binding.credentialGroupId, + }) + const token = new URL(invitationLink).pathname.split('/').at(-1) + if (!token) throw new Error('Account enrollment did not return an invitation token') + const oauth = await getCredentialGroupOAuthContextForEnrollment( + { + organizationId: input.organizationId, + credentialGroupId: binding.credentialGroupId, + enrollmentId: enrollment.id, + email: enrollment.email, + userId, + }, + binding.credentialGroupOptionId + ) + if (!oauth) + throw new OrchestrationError('forbidden', 'This account connection is no longer available') + return { + kind: 'authorization', + url: await startCredentialGroupOAuth(oauth, token, { + completionRedirect: true, + returnTo: 'search', + completionId: input.oauthCompletionId, + connectionIntent: { kind: 'create' }, + }), + } + } + + await authorizePersonalSearchSetupCredential(principal, input) + const domain = normalizeSetupDomain(input.domain) + const selectorInput = { + selectorKey: + input.connectorType === 'jira' + ? ('jira.projectKeys' as const) + : ('confluence.spaces' as const), + scope: { kind: 'organization' as const, organizationId: input.organizationId }, + context: { oauthCredential: input.credentialId, domain }, + personalSearchSetup: input.connectorType, + } + if (input.action === 'options') { + return executeSelector.execute({ + principal, + request, + input: { ...selectorInput, request: input.request }, + }) + } + if ( + !input.keys.length || + input.keys.length > MAX_PERSONAL_SOURCE_SETUP_KEYS || + input.keys.some((key) => !key.trim() || key.length > 255) + ) { + throw new OrchestrationError('validation', 'Select between 1 and 1,000 projects or spaces') + } + const keys = [...new Set(input.keys.map((key) => key.trim()))] + const remaining = new Set(keys) + const cursors = new Set() + const timeout = AbortSignal.timeout(30_000) + const signal = request?.signal ? AbortSignal.any([request.signal, timeout]) : timeout + let cursor: string | undefined + for (let page = 0; page < MAX_SELECTOR_PAGES; page++) { + let result: SelectorExecutionResult + try { + result = await executeSelector.execute({ + principal, + request, + input: { + ...selectorInput, + signal, + request: { kind: 'list', ...(cursor ? { cursor } : {}) }, + }, + }) + } catch (error) { + if (timeout.aborted && !request?.signal?.aborted) { + throw new OrchestrationError( + 'validation', + 'Checking the selected projects or spaces took too long. Try fewer selections.' + ) + } + throw error + } + if (result.kind !== 'list') throw new Error('Source discovery returned an unexpected result') + for (const option of result.items) remaining.delete(option.id) + if (remaining.size === 0) break + if (!result.nextCursor || result.truncated || cursors.has(result.nextCursor)) break + cursor = result.nextCursor + cursors.add(cursor) + } + if (remaining.size > 0) { + throw new OrchestrationError( + 'validation', + 'Some selected projects or spaces could not be found with this account. Refresh the choices and try again.' + ) + } + const [binding, group] = await Promise.all([ + loadManagedCredentialGroupBinding(input.credentialId), + loadScopedAccountsCredentialListContext({ + kind: 'organization', + organizationId: input.organizationId, + }), + ]) + if ( + !binding || + !group || + binding.credentialGroupId !== group.credentialGroupId || + binding.organizationId !== input.organizationId + ) { + throw new OrchestrationError( + 'not_found', + 'Connect your account again before choosing sources' + ) + } + await authorizePersonalSearchSetupCredential(principal, input) + const result = await configureSimSearchConnector.execute({ + principal, + request, + input: { + organizationId: input.organizationId, + connectorType: input.connectorType, + memberCredentialBinding: { + credentialGroupId: binding.credentialGroupId, + credentialGroupOptionId: binding.credentialGroupOptionId, + }, + sourceConfig: { + domain, + [input.connectorType === 'jira' ? 'projectKey' : 'spaceKey']: [...keys].join(','), + }, + }, + }) + try { + const { dispatchMemberSync } = await import('@/lib/knowledge/connectors/member-queue') + await dispatchMemberSync(result.connectorId, { + billingAttribution: await resolveKnowledgeBillingAttribution(principal, context), + }) + } catch (error) { + logger.warn('Initial personal source sync will retry on its schedule', { + error: getErrorMessage(error), + }) + } + return { kind: 'connected', ...result } + }, +}) diff --git a/apps/sim/lib/knowledge/application/sim-search.test.ts b/apps/sim/lib/knowledge/application/sim-search.test.ts index 78e2fbf60c7..fd1b47aa7e0 100644 --- a/apps/sim/lib/knowledge/application/sim-search.test.ts +++ b/apps/sim/lib/knowledge/application/sim-search.test.ts @@ -145,6 +145,7 @@ vi.mock('@/connectors/registry', () => ({ })) import { + configureSimSearchConnector, connectSimSearchConnector, prepareSearchSource, } from '@/lib/knowledge/application/sim-search' @@ -202,6 +203,53 @@ describe('connectSimSearchConnector', () => { ) }) + it('reuses a prepared account only when the source enrollment group and option match', async () => { + mocks.resolvePermission.mockResolvedValue('read') + queueTableRows(knowledgeConnector, [ + { ...existingConnector, credentialGroupId: 'group-1', credentialGroupOptionId: 'option-1' }, + ]) + await expect( + configureSimSearchConnector.execute({ + principal, + input: { + workspaceId: 'workspace-1', + connectorType: 'google_drive', + memberCredentialBinding: { + credentialGroupId: 'group-1', + credentialGroupOptionId: 'option-1', + }, + }, + }) + ).resolves.toEqual(existingConnector) + expect(mocks.enroll).not.toHaveBeenCalled() + }) + + it.each([ + { credentialGroupId: 'other-group', credentialGroupOptionId: 'option-1' }, + { credentialGroupId: 'group-1', credentialGroupOptionId: 'other-option' }, + ])( + 'refuses an existing source with a mismatched prepared account binding %#', + async (sourceBinding) => { + mocks.resolvePermission.mockResolvedValue('read') + queueTableRows(knowledgeConnector, [{ ...existingConnector, ...sourceBinding }]) + await expect( + configureSimSearchConnector.execute({ + principal, + input: { + workspaceId: 'workspace-1', + connectorType: 'google_drive', + memberCredentialBinding: { + credentialGroupId: 'group-1', + credentialGroupOptionId: 'option-1', + }, + }, + }) + ).rejects.toMatchObject({ code: 'conflict' }) + expect(mocks.enroll).not.toHaveBeenCalled() + expect(mocks.createConnector).not.toHaveBeenCalled() + } + ) + it('prepares a supported administrative source in the existing workspace index', async () => { mocks.resolvePermission.mockResolvedValue('admin') queueTableRows(knowledgeBase, [{ id: 'kb-existing' }]) diff --git a/apps/sim/lib/knowledge/application/sim-search.ts b/apps/sim/lib/knowledge/application/sim-search.ts index 92367573822..94508a94d9b 100644 --- a/apps/sim/lib/knowledge/application/sim-search.ts +++ b/apps/sim/lib/knowledge/application/sim-search.ts @@ -69,6 +69,8 @@ export interface ConnectSimSearchConnectorInput extends ResourceOwner { /** Correlates a direct provider authorization with the initiating Integrations tab. */ connectionIntent?: CredentialGroupConnectionIntent oauthCompletionId?: string + /** Internal setup assertion; a reused source must use the viewer's prepared enrollment option. */ + memberCredentialBinding?: { credentialGroupId: string; credentialGroupOptionId: string } } export interface ConnectSimSearchConnectorResult { @@ -84,6 +86,8 @@ async function findSimSearchConnector(input: ConnectSimSearchConnectorInput) { knowledgeBaseId: knowledgeBase.id, connectorId: knowledgeConnector.id, sourceConfig: knowledgeConnector.sourceConfig, + credentialGroupId: knowledgeConnector.credentialGroupId, + credentialGroupOptionId: knowledgeConnector.credentialGroupOptionId, }) .from(knowledgeConnector) .innerJoin(knowledgeBase, eq(knowledgeBase.id, knowledgeConnector.knowledgeBaseId)) @@ -119,6 +123,17 @@ async function findSimSearchConnector(input: ConnectSimSearchConnectorInput) { ) } const match = matches[0] + if ( + match && + input.memberCredentialBinding && + (match.credentialGroupId !== input.memberCredentialBinding.credentialGroupId || + match.credentialGroupOptionId !== input.memberCredentialBinding.credentialGroupOptionId) + ) { + throw new OrchestrationError( + 'conflict', + 'This source uses a different account configuration. Ask an admin to review its settings.' + ) + } return match ? { knowledgeBaseId: match.knowledgeBaseId, connectorId: match.connectorId } : null } @@ -282,11 +297,11 @@ async function requireSimSearchSetupAdmin( * singleflight also coalesces repeated setup clicks for each source; concurrent * source creation is serialized by the connector insert transaction before enrollment. */ -export const connectSimSearchConnector = defineAuthorizedKnowledgeUseCase({ +export const configureSimSearchConnector = defineAuthorizedKnowledgeUseCase({ operation: knowledgeOperations.simSearchConnect, resolveContext: ({ input }: { input: ConnectSimSearchConnectorInput }) => resolveKnowledgeOwnerContext(input), - async execute({ principal, input, context, request }): Promise { + async execute({ principal, input, context, request }) { const meta = CONNECTOR_META_REGISTRY[input.connectorType] if (!meta || !canConnectPersonally(meta)) { throw new OrchestrationError( @@ -373,12 +388,23 @@ export const connectSimSearchConnector = defineAuthorizedKnowledgeUseCase({ } ) } + return target + }, +}) + +/** Creates or reuses the source, then authorizes the member when setup has not already done so. */ +export const connectSimSearchConnector = defineAuthorizedKnowledgeUseCase({ + operation: knowledgeOperations.simSearchConnect, + resolveContext: ({ input }: { input: ConnectSimSearchConnectorInput }) => + resolveKnowledgeOwnerContext(input), + async execute({ principal, input, context, request }): Promise { + const target = await configureSimSearchConnector.execute({ principal, input, request }) const { url } = await startKnowledgeConnectorMemberEnrollment.execute({ principal, input: { knowledgeBaseId: target.knowledgeBaseId, connectorId: target.connectorId, - assertedWorkspaceId: workspaceId, + assertedWorkspaceId: context.workspaceId, assertedOrganizationId: context.organizationId, oauthCompletionId: input.oauthCompletionId, connectionIntent: input.connectionIntent, diff --git a/apps/sim/lib/selectors/application/execute-selector.test.ts b/apps/sim/lib/selectors/application/execute-selector.test.ts index 60f75064fa7..a0aa015b5b8 100644 --- a/apps/sim/lib/selectors/application/execute-selector.test.ts +++ b/apps/sim/lib/selectors/application/execute-selector.test.ts @@ -20,6 +20,15 @@ const mocks = vi.hoisted(() => ({ resolveReferences: vi.fn(), resolveScope: vi.fn(), sanitize: vi.fn(), + authorizePersonalSearch: vi.fn(), + requireOrganizationMembership: vi.fn(), +})) + +vi.mock('@/lib/knowledge/application/personal-search-account', () => ({ + authorizePersonalSearchSetup: mocks.authorizePersonalSearch, +})) +vi.mock('@/lib/core/application/organization-authorization', () => ({ + requireOrganizationMembership: mocks.requireOrganizationMembership, })) vi.mock('@sim/audit', () => ({ recordAudit: vi.fn() })) @@ -157,6 +166,105 @@ describe('executeSelector', () => { ]) }) + it('keeps generic organization browsing admin-only', async () => { + mocks.requireOrganizationMembership.mockRejectedValueOnce(new Error('Admin required')) + await expect( + execute({ scope: { kind: 'organization', organizationId: 'org-1' } }) + ).rejects.toThrow('Admin required') + expect(mocks.requireOrganizationMembership).toHaveBeenCalledWith( + principal, + 'org-1', + 'admin', + 'knowledge.use' + ) + expect(mocks.authorizePersonalSearch).not.toHaveBeenCalled() + expect(mocks.getAttachment).not.toHaveBeenCalled() + }) + + it('rejects a personal setup marker outside its approved provider selector and organization scope', async () => { + await expect(execute({ personalSearchSetup: 'jira' })).rejects.toBeInstanceOf( + SelectorContextUnavailableError + ) + await expect( + execute({ + scope: { kind: 'organization', organizationId: 'org-1' }, + selectorKey: 'jira.issues', + personalSearchSetup: 'jira', + }) + ).rejects.toBeInstanceOf(SelectorContextUnavailableError) + expect(mocks.authorizeCredential).not.toHaveBeenCalled() + expect(mocks.executeAttachment).not.toHaveBeenCalled() + }) + + it('requires the personal setup authorization before canonical discovery and provider calls', async () => { + mocks.authorizePersonalSearch.mockRejectedValueOnce(new Error('Integration unapproved')) + await expect( + execute({ + scope: { kind: 'organization', organizationId: 'org-1' }, + selectorKey: 'jira.projectKeys', + context: { oauthCredential: 'managed-1', domain: 'example.atlassian.net' }, + personalSearchSetup: 'jira', + }) + ).rejects.toThrow('Integration unapproved') + expect(mocks.authorizePersonalSearch).toHaveBeenCalledWith(principal, { + organizationId: 'org-1', + connectorType: 'jira', + }) + expect(mocks.resolveScope).not.toHaveBeenCalled() + expect(mocks.executeAttachment).not.toHaveBeenCalled() + }) + + it('uses the shared selector execution and records the prepared account access once', async () => { + const personalScope = { kind: 'organization' as const, organizationId: 'org-1' } + mocks.resolveScope.mockResolvedValueOnce({ + organizationId: 'org-1', + workspaceId: undefined, + selectorKey: 'jira.projectKeys', + selectorManifest: getSelectorManifestEntry('jira.projectKeys'), + selectorScope: personalScope, + }) + mocks.resolveReferences.mockResolvedValueOnce({ + context: { oauthCredential: 'managed-1', domain: 'example.atlassian.net' }, + request: { kind: 'list' }, + references: new Map(), + }) + mocks.authorizeCredential.mockResolvedValueOnce({ + suppliedId: 'managed-1', + providerId: 'jira', + personalSearchSetup: { principal, organizationId: 'org-1', connectorType: 'jira' }, + }) + mocks.getAttachment.mockReturnValueOnce({ + destination: 'fixed', + credential: { kind: 'stored', field: 'oauthCredential', serviceIds: ['jira'] }, + auditCredentialUse: true, + execute: async (args: ExecuteServerSelectorArgs) => { + args.recordCredentialUse?.('jira') + args.recordCredentialUse?.('jira') + return { kind: 'list', items: [{ id: 'PROJECT', label: 'Project' }] } + }, + }) + await expect( + execute({ + selectorKey: 'jira.projectKeys', + scope: personalScope, + context: { oauthCredential: 'managed-1', domain: 'example.atlassian.net' }, + personalSearchSetup: 'jira', + }) + ).resolves.toEqual({ kind: 'list', items: [{ id: 'PROJECT', label: 'Project' }] }) + expect(mocks.authorizeCredential).toHaveBeenCalledWith( + expect.objectContaining({ personalSearchSetup: 'jira', organizationId: 'org-1' }) + ) + expect(mocks.requireOrganizationMembership).not.toHaveBeenCalled() + expect(mocks.recordCredentialAccess).toHaveBeenCalledTimes(1) + expect(mocks.recordCredentialAccess).toHaveBeenCalledWith( + expect.objectContaining({ + actorId: principal.userId, + resourceId: 'managed-1', + providerId: 'jira', + }) + ) + }) + /** * The picker is a use of the integration, not a neutral list: it reaches the * provider's API with the caller's credential. The authorization funnel never diff --git a/apps/sim/lib/selectors/application/execute-selector.ts b/apps/sim/lib/selectors/application/execute-selector.ts index 1f70f08cc9f..32ca55fb3b5 100644 --- a/apps/sim/lib/selectors/application/execute-selector.ts +++ b/apps/sim/lib/selectors/application/execute-selector.ts @@ -8,6 +8,7 @@ import { defineAuthorizedWorkspaceUseCase } from '@/lib/core/application' import type { OperationUseCase } from '@/lib/core/application/operation' import { requireOrganizationMembership } from '@/lib/core/application/organization-authorization' import { OrchestrationError } from '@/lib/core/orchestration/types' +import { authorizePersonalSearchSetup } from '@/lib/knowledge/application/personal-search-account' import { type CredentialAuditRequest, recordCredentialAccess } from '@/lib/oauth/token-resolution' import { selectorOperations } from '@/lib/selectors/application/operations' import { @@ -39,6 +40,8 @@ const logger = createLogger('ExecuteSelector') export interface ExecuteSelectorInput extends ExecuteSelectorRequest { signal?: AbortSignal auditRequest?: CredentialAuditRequest + /** Set only by the personal Search setup use case; excluded from the public selector contract. */ + personalSearchSetup?: 'jira' | 'confluence' } function validateAuthorizedInput( @@ -164,6 +167,7 @@ async function executeAuthorizedSelector(args: { scope: args.input.scope, workspaceId: args.context.workspaceId, organizationId, + personalSearchSetup: args.input.personalSearchSetup, policy: attachment.credential, protectedValues, references: resolved.references, @@ -194,19 +198,24 @@ async function executeAuthorizedSelector(args: { }) const credentialAccess = credential?.access + const credentialResourceId = credential?.personalSearchSetup + ? credential.suppliedId + : credentialAccess?.resolvedCredentialId let credentialUseRecorded = false const recordCredentialUse = - attachment.auditCredentialUse && credentialAccess?.resolvedCredentialId + attachment.auditCredentialUse && credentialResourceId ? (providerId: string) => { if (credentialUseRecorded) return credentialUseRecorded = true recordCredentialAccess({ actorId: args.principal.userId, workspaceId: args.context.workspaceId ?? null, - resourceId: credentialAccess.resolvedCredentialId!, + resourceId: credentialResourceId, providerId: credential?.providerId ?? providerId, credentialType: - credentialAccess.credentialType === 'service_account' ? 'service_account' : 'oauth', + credentialAccess?.credentialType === 'service_account' + ? 'service_account' + : 'oauth', auditRequest: args.input.auditRequest, }) } @@ -337,14 +346,26 @@ export const executeSelector: OperationUseCase< auditRequest: args.input.auditRequest ?? args.request, }, } - if (args.input.scope.kind !== 'organization') return executeWorkspaceSelector.execute(args) + if (args.input.scope.kind !== 'organization') { + if (args.input.personalSearchSetup) throw new SelectorContextUnavailableError() + return executeWorkspaceSelector.execute(args) + } if (args.principal.kind !== 'session') throw new SelectorContextUnavailableError() - await requireOrganizationMembership( - args.principal, - args.input.scope.organizationId, - 'admin', - 'knowledge.use' - ) + if (args.input.personalSearchSetup) { + const selectorKey = + args.input.personalSearchSetup === 'jira' ? 'jira.projectKeys' : 'confluence.spaces' + if (args.input.selectorKey !== selectorKey) throw new SelectorContextUnavailableError() + await authorizePersonalSearchSetup(args.principal, { + organizationId: args.input.scope.organizationId, + connectorType: args.input.personalSearchSetup, + }) + } else + await requireOrganizationMembership( + args.principal, + args.input.scope.organizationId, + 'admin', + 'knowledge.use' + ) const context = await resolveSelectorApplicationContext({ selectorKey: args.input.selectorKey as ServerSelectorKey, scope: args.input.scope, diff --git a/apps/sim/lib/selectors/server/credentials.test.ts b/apps/sim/lib/selectors/server/credentials.test.ts index 1276041dfa8..f895d933793 100644 --- a/apps/sim/lib/selectors/server/credentials.test.ts +++ b/apps/sim/lib/selectors/server/credentials.test.ts @@ -13,6 +13,8 @@ const mocks = vi.hoisted(() => ({ credentialProviderMatchesService: vi.fn(), getServiceConfig: vi.fn(), resolveCredentialTokenBundle: vi.fn(), + authorizePersonalSearch: vi.fn(), + resolveManagedOAuthToken: vi.fn(), })) vi.mock('@/lib/auth/credential-access', () => ({ @@ -28,6 +30,13 @@ vi.mock('@/lib/oauth/credential-service', () => ({ resolveCredentialTokenBundle: mocks.resolveCredentialTokenBundle, })) +vi.mock('@/lib/knowledge/application/personal-search-account', () => ({ + authorizePersonalSearchSetupCredential: mocks.authorizePersonalSearch, +})) +vi.mock('@/lib/credentials/managed-oauth', () => ({ + resolveManagedOAuthToken: mocks.resolveManagedOAuthToken, +})) + vi.mock('@/lib/oauth/utils', () => ({ credentialProviderMatchesService: mocks.credentialProviderMatchesService, getServiceConfigByServiceId: mocks.getServiceConfig, @@ -117,6 +126,83 @@ describe('authorizeSelectorCredential', () => { }) }) + it('browses with only the member’s own prepared account and refreshes it without the admin credential path', async () => { + mocks.authorizePersonalSearch.mockResolvedValue({ id: 'managed-1', providerId: 'jira' }) + mocks.resolveManagedOAuthToken.mockResolvedValue({ accessToken: 'private-token' }) + const selected = await authorizeSelectorCredential({ + principal, + context: { oauthCredential: 'managed-1' }, + scope: { kind: 'organization', organizationId: 'org-1' }, + organizationId: 'org-1', + personalSearchSetup: 'jira', + policy: { kind: 'stored', field: 'oauthCredential', serviceIds: ['jira'] }, + protectedValues: createSelectorProtectedValues(), + references: new Map(), + }) + const protectedValues = createSelectorProtectedValues() + const recordCredentialUse = vi.fn() + await expect( + resolveSelectorOAuthAccessToken({ + credential: selected, + serviceId: 'jira', + scopes: ['read:jira-work'], + protectedValues, + recordCredentialUse, + }) + ).resolves.toBe('private-token') + expect(mocks.authorizePersonalSearch).toHaveBeenCalledTimes(2) + expect(mocks.resolveManagedOAuthToken).toHaveBeenCalledWith({ + organizationId: 'org-1', + credentialId: 'managed-1', + expectedProviderId: 'jira', + requiredScopes: ['read:jira-work'], + }) + expect(protectedValues.contains('private-token')).toBe(true) + expect(recordCredentialUse).toHaveBeenCalledWith('jira') + expect(mocks.authorizeOrganizationCredentialUse).not.toHaveBeenCalled() + expect(mocks.resolveOrganizationCredentialTokenBundle).not.toHaveBeenCalled() + }) + + it('rejects a revoked prepared credential before refreshing its token', async () => { + mocks.authorizePersonalSearch.mockRejectedValue(new Error('Credential revoked')) + await expect( + resolveSelectorOAuthAccessToken({ + credential: { + suppliedId: 'managed-1', + providerId: 'jira', + personalSearchSetup: { principal, organizationId: 'org-1', connectorType: 'jira' }, + }, + serviceId: 'jira', + protectedValues: createSelectorProtectedValues(), + }) + ).rejects.toThrow('Credential revoked') + expect(mocks.resolveManagedOAuthToken).not.toHaveBeenCalled() + }) + + it('refuses using a prepared Jira credential for another provider or impersonation', async () => { + const selected = { + suppliedId: 'managed-1', + providerId: 'jira', + personalSearchSetup: { principal, organizationId: 'org-1', connectorType: 'jira' as const }, + } + await expect( + resolveSelectorOAuthAccessToken({ + credential: selected, + serviceId: 'confluence', + protectedValues: createSelectorProtectedValues(), + }) + ).rejects.toBeInstanceOf(SelectorConnectionUnavailableError) + await expect( + resolveSelectorOAuthAccessToken({ + credential: selected, + serviceId: 'jira', + impersonateEmail: 'other@example.com', + protectedValues: createSelectorProtectedValues(), + }) + ).rejects.toBeInstanceOf(SelectorConnectionUnavailableError) + expect(mocks.resolveManagedOAuthToken).not.toHaveBeenCalled() + }) + it('rejects an organization connection for the wrong selector provider', async () => { mocks.authorizeOrganizationCredentialUse.mockResolvedValue({ credential: { id: 'managed-1', providerId: 'jira', type: 'managed_oauth' }, diff --git a/apps/sim/lib/selectors/server/credentials.ts b/apps/sim/lib/selectors/server/credentials.ts index 83a152cb560..82f1d9a7bcc 100644 --- a/apps/sim/lib/selectors/server/credentials.ts +++ b/apps/sim/lib/selectors/server/credentials.ts @@ -9,6 +9,8 @@ import { authorizeOrganizationCredentialUse, resolveOrganizationCredentialTokenBundle, } from '@/lib/credentials/application/organization-credentials' +import { resolveManagedOAuthToken } from '@/lib/credentials/managed-oauth' +import { authorizePersonalSearchSetupCredential } from '@/lib/knowledge/application/personal-search-account' import { resolveCredentialTokenBundle } from '@/lib/oauth/credential-service' import { credentialProviderMatchesService, getServiceConfigByServiceId } from '@/lib/oauth/utils' import { SelectorConnectionUnavailableError } from '@/lib/selectors/server/errors' @@ -104,6 +106,7 @@ export async function authorizeSelectorCredential(input: { scope: SelectorScope workspaceId?: string organizationId?: string + personalSearchSetup?: 'jira' | 'confluence' policy: SelectorCredentialPolicy protectedValues: SelectorProtectedValues references: ReadonlyMap @@ -111,6 +114,32 @@ export async function authorizeSelectorCredential(input: { const suppliedId = input.context[input.policy.field] if (!suppliedId) throw new SelectorConnectionUnavailableError() + if (input.personalSearchSetup) { + if ( + input.scope.kind !== 'organization' || + input.principal.kind !== 'session' || + input.organizationId !== input.scope.organizationId || + input.workspaceId || + !input.policy.serviceIds.includes(input.personalSearchSetup) + ) + throw new SelectorConnectionUnavailableError() + const row = await authorizePersonalSearchSetupCredential(input.principal, { + organizationId: input.scope.organizationId, + connectorType: input.personalSearchSetup, + credentialId: suppliedId, + }) + input.protectedValues.add(suppliedId, 'reference') + return { + suppliedId, + providerId: row.providerId, + personalSearchSetup: { + principal: input.principal, + organizationId: input.scope.organizationId, + connectorType: input.personalSearchSetup, + }, + } + } + if (input.scope.kind === 'organization') { if ( input.principal.kind !== 'session' || @@ -187,6 +216,31 @@ export async function resolveSelectorOAuthAccessToken(input: { input.credential.signal?.throwIfAborted() if (input.credential.fixedToken) return input.credential.fixedToken + if (input.credential.personalSearchSetup) { + const setup = input.credential.personalSearchSetup + if (input.impersonateEmail || input.serviceId !== setup.connectorType) { + throw new SelectorConnectionUnavailableError() + } + await authorizePersonalSearchSetupCredential(setup.principal, { + ...setup, + credentialId: input.credential.suppliedId, + }) + const result = await waitForSelectorCredentialResolution( + resolveManagedOAuthToken({ + organizationId: setup.organizationId, + credentialId: input.credential.suppliedId, + expectedProviderId: setup.connectorType, + requiredScopes: input.scopes ? [...input.scopes] : [], + }), + input.credential.signal + ) + input.credential.signal?.throwIfAborted() + if (!result?.accessToken) throw new SelectorConnectionUnavailableError() + input.protectedValues.add(result.accessToken) + input.recordCredentialUse?.(setup.connectorType) + return result.accessToken + } + if (input.credential.organization) { const result = await waitForSelectorCredentialResolution( resolveOrganizationCredentialTokenBundle({ diff --git a/apps/sim/lib/selectors/server/providers/credential-bundle.test.ts b/apps/sim/lib/selectors/server/providers/credential-bundle.test.ts index 58a875458b2..88b453da715 100644 --- a/apps/sim/lib/selectors/server/providers/credential-bundle.test.ts +++ b/apps/sim/lib/selectors/server/providers/credential-bundle.test.ts @@ -5,6 +5,15 @@ import { beforeEach, describe, expect, it, vi } from 'vitest' const mockResolveCredentialAccessToken = vi.hoisted(() => vi.fn()) const mockResolveOrganizationToken = vi.hoisted(() => vi.fn()) +const mockOwnAccount = vi.hoisted(() => vi.fn()) +const mockResolveManagedToken = vi.hoisted(() => vi.fn()) + +vi.mock('@/lib/knowledge/application/personal-search-account', () => ({ + authorizePersonalSearchSetupCredential: mockOwnAccount, +})) +vi.mock('@/lib/credentials/managed-oauth', () => ({ + resolveManagedOAuthToken: mockResolveManagedToken, +})) vi.mock('@/lib/credentials/application/organization-credentials', () => ({ resolveOrganizationCredentialTokenBundle: mockResolveOrganizationToken, @@ -20,6 +29,42 @@ import { resolveSelectorCredentialBundle } from '@/lib/selectors/server/provider describe('selector credential bundles', () => { beforeEach(() => vi.clearAllMocks()) + it('resolves a personal Atlassian grant through the owned managed-account path', async () => { + mockOwnAccount.mockResolvedValue({ id: 'managed-1', providerId: 'jira' }) + mockResolveManagedToken.mockResolvedValue({ accessToken: 'own-managed-token' }) + const principal = { kind: 'session', userId: 'member-1', sessionId: 'session-1' } as const + const protectedValues = createSelectorProtectedValues() + await expect( + resolveSelectorCredentialBundle({ + credential: { + suppliedId: 'managed-1', + providerId: 'jira', + personalSearchSetup: { principal, organizationId: 'org-1', connectorType: 'jira' }, + }, + providerId: 'jira', + scopes: ['read:jira-work'], + protectedValues, + }) + ).resolves.toEqual({ accessToken: 'own-managed-token' }) + expect(mockOwnAccount).toHaveBeenCalledWith( + principal, + expect.objectContaining({ + credentialId: 'managed-1', + organizationId: 'org-1', + connectorType: 'jira', + }) + ) + expect(mockResolveManagedToken).toHaveBeenCalledWith({ + organizationId: 'org-1', + credentialId: 'managed-1', + expectedProviderId: 'jira', + requiredScopes: ['read:jira-work'], + }) + expect(mockResolveOrganizationToken).not.toHaveBeenCalled() + expect(mockResolveCredentialAccessToken).not.toHaveBeenCalled() + expect(protectedValues.contains('own-managed-token')).toBe(true) + }) + it('protects short credential-bound cloud ids as exact identifiers', async () => { mockResolveCredentialAccessToken.mockResolvedValue({ accessToken: 'server-only-token', diff --git a/apps/sim/lib/selectors/server/providers/credential-bundle.ts b/apps/sim/lib/selectors/server/providers/credential-bundle.ts index 97669ff8a8f..b134cf89047 100644 --- a/apps/sim/lib/selectors/server/providers/credential-bundle.ts +++ b/apps/sim/lib/selectors/server/providers/credential-bundle.ts @@ -3,7 +3,10 @@ import { resolveCredentialTokenBundle, type ServiceAccountTokenResult, } from '@/lib/oauth/credential-service' -import { waitForSelectorCredentialResolution } from '@/lib/selectors/server/credentials' +import { + resolveSelectorOAuthAccessToken, + waitForSelectorCredentialResolution, +} from '@/lib/selectors/server/credentials' import { SelectorConnectionUnavailableError } from '@/lib/selectors/server/errors' import type { AuthorizedSelectorCredential, @@ -26,6 +29,16 @@ export async function resolveSelectorCredentialBundle(input: { if (!credential) throw new SelectorConnectionUnavailableError() credential.signal?.throwIfAborted() + if (credential.personalSearchSetup) { + if (!input.providerId) throw new SelectorConnectionUnavailableError() + return { + accessToken: await resolveSelectorOAuthAccessToken({ + ...input, + credential, + serviceId: input.providerId, + }), + } + } if (credential.fixedToken) { if (input.providerId) { input.recordCredentialUse?.(credential.providerId ?? input.providerId) diff --git a/apps/sim/lib/selectors/server/types.ts b/apps/sim/lib/selectors/server/types.ts index 05546532f2d..a8d12395bb6 100644 --- a/apps/sim/lib/selectors/server/types.ts +++ b/apps/sim/lib/selectors/server/types.ts @@ -51,6 +51,11 @@ export type SelectorCredentialPolicy = export interface AuthorizedSelectorCredential { suppliedId: string organization?: { principal: SessionPrincipal; organizationId: string } + personalSearchSetup?: { + principal: SessionPrincipal + organizationId: string + connectorType: 'jira' | 'confluence' + } access?: CredentialAccessResult fixedToken?: string /** Trusted provider id loaded during server-side credential binding. */ diff --git a/apps/sim/lib/selectors/types.ts b/apps/sim/lib/selectors/types.ts index c97382e32f0..2a20eac3cde 100644 --- a/apps/sim/lib/selectors/types.ts +++ b/apps/sim/lib/selectors/types.ts @@ -104,6 +104,13 @@ export type SelectorScope = workspaceId: string } +/** Chooses a dedicated client transport without granting access through the generic selector API. */ +export interface SelectorSurface { + kind: 'personal-search-setup' + organizationId: string + connectorType: 'jira' | 'confluence' +} + export type SelectorRequest = | { kind: 'list' diff --git a/apps/sim/lib/sim-search/personal-source-setup.ts b/apps/sim/lib/sim-search/personal-source-setup.ts new file mode 100644 index 00000000000..8afb1049c9f --- /dev/null +++ b/apps/sim/lib/sim-search/personal-source-setup.ts @@ -0,0 +1,2 @@ +/** Personal Atlassian setup stores an explicit, bounded snapshot of selected project or space keys. */ +export const MAX_PERSONAL_SOURCE_SETUP_KEYS = 1000 diff --git a/packages/emcn/src/components/combobox/combobox.dom.test.tsx b/packages/emcn/src/components/combobox/combobox.dom.test.tsx index 958fc8bbb38..f410e4a96ca 100644 --- a/packages/emcn/src/components/combobox/combobox.dom.test.tsx +++ b/packages/emcn/src/components/combobox/combobox.dom.test.tsx @@ -76,6 +76,28 @@ afterEach(() => { }) describe('Combobox onOpenChange', () => { + it.each([false, true])( + 'puts the field name and validation ARIA on the interactive control (editable=%s)', + (editable) => { + render( + + ) + const control = trigger() + expect(control.getAttribute('aria-label')).toBe('Projects') + expect(control.getAttribute('aria-describedby')).toBe('projects-hint') + expect(control.getAttribute('aria-required')).toBe('true') + expect(control.getAttribute('aria-invalid')).toBe('true') + expect(control.closest('[aria-label="Projects"]')).toBe(control) + } + ) + it('renders the dropdown inside the component subtree when portals are disabled', () => { render() diff --git a/packages/emcn/src/components/combobox/combobox.tsx b/packages/emcn/src/components/combobox/combobox.tsx index ddf79d53e71..42757411481 100644 --- a/packages/emcn/src/components/combobox/combobox.tsx +++ b/packages/emcn/src/components/combobox/combobox.tsx @@ -222,6 +222,11 @@ const Combobox = memo( searchActive = false, onLoadMore, onLoadAll, + 'aria-label': ariaLabel, + 'aria-labelledby': ariaLabelledBy, + 'aria-describedby': ariaDescribedBy, + 'aria-required': ariaRequired, + 'aria-invalid': ariaInvalid, ...props }, ref @@ -795,6 +800,11 @@ const Combobox = memo( onBlur={handleBlur} onKeyDown={handleKeyDown} disabled={disabled} + aria-label={ariaLabel} + aria-labelledby={ariaLabelledBy} + aria-describedby={ariaDescribedBy} + aria-required={ariaRequired} + aria-invalid={ariaInvalid} {...inputProps} role='combobox' aria-expanded={open} @@ -840,6 +850,11 @@ const Combobox = memo(
Date: Thu, 10 Sep 2026 13:29:22 -0700 Subject: [PATCH 2/5] fix(search): validate Atlassian keys beyond discovery limits --- .../application/personal-source-setup.test.ts | 190 +++++++++++++++++- .../application/personal-source-setup.ts | 57 +++++- .../server/providers/confluence.test.ts | 67 +++++- .../selectors/server/providers/confluence.ts | 2 +- .../selectors/server/providers/jira.test.ts | 14 +- .../lib/selectors/server/providers/jira.ts | 5 +- 6 files changed, 301 insertions(+), 34 deletions(-) diff --git a/apps/sim/lib/knowledge/application/personal-source-setup.test.ts b/apps/sim/lib/knowledge/application/personal-source-setup.test.ts index b8463118228..9ae1a409a4d 100644 --- a/apps/sim/lib/knowledge/application/personal-source-setup.test.ts +++ b/apps/sim/lib/knowledge/application/personal-source-setup.test.ts @@ -1,5 +1,5 @@ /** @vitest-environment node */ -import { beforeEach, describe, expect, it, vi } from 'vitest' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' const mocks = vi.hoisted(() => ({ authorizeOperation: vi.fn(), @@ -69,6 +69,12 @@ import { listPersonalSourceSetupAccounts, personalSourceSetup, } from '@/lib/knowledge/application/personal-source-setup' +import { MAX_SELECTOR_PAGES } from '@/lib/selectors/limits' +import type { SelectorRequest } from '@/lib/selectors/types' + +interface ValidationSelectorCall { + input: { request: SelectorRequest; signal: AbortSignal } +} const principal = { kind: 'session', userId: 'member-1', sessionId: 'session-1' } as const const owner = { organizationId: 'organization-1', connectorType: 'jira' } as const @@ -84,6 +90,10 @@ const runConnect = (changes = {}) => personalSourceSetup.execute({ principal, input: { ...connect, keys: ['PROJECT'], ...changes } }) describe('personal source setup', () => { + afterEach(() => { + vi.restoreAllMocks() + }) + beforeEach(() => { vi.resetAllMocks() mocks.authorize.mockResolvedValue(principal.userId) @@ -245,15 +255,154 @@ describe('personal source setup', () => { { kind: 'list', items: [], truncated: true, nextCursor: '50' }, { kind: 'list', items: [] }, ])('rejects unavailable manually entered keys before source creation %#', async (page) => { - mocks.selector.mockResolvedValue(page) + mocks.selector.mockResolvedValueOnce(page).mockResolvedValue({ kind: 'detail', item: null }) await expect(runConnect({ keys: ['MISSING'] })).rejects.toThrow('could not be found') expect(mocks.configure).not.toHaveBeenCalled() }) - it('rejects a repeated pagination cursor without looping or creating a source', async () => { - mocks.selector.mockResolvedValue({ kind: 'list', items: [], nextCursor: '50' }) + it.each(['jira', 'confluence'] as const)( + 'verifies a manually entered %s key outside the available listing through the same authorized selector', + async (connectorType) => { + mocks.selector + .mockResolvedValueOnce({ kind: 'list', items: [] }) + .mockResolvedValueOnce({ kind: 'detail', item: { id: 'PROJECT', label: 'Project' } }) + await expect(runConnect({ connectorType })).resolves.toMatchObject({ kind: 'connected' }) + expect(mocks.selector).toHaveBeenLastCalledWith({ + principal, + request: undefined, + input: { + selectorKey: connectorType === 'jira' ? 'jira.projectKeys' : 'confluence.spaces', + scope: { kind: 'organization', organizationId: owner.organizationId }, + context: { oauthCredential: credential.credentialId, domain: credential.domain }, + personalSearchSetup: connectorType, + signal: expect.any(AbortSignal), + request: { kind: 'detail', id: 'PROJECT' }, + }, + }) + expect(mocks.ownAccount).toHaveBeenCalledTimes(2) + expect(mocks.oauth).not.toHaveBeenCalled() + } + ) + + it.each([ + { name: 'truncated results', pages: 1, truncated: true, nextCursor: '50' }, + { name: 'a repeated cursor', pages: 2, nextCursor: '50' }, + { name: 'the page limit', pages: MAX_SELECTOR_PAGES }, + ])('resolves remaining keys directly after $name', async ({ pages, truncated, nextCursor }) => { + let listed = 0 + mocks.selector.mockImplementation(({ input }: ValidationSelectorCall) => { + if (input.request.kind === 'detail') { + return { kind: 'detail', item: { id: input.request.id, label: 'Project' } } + } + listed++ + return { kind: 'list', items: [], nextCursor: nextCursor ?? String(listed), truncated } + }) + await expect(runConnect()).resolves.toMatchObject({ kind: 'connected' }) + expect(listed).toBe(pages) + expect(mocks.selector).toHaveBeenCalledTimes(pages + 1) + expect(mocks.oauth).not.toHaveBeenCalled() + }) + + it('gives direct validation a fresh deadline when listing times out', async () => { + const listing = new AbortController() + const details = new AbortController() + vi.spyOn(AbortSignal, 'timeout') + .mockReturnValueOnce(listing.signal) + .mockReturnValueOnce(details.signal) + mocks.selector + .mockImplementationOnce(({ input }: ValidationSelectorCall) => { + listing.abort(new DOMException('Listing timed out', 'TimeoutError')) + input.signal.throwIfAborted() + }) + .mockImplementationOnce(({ input }: ValidationSelectorCall) => { + expect(input.signal.aborted).toBe(false) + expect(input.request).toEqual({ kind: 'detail', id: 'PROJECT' }) + return { kind: 'detail', item: { id: 'PROJECT', label: 'Project' } } + }) + await expect(runConnect()).resolves.toMatchObject({ kind: 'connected' }) + expect(AbortSignal.timeout).toHaveBeenCalledTimes(2) + expect(mocks.oauth).not.toHaveBeenCalled() + }) + + it('fails before mutation when direct validation also exceeds its deadline', async () => { + const listing = new AbortController() + const details = new AbortController() + vi.spyOn(AbortSignal, 'timeout') + .mockReturnValueOnce(listing.signal) + .mockReturnValueOnce(details.signal) + mocks.selector + .mockResolvedValueOnce({ kind: 'list', items: [] }) + .mockImplementationOnce(({ input }: ValidationSelectorCall) => { + details.abort(new DOMException('Validation timed out', 'TimeoutError')) + input.signal.throwIfAborted() + }) + await expect(runConnect()).rejects.toThrow('took too long') + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('does not retry direct validation after the caller cancels listing', async () => { + const caller = new AbortController() + mocks.selector.mockImplementationOnce(({ input }: ValidationSelectorCall) => { + caller.abort(new Error('Setup cancelled')) + input.signal.throwIfAborted() + }) + await expect( + personalSourceSetup.execute({ + principal, + input: { ...connect, keys: ['PROJECT'] }, + request: { headers: new Headers(), signal: caller.signal }, + }) + ).rejects.toThrow('Setup cancelled') + expect(mocks.selector).toHaveBeenCalledTimes(1) + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('rejects a detail response for a different key', async () => { + mocks.selector + .mockResolvedValueOnce({ kind: 'list', items: [] }) + .mockResolvedValueOnce({ kind: 'detail', item: { id: 'OTHER', label: 'Other project' } }) await expect(runConnect()).rejects.toThrow('could not be found') - expect(mocks.selector).toHaveBeenCalledTimes(2) + expect(mocks.configure).not.toHaveBeenCalled() + }) + + it('bounds direct validation concurrency and validates each unresolved key only once', async () => { + let release = () => {} + let allStarted = () => {} + const gate = new Promise((resolve) => { + release = resolve + }) + const started = new Promise((resolve) => { + allStarted = resolve + }) + let active = 0 + let maximumActive = 0 + mocks.selector.mockImplementation(async ({ input }: ValidationSelectorCall) => { + if (input.request.kind === 'list') return { kind: 'list', items: [] } + active++ + maximumActive = Math.max(maximumActive, active) + if (active === 5) allStarted() + await gate + active-- + return { kind: 'detail', item: { id: input.request.id, label: input.request.id } } + }) + const keys = Array.from({ length: 12 }, (_, index) => `PROJECT${index}`) + const connection = runConnect({ keys: [...keys, ...keys] }) + await started + try { + expect(mocks.selector).toHaveBeenCalledTimes(6) + expect(mocks.configure).not.toHaveBeenCalled() + } finally { + release() + } + await expect(connection).resolves.toMatchObject({ kind: 'connected' }) + expect(maximumActive).toBe(5) + expect(mocks.selector).toHaveBeenCalledTimes(keys.length + 1) + }) + + it('propagates listing failures without starting direct validation', async () => { + mocks.selector.mockRejectedValueOnce(new Error('Account revoked')) + await expect(runConnect()).rejects.toThrow('Account revoked') + expect(mocks.selector).toHaveBeenCalledTimes(1) expect(mocks.configure).not.toHaveBeenCalled() }) @@ -274,6 +423,37 @@ describe('personal source setup', () => { expect(mocks.configure).not.toHaveBeenCalled() }) + it.each(['binding', 'ownership'] as const)( + 'stops before source creation if the caller cancels during the final %s check', + async (phase) => { + const caller = new AbortController() + if (phase === 'binding') { + mocks.binding.mockImplementationOnce(() => { + caller.abort(new Error('Setup cancelled')) + return { + organizationId: owner.organizationId, + credentialGroupId: 'group-1', + credentialGroupOptionId: 'option-1', + } + }) + } else { + mocks.ownAccount.mockResolvedValueOnce(account).mockImplementationOnce(() => { + caller.abort(new Error('Setup cancelled')) + return account + }) + } + await expect( + personalSourceSetup.execute({ + principal, + input: { ...connect, keys: ['PROJECT'] }, + request: { headers: new Headers(), signal: caller.signal }, + }) + ).rejects.toThrow('Setup cancelled') + expect(mocks.configure).not.toHaveBeenCalled() + expect(mocks.dispatch).not.toHaveBeenCalled() + } + ) + it('rejects a current operation authorization denial before any setup effects', async () => { mocks.authorizeOperation.mockRejectedValue(new Error('Membership ended')) await expect(runConnect()).rejects.toThrow('Membership ended') diff --git a/apps/sim/lib/knowledge/application/personal-source-setup.ts b/apps/sim/lib/knowledge/application/personal-source-setup.ts index e17a73c3792..407ad85b918 100644 --- a/apps/sim/lib/knowledge/application/personal-source-setup.ts +++ b/apps/sim/lib/knowledge/application/personal-source-setup.ts @@ -2,6 +2,7 @@ import { createLogger } from '@sim/logger' import { getErrorMessage } from '@sim/utils/errors' import { normalizeAtlassianSiteUrl } from '@/lib/atlassian/discovery' import { OrchestrationError } from '@/lib/core/orchestration/types' +import { mapWithConcurrency } from '@/lib/core/utils/concurrency' import { loadManagedCredentialGroupBinding, loadScopedAccountsCredentialListContext, @@ -29,6 +30,8 @@ import { MAX_PERSONAL_SOURCE_SETUP_KEYS } from '@/lib/sim-search/personal-source import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' const logger = createLogger('PersonalSourceSetup') +const VALIDATION_PHASE_TIMEOUT_MS = 30_000 +const DETAIL_VALIDATION_CONCURRENCY = 5 interface PersonalSourceSetupOwner { organizationId: string @@ -176,12 +179,13 @@ export const personalSourceSetup = defineAuthorizedKnowledgeUseCase({ const keys = [...new Set(input.keys.map((key) => key.trim()))] const remaining = new Set(keys) const cursors = new Set() - const timeout = AbortSignal.timeout(30_000) + const timeout = AbortSignal.timeout(VALIDATION_PHASE_TIMEOUT_MS) const signal = request?.signal ? AbortSignal.any([request.signal, timeout]) : timeout let cursor: string | undefined for (let page = 0; page < MAX_SELECTOR_PAGES; page++) { let result: SelectorExecutionResult try { + signal.throwIfAborted() result = await executeSelector.execute({ principal, request, @@ -191,13 +195,9 @@ export const personalSourceSetup = defineAuthorizedKnowledgeUseCase({ request: { kind: 'list', ...(cursor ? { cursor } : {}) }, }, }) + signal.throwIfAborted() } catch (error) { - if (timeout.aborted && !request?.signal?.aborted) { - throw new OrchestrationError( - 'validation', - 'Checking the selected projects or spaces took too long. Try fewer selections.' - ) - } + if (timeout.aborted && !request?.signal?.aborted) break throw error } if (result.kind !== 'list') throw new Error('Source discovery returned an unexpected result') @@ -207,11 +207,45 @@ export const personalSourceSetup = defineAuthorizedKnowledgeUseCase({ cursor = result.nextCursor cursors.add(cursor) } + request?.signal?.throwIfAborted() if (remaining.size > 0) { - throw new OrchestrationError( - 'validation', - 'Some selected projects or spaces could not be found with this account. Refresh the choices and try again.' - ) + const detailTimeout = AbortSignal.timeout(VALIDATION_PHASE_TIMEOUT_MS) + const details = new AbortController() + const detailSignal = AbortSignal.any([ + detailTimeout, + details.signal, + ...(request?.signal ? [request.signal] : []), + ]) + try { + await mapWithConcurrency([...remaining], DETAIL_VALIDATION_CONCURRENCY, async (key) => { + detailSignal.throwIfAborted() + const result = await executeSelector.execute({ + principal, + request, + input: { + ...selectorInput, + signal: detailSignal, + request: { kind: 'detail', id: key }, + }, + }) + detailSignal.throwIfAborted() + if (result.kind !== 'detail' || result.item?.id !== key) { + throw new OrchestrationError( + 'validation', + 'Some selected projects or spaces could not be found with this account. Refresh the choices and try again.' + ) + } + }) + } catch (error) { + details.abort(error) + if (detailTimeout.aborted && !request?.signal?.aborted) { + throw new OrchestrationError( + 'validation', + 'Checking the selected projects or spaces took too long. Try fewer selections.' + ) + } + throw error + } } const [binding, group] = await Promise.all([ loadManagedCredentialGroupBinding(input.credentialId), @@ -232,6 +266,7 @@ export const personalSourceSetup = defineAuthorizedKnowledgeUseCase({ ) } await authorizePersonalSearchSetupCredential(principal, input) + request?.signal?.throwIfAborted() const result = await configureSimSearchConnector.execute({ principal, request, diff --git a/apps/sim/lib/selectors/server/providers/confluence.test.ts b/apps/sim/lib/selectors/server/providers/confluence.test.ts index a4437bb0b90..75b131f34dc 100644 --- a/apps/sim/lib/selectors/server/providers/confluence.test.ts +++ b/apps/sim/lib/selectors/server/providers/confluence.test.ts @@ -134,23 +134,70 @@ describe('Confluence server selector adapters', () => { ) }) - it('hydrates a legacy numeric value in the key selector without rewriting it', async () => { - mockFetch.mockResolvedValueOnce( - new Response(JSON.stringify({ id: '12345', key: 'ENG', name: 'Engineering' }), { - status: 200, + it.each(['current', 'archived'] as const)( + 'looks up a numeric %s space key as a key rather than a resource ID', + async (status) => { + mockFetch.mockImplementation((input: URL) => { + const matches = new URL(input).searchParams.get('status') === status + return new Response( + JSON.stringify({ + results: matches ? [{ id: '99999', key: '12345', name: 'Numeric key' }] : [], + }), + { status: 200 } + ) }) - ) + await expect( + confluenceSelectorAttachments['confluence.spaces'].execute({ + ...spaceDetailArgs(), + request: { kind: 'detail', id: '12345' }, + }) + ).resolves.toEqual({ + kind: 'detail', + item: { + id: '12345', + label: status === 'archived' ? 'Numeric key (12345) — archived' : 'Numeric key (12345)', + }, + }) + expect(mockFetch).toHaveBeenCalledTimes(2) + for (const [input] of mockFetch.mock.calls) { + const url = new URL(String(input)) + expect(url.pathname).toBe('/ex/confluence/cloud-1/wiki/api/v2/spaces') + expect(url.searchParams.get('keys')).toBe('12345') + } + } + ) + + it('does not accept a numeric resource ID as a matching space key', async () => { + mockFetch.mockImplementation( + () => + new Response( + JSON.stringify({ results: [{ id: '12345', key: 'ENG', name: 'Engineering' }] }), + { status: 200 } + ) + ) await expect( confluenceSelectorAttachments['confluence.spaces'].execute({ ...spaceDetailArgs(), request: { kind: 'detail', id: '12345' }, }) - ).resolves.toEqual({ - kind: 'detail', - item: { id: '12345', label: 'Engineering (ENG)' }, - }) - expect(String(mockFetch.mock.calls[0]?.[0])).toContain('/wiki/api/v2/spaces/12345') + ).resolves.toEqual({ kind: 'detail', item: null }) + }) + + it('preserves key aliases when hydrating the ID selector', async () => { + mockFetch.mockImplementation( + () => + new Response( + JSON.stringify({ results: [{ id: '12345', key: 'ENG', name: 'Engineering' }] }), + { status: 200 } + ) + ) + await expect( + confluenceSelectorAttachments['confluence.spacesById'].execute({ + ...spaceIdDetailArgs(), + request: { kind: 'detail', id: 'ENG' }, + }) + ).resolves.toEqual({ kind: 'detail', item: { id: 'ENG', label: 'Engineering (ENG)' } }) }) it('projects provider IDs for block space lists while key selectors remain unchanged', async () => { diff --git a/apps/sim/lib/selectors/server/providers/confluence.ts b/apps/sim/lib/selectors/server/providers/confluence.ts index d2ae95ada2a..69b5b4c05de 100644 --- a/apps/sim/lib/selectors/server/providers/confluence.ts +++ b/apps/sim/lib/selectors/server/providers/confluence.ts @@ -135,7 +135,7 @@ async function executeSpaces(args: ExecuteServerSelectorArgs, identifier: 'key' if (args.request.kind === 'detail') { const requestedId = args.request.id.trim() if (!requestedId || requestedId.length > 255) throw new SelectorContextUnavailableError() - if (/^[1-9][0-9]{0,19}$/.test(requestedId)) { + if (identifier === 'id' && /^[1-9][0-9]{0,19}$/.test(requestedId)) { const space = await fetchProviderJson( `https://api.atlassian.com/ex/confluence/${auth.cloudId}/wiki/api/v2/spaces/${requestedId}`, { diff --git a/apps/sim/lib/selectors/server/providers/jira.test.ts b/apps/sim/lib/selectors/server/providers/jira.test.ts index d4ea2fcf665..a3807abda7a 100644 --- a/apps/sim/lib/selectors/server/providers/jira.test.ts +++ b/apps/sim/lib/selectors/server/providers/jira.test.ts @@ -87,12 +87,14 @@ describe('Jira server selector adapter', () => { ) it.each([ - ['jira.projects', 'ENG'], - ['jira.projectKeys', 'ENG'], - ['jira.projectKeys', '10001'], + ['jira.projects', 'ENG', 'ENG'], + ['jira.projects', '10001', '10001'], + ['jira.projectKeys', 'ENG', 'ENG'], + ['jira.projectKeys', '10001', 'ENG'], + ['jira.projectKeys', 'LEGACY', 'ENG'], ] as const)( - 'hydrates %s selection %s without replacing its saved value', - async (selectorKey, id) => { + 'hydrates %s selection %s as %s, preserving ID-selector aliases and returning canonical keys', + async (selectorKey, id, expectedId) => { mockFetch.mockResolvedValueOnce( new Response(JSON.stringify({ id: '10001', key: 'ENG', name: 'Engineering' }), { status: 200, @@ -107,7 +109,7 @@ describe('Jira server selector adapter', () => { }) ).resolves.toEqual({ kind: 'detail', - item: { id, label: 'Engineering' }, + item: { id: expectedId, label: 'Engineering' }, }) expect(String(mockFetch.mock.calls[0]?.[0])).toBe( `https://api.atlassian.com/ex/jira/cloud-1/rest/api/3/project/${id}` diff --git a/apps/sim/lib/selectors/server/providers/jira.ts b/apps/sim/lib/selectors/server/providers/jira.ts index bf5e028837a..e27f4017516 100644 --- a/apps/sim/lib/selectors/server/providers/jira.ts +++ b/apps/sim/lib/selectors/server/providers/jira.ts @@ -149,7 +149,10 @@ async function getProject(args: ExecuteServerSelectorArgs, projectId: string) { ) const parsed = jiraProjectSchema.safeParse(body) if (!parsed.success) throw new SelectorOptionsUnavailableError() - return { id: projectId, label: parsed.data.name } + return { + id: args.selectorKey === 'jira.projectKeys' ? parsed.data.key : projectId, + label: parsed.data.name, + } } async function fetchIssues( From a8e7d22f592505ecd7294938635e48e309f58d99 Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 10 Sep 2026 13:41:16 -0700 Subject: [PATCH 3/5] fix(search): preserve partial Confluence lookup failures --- .../atlassian-source-setup-modal.tsx | 2 +- .../server/providers/confluence.test.ts | 81 +++++++++++++++++++ .../selectors/server/providers/confluence.ts | 14 ++-- 3 files changed, 90 insertions(+), 7 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx index c4009ea5405..4b60deaa7cb 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/search-sources/atlassian-source-setup-modal.tsx @@ -36,7 +36,6 @@ export function AtlassianSourceSetupModal({ onClose, onConnected, }: AtlassianSourceSetupModalProps) { - const [selectedAccount, setSelectedAccount] = useState() const account = usePersonalSourceAccount({ organizationId, connectorType, @@ -50,6 +49,7 @@ export function AtlassianSourceSetupModal({ connectorConfig: connector.meta, accessMode: 'members', }) + const [selectedAccount, setSelectedAccount] = useState() const accounts = account.accounts.data?.accounts ?? [] const requestedAccount = selectedAccount ?? diff --git a/apps/sim/lib/selectors/server/providers/confluence.test.ts b/apps/sim/lib/selectors/server/providers/confluence.test.ts index 75b131f34dc..5faa48c5e68 100644 --- a/apps/sim/lib/selectors/server/providers/confluence.test.ts +++ b/apps/sim/lib/selectors/server/providers/confluence.test.ts @@ -354,6 +354,87 @@ describe('Confluence server selector adapters', () => { ).rejects.toMatchObject({ name: 'SelectorConnectionUnavailableError', status: 403 }) }) + it.each([ + { failedStatus: 'current', status: 401 }, + { failedStatus: 'current', status: 403 }, + { failedStatus: 'current', status: 429 }, + { failedStatus: 'archived', status: 401 }, + { failedStatus: 'archived', status: 403 }, + { failedStatus: 'archived', status: 429 }, + ])( + 'preserves $status from the $failedStatus lookup when the other status has no matching space', + async ({ failedStatus, status }) => { + mockFetch.mockImplementation((input: URL) => + new URL(input).searchParams.get('status') === failedStatus + ? new Response(null, { status }) + : Response.json({ results: [{ id: '99999', key: 'OTHER', name: 'Other space' }] }) + ) + + await expect( + confluenceSelectorAttachments['confluence.spaces'].execute(spaceDetailArgs()) + ).rejects.toMatchObject({ + name: + status === 429 ? 'SelectorOptionsUnavailableError' : 'SelectorConnectionUnavailableError', + status, + }) + expect(mockFetch).toHaveBeenCalledTimes(2) + } + ) + + it.each(['current', 'archived'] as const)( + 'returns an exact %s match even when the other status lookup fails', + async (matchingStatus) => { + mockFetch.mockImplementation((input: URL) => + new URL(input).searchParams.get('status') === matchingStatus + ? Response.json({ results: [{ id: '12345', key: 'ENG', name: 'Engineering' }] }) + : new Response(null, { status: 429 }) + ) + + await expect( + confluenceSelectorAttachments['confluence.spaces'].execute(spaceDetailArgs()) + ).resolves.toEqual({ + kind: 'detail', + item: { + id: 'ENG', + label: + matchingStatus === 'archived' ? 'Engineering (ENG) — archived' : 'Engineering (ENG)', + }, + }) + } + ) + + it('reports a space key missing only when both status lookups succeed without a match', async () => { + mockFetch + .mockResolvedValueOnce( + Response.json({ results: [{ id: '99999', key: 'OTHER', name: 'Other space' }] }) + ) + .mockResolvedValueOnce(Response.json({ results: [] })) + + await expect( + confluenceSelectorAttachments['confluence.spaces'].execute(spaceDetailArgs()) + ).resolves.toEqual({ kind: 'detail', item: null }) + expect(mockFetch).toHaveBeenCalledTimes(2) + }) + + it('sanitizes an arbitrary partial lookup failure rather than reporting the key missing', async () => { + const fetchProviderJson = vi + .spyOn(providerHttp, 'fetchProviderJson') + .mockRejectedValueOnce(new Error('raw provider failure')) + .mockResolvedValueOnce({ results: [] }) + + try { + await expect( + confluenceSelectorAttachments['confluence.spaces'].execute(spaceDetailArgs()) + ).rejects.toMatchObject({ + name: 'SelectorOptionsUnavailableError', + message: 'Options unavailable', + status: 502, + }) + } finally { + fetchProviderJson.mockRestore() + } + }) + it('preserves the first safe provider failure when both space detail requests fail', async () => { mockFetch .mockResolvedValueOnce(new Response(null, { status: 401 })) diff --git a/apps/sim/lib/selectors/server/providers/confluence.ts b/apps/sim/lib/selectors/server/providers/confluence.ts index 69b5b4c05de..dfaee7bfb51 100644 --- a/apps/sim/lib/selectors/server/providers/confluence.ts +++ b/apps/sim/lib/selectors/server/providers/confluence.ts @@ -162,12 +162,6 @@ async function executeSpaces(args: ExecuteServerSelectorArgs, identifier: 'key' requestSpaces({ ...auth, params: paramsFor('archived'), signal: args.signal }), ]) args.signal?.throwIfAborted() - if (current.status === 'rejected' && archived.status === 'rejected') { - for (const result of [current, archived]) { - if (isPublicSelectorError(result.reason)) throw result.reason - } - throw new SelectorOptionsUnavailableError() - } const spaces = [ ...(current.status === 'fulfilled' ? (current.value.results ?? []).map((space) => ({ space, status: 'current' as const })) @@ -177,6 +171,14 @@ async function executeSpaces(args: ExecuteServerSelectorArgs, identifier: 'key' : []), ] const match = spaces.find(({ space }) => space.key === key) + if (!match && (current.status === 'rejected' || archived.status === 'rejected')) { + for (const result of [current, archived]) { + if (result.status === 'rejected' && isPublicSelectorError(result.reason)) { + throw result.reason + } + } + throw new SelectorOptionsUnavailableError() + } return detailSelectorResult( match ? { From f2077f9854ecda248dd6ff2e035a952fa70127aa Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 10 Sep 2026 13:50:22 -0700 Subject: [PATCH 4/5] fix(search): remove redundant source account banner --- .../sources/[connectorId]/source-detail.test.tsx | 16 ---------------- .../sources/[connectorId]/source-detail.tsx | 9 --------- 2 files changed, 25 deletions(-) diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.test.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.test.tsx index fd1fc7944d9..e1753c414f5 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.test.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.test.tsx @@ -205,22 +205,6 @@ describe('organization source detail navigation', () => { ) }) - it.each(['members', 'admin'] as const)( - 'links member sources to personal Search connections: %s', - async (accessMode) => { - mocks.detail.mockReturnValue({ data: { ...connector, accessMode } }) - await render() - const link = container.querySelector('a[aria-label="Manage your Search accounts"]') - if (accessMode === 'members') { - expect(link).toHaveAttribute('href', '/o/org-one/integrations') - expect(container.textContent).toContain( - 'Each person connects from Integrations to sync content they can access.' - ) - } else { - expect(link).toBeNull() - } - } - ) it('restores document search and status from the shared URL', async () => { await render('?search=notes&document-filter=excluded') expect(mocks.documents).toHaveBeenLastCalledWith( diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx index 1439c907041..648ca14f1f6 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx @@ -241,15 +241,6 @@ function SourceDetailContent({ description='Its content is unavailable in Search, Assistant, and MCP.' /> )} - {connector.accessMode === 'members' && ( - - )} ) if (view === 'settings') From 1af4667ed058af7da55bdeee76b45a45e739fe1f Mon Sep 17 00:00:00 2001 From: Waleed Latif Date: Thu, 10 Sep 2026 16:05:25 -0700 Subject: [PATCH 5/5] feat(search): unify source setup and organization usage --- apps/docs/content/docs/search/confluence.mdx | 22 +- .../docs/search/connect-your-account.mdx | 8 +- apps/docs/content/docs/search/github.mdx | 20 +- apps/docs/content/docs/search/gitlab.mdx | 10 +- apps/docs/content/docs/search/gmail.mdx | 24 +- .../content/docs/search/google-calendar.mdx | 22 +- .../docs/content/docs/search/google-drive.mdx | 26 +- apps/docs/content/docs/search/index.mdx | 46 +- apps/docs/content/docs/search/jira.mdx | 22 +- apps/docs/content/docs/search/slack.mdx | 12 +- .../search/confluence-personal-setup.png | Bin 68304 -> 68053 bytes .../static/search/github-indexing-options.jpg | Bin 17946 -> 0 bytes .../public/static/search/github-setup.jpg | Bin 31061 -> 0 bytes .../public/static/search/gitlab-options.jpg | Bin 47941 -> 0 bytes .../public/static/search/gitlab-setup.jpg | Bin 35088 -> 0 bytes .../static/search/google-drive-setup.jpg | Bin 22911 -> 0 bytes .../static/search/google-drive-setup.png | Bin 0 -> 59707 bytes .../static/search/integration-provider.jpg | Bin 21510 -> 0 bytes .../static/search/integration-provider.png | Bin 0 -> 37791 bytes .../static/search/integration-settings.jpg | Bin 32832 -> 0 bytes .../static/search/integration-settings.png | Bin 0 -> 118870 bytes .../static/search/jira-personal-setup.png | Bin 66883 -> 66834 bytes .../public/static/search/source-settings.jpg | Bin 37543 -> 0 bytes .../api/knowledge/sim-search/stats/route.ts | 24 + .../add-organization-source-modal.tsx | 106 + ...rganization-integrations-settings.test.tsx | 166 +- .../organization-integrations-settings.tsx | 94 +- .../organization-integrations-setup.test.tsx | 351 +- .../organization-integrations-setup.tsx | 260 +- .../organization-search-stats-period.test.tsx | 127 + .../organization-search-stats-period.tsx | 89 + .../organization-search-status.test.ts | 6 +- .../organization-search-status.ts | 6 +- .../organization-source-people.tsx | 79 + .../organization-source-stats.test.tsx | 152 + .../organization-source-stats.tsx | 227 + .../components/integrations/search-params.ts | 17 +- .../integrations/slack-account-removal.tsx | 4 +- .../integrations/slack-account-setup.test.tsx | 53 +- .../integrations/slack-account-setup.tsx | 39 +- .../providers/[connectorType]/page.test.tsx | 146 +- .../providers/[connectorType]/page.tsx | 28 +- .../[connectorType]/provider-detail.test.tsx | 262 +- .../[connectorType]/provider-detail.tsx | 180 +- .../[connectorId]/source-detail.test.tsx | 24 +- .../sources/[connectorId]/source-detail.tsx | 28 +- .../add-connector-modal.test.tsx | 63 +- .../add-connector-modal.tsx | 48 +- .../connector-access-field.test.tsx | 2 +- .../connector-access-field.tsx | 2 +- .../connector-selector-field.queries.test.tsx | 79 +- .../connector-selector-field.test.tsx | 14 +- .../connector-selector-field.tsx | 81 +- .../connector-selector-field.ui.test.tsx | 179 + .../connectors-section/connector-actions.tsx | 6 +- .../connector-settings-fields.test.tsx | 2 +- .../connector-settings-fields.tsx | 16 +- .../components/search-source-pagination.tsx | 2 +- .../components/search-source-setup.test.tsx | 140 +- .../search/components/search-source-setup.tsx | 26 +- apps/sim/components/charts/bar-chart.tsx | 7 +- apps/sim/components/charts/chart-format.ts | 7 +- .../components/charts/chart-geometry.test.ts | 6 + apps/sim/components/charts/chart-geometry.ts | 13 +- .../components/charts/chart-layout.test.tsx | 21 + apps/sim/connectors/confluence/meta.ts | 2 +- apps/sim/connectors/jira/meta.ts | 2 +- .../organization-account-people.tsx | 37 +- .../organization-person-connections.tsx | 86 + .../components/slack-managed-users-modal.tsx | 2 +- .../search-params.ts | 22 + .../queries/organization-accounts.test.tsx | 86 + .../hooks/queries/organization-accounts.ts | 7 +- .../queries/organization-search-stats.ts | 28 + .../api/contracts/knowledge/search-stats.ts | 76 + .../lib/copilot/request/lifecycle/run.test.ts | 29 + apps/sim/lib/copilot/request/lifecycle/run.ts | 3 + apps/sim/lib/copilot/tool-executor/types.ts | 2 + .../registry/server-tool-adapter.test.ts | 20 + .../tools/registry/server-tool-adapter.ts | 1 + .../sim/lib/copilot/tools/server/base-tool.ts | 2 + .../server/knowledge/knowledge-base.test.ts | 16 + .../tools/server/knowledge/knowledge-base.ts | 2 +- .../server/knowledge/workspace-search.test.ts | 25 + .../server/knowledge/workspace-search.ts | 2 +- apps/sim/lib/credential-groups/service.ts | 2 +- .../knowledge/application/operations.test.ts | 1 + .../lib/knowledge/application/operations.ts | 9 + .../organization-search-stats.test.ts | 82 + .../application/organization-search-stats.ts | 21 + .../lib/knowledge/application/search.test.ts | 23 + apps/sim/lib/knowledge/application/search.ts | 12 +- .../slack-search/assistant.test.ts | 1 + .../application/slack-search/assistant.ts | 1 + .../workspace-search.activity.test.ts | 144 + .../knowledge/application/workspace-search.ts | 38 +- .../lib/knowledge/search/activity-stats.ts | 100 + .../sim/lib/knowledge/search/activity.test.ts | 98 + apps/sim/lib/knowledge/search/activity.ts | 38 + apps/sim/lib/knowledge/search/stats.test.ts | 97 + apps/sim/lib/knowledge/search/stats.ts | 74 + apps/sim/lib/sim-search/connection-labels.ts | 71 + .../0338_organization_search_activity.sql | 16 + .../db/migrations/meta/0338_snapshot.json | 26162 ++++++++++++++++ packages/db/migrations/meta/_journal.json | 7 + packages/db/schema.ts | 31 + .../emcn/src/components/combobox/combobox.tsx | 20 +- packages/testing/src/mocks/schema.mock.ts | 9 + 108 files changed, 29771 insertions(+), 1130 deletions(-) delete mode 100644 apps/docs/public/static/search/github-indexing-options.jpg delete mode 100644 apps/docs/public/static/search/github-setup.jpg delete mode 100644 apps/docs/public/static/search/gitlab-options.jpg delete mode 100644 apps/docs/public/static/search/gitlab-setup.jpg delete mode 100644 apps/docs/public/static/search/google-drive-setup.jpg create mode 100644 apps/docs/public/static/search/google-drive-setup.png delete mode 100644 apps/docs/public/static/search/integration-provider.jpg create mode 100644 apps/docs/public/static/search/integration-provider.png delete mode 100644 apps/docs/public/static/search/integration-settings.jpg create mode 100644 apps/docs/public/static/search/integration-settings.png delete mode 100644 apps/docs/public/static/search/source-settings.jpg create mode 100644 apps/sim/app/api/knowledge/sim-search/stats/route.ts create mode 100644 apps/sim/app/o/[organizationId]/settings/components/integrations/add-organization-source-modal.tsx create mode 100644 apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.test.tsx create mode 100644 apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.tsx create mode 100644 apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-people.tsx create mode 100644 apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.test.tsx create mode 100644 apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.tsx create mode 100644 apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.ui.test.tsx create mode 100644 apps/sim/ee/credential-groups/components/organization-person-connections.tsx create mode 100644 apps/sim/ee/organization-search-stats/search-params.ts create mode 100644 apps/sim/hooks/queries/organization-search-stats.ts create mode 100644 apps/sim/lib/api/contracts/knowledge/search-stats.ts create mode 100644 apps/sim/lib/knowledge/application/organization-search-stats.test.ts create mode 100644 apps/sim/lib/knowledge/application/organization-search-stats.ts create mode 100644 apps/sim/lib/knowledge/application/workspace-search.activity.test.ts create mode 100644 apps/sim/lib/knowledge/search/activity-stats.ts create mode 100644 apps/sim/lib/knowledge/search/activity.test.ts create mode 100644 apps/sim/lib/knowledge/search/activity.ts create mode 100644 apps/sim/lib/knowledge/search/stats.test.ts create mode 100644 apps/sim/lib/knowledge/search/stats.ts create mode 100644 apps/sim/lib/sim-search/connection-labels.ts create mode 100644 packages/db/migrations/0338_organization_search_activity.sql create mode 100644 packages/db/migrations/meta/0338_snapshot.json diff --git a/apps/docs/content/docs/search/confluence.mdx b/apps/docs/content/docs/search/confluence.mdx index d332940b739..8943a97d197 100644 --- a/apps/docs/content/docs/search/confluence.mdx +++ b/apps/docs/content/docs/search/confluence.mdx @@ -31,14 +31,14 @@ Teammates authorize Sim's shared Confluence app, which also requests workflow pe ### Choose Confluence -Open your organization's **Settings → Sources**, turn on **Confluence**, then select **Set up** (or **Manage**) → **Add source**. This opens service-account setup. +Open **Settings → Sources → Add source** and select **Confluence**. This opens **Connect Confluence site** with service-account authentication. To connect another site later, open **Confluence** from the Sources list and select **Add Confluence site**. ### Choose the account and spaces -Under **Indexing account**, select a service account or [add one](#using-a-service-account). Enter the same **Confluence Domain** as the credential, then choose **Spaces**. **Select all** selects every space the account can currently browse; newly created spaces are not added automatically. Clear the picker search before selecting all. +Under **Service account**, select a service account or [add one](#using-a-service-account). Enter the same **Confluence site** as the credential, then choose **Spaces**. **All** in the dropdown selects every space the account can currently browse; newly created spaces are not added automatically. Clear the picker search before selecting all. To enter comma-separated keys such as `ENG, PRODUCT`, use the switch beside **Spaces**. Switching between the picker and manual entry keeps your selection. @@ -65,17 +65,17 @@ After an admin allows Confluence, open **Integrations → Connect**. For an exis If no source exists, or you choose **Connect a different site or content scope**: 1. Under **Your account**, select a saved account or choose **Connect account**. Authorize using the Atlassian email matching your verified Sim email. -2. Enter the hostname under **Atlassian site**, then choose **Spaces**. Use **Select all** for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 spaces in this form. +2. Enter the hostname under **Atlassian site**, then choose **Spaces**. Use **All** in the dropdown for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 spaces in this form. 3. Select **Connect & Sync**. Sim saves the selected scope and starts indexing with your account. Confluence personal source setup with a saved account, Atlassian site, and selected spaces -Admins manage these sources under **Settings → Sources → Confluence → Manage**. In **Add source**, an **Account for browsing** populates the space picker; a saved personal Search account can be reused here. Choosing a browsing account does not enroll it for Search. Manual space keys work without a browsing account. +Admins manage these sources under **Settings → Sources → Confluence**. When configuring a member-account connection, an **Account for browsing** populates the space picker; a saved personal Search account can be reused here. Choosing a browsing account does not enroll it for Search. Manual space keys work without a browsing account. ## Using a service account @@ -103,7 +103,7 @@ read:group:confluence Use all 12 scopes for account validation, pickers, content, permissions, and directory reads. Central indexing does not need write scopes. 4. Review and create the token, then copy it. Atlassian shows it only once. -5. In Sim's source form, use **Indexing account** to add a service account. Paste the **API token**, enter **Site domain** (hostname only), and select **Add service account**. Continue in the source form with the same domain. +5. In Sim's source form, use **Service account** to add a service account. Paste the **API token**, enter **Site domain** (hostname only), and select **Add service account**. Continue in the source form with the same domain. -See Atlassian's [account setup](https://support.atlassian.com/user-management/docs/manage-your-service-accounts/) and [token instructions](https://support.atlassian.com/user-management/docs/manage-api-tokens-for-service-accounts/). Scopes do not grant space or page access. To replace an expiring token or change scopes, add a new credential in the source's **Settings**, select **Change indexing account**, and verify a sync before revoking the old token. +See Atlassian's [account setup](https://support.atlassian.com/user-management/docs/manage-your-service-accounts/) and [token instructions](https://support.atlassian.com/user-management/docs/manage-api-tokens-for-service-accounts/). Scopes do not grant space or page access. To replace an expiring token or change scopes, add a new credential in the source's **Settings**, select **Change service account**, and verify a sync before revoking the old token. ## Configuration and indexed content | Setting | What it controls | | --- | --- | -| **Confluence Domain** | Cloud hostname only, such as `your-team.atlassian.net`; omit page URLs and `/wiki`. | +| **Confluence site** | Cloud hostname only, such as `your-team.atlassian.net`; omit page URLs and `/wiki`. | | **Spaces / Space Keys** | Required spaces. The picker and manual input set the same scope. | | **Content Type** | **Pages only** (default), **Blog posts only**, or **All content** for both. | | **Filter by Label** | Optional comma-separated labels; content can match any listed label. | @@ -130,7 +130,7 @@ Search manages the schedule and hides item limits. It indexes published/current Central sources combine space permissions, page and ancestor restrictions, and group membership. Before returning central content, Sim uses your personal connection to check that you still have access to the configured Confluence site. If Atlassian cannot confirm that access, the content is hidden. Member sources use each person's provider listing. Sim admin status does not grant access to all pages, and permission changes take effect after syncing and processing. -Open **Settings → Sources → Confluence → Manage**, then a source's **Documents**, **Settings**, or **Sync history**. Invite teammates through **Settings → Members → Invite** or SSO, then have them connect through **Integrations**. **Accounts → Request connections** only requests a provider connection; it does not invite people to the organization. +Open **Settings → Sources → Confluence**, then a source's **Documents**, **Settings**, or **Sync history**. Invite teammates through **Settings → Members → Invite** or SSO, then have them connect through **Integrations**. **People → Request connections** only requests a provider connection; it does not invite people to the organization. ## Troubleshooting @@ -155,6 +155,6 @@ Configure one shared Confluence OAuth app for teammates' connections: 2. Under **Authorization → OAuth 2.0 (3LO)**, add `https:///api/auth/oauth2/callback/confluence` as a callback. 3. Under **Permissions**, add the Confluence API and its full `confluence` scope list from [Sim's OAuth configuration](https://github.com/simstudioai/sim/blob/staging/apps/sim/lib/oauth/oauth.ts), including `read:group:confluence`. Add **User Identity API → read:me**. Sim requests `offline_access` for refresh tokens; the service-account list above does not replace this shared OAuth scope set. 4. Enable sharing under **Distribution**. Set `CONFLUENCE_CLIENT_ID` and `CONFLUENCE_CLIENT_SECRET` from the app's **Settings**, verify `NEXT_PUBLIC_APP_URL`, and restart Sim. -5. Connect from **Integrations** and select the configured site. After changing the OAuth client or requested scopes, use **Settings → Sources → More → Refresh connection settings**, then have affected teammates reconnect. +5. Connect from **Integrations** and select the configured site. After changing the OAuth client or requested scopes, use **Settings → Sources → More → Update sign-in settings**, then have affected teammates reconnect. The callback must match Sim's scheme, hostname, port, and path exactly. If only the app owner can connect, check **Distribution**. See the [Atlassian OAuth guide](https://developer.atlassian.com/cloud/confluence/oauth-2-3lo-apps/) and [Sim deployment reference](/platform/self-hosting/integrations-oauth). diff --git a/apps/docs/content/docs/search/connect-your-account.mdx b/apps/docs/content/docs/search/connect-your-account.mdx index 7b031e1cf82..bfe41deae8f 100644 --- a/apps/docs/content/docs/search/connect-your-account.mdx +++ b/apps/docs/content/docs/search/connect-your-account.mdx @@ -23,7 +23,7 @@ For a central Google source, use your primary Workspace email and open **Search* ## Open Integrations -Open **Integrations** in the main sidebar, find the provider or source, and select **Connect**. Your first connection may ask for a GitHub repository, Confluence domain and space keys, or Jira domain and project keys. Enter the required fields and select **Connect**. If the provider is missing, ask an organization admin to turn it on under **Settings → Sources**. +Open **Integrations** in the main sidebar, find the provider or source, and select **Connect**. First-time setup can also ask which content to index. For [Confluence](/search/confluence) and [Jira](/search/jira), connect your Atlassian account first, then choose the site and spaces or projects and select **Connect & Sync**. [GitHub](/search/github) asks for a repository. If the provider is missing, ask an organization admin to add it under **Settings → Sources → Add source**. To connect another supported repository, site, or project scope, find the provider row labeled **Connect a different site or content scope** and select **Connect**. Connecting an existing source does not ask you to configure it again. @@ -36,7 +36,7 @@ To connect another supported repository, site, or project scope, find the provid Complete the provider's authorization in the new tab. Choose the account associated with your verified Sim email. The provider may require your organization's SSO or app approval. -The authorization tab closes when the connection completes and Integrations updates. If the tab stays open, return to Integrations. Your account is saved when authorization completes; there is no separate submit step. If the popup was blocked or closed, allow popups and select **Connect** again. While authorization is pending, use **Open again**. +The authorization tab closes when the connection completes and Integrations updates. If the tab stays open, return to Integrations. For an existing source, your account is saved when authorization completes. For first-time Atlassian setup, return to the form, choose your content, and select **Connect & Sync**. If the popup was blocked or closed, allow popups and select **Connect** again. While authorization is pending, use **Open again**. @@ -74,7 +74,7 @@ An account connection request does not invite you into the Sim organization. You On the main **Integrations** page, use **Reconnect** beside an expired connection to renew it. To withdraw an account, open its row's actions menu and select **Disconnect**, then confirm. If several accounts are connected, choose the account to disconnect. Disconnecting stops that account from being used for organization indexing and workflows, and removes Search access that depends on it. -Admins manage setup from **Settings → Sources**. Select **Manage** beside the integration. Providers with personal connections have **Accounts** and a source list under **Advanced** (Google) or **Sources**. Without personal connections, the source list opens directly. This does not grant the admin access to every document. +Admins manage setup from **Settings → Sources**. Open an integration, then its connection to see **Documents**, **Settings**, and **Sync history**. **People** shows account contributors across integrations and supports filtering by integration. This does not grant the admin access to every document. ## If you get stuck @@ -87,7 +87,7 @@ Admins manage setup from **Settings → Sources**. Select **Manage** beside the | **Verify email** | Verify your Sim email to return to the connection page. Reopen the original link if you are not redirected. | | Expired or cancelled authorization | Return to the original connection page and start again. If the invitation itself expired, ask the admin for a new request. | | Access revoked | Ask the organization admin to restore your account contribution access before reconnecting. | -| Needs admin attention | Ask your admin to open **Settings → Sources**, select **Manage** beside the integration, and open its source or sync configuration to inspect the error. | +| Needs admin attention | Ask your admin to open **Settings → Sources**, select the integration, and open its connection to inspect the error. | Your Sim role does not override document access at the source. Connecting a different account or receiving a Search link does not share someone else's mailbox, private calendar, or restricted documents with you. diff --git a/apps/docs/content/docs/search/github.mdx b/apps/docs/content/docs/search/github.mdx index 9a69063e165..8c3da90651a 100644 --- a/apps/docs/content/docs/search/github.mdx +++ b/apps/docs/content/docs/search/github.mdx @@ -9,7 +9,7 @@ import { Image } from '@/components/ui/image' GitHub Search indexes text files from repositories on `github.com`. An organization admin can install the GitHub App once and use it to index selected repositories. Each person connects their own GitHub account once to search the repositories they can access. Installing the App does not connect teammates or give them the installer's permissions. -Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. Installation indexing is available for organization Search. For workspace Search, use **Search → Add source** with member accounts or a dedicated user account; **Create & Invite** is the workspace equivalent of **Add source**. +Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. Installation indexing is available for organization Search. For workspace Search, use **Search → Add source** with member accounts or a dedicated user account. ## Before you start @@ -26,7 +26,7 @@ To connect an installation for central indexing, you must be a Sim organization ### Open GitHub setup -Open **Settings → Sources** and turn on **GitHub**. Select **Set up** (or **Manage** if sources already exist), then **Add source**. +Open **Settings → Sources → Add source** and select **GitHub**. This opens **Add GitHub repository**. Add one repository per connection; to add another, open **GitHub** from the Sources list and select **Add repository**. @@ -35,8 +35,6 @@ Open **Settings → Sources** and turn on **GitHub**. Select **Set up** (or **Ma In **Sync documents with**, choose **Connect GitHub App** to index through an installation: -GitHub source setup with indexing choices for connected members, a GitHub account, or a GitHub App - 1. Select **Connect your GitHub account** if prompted. Finish authorization in the new tab, then return and select **Refresh**. Connect GitHub App dialog requiring a personal GitHub connection to verify manageable installations @@ -55,20 +53,18 @@ Alternatively, leave **Connected members** selected to use members' accounts for ### Choose what to index -Enter **Repository** as `owner/repo`. For installation indexing, it must belong to the installation's account and be included in the repositories granted to the App. Add one source per repository; installing on all repositories does not automatically create sources for them. +Enter **Repository** as `owner/repo`. For installation indexing, it must belong to the installation's account and be included in the repositories granted to the App. Add one connection per repository; installing on all repositories does not automatically add them to Search. Open **More options** if you need a different branch, path or extension filters, or metadata tags. -GitHub repository configuration with branch, path filter, file extensions, and metadata tags - | Field | What to enter | |---|---| -| Repository | `owner/repo`. Add another source for another repository. | +| Repository | `owner/repo`. Use **Add repository** for another repository. | | Branch | Optional. Leave blank to follow the repository's default branch. | | Path Filter | Optional prefix such as `docs/`. | | File Extensions | Optional comma-separated list, such as `.md, .txt, .mdx`. | -**Metadata tags** controls the metadata stored with results. Its defaults are suitable for most sources. Select **Add source** to save the source. +**Metadata tags** controls the metadata stored with results. Its defaults are suitable for most sources. Select **Add repository** to save the connection. @@ -79,9 +75,9 @@ Open **Integrations** in the main sidebar, select **Connect** on the GitHub sour An App installation or dedicated indexing account can start syncing after the source is saved. With **Connected members**, indexing begins after someone connects. Each teammate still connects before searching. An existing GitHub connection in the same Sim organization is reused across its GitHub sources. -Open **Settings → Sources**, select **Manage** beside **GitHub**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. +Open **Settings → Sources**, open **GitHub**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. -Use **GitHub → Accounts → Request connections** to send provider-specific connection requests. These requests do not grant organization membership. For another repository, add another source; members can also select **Connect** beside the GitHub row labeled **Connect a different site or content scope** in Integrations. +Use **Settings → Sources → People**, filter by **GitHub**, then select **Request connections** to send provider-specific connection requests. These requests do not grant organization membership. For another repository, add another source; members can also select **Connect** beside the GitHub row labeled **Connect a different site or content scope** in Integrations. @@ -106,7 +102,7 @@ This is an installation plus personal authorization flow. GitHub Search does not | Identity verification fails | Verify the email used by your Sim account in GitHub's email settings, then reconnect. A public profile email alone is insufficient. | | Authorization fails after installation | Return to Sim and start **Connect** there. Do not enable authorization during installation. | | Account authorization did not complete | Start the connection again from Sim. If it repeats, contact your organization admin or Sim support. For self-hosted Sim, check the [App callback and credentials](/platform/self-hosting/integrations-oauth#github-search). | -| GitHub asks for a provider configuration update | An organization admin selects **Settings → Sources → More → Refresh connection settings**, then affected users reconnect GitHub. | +| GitHub asks for a provider configuration update | An organization admin selects **Settings → Sources → More → Update sign-in settings**, then affected users reconnect GitHub. | | Indexed files no longer appear | Confirm your own repository access, App repository selection, and connection status. Installation-indexed content is also withheld when GitHub cannot verify current access; retry once GitHub is available. | | Sync is incomplete | Review the source status. Very large Git trees, file size limits, and unreadable files can limit indexing. | | Empty repository returns an error | Add an initial commit, then sync again. GitHub does not return a file tree for an uninitialized repository. | diff --git a/apps/docs/content/docs/search/gitlab.mdx b/apps/docs/content/docs/search/gitlab.mdx index 39fb464de65..45f91816db9 100644 --- a/apps/docs/content/docs/search/gitlab.mdx +++ b/apps/docs/content/docs/search/gitlab.mdx @@ -9,8 +9,6 @@ import { Image } from '@/components/ui/image' GitLab Search uses an administrator connection to sync a project's content and permissions. Teammates do not connect individual GitLab accounts. They sign in to the Sim organization with a verified email matching their confirmed primary GitLab email. -GitLab source setup in Sim Search - Admin setup uses your organization's **Settings → Sources** page. Teammates do not need a personal GitLab connection. For workspace Search, use **Search → Add source** instead. ## Before you start @@ -49,12 +47,12 @@ The token must read the project, users, inherited project membership, instance s ### Configure the source in Sim -Open **Settings → Sources** and turn on **GitLab**. Select **Set up** (or **Manage** if sources already exist), then **Add source**. Paste the **Personal Access Token**, enter your **Host** and **Project**, and choose the content to index. +Open **Settings → Sources → Add source** and select **GitLab**. This opens **Add GitLab project**. Add one project per connection; to add another, open **GitLab** from the Sources list and select **Add project**. Paste the **Personal Access Token**, enter your **Host** and **Project**, and choose the content to index. | Field | What to enter | |---|---| | Host | Your self-managed domain, such as `gitlab.example.com`. | -| Project | `group/project` or the numeric project ID. Add another source for another project. | +| Project | `group/project` or the numeric project ID. Use **Add project** for another project. | | Content | Defaults to **Wiki & Issues**. Choose **Code, Wiki, Issues & Merge Requests** to include all supported types. | | Branch | Optional branch or tag for repository files; blank uses the project's default branch. | | Path Filter / File Extensions | Optional limits for repository files. | @@ -63,8 +61,6 @@ Open **Settings → Sources** and turn on **GitLab**. Select **Set up** (or **Ma **More options** contains the repository and issue filters, **Max Items**, and **Metadata tags**. Unlike member-account sources, GitLab retains this optional item limit. -GitLab source setup with More options expanded for repository and issue filters, item limit, and metadata tags - Select **Connect & Sync**. Sim validates the token and source policy, then starts indexing. @@ -74,7 +70,7 @@ Select **Connect & Sync**. Sim validates the token and source policy, then start Invite teammates to the Sim organization using their verified work email. Sim matches that email against their confirmed primary GitLab email and applies project, feature, and confidential-issue permissions. Confirmed secondary addresses are not matched. No GitLab **Connect** step is required. -Admins open **Settings → Sources**, select **Manage** beside **GitLab**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. GitLab has no personal **Accounts** tab. Permission and membership changes are picked up during background refreshes. +Admins open **Settings → Sources**, open **GitLab**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. Permission and membership changes are picked up during background refreshes. diff --git a/apps/docs/content/docs/search/gmail.mdx b/apps/docs/content/docs/search/gmail.mdx index b4ce9e2e53f..990e806d51f 100644 --- a/apps/docs/content/docs/search/gmail.mdx +++ b/apps/docs/content/docs/search/gmail.mdx @@ -9,7 +9,7 @@ import { Image } from '@/components/ui/image' Search email threads from your Gmail account. Members can connect their own accounts, or an administrator can index Google Workspace mailboxes with a service account. In either case, each mailbox stays private to its owner. -Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. For workspace Search, use **Search → Add source** instead; **Create & Invite** is the workspace equivalent of **Add source**. +Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. For workspace Search, use **Search → Add source** instead. ## Choose your setup @@ -29,34 +29,34 @@ Central indexing does not make email searchable by the administrator, other reci ### Allow Gmail -Open **Settings → Sources** and turn on **Gmail**. This allows personal connections; it does not connect anyone's account. +An admin selects **Settings → Sources → Add source → Gmail**, chooses **Sync using → Member accounts**, sets any filters, and selects **Set up member accounts**. ### Connect your account -Join the Sim organization, then open **Integrations** and select **Connect** beside Gmail. Authorize the Google account matching your verified Sim email. The first connection creates the default sync configuration: the last 6 months across all labels, excluding Promotions, Social, Spam, and Trash. Return to Integrations to see indexing status and your searchable document count. +Join the Sim organization, then open **Integrations** and select **Connect** beside Gmail. Authorize the Google account matching your verified Sim email. The default filters cover the last 6 months across all labels, excluding Promotions, Social, Spam, and Trash. Return to Integrations to see indexing status and your searchable document count. ### Adjust filters if needed -An admin selects **Manage** beside Gmail in **Settings → Sources**, opens **Advanced**, then selects the configuration's **Settings** tab. Change **Labels**, **Date Range**, or other filters and save. +An admin opens **Settings → Sources → Gmail**, selects the connection, then selects the connection's **Settings** tab. Change **Labels**, **Date Range**, or other filters and save. -One member-account configuration is usually enough. Its filters apply to all active Gmail connections, including accounts connected later. It does not assign different filters to selected people or let teammates search each other's mail. **Add sync configuration** opens the [central service-account setup](#set-up-a-central-service-account); it does not edit this member configuration. +One member-account connection is usually enough. Its filters apply to all active Gmail connections, including accounts connected later. It does not assign different filters to selected people or let teammates search each other's mail. **Connect service account** opens the [central service-account setup](#set-up-a-central-service-account); it does not edit this member connection. -Configurations are additive: a narrower one does not restrict an existing broader one, and overlapping configurations can index the same thread more than once. For one organization-wide policy, edit the existing configuration. +Connections are additive: a narrower one does not restrict an existing broader one, and overlapping connections can index the same thread more than once. For one organization-wide policy, edit the existing connection. -Admins can request member connections from **Manage → Accounts → Request connections**. These requests do not invite recipients to the Sim organization. See [Connect your account](/search/connect-your-account) for the shared connection and recovery steps. +Admins can request member connections from **Settings → Sources → People → Request connections** (filter by the integration first). These requests do not invite recipients to the Sim organization. See [Connect your account](/search/connect-your-account) for the shared connection and recovery steps. ## Set up a central service account -Open **Settings → Sources**, enable **Gmail**, and select **Manage → Advanced → Add sync configuration**. If personal connections are disabled for your organization, select **Add source** from the provider page instead. +Open **Settings → Sources → Add source** and select **Gmail**. This opens **Connect Gmail service account**. To add another connection later, open **Gmail** from the Sources list and select **Connect service account**. This requires Google Workspace and a Workspace super administrator to authorize delegation. Consumer Gmail accounts cannot use this path. Each selected user must have Gmail enabled. @@ -91,7 +91,7 @@ If your organization requires multi-party approval, another super administrator ### Configure Gmail in Sim -Under **Indexing account**, select **Add service account** and paste the JSON key into **Add Google Service Account**, or select an existing service account. Set **Directory administrator email** to an active Workspace administrator who can read users in the Directory API. This account supplies directory access; each mailbox is read using that mailbox owner's delegated identity. +Under **Service account**, select **Add service account** and paste the JSON key into **Add Google Service Account**, or select an existing service account. Set **Directory administrator email** to an active Workspace administrator who can read users in the Directory API. This account supplies directory access; each mailbox is read using that mailbox owner's delegated identity. Keep the default **Date Range** of **Last 6 months**, or adjust it and **Labels**. Use label names or system IDs such as `INBOX`; custom `Label_…` IDs are mailbox-specific. A label that does not exist in one mailbox simply matches no threads there. @@ -104,9 +104,9 @@ Teammates join the Sim organization with their matching verified primary email. ## Source options -An admin opens **Settings → Sources** and selects **Manage** beside **Gmail** to open its configuration list. Each row shows **Member accounts** or **Service account** beside its sync status. Open a configuration's **Settings** tab to edit its filters, then select **Save**. Filters apply separately to each mailbox in the source. **Documents** shows indexed threads and **Sync history** shows recent runs. +An admin opens **Settings → Sources → Gmail** to open its configuration list. Each row shows **Member accounts** or **Service account** beside its sync status. Open a connection's **Settings** tab to edit its filters, then select **Save**. Filters apply separately to each mailbox in the connection. **Documents** shows indexed threads and **Sync history** shows recent runs. -**Sync using** identifies the configuration's fixed connection method. To replace a central credential, choose another **Indexing account** and select **Change indexing account**. +**Sync using** identifies the configuration's fixed connection method. To replace a central credential, choose another **Service account** and select **Change service account**. | Option | Behavior | | --- | --- | @@ -155,7 +155,7 @@ Member-account connections use the deployment's Google OAuth client below. Centr 1. In [Google Cloud Console](https://console.cloud.google.com/), select your project. Open **APIs & Services → Library**, find **Gmail API**, and enable it. 2. Open **Google Auth platform → Branding**. Select **Get started** if needed, then enter the app name, support email, and contact email. Under **Audience**, use **Internal** only for an app limited to your Google Workspace organization; otherwise use **External** and add test users while testing. Review the app's permissions under **Data Access → Add or remove scopes**, using the current Sim scopes below. Follow Google's [consent and verification guidance](https://developers.google.com/workspace/guides/configure-oauth-consent) for your audience. 3. Open **Google Auth platform → Clients → Create client**. Choose **Web application**, give the client a name, and add the URI below under **Authorized redirect URIs**. If this instance already has a Google client, add this URI to that client instead. See [Google's credential setup](https://developers.google.com/workspace/guides/create-credentials#web-application). -4. Save the client ID and secret as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. Set `NEXT_PUBLIC_APP_URL` to the same Sim origin used in the callback, then restart Sim. See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). If you change an existing deployment's OAuth client or scopes, an organization admin selects **Settings → Sources → More → Refresh connection settings**, then affected teammates reconnect. +4. Save the client ID and secret as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. Set `NEXT_PUBLIC_APP_URL` to the same Sim origin used in the callback, then restart Sim. See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). If you change an existing deployment's OAuth client or scopes, an organization admin selects **Settings → Sources → More → Update sign-in settings**, then affected teammates reconnect. ```text https:///api/auth/oauth2/callback/google-email diff --git a/apps/docs/content/docs/search/google-calendar.mdx b/apps/docs/content/docs/search/google-calendar.mdx index 37f427a369e..e9ff7efbbf6 100644 --- a/apps/docs/content/docs/search/google-calendar.mdx +++ b/apps/docs/content/docs/search/google-calendar.mdx @@ -9,7 +9,7 @@ import { Image } from '@/components/ui/image' Search meetings and event details available to your Google account. Members can connect personal accounts, or a Google Workspace administrator can configure a central service-account crawl. Both paths keep each person's own view of events separate. -Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. For workspace Search, use **Search → Add source** instead; **Create & Invite** is the workspace equivalent of **Add source**. +Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. For workspace Search, use **Search → Add source** instead. ## Choose your setup @@ -29,28 +29,28 @@ These are alternative setup paths. When only a central Calendar source is config ### Allow and connect Google Calendar -An admin opens **Settings → Sources** and turns on **Google Calendar**. Each person joins the Sim organization, opens **Integrations**, selects **Connect** beside Google Calendar, and authorizes the Google account matching their verified Sim email. The first connection creates the default member-account sync configuration. Return to Integrations to see indexing status and your searchable document count. +An admin selects **Settings → Sources → Add source → Google Calendar**, chooses **Sync using → Member accounts**, sets any filters, and selects **Set up member accounts**. Each person joins the Sim organization, opens **Integrations**, selects **Connect** beside Google Calendar, and authorizes the Google account matching their verified Sim email. Return to Integrations to see indexing status and your searchable document count. ### Choose calendars if needed -An admin selects **Manage** beside Google Calendar in **Settings → Sources**, opens **Advanced**, and selects the configuration's **Settings** tab. Leave **Calendars** empty to search each person's primary calendar. To include specific shared calendars, select an **Account for browsing** and choose calendars, or switch to **Calendar IDs** and enter their IDs. +An admin opens **Settings → Sources → Google Calendar**, selects the connection, then opens **Settings**. Leave **Calendars** empty to search each person's primary calendar. To include specific shared calendars, select an **Account for browsing** and choose calendars, or switch to **Calendar IDs** and enter their IDs. **Account for browsing** only helps you choose calendars. It does not connect your account for Search or grant teammates access. -### Save the configuration +### Save the connection -The default date range covers the previous and next 30 days. Save any changes to the existing configuration. Its calendar and date filters apply separately to each connected member's access. **Add sync configuration** opens the [central service-account setup](#set-up-a-central-service-account); it does not edit this member configuration. +The default date range covers the previous and next 30 days. Save any changes to the existing connection. Its calendar and date filters apply separately to each connected member's access. **Connect service account** opens the [central service-account setup](#set-up-a-central-service-account); it does not edit this member connection. -Admins can request member connections from **Manage → Accounts → Request connections**. These requests do not grant organization membership. Connecting Gmail or Drive does not replace the Calendar connection. See [Connect your account](/search/connect-your-account) for the shared connection and recovery steps. +Admins can request member connections from **Settings → Sources → People → Request connections** (filter by the integration first). These requests do not grant organization membership. Connecting Gmail or Drive does not replace the Calendar connection. See [Connect your account](/search/connect-your-account) for the shared connection and recovery steps. `primary` means the connected or impersonated person's main calendar. A calendar selected from the list is a specific calendar ID, even when it is your main calendar. That same ID applies to every selected user, and only users with access to it can search its events. @@ -58,7 +58,7 @@ Admins can request member connections from **Manage → Accounts → Request con ## Set up a central service account -Open **Settings → Sources** and turn on **Google Calendar**. Select **Manage → Advanced → Add sync configuration** to open the central service-account form. If personal connections are disabled for your organization, select **Add source** from the provider page instead. +Open **Settings → Sources → Add source** and select **Google Calendar**. This opens **Connect Google Calendar service account**. To add another connection later, open **Google Calendar** from the Sources list and select **Connect service account**. This requires a Google Workspace customer and a super administrator to authorize domain-wide delegation. Consumer Gmail accounts cannot use this path. @@ -93,7 +93,7 @@ The **Directory administrator email** must be an active Workspace administrator ### Add the credential and choose users -Under **Indexing account**, select **Add service account** or an existing service account. In **Add Google Service Account**, give the credential a name and paste its JSON key. Back in the source form, enter the **Directory administrator email**. +Under **Service account**, select **Add service account** or an existing service account. In **Add Google Service Account**, give the credential a name and paste its JSON key. Back in the source form, enter the **Directory administrator email**. Leave **Calendar IDs** empty for each user's `primary` calendar. To include shared calendars, enter their IDs, optionally alongside `primary`. IDs apply to each selected user who can read that calendar; this does not share calendars or expand anyone's Google access. Central setup uses manual IDs because an administrator's calendar picker would not represent every user's calendars. @@ -106,9 +106,9 @@ Sim verifies Directory access and selected users, then probes one selected user' ## Source options -An admin opens **Settings → Sources** and selects **Manage** beside **Google Calendar** to open its configuration list. Each row shows **Member accounts** or **Service account** beside its sync status. Open a configuration's **Settings** tab to edit its filters, then select **Save**. **Documents** shows indexed events and **Sync history** shows recent runs. +An admin opens **Settings → Sources → Google Calendar** to open its configuration list. Each row shows **Member accounts** or **Service account** beside its sync status. Open a connection's **Settings** tab to edit its filters, then select **Save**. **Documents** shows indexed events and **Sync history** shows recent runs. -**Sync using** identifies the configuration's fixed connection method. To replace a central credential, choose another **Indexing account** and select **Change indexing account**. +**Sync using** identifies the configuration's fixed connection method. To replace a central credential, choose another **Service account** and select **Change service account**. | Option | Behavior | | --- | --- | @@ -153,7 +153,7 @@ The deployment operator configures Google OAuth for member accounts and the memb 1. In [Google Cloud Console](https://console.cloud.google.com/), select your project. Open **APIs & Services → Library**, find **Google Calendar API**, and enable it. 2. Open **Google Auth platform → Branding** and configure the app name and contact details. Under **Audience**, choose **Internal** for your Google Workspace organization only, or **External** for other users. Add test users while an external app is testing. Review **Data Access → Add or remove scopes** using the current Sim scopes below. See Google's [consent and verification guidance](https://developers.google.com/workspace/guides/configure-oauth-consent). 3. Open **Google Auth platform → Clients → Create client**, choose **Web application**, and add the URI below under **Authorized redirect URIs**. Add it to the existing Google client if the instance already uses one. See [Google's credential setup](https://developers.google.com/workspace/guides/create-credentials#web-application). -4. Save the client ID and secret as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. Set `NEXT_PUBLIC_APP_URL` to the same Sim origin used in the callback, then restart Sim. See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). If you change an existing deployment's OAuth client or scopes, an organization admin selects **Settings → Sources → More → Refresh connection settings**, then affected teammates reconnect. +4. Save the client ID and secret as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. Set `NEXT_PUBLIC_APP_URL` to the same Sim origin used in the callback, then restart Sim. See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). If you change an existing deployment's OAuth client or scopes, an organization admin selects **Settings → Sources → More → Update sign-in settings**, then affected teammates reconnect. ```text https:///api/auth/oauth2/callback/google-calendar diff --git a/apps/docs/content/docs/search/google-drive.mdx b/apps/docs/content/docs/search/google-drive.mdx index 52ecfc4864b..0ba9cb742a2 100644 --- a/apps/docs/content/docs/search/google-drive.mdx +++ b/apps/docs/content/docs/search/google-drive.mdx @@ -9,7 +9,7 @@ import { Image } from '@/components/ui/image' Search Google Docs, Sheets, Slides, and supported files in Drive. Members can connect their own accounts after an admin allows Google Drive, or an admin can configure a central service-account crawl. -Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. For workspace Search, use **Search → Add source** instead; **Create & Invite** is the workspace equivalent of **Add source**. +Admin setup uses your organization's **Settings → Sources** page. Teammates connect from **Integrations** in the main sidebar. For workspace Search, use **Search → Add source** instead. ## Choose your setup @@ -31,36 +31,36 @@ These are alternative setup paths. When only a central Drive source is configure ### Allow Google Drive -An organization admin opens **Settings → Sources** and turns on **Google Drive**. This allows personal connections; it does not create a source or connect anyone's account. +An admin selects **Settings → Sources → Add source → Google Drive**, chooses **Sync using → Member accounts**, sets any filters, and selects **Set up member accounts**. ### Connect your account -Join the Sim organization, then open **Integrations** and select **Connect** beside Google Drive. Use the Google account matching your verified Sim email. The first personal connection can create a source with default filters. Return to Integrations to see indexing status and your searchable document count. +Join the Sim organization, then open **Integrations** and select **Connect** beside Google Drive. Use the Google account matching your verified Sim email. Return to Integrations to see indexing status and your searchable document count. ### Adjust filters if needed -An admin opens **Settings → Sources**, selects **Manage** beside **Google Drive**, opens **Advanced**, and selects the sync configuration's **Settings** tab. Leave **Folders** empty to include supported files each member can access, or narrow the source to folders. **Account for browsing** helps select folders; manual **Folder IDs** work without it. Browsing does not connect that account to Search. +An admin opens **Settings → Sources → Google Drive**, selects the connection, then opens **Settings**. Leave **Folders** empty to include supported files each member can access, or narrow the source to folders. **Account for browsing** helps select folders; manual **Folder IDs** work without it. Browsing does not connect that account to Search. Keep **Sync documents with → Connected members** unless a dedicated account should fetch content. Members still connect to establish access. If the dedicated account is a delegated service account, **Crawl as** selects the Google Workspace user whose files it fetches. Save the source settings when finished. -Admins can request member connections from **Manage → Accounts → Request connections**. These requests do not grant organization membership. See [Connect your account](/search/connect-your-account) for the shared connection and recovery steps. +Admins can request member connections from **Settings → Sources → People → Request connections** (filter by the integration first). These requests do not grant organization membership. See [Connect your account](/search/connect-your-account) for the shared connection and recovery steps. ## Set up a central service account -Open **Settings → Sources** and turn on **Google Drive**. Select **Manage → Advanced → Add sync configuration** to open the central service-account form directly. If personal connections are disabled for your organization, select **Add source** from the provider page instead. Teammates do not need a personal Drive connection for this source. +Open **Settings → Sources → Add source** and select **Google Drive**. This opens **Connect Google Drive service account**. To add another connection later, open **Google Drive** from the Sources list and select **Connect service account**. This requires a Google Workspace domain and a Workspace super administrator to authorize domain-wide delegation. Consumer Gmail accounts cannot use this path. -Google Drive central source setup with a service account, Directory administrator email, sharing policy, and optional folders +Google Drive setup with member and service-account methods, account selection, and folders @@ -101,7 +101,7 @@ Group permissions require groups and memberships that this administrator can rea ### Add the credential in Sim -Under **Indexing account**, choose **Add service account**, or select an existing service account. Paste the JSON key into **Add Google Service Account**, give it a name, and add it. Sim returns you to the source form with that credential selected. +Under **Service account**, choose **Add service account**, or select an existing service account. Paste the JSON key into **Add Google Service Account**, give it a name, and add it. Sim returns you to the source form with that credential selected. Add Google Service Account credential modal in Sim @@ -112,7 +112,7 @@ Under **Indexing account**, choose **Add service account**, or select an existin Set **Directory administrator email** to the Workspace administrator described above. Under **More options**, leave **Users** blank for everyone, or enter up to 100 primary Workspace email addresses separated by commas. Suspended, archived, and guest accounts are excluded. -Leave **Folders** empty to include supported files each selected user can access. To narrow the source, select folders visible to the Directory administrator or enter **Folder IDs** manually. The same folder filter applies to each selected user and does not grant access. Choose **Connect & Sync**. Sim validates the administrator and any selected users, and probes Drive access for an active user, before accepting the source. +Leave **Folders** empty to include supported files each selected user can access. To narrow the source, select folders visible to the Directory administrator or enter **Folder IDs** manually. The same folder filter applies to each selected user and does not grant access. Choose **Connect & Sync**. Sim validates the administrator and any selected users, and probes Drive access for an active user, before accepting the connection. The crawl pages through each user’s files and shared drives, including shared-drive files the user has never opened. It resumes unfinished work and indexes a shared file once even when several users can access it. A file must be downloadable by at least one selected user to be indexed; the same requirement applies to a shortcut’s target. Sim must also verify its permissions before showing it in Search. Google can let a reader download a file while refusing to list its permissions; include an owner or another user who can read those permissions. Externally owned files can remain hidden when no selected user can verify their permissions. @@ -123,9 +123,9 @@ Teammates join the Sim organization with their matching verified email; they do ## Source options -An admin opens **Settings → Sources** and selects **Manage** beside **Google Drive** to open its configuration list. Each row shows **Member accounts** or **Service account** beside its sync status. Open a configuration's **Settings** tab to edit its filters, then select **Save**. **Documents** shows indexed files and **Sync history** shows recent runs. +An admin opens **Settings → Sources → Google Drive** to open its configuration list. Each row shows **Member accounts** or **Service account** beside its sync status. Open a connection's **Settings** tab to edit its filters, then select **Save**. **Documents** shows indexed files and **Sync history** shows recent runs. -**Sync using** identifies the configuration's fixed connection method. To replace a central credential, choose another **Indexing account** and select **Change indexing account**. +**Sync using** identifies the configuration's fixed connection method. To replace a central credential, choose another **Service account** and select **Change service account**. | Option | Behavior | | --- | --- | @@ -139,7 +139,7 @@ An admin opens **Settings → Sources** and selects **Manage** beside **Google D Sim exports Docs and Slides as text and Sheets as XLSX spreadsheets. Supported uploaded files use the knowledge-base document pipeline, including PDF and Office formats. Unsupported files and oversized exports cannot be indexed; Google limits Workspace exports to 10 MB. See [Drive export formats](https://developers.google.com/workspace/drive/api/guides/ref-export-formats) and [download limits](https://developers.google.com/workspace/drive/api/guides/manage-downloads). -Search schedules syncs hourly. Central crawls revisit the selected users' files and permissions, including unchanged files, so permission changes and a new employee's older files are included. Unfinished crawls resume before deletion reconciliation. Content, deletions, and permissions refresh in the background; results are not a live read from Drive. **Accounts** on the provider page shows personal account connections where configured; it does not list the central service-account credential. +Search schedules syncs hourly. Central crawls revisit the selected users' files and permissions, including unchanged files, so permission changes and a new employee's older files are included. Unfinished crawls resume before deletion reconciliation. Content, deletions, and permissions refresh in the background; results are not a live read from Drive. **People** on the Sources settings page shows personal account connections; it does not list the central service-account credential. ## Troubleshooting @@ -168,7 +168,7 @@ https:///api/auth/oauth2/callback/google-drive This Google Cloud example uses one client for all three services. Replace `https://sim.example.com` with your Sim origin and add only the callbacks for services you enable. -Save the client ID and secret as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. Set `NEXT_PUBLIC_APP_URL` to the same Sim origin used in the callback, then restart Sim. See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). If you change an existing deployment's OAuth client or scopes, an organization admin selects **Settings → Sources → More → Refresh connection settings**, then affected teammates reconnect. +Save the client ID and secret as `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET`. Set `NEXT_PUBLIC_APP_URL` to the same Sim origin used in the callback, then restart Sim. See [Integrations & OAuth](/platform/self-hosting/integrations-oauth). If you change an existing deployment's OAuth client or scopes, an organization admin selects **Settings → Sources → More → Update sign-in settings**, then affected teammates reconnect. The current Sim Drive OAuth connection uses these scopes: diff --git a/apps/docs/content/docs/search/index.mdx b/apps/docs/content/docs/search/index.mdx index b3b9aa797be..f9203ead4e1 100644 --- a/apps/docs/content/docs/search/index.mdx +++ b/apps/docs/content/docs/search/index.mdx @@ -14,22 +14,18 @@ Search brings your connected sources into one place. An organization admin allow -### Allow an integration +### Choose an integration -As an organization admin, open **Settings → Sources** and turn on the integration. It stays in the list; no setup page opens automatically. - -The switch saves immediately and permits the integration in your organization. It does not connect an account, grant document access, or start indexing. Teammates connect from **Integrations** in the main sidebar; only admins manage these switches. +Open **Settings → Sources → Add source** and choose an integration. Unavailable integrations need deployment configuration before they can be connected. -### Connect or configure the source - -For personal Gmail, Calendar, or Drive, teammates can connect immediately from **Integrations**. The first account creates the default sync configuration. Admins can adjust it later under **Manage → Advanced** on the provider page. +### Connect the content -For other sources, select **Set up** or **Manage**, then **Add source**. For a central Gmail, Calendar, or Drive service account, use **Manage → Advanced → Add sync configuration**. For Slack, complete **Set up Slack app** first. Follow the provider's **Setup guide** to configure its connection and content. **More options** contains secondary filters and **Metadata tags**. +Follow the integration's **Setup guide**. Confluence connects a site and selected spaces; Jira adds projects; GitHub adds a repository; GitLab adds a project; Slack configures its app, then channels or DMs. Google service-account setup connects Drive, Gmail, or Calendar with the selected users and filters. -In the source form, select **Connect & Sync** for a central account or **Add source** for member accounts. Creating a source does not invite people or authorize their accounts. +Select **Connect & Sync** for a central account, or the form’s **Add** or **Set up member accounts** action for member accounts. **More options** contains additional filters. Saving a connection does not invite teammates or authorize their accounts. @@ -41,9 +37,9 @@ For member-account sources, open **Integrations** in the main sidebar and select -Organization Sources settings with provider switches and Set up or Manage actions +Organization Sources with Add source, connection status, People, and Stats -Source availability depends on the deployment and organization policy. An unavailable source needs operator configuration before setup can continue. If an existing provider asks for a configuration update after a deployment change, an admin selects **More → Refresh connection settings** on this page, then affected teammates reconnect. +Source availability depends on the deployment and organization policy. An unavailable source needs operator configuration before setup can continue. If an existing provider asks for a configuration update after a deployment change, an admin selects **More → Update sign-in settings** on this page, then affected teammates reconnect. ## Choose the right connection method @@ -57,7 +53,9 @@ Sources can use member accounts or a central connection. Gmail, Google Calendar, | **Confluence service account** | Connects an account that can read the selected content and its permissions. | Join the organization and connect Confluence to establish identity. | | **Administrator token** (GitLab) | Connects a self-managed instance administrator token and selects projects to index. | Join the organization with a verified Sim email matching GitLab. No personal connection is needed. | -Adding a Google or Confluence source from the admin page opens its central setup form directly. Google providers use **Manage → Advanced → Add sync configuration**; Confluence uses **Set up/Manage → Add source**. For personal connections, use **Integrations → Connect** in the main sidebar. An approved provider can create its first member source there; required repository, site, or project fields are collected before authorization. Admins can edit that source's filters afterward in its **Settings** tab. When personal connections are disabled for the organization, Google providers use **Add source** on the provider page instead of **Advanced**. +Open an integration from the Sources list to manage its connections. Use **Connect service account** for Google, **Add Confluence site**, **Add projects** for Jira, **Add repository** for GitHub, **Add project** for GitLab, or **Add channels or DMs** for Slack. + +For personal connections, teammates use **Integrations → Connect** in the main sidebar after the admin adds the provider. First-time setup may ask you to select content after connecting your account. Admins can edit those connections' filters afterward in **Settings**. Some member sources offer **Sync documents with**, either directly in setup or under **More options**. **Connected members** uses members' accounts for both content and access checks. Selecting a dedicated account uses it to fetch content; members still connect to establish which documents they may search. For GitHub organization sources, choose **Connect GitHub App** in this field to [connect an installation](/search/github#add-a-repository). **Account for browsing** only helps an admin pick source options—it does not enroll that account for Search. @@ -82,9 +80,9 @@ Some member sources offer **Sync documents with**, either directly in setup or u Invite people through the organization's **Settings → Members**, or use your organization's [SSO provisioning](/platform/enterprise/sso). Share the organization's **Home** or **Integrations** URL. People need their own Sim account and organization membership; they do not need access to a workspace. Connecting an external account alone does not grant organization membership. -To request a particular account connection, open **Settings → Sources**, select **Manage** beside the integration (or **Set up** if no sources exist), then **Accounts → Request connections**. This tab is available for providers that support personal connections. If setup is missing, complete the source or Slack app setup shown there first. The list shows organization account contributors and their connection status for that provider. +Open **Settings → Sources → People** to view account contributors and their connection status. Choose an integration in the filter to inspect its connections or send a targeted **Request connections** invitation. **All integrations** shows each person's connected providers and accounts needing reconnection. -These requests are separate from organization invitations. They let recipients contribute an external account; they do not grant Sim organization membership or Search access. **People** on the Sources settings page shows account contributors across providers. See [Connect your account](/search/connect-your-account) for the teammate walkthrough. +Connection requests do not grant organization membership. See [Connect your account](/search/connect-your-account) for the teammate walkthrough. **Revoke all account access** withdraws every account that person contributed to the organization, including other providers. It does not remove their organization membership. @@ -92,26 +90,28 @@ These requests are separate from organization invitations. They let recipients c ## Manage sources and documents -Open **Settings → Sources** and select **Manage** beside the integration. When personal connections are enabled, Gmail, Calendar, and Drive list their sync configurations under **Advanced** and connections under **Accounts**. Other providers with personal connections use **Sources** and **Accounts**. Providers without personal connections open directly to the source list. Select a source or sync configuration to manage it. Multiple sources can have different folder, repository, space, or project scopes. +Open **Settings → Sources**, choose the integration, then select its site, project, repository, or account connection. Each row identifies **Member accounts**, **Service account**, or **Admin account** and shows its sync status. -For Gmail, one configuration is usually enough. **Add sync configuration** creates another source; editing **Settings** updates the selected source. A member configuration applies to all connected Gmail accounts, including accounts connected later. A central configuration applies to the selected Workspace **Users**, or all active users when that field is blank. Its labels and filters are evaluated separately in each mailbox. +Edit **Settings** to change an existing connection's filters. Adding another connection creates a separate selection. For Gmail, one member-account connection is usually enough: its filters apply separately to each connected mailbox, including accounts connected later. A central Google connection applies to its selected **Users**, or all active users when that field is blank. -Gmail Advanced tab with a sync configuration, search, and Add sync configuration action +Gmail connections with the Connect service account action -| Source tab | What you can do | +| Connection tab | What you can do | | --- | --- | | **Documents** | Find indexed documents, inspect processing status, retry failed indexing, or exclude and restore documents. | | **Settings** | Edit the source's scope, filters, and supported indexing credentials. Select **Save** to apply changes or **Discard** to undo them. | | **Sync history** | Review run dates, document changes, and any sync or account errors. | -**Sync using** shows the method selected when the source was created. Create a new source to change that method. To replace a supported indexing credential, select its replacement and use **Change indexing account**. +**Sync using** shows the method selected when the source was created. Add a new connection to change that method. To replace a supported indexing credential, select its replacement and use **Change service account** or **Change account**, as shown. -Use the source header to sync, pause, resume, or remove that source. The back link returns to its integration. To disable an entire integration, turn off its switch in **Settings → Sources**. If it has sources, confirm **Deactivate**. Its content becomes unavailable in Search, Assistant, and MCP; sources and connected accounts are preserved. Turn the switch back on to allow it again. - -Gmail Settings with the read-only Sync using method and editable label, date range, and search filters +Use the connection header to sync, pause, resume, or remove it. To deactivate an entire integration, open it from **Settings → Sources**, select **Deactivate**, and confirm. Its content becomes unavailable in Search, Assistant, and MCP; saved connections remain. Select **Activate** on that integration to enable it again. Gmail Sync history showing run dates and document additions, deletions, or no changes +## Usage stats + +**Settings → Sources → Stats** shows successful Search invocations, active people, and results returned. Filter by entry point and a preset or custom date range of up to 90 days. Dates use UTC. Source usage counts requests that returned content from each integration; it is not a click or citation count. Tracking starts when enabled and does not backfill earlier activity. + ## Search, Assistant, and MCP **Search** in the organization sidebar finds documents directly. The assistant on **Home** can search and read the same sources to answer questions with citations. Conversations are private to their author, including when another organization member is an admin. @@ -135,7 +135,7 @@ Search runs background syncs on an hourly schedule. Large sources, provider limi A completed sync means the source was checked; some documents may still be indexing. Integrations lists personal connections; a central Google source can be searchable without appearing there. In the main **Integrations** page, each connected source row shows how many documents you can search and whether indexing failed for any documents you can access. -As an admin, open **Settings → Sources**, select **Manage** beside the integration, then open its source or sync configuration. In **Documents**, select **Failed** from the status dropdown to inspect those files. Use the search field to find a document by name. Select **Retry indexing** beside a file to try again. **Exclude** removes a file from search; select **Excluded** and then **Restore** to include it again. Fix a disconnected account or source configuration before retrying a sync that needs attention. +As an admin, open **Settings → Sources**, select the integration, then open its connection. In **Documents**, select **Failed** from the status dropdown to inspect those files. Use the search field to find a document by name. Select **Retry indexing** beside a file to try again. **Exclude** removes a file from search; select **Excluded** and then **Restore** to include it again. Fix a disconnected account or source configuration before retrying a sync that needs attention. Empty source Documents tab with search and an Included status filter diff --git a/apps/docs/content/docs/search/jira.mdx b/apps/docs/content/docs/search/jira.mdx index 83cf654726b..a50a7d6ffac 100644 --- a/apps/docs/content/docs/search/jira.mdx +++ b/apps/docs/content/docs/search/jira.mdx @@ -30,14 +30,14 @@ Search uses `read:jira-work`, `read:me`, and `offline_access` for issues, identi ### Choose Jira -Open your organization's **Settings → Sources**, turn on **Jira**, then select **Set up** (or **Manage**) → **Add source**. +Open **Settings → Sources → Add source** and select **Jira**. This opens **Add Jira projects**. To add another project selection later, open **Jira** from the Sources list and select **Add projects**. ### Choose the projects -Under **Account for browsing**, select a saved account (including your personal Search account) or choose **Connect Jira account**. Enter **Jira Domain**, then choose **Projects**. **Select all** selects every project the account can currently browse; newly created projects are not added automatically. Clear the picker search before selecting all. +Under **Account for browsing**, select a saved account (including your personal Search account) or choose **Connect Jira account**. Enter **Jira site**, then choose **Projects**. **All** in the dropdown selects every project the account can currently browse; newly created projects are not added automatically. Clear the picker search before selecting all. To enter keys such as `ENG, SUPPORT` manually, use the switch beside **Projects**; this works without a browsing account. Switching between the picker and manual entry keeps your selection. @@ -50,7 +50,7 @@ To enter keys such as `ENG, SUPPORT` manually, use the switch beside **Projects* Under **More options**, optionally set a **JQL Filter**, such as `status = "Done"`, and choose **Metadata tags**. Leave JQL empty for all accessible issues in the selected projects. Enter conditions only; omit `ORDER BY` because Sim supplies sorting. -Select **Add source**. This saves the shared scope; it does not authorize accounts or send invitations. +Select **Add projects**. This saves the shared scope; it does not authorize accounts or send invitations. @@ -71,23 +71,23 @@ For workspace Search, start from **Search → Add source**; its source-creation After an admin approves Jira, a teammate can start from **Integrations → Connect**. The same setup opens when you choose **Connect a different site or content scope**: 1. Under **Your account**, select a saved account or choose **Connect account**. Authorize using the Atlassian email matching your verified Sim email. -2. Enter the hostname under **Atlassian site**, then choose **Projects**. Use **Select all** for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 projects in this form. +2. Enter the hostname under **Atlassian site**, then choose **Projects**. Use **All** in the dropdown for the complete current list, or **Enter keys manually** for comma-separated keys. You can select up to 1,000 projects in this form. 3. Select **Connect & Sync**. Sim saves the selected scope and starts indexing with your account. Jira personal source setup with a saved account, Atlassian site, and selected projects -## Manage the source +## Manage project connections -Admins open **Settings → Sources → Jira → Manage**, then a source's **Documents**, **Settings**, or **Sync history**. Metadata tags include issue type, status, priority, labels, assignee, and last updated. +Admins open **Settings → Sources → Jira**, then a connection’s **Documents**, **Settings**, or **Sync history**. Metadata tags include issue type, status, priority, labels, assignee, and last updated. -Teammates share the configured scope and do not choose projects again. For another site or scope, add another source, or use **Connect** beside **Connect a different site or content scope** in Integrations. +Teammates share the configured scope and do not choose projects again. For another site or scope, select **Add projects**, or use **Connect** beside **Connect a different site or content scope** in Integrations. -Invite teammates through **Settings → Members → Invite** or SSO, then have them connect Jira through **Integrations**. **Jira → Accounts → Request connections** only requests a provider connection; it does not invite people to the organization. +Invite teammates through **Settings → Members → Invite** or SSO, then have them connect Jira through **Integrations**. **Settings → Sources → People**, filter by **Jira**, then select **Request connections** only requests a provider connection; it does not invite people to the organization. Sim checks Jira separately for each connected person. Content becomes searchable as indexing finishes; issue changes and lost access are reflected after later syncs. @@ -114,6 +114,6 @@ Configure one shared Jira OAuth app for the deployment: 2. Under **Authorization → OAuth 2.0 (3LO)**, add `https:///api/auth/oauth2/callback/jira` as a callback. 3. Under **Permissions**, add **Jira API** and configure the full `jira` scope list from [Sim's OAuth configuration](https://github.com/simstudioai/sim/blob/staging/apps/sim/lib/oauth/oauth.ts), including its Jira Service Management and Assets scopes. Add **User Identity API → read:me**. Sim requests `offline_access` for refresh tokens; Search's three scopes above are only a subset of this shared app's permissions. 4. Enable sharing under **Distribution**. Set `JIRA_CLIENT_ID` and `JIRA_CLIENT_SECRET` from the app's **Settings**, verify `NEXT_PUBLIC_APP_URL`, and restart Sim. -5. Connect from **Integrations** and select the configured site. After changing the OAuth client or requested scopes, use **Settings → Sources → More → Refresh connection settings**, then have affected teammates reconnect. +5. Connect from **Integrations** and select the configured site. After changing the OAuth client or requested scopes, use **Settings → Sources → More → Update sign-in settings**, then have affected teammates reconnect. The callback must match Sim's scheme, hostname, port, and path exactly. If only the app owner can connect, check **Distribution**. See the [Atlassian OAuth guide](https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/) and [Sim deployment reference](/platform/self-hosting/integrations-oauth). diff --git a/apps/docs/content/docs/search/slack.mdx b/apps/docs/content/docs/search/slack.mdx index 2b63bb88e82..11f17e1b687 100644 --- a/apps/docs/content/docs/search/slack.mdx +++ b/apps/docs/content/docs/search/slack.mdx @@ -23,7 +23,7 @@ Skip to **Connect the source** if the organization already has a verified Slack ### Open provider settings -Open **Settings → Sources** and turn on **Slack**. Select **Set up** (or **Manage** if sources already exist), then **Set up Slack app**. Allowing Slack does not configure the app or start indexing. +Open **Settings → Sources → Add source** and select **Slack**. Complete **Set up Slack app** before choosing messages to index. If Slack is already listed, open it and select **Set up Slack app**. @@ -53,14 +53,14 @@ Return to **Settings → Sources → Slack → Set up Slack app**. Select **Veri Member connections use one configured Slack app and workspace per organization. Installing another bot does not change that configuration. Changing the verified app requires members to reconnect. -After verification, open **Sources → Add source** on Slack’s provider page to choose what to index. A connected bot alone does not mean Slack messages have been indexed. +After verification, select **Add channels or DMs** on Slack’s provider page to choose what to index. A connected bot alone does not mean Slack messages have been indexed. ## Connect the source -Open **Sources → Add source** on Slack's provider page. Choose **Channel Messages**, **Direct Messages**, **Channels**, and **Earliest Message Date**. Open **More options** for exclusions, archived channels, metadata tags, and **Sync documents with**. Keep **Connected members** for the usual setup. +Open **Add channels or DMs** on Slack's provider page. Choose **Channel Messages**, **Direct Messages**, **Channels**, and **Earliest Message Date**. Open **More options** for exclusions, archived channels, metadata tags, and **Sync documents with**. Keep **Connected members** for the usual setup. | Field | Behavior | |---|---| @@ -71,15 +71,15 @@ Open **Sources → Add source** on Slack's provider page. Choose **Channel Messa | Archived Channels | Included by default. The picker lists active channels; use manual names/IDs to select archived channels. | | Earliest Message Date | Optional UTC date (`YYYY-MM-DD`). Applies to the thread's first message; replies are included with that thread. | -Select **Add source**. Each person opens **Integrations** in the main sidebar, selects **Connect** on the Slack source, and approves the configured app. Creating the source or verifying the Slack app does not authorize teammates automatically. +Select **Add channels or DMs**. Each person opens **Integrations** in the main sidebar, selects **Connect** on the Slack source, and approves the configured app. Creating the source or verifying the Slack app does not authorize teammates automatically. The Slack app's **Home → Connect sources** opens this same Integrations page. -To send a Slack connection request, open **Slack → Accounts → Request connections**. This requests an external account connection; it does not invite the recipient to the Sim organization. +To send a Slack connection request, open **Settings → Sources → People**, filter by **Slack**, then select **Request connections**. This requests an external account connection; it does not invite the recipient to the Sim organization. You can instead select an existing account under **Sync documents with** to supply message content centrally. Members still connect their own accounts to establish access. The selected account must itself be able to read the selected channels. -Admins open **Settings → Sources**, select **Manage** beside **Slack**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. Search reads indexed content, so source changes appear after background syncing. Slack retention and API limits determine how much history is available. +Admins open **Settings → Sources**, open **Slack**, then open the source to inspect **Documents**, edit **Settings**, or review **Sync history**. Search reads indexed content, so source changes appear after background syncing. Slack retention and API limits determine how much history is available. ## Permissions reference diff --git a/apps/docs/public/static/search/confluence-personal-setup.png b/apps/docs/public/static/search/confluence-personal-setup.png index 2d196b8937962dde2c4a2861148ae99b89296ed1..f8c4119d62cecac66dd452f21c0aadaa4157095e 100644 GIT binary patch literal 68053 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

%$$bDD%!YfOq&;NmatiK>9S?DY35VA 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

88J&%dbW>b~1$Q!94{o3aw` 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 diff --git a/apps/docs/public/static/search/github-indexing-options.jpg b/apps/docs/public/static/search/github-indexing-options.jpg deleted file mode 100644 index ff4a800f80838f5e288589dd343635736aebcac9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17946 zcmeIa2UL^Kn=qOXdY39qL1_sPklqO(NHZkm!13fPW6eKoB7j2>~hD z^=lJa0FZ!?07OnkOiD#SLH;73{>A2__7@6+r8Kk65-cd%P^u1Ekr$i-e ziZ(XM?utE)Xn1$be3M&T#mLs%C!?^w+pd^b^1fQQlC_eEzTow1iGQneIHU{i{gPc`d-`2`B;oQvAysflgrGqE61^RmL^I=4ZZ9 zxi92jFkb#?J9$5%9(PHI(a{iEJ&Ylk!Ka+9~EE=O%on|YM zs@^JJ+y}%4hpRQSanw=yuGzdH<_V^q@NBwcM{66joF}QG*D>W16lyQnFeHx?dPJC1 za){|F+%dGY4bsdDqqZ9oyh>DY41TW-H!$(5$gI}hS)3?hsv_`H?(As*J!&82X@BiY zG_yS|e?T5s!K0XbvItj4J!NiFhp0mcy2?SrfYLc&* z#W7vmpa%pY=($oSF)ifWRFmOt6oPbCk;fcE6WjHq_^FqBLj3SDW4Lz<*KVarMT{}@ zo<>T~*pR+6qvX8h;nnHB#$&YhlN$SSxmrQSP13e;^UIgrX=r=Hw z+in8n1{$AK=%JJi$f;WW#CK)|V0Ei071i7Y$LyOCY=a+F8P}-&d%A{ z4a*7JI}t%Y9#l#sMO9nN<^~zt4k1e#Dy_s_4Jft5a=g*+_fdxXJDxwE)!{Xn>E?Dj z<|N*GZ*Cj5%5icwU5!jt5nDgGA@v*|Sv#n1t0|{jF=i_}GW4;=Kx0tzP5k2~nG?E< zIHWNW7y?(kAql7M$^T-odtCd_AvDEz*6Y-O-u+IIIf#fIqjW9JNV(?<^WA?^~aJS2t$dS4pP6A z0--YPNd{>!IEkKMd-8H@*``>2#pKy~e`7TYLN60vD04U3!Z`;U(!S*`Vq!z)iQ8@{ z)6hEL7j$*O(pt;>W*My>DAfO&A@^AJEAFmnrLi!9{&6!~MuBU6f&jIyy=u(}4|0Ev z^(a)Rzk5lLyP~J69;SrAFhqFgbZIipS9aKEO!c7oJ`gad{e;C#gfS*pDd zev`h9&p_D9n8KSaca`8W@L??hT~e}wE}fgyspFo}Wj{zBqn30TOAhc~xqtb~6Oijh zV*L?hUjR`GhQY+79eFf6C}ga!ZrY_T-(?OUy+2u0X8 zm^webb_-W|PVm8%?G<XD?k2`#;1cRsahm}Ysx;}NpnhJ!_TNzcGx756Sgpe6 zw$UagP8GT}3ra%8rF$weH7cB>n^pH=&e}Y@+d$JU z0yOY|%9%dxyxpb^!6XEgz3LGhZa$3cQ9Ie=!Zov_Wj|NxFZ8YuFW22{O+aYIcfW#I zHa%B$eQ*wqt~jNRMnTunyG&+iWm1*&WL#yJRR(CeHcduI0TEQgmtgKCINBu0Gp(7u zMkBqiUmBr#6kJ^Btdfr9;^6^vvw^G|#c-A?2nF7rtP66n2DDalbHyozs;2Zwmd5i6 zq2!^*`e4Ggs>(upQxJ77ZcKYjWBjddPL(xZM|nI{4dVT!deaW5;ItPgGvHlv3e>IGllPk9l zN}Fcb%_&D9rawq%XKNoh@Z^Tn?Fj*)4TdGe%UlS4`R|y0&I5`B@6-PfTf+&-*E_&O z7JsDCC(Na~TDUa$U5^>Rv-ttDmDTc)eC0vsGYhMJG2?vG)WeZJNNT(JYd@l+Sfpls zJ~C>tAu$yxZ^YZ(HAuy_Fa3~WWABZDS)fE5S;b)6N4m`PqM!C9l4U@^5qiJmM%^Mv zn8Il`R)l@x=3S}MM?Abe@{)ta;#+BExd})OSL9oI-|CWc$gO*o)}lT}58J=XR~nXy z^gGF^*wIa!rq&MUX!xkjG=-=&O1Wea;D1ex7> zrrC$rLr6C)hc8to8649Dn}q8RN!Y5?WTV8U4cZm7AGrI3FS+!49iL>R^B4jpXURGz zw>sy^?LO1-&#&U|LF!fL<)H0BAN3UAnj^0rOyZ(Ry&CYD1d}2)PvKxNoEXScWB}12 zHu8+W7h3Sj#=nA|8ZpIc(>!FA9jIMcLYv|v`k*Y9&m|o$!gOyguJOFvutwYU-hzu^ z*bOZM9BWR``#^7ZO;IyX+{7jm6V?RX8pT<%0-=D{Q61SjO-47$+?07{5WBmR+g;Kk z&8uQ=;9`zXugFfb@hmg5KY?AKsW3N5e^IC+w3vY{;h9-Jr%*5VSBRX74oKdjz0ViX zy)2_B+Y)zD7<<%RbPe#Wc2c8Hwa(kvdxKf|6`K$PTW_0q7gJ?_INjbXLSnWO`^D2g z6;;#lot6W#We0qL;~|3}F#z+lP0Xz3 zW+`n$wlhzAGP>H3j;8Xe?iR72ulE%5{u&vkyf5MF4Ut4Sk;8k%ptRx^T&o^LLoezwu3Y zZEl)dqA4U__;v{h7;$^oBcp|>42(<2_i9Jq(tRsx>}t^mfRU<%mEiazpN>7`CKM3% z#pd_=`As#--TkTvKo5ylHW&!1oHb5)AW8^oCNCZ{#W^BLdCEvRIU>8*H1)&T_ttu3Xpyk>|NN z!kdRxt}@fPGw}|$gQ~wt(EDYlKsAS5k&i`kQxW0hUCix*{;)^8{+Ti~DaJAZFBx~# zfG9Br=IgVmZZ$r}m9mg^%ac2~;4Kl@Y7k-yle6ZY&y{Xi1FUCLhGZKL<;H-Un6`hA z#gA;7JlH=qD`FwM!sQhJz0q}SU9NS|G+DVFKPQ_v?c?lV^Kw>~N&@X{Q|H-iJ+xyp zn@gFA?5g+ym8-eApx#;4WErguYqVmK;~ZU1;glmwdc|y3b+i4pWdLS~sR71TcvtrX zx}~4nWm353TI??T1bKYx@kY>R_@ep9RURbM7(K9KYSSdtmA-n}#ks;wL_w$aROIFY zBX0G+;|`78jScqx!cxC>5TnZq!<>oNr7Bdaw&+(ZkiQ`nmr%lxQg?_MwbP(tai|l! z$Q6Fss%9Ky`b2%iFu=YZx;&It9j#w=Xc|3JhE;WXL)@QTa_fPi7rxnSs_`-PTdTZG zjgxd={j|N(Uszs&gwBmz73#lhxR`!;ZCC6$MjZz zD9`fO)%j3)(r|sioex5<+{X&oqI|aa`he+067ae^9~MS`p2Eu!4#9ic6F+A_3 z{s5e)hW_>8iC{axGD$?K{^xxXq4Daf->ePcEg5lDyvmm^$~CL^Cu=iqBU15TIH4;y z_|8^(!jc<_WbXwE*Z+8X)JMq2r3!QWOVN=!j+eEkR!b)*a$i3+J0|@U&BP+xEXXaG zhpzfcnV69AuKSF9mpV1 zjmB&B=|5R{pjbYx$C2vF_`zkgj<(@iW}+o{r>j_Bke}`qV{Fs9jGx)DmqQMFSream z@r=ErNUksIFNI|j{Zb8)C7;?(Y$09Zs#im%po!&2iPTg^*DgOnVDYM_eXWholrz$p z7#HD^)p0XwvCqZQX8%n??`th4RuA2RY9>_M2(w=@_C}@lJSmZf^76OG)EoB)ZOO$> z=LKjtiKgdM`eq?W7xBy7=Q8b3TMI1I;`?w8t}c@nA7ufnTo>BRBNVGl%517`9g5uE zI>~wq+4fAddWNDuiWi+X@1ANymdJh_<{qhbk;OAq;05WRfXC)TgE@23W%l?4A5p^f z5i>;93`&wgb#zEWb}_`n-wr~J zyBVpNVK_gd-7vv{ctL*WvXe}NRi3dx(UFh3MtU~DuRX_6B$zxTpu5Ugb0(3ggpWxn zLo&TCRicHLHp+#OwhZA0(8`~rVD>zzJV`s_&3Lo<%Jv(W6lrK*wwETF*sPy!=nc~v@}%gUs-X&_+|;TuMOVPEJ4{YHu&HijwNB@x*<2+( z5}>z14_t#w)o-&=udV)mTlDV;(&R&qS+lEI)GLf;t*WE6D@3=mO`HpuM%wiS8`4uw z(j^($a^0BPS}l9B{H-Wa1`kv7v-}OHIX*29bw7LUm{L%SOb(Q&g-Lcq5+;$;S?0F3 zeEc#~PBrzfX$>T?W0vKtDVvM4?S(nz_h1dl+>P-Ej@BPM3!aX?4_hTzD42_D!)DHV zTpbJ?{-R}EhpaQvjfC7DdOltSR93EeY6BVA$!WQ=W(S%zMOL@GdJ-}ZEHo1K5`vO# z%YC{Mp(d!cG7BDF{i&4xYo(4FSd;Wi>~_A}<(n)LfMHaVy?tMs5;pABAcmaE(_7;n zI^xl6bLgWkY4Wz3nhxBTP(6ts*6bj&rf1b{>=|N~!VbVLgV$?88mG6n6`>w!Kudz! z0Nld2FEwwgfZD*COTo8QPcGj!p275WUG4q=5Ca_{^CZBzUvyThorfUIL1>)t7b|~Y zm*3m_nLl2=2CU1j6>0qZu!8aA@R;QJb#T-rP2KV-_4l{yZb{6};9)^O>!?9Bm)vjv z3j<>Gn6&@vuhA>ll+V{gQ?~T7TW=eJJk(3c?a0yEuB}b3(j8{zzd$*ldw+xT46Xc` zir;3pWJB6w4I%GL_m1WaN7y1eHczXb?b%s~_Uwrs-Q6TVkyIrF5Z3FN>kjh-w z132PhelM?CEdbU|R#^Y%^g|1Y)Q7)O{=e4yKOzs*9~%N&L-OaBhJk$Dui8u3(oKhw zr&7%zdfcFpmwUh#9sX}!Dtad*l>}PRzukWQCBW%2e|0r_@AvJ`w6yWViFNyVe!YdH zZeUlVJ4m9zeayzqyIQ4RXG3!(v?q5t?h+avkmDwONE@MNFNXI_Q)(+5^7MxV!Omcf z0~q`+`YB=LW@gFGb8O}3$COh(0~DGwB0W%r*ph{6d>MGOnzXcctG6Gb`-sS5Oc86UxAa4&h)b$syE zo8?#MWMm6KfY9rbVx|V4#_wh{1P&^^l-8>TE6H+y{7P^j6lYWleXxnOa?K?E)YRAf z6zBmK#}2=levjRwJ-lk7r^J8Oc%tvZNc`+I^2A3+qtaf7d;bVQdGyqhyF5hX<_wh> z{$ZbAr9XR*tj2oW#buNF^j@lWYZSIkOdKE=Pe(O0*5IautCsNa@?1vju_cSO?l)!7 z1x`j=^cuTsEwul-(f-=OK{+FpX>&#GC^@o%CsbXx;}x(Vc{)iIQ8l80^2K%eP;2Ql z@j#=!1jwNyvOqL`!OZVlT4hZf4~&Qo4RnS2j=z5qmc#f4n>8RFq$pHkI}}B3Mm288 zDuyLOEPlbyOU)wPOG?g7D|mZJsm`9Kwad&@87EPz?`AOihmj&)i^X#&|oxY!?@A~K3Jq3sjye!Z=1x@e;Yj0x%71gs-Qu3R;d<&X$}?z#h}+~h_2VYinXHOpj+`YAH)g&ED~F>{y;>5+IgoR z>f&O*kN+&;>IKiBQ!Bv_uM6vUv{xvSasj$vSrbZ%`}6J(1?wsML21PsEI#r zB@cOosy{ziC0rPvD(pn%5a7g-Yus|rg{408+fWei(#Yd_BH8#k?%d+I?8g=1@UFHB zhm6u&gsud%1%>OW!oV-&pN#Sr#O`V554p)?%;wW~y)f<7f8wnBGCRFAOvvBuP4^4* z0Phkcu&ddq%{4uWh?`26g=M>t+RH(2q+NmfZ4A!2wbqBqh+j-_TyyYE+@wp2H+wOr!&INal6?LlX~t??+0a;;It z$O49g!t^*yu9>yYB+yRejK5Dh=k4=@fRF%p3*$`M?G=@rG8TRmdSfrcGDKk3!v^dY z9qtaib6H2L$#pIxra@^({#h~Tl}7nwR$l)%b^*(m{j)rsw_iy}gIr6adtdVq`=Q&9 zK7I0{;)27B2FY%5PS7)ruWPDB?P+w6Xc>6(QCMd)Yp4M$h8_*SlHCBi?AZ=!$m zm#LDOaweA4`5Gbh8u=c8rU=Nz@v}b5JJ_sj#(vsCm8CSQjK>O-E--koA8R65eO6CS zg(FId*wS6k)1PzLv<8_VJ5oyCt1rkG>*$rIZ8I2wGWeEPmJvbc%*ox3EQ?RiE#X7= z6z?$?@p{{_HZxW|3eIwmLY8b~n~L}IFjiz6*|WIYK*25CKS*#c$kJi1802DV6CD#& z@U|vG{FJUnOk~p#k56vGu@)i-dY^873uq>#Nd9;9I6(cABy+;IO9@j~nQl?#cZI4HavESu70ajM%JYVNC&DsxIYVy3<=B>fOjnFP@c4m2~su{dZcDd}u zBJdsRMQ-%?t;v>usMImj_hr~yvI`Yn*7o>raG<4PsMYufpe1?UM=CZe>p3<~;!H)g zgu5QlNdQB|Qn)ekz<}NUue$4gTRwJ}Js5KW;Krh?Jehv~So-+~P)7vurEpg=hDk$% zM}FA=*4w^_eTxKz@4gwIqy1~F|Ak%w^`~|vq8t6$e_VgvERwXIqsM>ivX%Tbhdj4A zg9^CkJ$A;YUVVE;H1uQSl=7PHXUwmlw6OF-5x+`DQ0EoEfxzWF_8MO7q4XLF~0sx>RUf!CGTHC7l zlL#PH?Z+KAH@BC!W4&R40?trkxON+1^pQm3^Cg8AI4g2AvdP_O0GyUVaETs8C+$sqx=s4h8lPAiGql=T{MdY`(^2jOBZpmyOIK;^DS`ZuZwhFqsa`O zS}rBb(+@k*Bs5Yd6#ce#CVAl_>%4PU-!z(em0jIGnBlc{P!e3fvo)`@5XxsVtLf@0 z9a&*Ih|m#=MTwjZj6S>ltP0Y-@CAOqnJT-dL0k|N>y%je>N(G@?kavUqaiM`wXTX= zbhXkjiZQVSF!JtF+Ziz?ShD4&l`~^2#2c;ZVP;kxuWr?!dG&fXrV{9N5^hX*zb#QA15 zT+#YX7?gN;2^PaZ=O&RYlN5W_{N6cx<(@O+qL3Zg=0zaRX2?tsS+6f9E@UF0PxM(ZYuL@Ilr2jRE9bX)0%oAF4Iis z#4pHMm3*vUp?}`&2b4{WM0_ek!9g49*;!5)0z7x3@+v}%h2~KxMRvKNmmz;p{!I6B zR^|SP$nvw-pZVKt849aT=xvLG2|;(yKJ;hv6Kn(0hs`Mc8BhGuHn z&q(U8`&C6%`7G19HP0C}CM#mDI9cJg%SlBxL)ru*BqEZ$g94W+Ay zA7h6{MeOa#rpt2#YKQ8uZT#o)946|lUS!)vWPNv~G_YDr>772A|8zti{RqCz@dr

K~^ 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 diff --git a/apps/docs/public/static/search/github-setup.jpg b/apps/docs/public/static/search/github-setup.jpg deleted file mode 100644 index 454bd18b10e60764164c26ea5ded4ed597630970..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31061 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 diff --git a/apps/docs/public/static/search/gitlab-options.jpg b/apps/docs/public/static/search/gitlab-options.jpg deleted file mode 100644 index c2ab696601f9e1e0b2c2dc4b39b482faeb6e6168..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 47941 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 diff --git a/apps/docs/public/static/search/google-drive-setup.jpg b/apps/docs/public/static/search/google-drive-setup.jpg deleted file mode 100644 index a61673d34957a2c96436cf60f6288bf04baac9c8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 22911 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

q?3hA_f~I&Sj+5q`s~t?yZ$zA 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 b7QdmbQ7|7_Sn+7yfj>vJ4YlrT*hTywh`nV2 literal 0 HcmV?d00001 diff --git a/apps/docs/public/static/search/integration-provider.jpg b/apps/docs/public/static/search/integration-provider.jpg deleted file mode 100644 index bf655343f517151e7bc2e65f75dad1a64786bf82..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21510 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 diff --git a/apps/docs/public/static/search/integration-provider.png b/apps/docs/public/static/search/integration-provider.png new file mode 100644 index 0000000000000000000000000000000000000000..535a5860a03afd3f069f65c8b5f1202d42ee6ae1 GIT binary patch literal 37791 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 literal 0 HcmV?d00001 diff --git a/apps/docs/public/static/search/integration-settings.jpg b/apps/docs/public/static/search/integration-settings.jpg deleted file mode 100644 index f4e517c06560e8d6eb21e668805d82c344d2c20b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 32832 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 Xo1Z|d#7;@xRN4oeG1+}w9L)X?Ik_n9 diff --git a/apps/docs/public/static/search/integration-settings.png b/apps/docs/public/static/search/integration-settings.png new file mode 100644 index 0000000000000000000000000000000000000000..8dcffb533364e8df7e65804458a83f579d31302f GIT binary patch literal 118870 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 )?-3Oae;Ny~jc@M;3WA>jSMe|1T5WtbUONrP|% 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�`6wdJp2y6|ViSHq# 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 literal 0 HcmV?d00001 diff --git a/apps/docs/public/static/search/jira-personal-setup.png b/apps/docs/public/static/search/jira-personal-setup.png index 60b2c1444023045ad9ac4e1c0fcb1bc39836a39a..9530eb542d2aa9c77b84dbdf63e15ee44bb00a45 100644 GIT binary patch literal 66834 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

Q9>J5K{Jd$bCS1xT5iXk8rh@Hzc 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 z z)q(20cxUhu`D6&w> z?&XeXqG)HxJ3rRbdpEsMKHBem;eJa%#4nX#{V8kSaciA)u9ywGrUHR{dw*(qUtUC_ z?0hFtLo)Suu_07aTQ=zum(T&#R@7YqE@B&`zbq%sQ+1v+kBOmgmR9&V{h~-;B}C7! za-ik9zG?D`H>?2yKED3DLd=9QX-E5 z!$b7e42?D`h`k)hI%yml|I$TBHP{!tdnV+C76h*ca5I|2x*zb8ebmD}P)F*Znnv)d zNmQbBrDSxB6ZQ+}EXY6t32nYE>LN9(C9C(|vgfuj!H3wH>3A%WR3JOn+?lqIu=p8X zK7%nfS1}x-%fU4J!ouH7nIG22WLMvv;C-n}W<}5d-e;)kU%yFcjTq=r_@0Zw&P$V@QaX0$hE9=Yb}wiU*qAVTo|}B@ zSGsmzHjl7uB9`4@o7Y&LW8WB<)|&oqdbG!F=A;vPP@*K8VSzd5YUs)*f9S)0l(*ru zI$DCUSy1SU=foe7KlUsW)lL$xE-Io;PUt8bO7_mUTS?^(40sJH8dkfphq#2aPukRo z{cZ|y`NXH7Uc!yc$kkIjM&}rjVRCY_ovw~Wt|l|(IyN`fhf}Y=C^5%W%YrI#L47^o z#U_anM@nPPlinaA;AI&F^QEpUEn96HJrYdT7tDz|t+Bflp2@rU81TIR_9MAt!E065 zQ(+fLw2=K`g*{)9caW$y%X&L=^LyBb_QZu}Do*9wTK{yn9M@KPKWzyR#loDVaCGeV zF{yTR93)0MQVsolg&IXrcQ%rb*9!mp90bipP$+sdK%6Tgycfi93k}B&@um9j0rtkmv(6sH(*7tZRfx!7_m@VDe-Bdkeg2qmr zaz>#%l%V3QR4aUd07SoDRx|llIkvI|j#$M(X=Q8dTi6Rw0w}TFliqI}vzDZmjLZJ_ zZv^eM&5RYle7~IE+al`^4znAmLN~A<;g@{n8|Vcgw`j;L0E$BhY5B|86|_r0QTZ*9 zm-9OhLTWK;@)68|5c>gsNpIw(2s6C*k(d4;BHv+7^77Qx$Stu6pi`;>RY=+Me<%uI zDIk-0KsN)w?{YE6i9O-Or}R*VQ70H z-?pNtRXI&?zAHP5?FG2%lRQ9z@;Qk26>v_ILy&nD1g~f%m#!?`EU-%Amvn*Bn$1C| zajk&;4yal}7Fl5QvOC33ZuAqfNzGxd?P7T|6M(g#j+|eXaqTWdp|+kyas+@BdJ~ES zAh2uTpQx3jh85EI8Z@58!BsIff!)WcXgL8vgenu_om?hVs?q>}9cN`CBo6fQwEPvM za`(#whx~p%{5i%>WoU3jMArD#UF4q$ozj6eJ9Zam(O`kkA--?gQmJYOX#>c&iDeF^ z#_y~9D4oxNL^+T+6-s*zx^Ew5zTC-#Gm_hh1Og@$3RFm$5#Debqo~||(f^IZiRe1C zOp)u@xzZ44;){IIiWzuG+3u;CNXft?NKvFpIOXx{Afcbps+vK}X4^q!SBQlh6LntA z_%p?>nguHeff@mUO8H2Z)>vyo@K zmS@}yru<*3&m35Rp~ukE6Dj!^rWc?Iz+ahHBgc_ok=Q4-RiI*G%0Jpi)0dkGtk5~$ zpWs|(2TaB>@M78JJl7dQ$?~xXl>D6g z`Qa%vTwfHb$D~BYB)1JnSb|G6T(!gk9Ej<8Rn@n~)Ug+NutO8bdB=hG8Mm+IYM_jT zrA2EN;AJg8A)Vsg)nm*URlUc^ZyOJdM{~PQ-PH7_hWbL)Z#is1vE~X@u0nhr*vZX_ z1{i5moNVt9C;&2Jcm52{CM83%itAL!Q)SpZ0fz}Cie<B9Lh;r*$*Q=Yf+L<0;h%%MQ*d20 zL|eW@9t?GUkz8iz zydOR;)_KAUi8vvo5`)!X-@tm+N3C(phH?4ND$OPo$m;8e5#_udJAND+^=EhlXR~jLdWBS_El_e)dfzH3P>MOE$-1_~VF+ zT=oyok=vwZQCB7844tBtSFov&Vh?Rul7-H{%EuDf9M~s^L*Nv&yX#sV43dv Ty9bKmkZp7{4Kyg~4w3%@3Zg6Z diff --git a/apps/docs/public/static/search/source-settings.jpg b/apps/docs/public/static/search/source-settings.jpg deleted file mode 100644 index d89c80623807b52f49e4bd2119f4c6b08cfc04ce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 37543 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 diff --git a/apps/sim/app/api/knowledge/sim-search/stats/route.ts b/apps/sim/app/api/knowledge/sim-search/stats/route.ts new file mode 100644 index 00000000000..e7ae7eb9777 --- /dev/null +++ b/apps/sim/app/api/knowledge/sim-search/stats/route.ts @@ -0,0 +1,24 @@ +import { readOrganizationSearchStatsContract } from '@/lib/api/contracts/knowledge/search-stats' +import { + defineInternalJsonRoute, + internalRateLimits, + internalSessionAuth, +} from '@/lib/api/server/routes' +import { internalKnowledgeErrorPolicies } from '@/lib/knowledge/api/route-policies' +import { knowledgeOperations } from '@/lib/knowledge/application/operations' +import { readOrganizationSearchStats } from '@/lib/knowledge/application/organization-search-stats' + +export const GET = defineInternalJsonRoute({ + contract: readOrganizationSearchStatsContract, + auth: internalSessionAuth, + operation: knowledgeOperations.readOrganizationSearchStats, + rateLimit: internalRateLimits.user({ + bucketName: 'organization-search-stats', + config: { maxTokens: 30, refillRate: 30, refillIntervalMs: 60_000 }, + }), + errorPolicy: internalKnowledgeErrorPolicies.connectors, + mapInput: ({ query }) => query, + useCase: readOrganizationSearchStats, + present: (data) => ({ success: true as const, data }), + staticResponseHeaders: { 'Cache-Control': 'private, no-store' }, +}) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/add-organization-source-modal.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/add-organization-source-modal.tsx new file mode 100644 index 00000000000..babcd4f2c91 --- /dev/null +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/add-organization-source-modal.tsx @@ -0,0 +1,106 @@ +'use client' + +import { type ReactNode, useState } from 'react' +import { + ChipInput, + ChipModal, + ChipModalBody, + ChipModalField, + ChipModalFooter, + ChipModalHeader, +} from '@sim/emcn' +import { Search } from '@sim/emcn/icons' +import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase' +import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' +import { + RESOURCE_LIST_STACK, + SettingsResourceRow, +} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' +import type { ConnectorMeta } from '@/connectors/types' + +interface AddOrganizationSourceModalProps { + sources: { + type: string + meta: ConnectorMeta + access: { admin: boolean; members: boolean } + }[] + pending: boolean + ready: boolean + feedback: ReactNode + onClose: () => void + onSelect: (type: string, accessMode: 'admin' | 'members') => void +} + +export function AddOrganizationSourceModal({ + sources, + pending, + ready, + feedback, + onClose, + onSelect, +}: AddOrganizationSourceModalProps) { + const [search, setSearch] = useState('') + const query = search.trim().toLowerCase() + const visible = sources.filter(({ meta }) => meta.name.toLowerCase().includes(query)) + + return ( + !open && onClose()} + srTitle='Add source' + > + Add source + + + setSearch(event.target.value)} + disabled={pending} + /> + + + {feedback} +

+ + + + + ) +} diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.test.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.test.tsx index 952880c34ee..45b6307162e 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.test.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.test.tsx @@ -23,6 +23,14 @@ vi.mock( '@/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup', () => ({ OrganizationIntegrationsSetup: () =>
Provider setup
}) ) +vi.mock( + '@/app/o/[organizationId]/settings/components/integrations/organization-source-stats', + () => ({ + OrganizationSourceStats: ({ organizationId }: { organizationId: string }) => ( +
Stats for {organizationId}
+ ), + }) +) vi.mock('@/hooks/queries/organization-accounts', () => ({ useOrganizationAccounts: mocks.accounts, useUpdateOrganizationAccounts: () => ({ @@ -53,6 +61,7 @@ describe('organization integration invitations', () => { vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) mocks.context.mockReturnValue({ organization: { id: 'org-a' }, viewer: { isAdmin: true } }) mocks.accounts.mockReturnValue({ + isSuccess: true, data: { credentialGroup: { id: 'group-a', options: [] } }, error: null, refetch: mocks.refetch, @@ -111,9 +120,9 @@ describe('organization integration invitations', () => { ) ) const item = document.querySelector('[role="menuitem"]') - expect(item?.textContent).toBe('Refresh connection settings') + expect(item?.textContent).toBe('Update sign-in settings') await act(async () => item?.click()) - expect(document.body.textContent).toContain('Affected accounts will need to reconnect.') + expect(document.body.textContent).toContain('People whose settings changed must reconnect.') } it('keeps provider setup as the default and sends manual invitations from People to this org', async () => { @@ -147,6 +156,7 @@ describe('organization integration invitations', () => { it('refreshes saved provider identities only after choosing the maintenance action and confirming', async () => { mocks.accounts.mockReturnValue({ + isSuccess: true, data: { credentialGroup: { id: 'group-a', @@ -173,7 +183,7 @@ describe('organization integration invitations', () => { mocks.update.mockImplementationOnce((_input, { onSuccess }) => onSuccess()) await render() await openRefresh() - await click('Refresh') + await click('Update') expect(mocks.update).toHaveBeenCalledWith( { organizationId: 'org-a', @@ -198,26 +208,27 @@ describe('organization integration invitations', () => { }, expect.any(Object) ) - expect(toast.success).toHaveBeenCalledWith('Connection settings refreshed') + expect(toast.success).toHaveBeenCalledWith('Sign-in settings updated') expect(document.querySelector('[role="dialog"]')).toBeNull() }) it('keeps failed refreshes open for retry and blocks duplicate submissions', async () => { mocks.accounts.mockReturnValue({ + isSuccess: true, data: { credentialGroup: { id: 'group-a', options: [{ provider: 'gmail' }] } }, error: null, }) await render() await openRefresh() - await click('Refresh') + await click('Update') mocks.updateError = new Error('Update denied') await render() expect(document.body.textContent).toContain('Update denied') expect(document.querySelector('[role="dialog"]')).not.toBeNull() mocks.updatePending = true await render() - expect(findButton('Refresh')).toBeDisabled() + expect(findButton('Update')).toBeDisabled() expect(mocks.update).toHaveBeenCalledOnce() }) @@ -233,11 +244,16 @@ describe('organization integration invitations', () => { expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: true }) }) - it('loads people alongside setup but waits for the pool before allowing invitations', async () => { - mocks.accounts.mockReturnValue({ data: undefined, error: null, isPending: true }) - await render('?tab=people') + it('waits for integration options before loading filtered people or allowing invitations', async () => { + mocks.accounts.mockReturnValue({ + isSuccess: false, + data: undefined, + error: null, + isPending: true, + }) + await render('?tab=people&integration=jira') expect(mocks.accounts).toHaveBeenLastCalledWith('org-a') - expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: true }) + expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: false }) expect(container.textContent).toContain('Loading connected accounts') expect(container.textContent).not.toContain('No people invited yet') expect(findButton('Request connections')).toBeDisabled() @@ -245,10 +261,11 @@ describe('organization integration invitations', () => { expect(document.querySelector('[role="dialog"]')).toBeNull() mocks.accounts.mockReturnValue({ + isSuccess: true, data: { credentialGroup: { id: 'group-a', options: [] } }, error: null, }) - await render('?tab=people') + await render('?tab=people&integration=jira') expect(container.textContent).not.toContain('Loading connected accounts') expect(findButton('Request connections')).not.toBeDisabled() await click('Request connections') @@ -257,14 +274,23 @@ describe('organization integration invitations', () => { }) it('stops the people query when setup resolves without a pool and preserves the setup action', async () => { - mocks.accounts.mockReturnValue({ data: undefined, error: null, isPending: true }) + mocks.accounts.mockReturnValue({ + isSuccess: false, + data: undefined, + error: null, + isPending: true, + }) mocks.people.mockReturnValue({ error: new Error('Organization accounts not configured') }) - await render('?tab=people') - expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: true }) + await render('?tab=people&integration=jira') + expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: false }) expect(container.textContent).not.toContain('Organization accounts not configured') - mocks.accounts.mockReturnValue({ data: { credentialGroup: null }, error: null }) - await render('?tab=people') + mocks.accounts.mockReturnValue({ + isSuccess: true, + data: { credentialGroup: null }, + error: null, + }) + await render('?tab=people&integration=jira') expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: false }) expect(container.textContent).toContain('before requesting connections') expect(container.textContent).not.toContain('Organization accounts not configured') @@ -272,7 +298,11 @@ describe('organization integration invitations', () => { }) it('sends an org without a credential group back to provider setup before invitations', async () => { - mocks.accounts.mockReturnValue({ data: { credentialGroup: null }, error: null }) + mocks.accounts.mockReturnValue({ + isSuccess: true, + data: { credentialGroup: null }, + error: null, + }) await render('?tab=people') expect(container.textContent).toContain('before requesting connections') expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: false }) @@ -284,6 +314,7 @@ describe('organization integration invitations', () => { it('surfaces account lookup errors instead of treating them as missing setup', async () => { mocks.accounts.mockReturnValue({ + isSuccess: true, error: new Error('Account access denied'), refetch: mocks.refetch, }) @@ -304,4 +335,105 @@ describe('organization integration invitations', () => { expect(mocks.people).not.toHaveBeenCalled() expect(mocks.invite).not.toHaveBeenCalled() }) + it('opens organization stats without loading people', async () => { + await render() + await click('Stats') + expect(container.textContent).toContain('Stats for org-a') + expect(mocks.people).not.toHaveBeenCalled() + }) + + it('filters connection summaries and requests to the selected integration, then returns to All', async () => { + mocks.accounts.mockReturnValue({ + isSuccess: true, + data: { + credentialGroup: { + id: 'group-a', + options: [ + { id: 'jira-option', provider: 'jira', status: 'active' }, + { id: 'gmail-option', provider: 'gmail', status: 'active' }, + { id: 'old-option', provider: 'confluence', status: 'revoked' }, + ], + }, + }, + }) + await render('?tab=people&integration=jira&credential-group-people=alex') + expect(mocks.people).toHaveBeenLastCalledWith('org-a', 'alex', { + enabled: true, + optionId: 'jira-option', + }) + expect(findButton('Filter people by integration').textContent).toContain('Jira') + await click('Request connections') + expect(document.querySelector('[role="dialog"]')?.textContent).toContain( + 'Request Jira connections' + ) + await click('Cancel') + await act(async () => + findButton('Filter people by integration').dispatchEvent( + new MouseEvent('pointerdown', { bubbles: true, button: 0 }) + ) + ) + const all = Array.from(document.querySelectorAll('[role="menuitem"]')).find( + (item) => item.textContent === 'All integrations' + ) + expect(all).toBeDefined() + expect(document.querySelector('[role="menu"]')?.textContent).not.toContain('Confluence') + await act(async () => all?.click()) + await vi.waitFor(() => + expect(mocks.people).toHaveBeenLastCalledWith('org-a', 'alex', { enabled: true }) + ) + expect(container.querySelector('input[placeholder="Search people..."]')).toHaveValue('alex') + }) + + it.each(['', '&integration=gmail'])( + 'defaults to All on navigation with one integration and initial filter %s', + async (filter) => { + mocks.accounts.mockReturnValue({ + isSuccess: true, + data: { + credentialGroup: { + id: 'group-a', + options: [{ id: 'gmail-option', provider: 'gmail', status: 'active' }], + }, + }, + }) + await render(`?tab=people${filter}`) + expect(findButton('Filter people by integration').textContent).toContain( + filter ? 'Gmail' : 'All integrations' + ) + expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { + enabled: true, + ...(filter ? { optionId: 'gmail-option' } : {}), + }) + await click('Sources') + await click('People') + expect(findButton('Filter people by integration').textContent).toContain('All integrations') + expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { enabled: true }) + } + ) + + it('preserves Slack setup recovery in People without hiding existing connections', async () => { + mocks.accounts.mockReturnValue({ + isSuccess: true, + data: { + credentialGroup: { + id: 'group-a', + options: [ + { + id: 'slack-option', + provider: 'slack', + status: 'active', + configurationStatus: 'needs_update', + }, + ], + }, + }, + }) + await render('?tab=people&integration=slack') + expect(mocks.people).toHaveBeenLastCalledWith('org-a', '', { + enabled: true, + optionId: 'slack-option', + }) + expect(findButton('Request connections')).toBeDisabled() + expect(container.textContent).toContain('Update the Slack app from Sources') + }) }) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.tsx index 5a88385585a..4753f09eb96 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-settings.tsx @@ -2,17 +2,21 @@ import { useState } from 'react' import { Chip, ChipConfirmModal, ChipModalError, ChipSwitch, toast } from '@sim/emcn' -import { useQueryState } from 'nuqs' +import { useQueryStates } from 'nuqs' import { getOrganizationAccountUpdateOptions } from '@/lib/credential-groups/organization-account-options' import { useOrganizationContext } from '@/app/o/[organizationId]/providers/organization-provider' import { OrganizationIntegrationsSetup } from '@/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup' -import { organizationIntegrationsTabParam } from '@/app/o/[organizationId]/settings/components/integrations/search-params' +import { OrganizationSourcePeople } from '@/app/o/[organizationId]/settings/components/integrations/organization-source-people' +import { OrganizationSourceStats } from '@/app/o/[organizationId]/settings/components/integrations/organization-source-stats' +import { + organizationIntegrationsTabParam, + organizationPeopleIntegrationParam, +} from '@/app/o/[organizationId]/settings/components/integrations/search-params' import { RowActionsMenu } from '@/app/workspace/[workspaceId]/settings/components/row-actions-menu' import { SettingsEmptyState, SettingsQueryErrorState, } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' -import { OrganizationAccountPeople } from '@/ee/credential-groups/components/organization-account-people' import { useOrganizationAccounts, useUpdateOrganizationAccounts, @@ -20,10 +24,10 @@ import { export function OrganizationIntegrationsSettings() { const { organization, viewer } = useOrganizationContext() - const [tab, setTab] = useQueryState( - organizationIntegrationsTabParam.key, - organizationIntegrationsTabParam.parser - ) + const [{ tab }, setNavigation] = useQueryStates({ + [organizationIntegrationsTabParam.key]: organizationIntegrationsTabParam.parser, + [organizationPeopleIntegrationParam.key]: organizationPeopleIntegrationParam.parser, + }) const accounts = useOrganizationAccounts(viewer.isAdmin ? organization.id : undefined) const update = useUpdateOrganizationAccounts() const [refreshOpen, setRefreshOpen] = useState(false) @@ -39,58 +43,68 @@ export function OrganizationIntegrationsSettings() { { onSuccess: () => { setRefreshOpen(false) - toast.success('Connection settings refreshed') + toast.success('Sign-in settings updated') }, } ) } if (!viewer.isAdmin) return null + const tabs = ( + void setNavigation({ tab: value, integration: null })} + options={[ + { value: 'providers', label: 'Sources' }, + { value: 'people', label: 'People' }, + { value: 'stats', label: 'Stats' }, + ]} + /> + ) + return (
-
- void setTab(value)} - options={[ - { value: 'providers', label: 'Sources' }, - { value: 'people', label: 'People' }, - ]} - /> - {tab === 'providers' && !accounts.error && group && group.options.length > 0 && ( - { - update.reset() - setRefreshOpen(true) + {tab === 'providers' && ( +
+ {tabs} + {tab === 'providers' && !accounts.error && group && group.options.length > 0 && ( + { + update.reset() + setRefreshOpen(true) + }, }, - }, - ]} - /> - )} -
+ ]} + /> + )} +
+ )} { if (!update.isPending) setRefreshOpen(open) }} - title='Refresh connection settings?' - text='Apply the latest sign-in settings to all integrations. Affected accounts will need to reconnect.' - confirm={{ label: 'Refresh', pending: update.isPending, onClick: refreshConnections }} + title='Update sign-in settings?' + text='Apply Sim’s current OAuth app and permission settings to member connections. People whose settings changed must reconnect. This does not sync content.' + confirm={{ label: 'Update', pending: update.isPending, onClick: refreshConnections }} > {update.error?.message} {tab === 'providers' && } + {tab === 'stats' && } {tab === 'people' && ( - Add a source that uses member accounts before requesting connections. - void setTab('providers')}>View sources + void setNavigation({ tab: 'providers', integration: null })}> + View sources +
) : undefined } diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.test.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.test.tsx index 9c1f75f361e..bb3eab8e511 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.test.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.test.tsx @@ -8,6 +8,9 @@ import type { OrganizationSearchProviderSummary } from '@/lib/api/contracts/know const mocks = vi.hoisted(() => ({ admin: true, + memberAccess: true, + mirroredAccess: true, + updateUrl: vi.fn(), overview: vi.fn(), push: vi.fn(), add: vi.fn(), @@ -25,7 +28,7 @@ vi.mock('@/app/o/[organizationId]/providers/organization-provider', () => ({ useOrganizationContext: () => ({ organization: { id: 'org-one' }, viewer: { isAdmin: mocks.admin }, - searchAccess: { memberScoped: true, sourceMirrored: true }, + searchAccess: { memberScoped: mocks.memberAccess, sourceMirrored: mocks.mirroredAccess }, }), })) vi.mock('@/hooks/queries/kb/connectors', () => ({ useOrganizationSearchOverview: mocks.overview })) @@ -73,6 +76,8 @@ let container: HTMLDivElement beforeEach(() => { vi.clearAllMocks() mocks.admin = true + mocks.memberAccess = true + mocks.mirroredAccess = true mocks.pending = false mocks.mutationError = null mocks.add.mockReset() @@ -83,6 +88,7 @@ beforeEach(() => { ['confluence', true], ['google-drive', true], ['google-email', true], + ['jira', true], ]), isIntegrationAvailabilityReady: true, refetchIntegrationAvailability: mocks.refetch, @@ -110,7 +116,7 @@ afterEach(async () => { async function render(searchParams = '') { await act(async () => root.render( - + @@ -128,253 +134,280 @@ async function click(label: string) { await act(async () => button!.click()) } -describe('organization integration management entry', () => { - it('uses Sources terminology in search and its empty state', async () => { - await render('?search=not-a-real-source') - expect(container.querySelector('input[placeholder="Search sources..."]')).toHaveValue( - 'not-a-real-source' - ) - expect(container.textContent).toContain('No matching sources') - expect(container.textContent).not.toContain('No matching integrations') - }) - it('offers Drive account management before anyone has connected', async () => { - mocks.overview.mockReturnValue({ - data: { - providers: [ - { - connectorType: 'google_drive', - approved: true, - sourceCount: 0, - status: 'waiting_for_connections', - issue: null, - isSyncing: false, - }, - ], - }, - isPending: false, +async function expectSetup(type: string | null, access: string | null = null) { + await act(async () => { + await vi.waitFor(() => { + const params = mocks.updateUrl.mock.calls.at(-1)?.[0].searchParams + expect(params).toBeDefined() + expect(params.get('addConnector')).toBe(type) + expect(params.get('source-access')).toBe(access) }) - await render() - expect(document.querySelector('a[aria-label="Manage Google Drive"]')).toHaveAttribute( - 'href', - '/o/org-one/settings/integrations/providers/google_drive' - ) - expect(document.querySelector('a[aria-label="Set up Google Drive"]')).toBeNull() - expect(container.textContent).toContain('Waiting for connections') }) - it('shows the stable catalog with switches and separate setup and management links', async () => { +} + +async function fillPicker(value: string) { + const input = document.querySelector('[aria-label="Find a source"]') + expect(input).not.toBeNull() + await act(async () => { + Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set?.call(input, value) + input?.dispatchEvent(new Event('input', { bubbles: true })) + }) +} + +describe('organization integration management entry', () => { + it('uses navigable settings rows for added sources without switches or setup buttons', async () => { await render() - expect(document.querySelector('a[aria-label="Manage Gmail"]')).toHaveAttribute( + expect(container.textContent).toContain('Waiting for connections') + expect(container.textContent).toContain('Deactivated · 2 connections') + expect(container.querySelector('a[aria-label="Manage Gmail"]')).toHaveAttribute( 'href', '/o/org-one/settings/integrations/providers/gmail' ) - expect(document.querySelector('a[aria-label="Manage Google Drive"]')).toHaveAttribute( - 'href', - '/o/org-one/settings/integrations/providers/google_drive' - ) - expect(container.textContent).toContain('Waiting for connections') - expect(container.textContent).not.toContain('Needs setup') - expect(container.textContent).toContain('Disabled') - expect(container.textContent).toContain('Confluence') - expect(container.textContent).not.toContain('Add integration') - expect(document.querySelector('[aria-label="Allow Gmail in Sim Search"]')).toHaveAttribute( - 'aria-checked', - 'true' - ) - expect( - document.querySelector('[aria-label="Allow Google Drive in Sim Search"]') - ).toHaveAttribute('aria-checked', 'false') - expect(document.querySelector('a[aria-label="Set up Confluence"]')).toBeNull() - }) - - it('offers the catalog for a new organization without a modal or writes', async () => { - mocks.overview.mockReturnValue({ data: { providers: [] }, isPending: false }) - await render() - expect(container.textContent).toContain('Confluence') - expect(container.textContent).toContain('Google Drive') - expect(document.querySelector('[role="dialog"]')).toBeNull() + expect(container.querySelector('a[aria-label="Manage Google Drive"]')).not.toBeNull() + expect(container.textContent).not.toContain('Confluence') + expect(container.querySelector('[role="switch"]')).toBeNull() + expect(container.querySelector('a[aria-label="Set up Gmail"]')).toBeNull() expect(mocks.add).not.toHaveBeenCalled() }) - it('enables in place and shows setup after the server confirms approval', async () => { - await render() - const row = document.querySelector('[aria-label="Allow Confluence in Sim Search"]') - await click('Allow Confluence in Sim Search') - expect(mocks.add).toHaveBeenCalledExactlyOnceWith( - { organizationId: 'org-one', connectorType: 'confluence', approved: true }, - expect.any(Object) - ) - expect(row).toHaveAttribute('aria-checked', 'false') + it('keeps approved sources with unfinished setup visible', async () => { mocks.overview.mockReturnValue({ data: { providers: [ - ...providers, { + ...providers[0], connectorType: 'confluence', - approved: true, - sourceCount: 0, status: 'needs_setup', - isSyncing: false, }, ], }, isPending: false, }) await render() - expect(document.querySelector('[aria-label="Allow Confluence in Sim Search"]')).toBe(row) - expect(row).toHaveAttribute('aria-checked', 'true') - expect(document.querySelector('a[aria-label="Set up Confluence"]')).not.toBeNull() - expect(mocks.push).not.toHaveBeenCalled() - expect(document.querySelector('[role="dialog"]')).toBeNull() + expect(container.textContent).toContain('Setup required') + expect(container.querySelector('a[aria-label="Manage Confluence"]')).not.toBeNull() }) - it('requires confirmation before disabling existing sources and lets the admin cancel', async () => { - mocks.overview.mockReturnValue({ - data: { providers: [{ ...providers[1], approved: true }] }, - isPending: false, - }) + it('opens the catalog from the header without changing any approvals', async () => { + mocks.overview.mockReturnValue({ data: { providers: [] }, isPending: false }) await render() - await click('Allow Google Drive in Sim Search') - expect(document.querySelector('[role="dialog"]')).toHaveTextContent( - 'Sources and connected accounts are preserved.' - ) + expect(container.textContent).toContain('No sources yet. Add a source to get started.') + expect(document.querySelector('[role="dialog"]')).toBeNull() + await click('Add source') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent('Confluence') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent('Jira') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent('Connect a service account') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent('Connect member accounts') expect(mocks.add).not.toHaveBeenCalled() await click('Cancel') expect(document.querySelector('[role="dialog"]')).toBeNull() + await expectSetup(null) expect(mocks.add).not.toHaveBeenCalled() - await click('Allow Google Drive in Sim Search') - mocks.add.mockImplementation((_input, options) => options.onSuccess()) - await click('Deactivate') + }) + + it('approves a new source before opening its central configuration form', async () => { + await render('?addConnector=') + await click('Set up Confluence') expect(mocks.add).toHaveBeenCalledExactlyOnceWith( - { organizationId: 'org-one', connectorType: 'google_drive', approved: false }, + { organizationId: 'org-one', connectorType: 'confluence', approved: true }, expect.any(Object) ) + expect(document.querySelector('[role="dialog"]')).not.toBeNull() + await act(async () => mocks.add.mock.calls[0][1].onSuccess()) + await expectSetup('confluence') expect(document.querySelector('[role="dialog"]')).toBeNull() }) - it('allows disabling an integration with no sources in place', async () => { - await render() - await click('Allow Gmail in Sim Search') - expect(mocks.add).toHaveBeenCalledExactlyOnceWith( - { organizationId: 'org-one', connectorType: 'gmail', approved: false }, + it('opens an approved source directly without a duplicate approval', async () => { + await render('?addConnector=&search=retained') + await click('Set up Gmail') + await expectSetup('gmail') + expect(mocks.updateUrl.mock.calls.at(-1)?.[0].searchParams.get('search')).toBe('retained') + expect(mocks.add).not.toHaveBeenCalled() + }) + + it.each(['jira', 'confluence'])( + 'uses member setup for %s when central indexing is unavailable', + async (type) => { + mocks.mirroredAccess = false + mocks.add.mockImplementation((_input, options) => options.onSuccess()) + await render('?addConnector=') + await click(`Set up ${type === 'jira' ? 'Jira' : 'Confluence'}`) + await expectSetup(type, 'members') + } + ) + + it('routes Slack into the existing member setup with its custom-app step', async () => { + mocks.availability.mockReturnValue({ + integrationAvailability: new Map([['slack_v2', { state: 'limited' }]]), + oauthServiceAvailability: new Map(), + isIntegrationAvailabilityReady: true, + }) + mocks.add.mockImplementation((_input, options) => options.onSuccess()) + await render('?addConnector=') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent('Set up your Slack app') + await click('Set up Slack') + await expectSetup('slack', 'members') + }) + + it('reactivates a retained source before opening another configuration', async () => { + mocks.add.mockImplementation((_input, options) => options.onSuccess()) + await render('?addConnector=') + await click('Set up Google Drive') + await expectSetup('google_drive') + expect(mocks.add).toHaveBeenCalledWith( + { organizationId: 'org-one', connectorType: 'google_drive', approved: true }, expect.any(Object) ) - expect(document.querySelector('[role="dialog"]')).toBeNull() }) - it('keeps the confirmed state and reports failed approval changes', async () => { + it('keeps the picker open and toasts a failed approval for retry', async () => { mocks.add.mockImplementation((_input, options) => - options.onError(new Error('Could not update integration')) + options.onError(new Error('Could not add source')) ) - await render() - await click('Allow Confluence in Sim Search') - expect(toast.error).toHaveBeenCalledWith('Could not update integration') - expect(document.querySelector('[aria-label="Allow Confluence in Sim Search"]')).toHaveAttribute( - 'aria-checked', - 'false' - ) - expect(document.querySelector('a[aria-label="Set up Confluence"]')).toBeNull() + await render('?addConnector=') + await click('Set up Confluence') + expect(toast.error).toHaveBeenCalledWith('Could not add source') + expect(document.querySelector('[role="dialog"]')).not.toBeNull() + expect(mocks.updateUrl).not.toHaveBeenCalled() }) - it('keeps a failed deactivation in the confirmation dialog for retry', async () => { - mocks.overview.mockReturnValue({ - data: { providers: [{ ...providers[1], approved: true }] }, - isPending: false, + it('prevents another selection or dismissal while approval is pending', async () => { + mocks.pending = true + await render('?addConnector=') + expect(document.querySelector('button[aria-label="Set up Confluence"]')).toBeNull() + expect(document.querySelector('[aria-label="Find a source"]')).toBeDisabled() + await click('Cancel') + expect(document.querySelector('[role="dialog"]')).not.toBeNull() + expect(mocks.add).not.toHaveBeenCalled() + expect(mocks.updateUrl).not.toHaveBeenCalled() + }) + + it('explains unavailable providers in the picker without allowing setup', async () => { + mocks.availability.mockReturnValue({ + integrationAvailability: new Map(), + oauthServiceAvailability: new Map(), + isIntegrationAvailabilityReady: true, }) - await render() - await click('Allow Google Drive in Sim Search') - await click('Deactivate') - mocks.mutationError = new Error('Could not deactivate integration') - await render() + await render('?addConnector=') expect(document.querySelector('[role="dialog"]')).toHaveTextContent( - 'Could not deactivate integration' + 'Unavailable in this deployment' ) - expect( - document.querySelector('[aria-label="Allow Google Drive in Sim Search"]') - ).toHaveAttribute('aria-checked', 'true') - }) - - it('prevents duplicate changes while a mutation is pending', async () => { - mocks.pending = true - await render() - await click('Allow Confluence in Sim Search') + expect(document.querySelector('button[aria-label="Set up Confluence"]')).toBeNull() expect(mocks.add).not.toHaveBeenCalled() - expect(document.querySelector('[aria-label="Allow Confluence in Sim Search"]')).toBeDisabled() }) - it('blocks unavailable setup while keeping existing sources manageable and deactivatable', async () => { + it('keeps existing unavailable sources manageable', async () => { mocks.availability.mockReturnValue({ integrationAvailability: new Map(), oauthServiceAvailability: new Map(), isIntegrationAvailabilityReady: true, }) + await render() + expect(container.querySelector('a[aria-label="Manage Gmail"]')).not.toBeNull() + expect(container.querySelector('a[aria-label="Manage Google Drive"]')).not.toBeNull() + }) + + it('filters the picker independently from the main source list and resets when reopened', async () => { + await render('?search=gmail') + await click('Add source') + await fillPicker('confluence') + const dialog = document.querySelector('[role="dialog"]') + expect(dialog).toHaveTextContent('Confluence') + expect(dialog).not.toHaveTextContent('Google Drive') + expect(container.querySelector('a[aria-label="Manage Gmail"]')).not.toBeNull() + await fillPicker('no-such-source') + expect(dialog).toHaveTextContent('No matching sources') + await click('Cancel') + await click('Add source') + expect(document.querySelector('[aria-label="Find a source"]')).toHaveValue('') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent('Google Drive') + expect(mocks.add).not.toHaveBeenCalled() + }) + + it('keeps source health visible alongside the configuration count', async () => { mocks.overview.mockReturnValue({ - data: { providers: [{ ...providers[1], approved: true }] }, + data: { + providers: [ + { + ...providers[1], + approved: true, + status: 'needs_attention', + issue: 'sync_failed', + }, + ], + }, isPending: false, }) await render() - expect(document.querySelector('[aria-label="Allow Confluence in Sim Search"]')).toBeDisabled() - expect( - document.querySelector('[aria-label="Allow Google Drive in Sim Search"]') - ).not.toBeDisabled() - expect(document.querySelector('a[aria-label="Manage Google Drive"]')).not.toBeNull() - expect(container.textContent).toContain('Unavailable in this deployment') - await click('Allow Confluence in Sim Search') - expect(mocks.add).not.toHaveBeenCalled() + expect(container.textContent).toContain('Sync failed · 2 connections') }) - it('fails closed while availability loads and offers retry if it fails', async () => { + it('fails closed and offers retry when availability fails inside the picker', async () => { mocks.availability.mockReturnValue({ integrationAvailability: new Map(), oauthServiceAvailability: new Map(), - isIntegrationAvailabilityReady: false, + isIntegrationAvailabilityReady: true, integrationAvailabilityError: new Error('Could not load connection availability'), refetchIntegrationAvailability: mocks.refetch, }) - await render() - expect(document.querySelector('[aria-label="Allow Confluence in Sim Search"]')).toBeDisabled() + await render('?addConnector=') + expect(document.querySelector('[role="dialog"]')).toHaveTextContent( + 'Could not load connection availability' + ) + expect(document.querySelector('button[aria-label="Set up Confluence"]')).toBeNull() await click('Try again') expect(mocks.refetch).toHaveBeenCalledOnce() }) - it('does not hide actionable sync failures behind a source count', async () => { - mocks.overview.mockReturnValue({ - data: { providers: [{ ...providers[1], approved: true, status: 'needs_attention' }] }, - isPending: false, - }) - await render() - expect(container.textContent).toContain('Sync failed') - expect(document.querySelector('a[aria-label="Manage Google Drive"]')).not.toBeNull() - }) - - it('does not turn a failed overview into unapproved switches', async () => { + it('does not turn a failed overview into an empty source list', async () => { mocks.overview.mockReturnValue({ error: new Error('Could not load sources'), isError: true, refetch: mocks.refetch, }) await render() - expect(document.querySelector('[role="switch"]')).toBeNull() + expect(container.textContent).not.toContain('No sources yet') + expect( + Array.from(container.querySelectorAll('button')).find( + (node) => node.textContent === 'Add source' + ) + ).toBeDisabled() await click('Try again') expect(mocks.refetch).toHaveBeenCalledOnce() }) - it('keeps loading distinct from unapproved integrations', async () => { + it('keeps loading distinct from a new organization', async () => { mocks.overview.mockReturnValue({ isPending: true }) await render() expect(container.textContent).toContain('Loading sources') - expect(document.querySelector('[role="switch"]')).toBeNull() + expect(container.textContent).not.toContain('No sources yet') + expect( + Array.from(container.querySelectorAll('button')).find( + (node) => node.textContent === 'Add source' + ) + ).toBeDisabled() }) it('does not expose admin controls or load admin data for members', async () => { mocks.admin = false - await render() + await render('?addConnector=') expect(mocks.overview).toHaveBeenLastCalledWith('org-one', { enabled: false }) expect(container.textContent).toBe('') + expect(document.querySelector('[role="dialog"]')).toBeNull() + }) + + it('does not expose setup when Search is disabled', async () => { + mocks.memberAccess = false + mocks.mirroredAccess = false + await render('?addConnector=') + expect(container.textContent).toContain('Search sources are not enabled') + expect(document.querySelector('[role="dialog"]')).toBeNull() }) - it('filters the whole catalog without changing approvals', async () => { - await render('?search=confluence') - expect(container.textContent).toContain('Confluence') + it('filters added sources without changing approvals', async () => { + await render('?search=gmail') + expect(container.textContent).toContain('Gmail') expect(container.textContent).not.toContain('Google Drive') expect(mocks.add).not.toHaveBeenCalled() }) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.tsx index a3de964ef15..359388941bd 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-integrations-setup.tsx @@ -1,19 +1,21 @@ 'use client' -import { useState } from 'react' -import { ChipConfirmModal, ChipLink, ChipModalError, Switch, toast } from '@sim/emcn' +import { toast } from '@sim/emcn' +import { Plus } from '@sim/emcn/icons' +import { useQueryStates } from 'nuqs' import { SettingsPanel } from '@/components/settings/settings-panel' import { organizationRoutes } from '@/lib/navigation/paths' -import { - canConnectWithDefaults, - getConnectorAccessAvailability, - SEARCH_SOURCE_TYPES, -} from '@/lib/sim-search/connectors' +import { getConnectorAccessAvailability, SEARCH_SOURCE_TYPES } from '@/lib/sim-search/connectors' import { useOrganizationContext } from '@/app/o/[organizationId]/providers/organization-provider' +import { AddOrganizationSourceModal } from '@/app/o/[organizationId]/settings/components/integrations/add-organization-source-modal' import { organizationSearchStatusLabel } from '@/app/o/[organizationId]/settings/components/integrations/organization-search-status' import { OrganizationSlackAccountSetup } from '@/app/o/[organizationId]/settings/components/integrations/slack-account-setup' import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase' import { SearchSourceSetup } from '@/app/workspace/[workspaceId]/search/components/search-source-setup' +import { + searchSetupAccessParam, + searchSetupParam, +} from '@/app/workspace/[workspaceId]/search/search-params' import { SettingsEmptyState, SettingsQueryErrorState, @@ -30,25 +32,62 @@ import { usePermissionConfig } from '@/hooks/use-permission-config' export function OrganizationIntegrationsSetup() { const { organization, viewer, searchAccess } = useOrganizationContext() const [search, setSearch] = useSettingsSearch() + const [setup, setSetup] = useQueryStates( + { + [searchSetupParam.key]: searchSetupParam.parser, + [searchSetupAccessParam.key]: searchSetupAccessParam.parser, + }, + { history: 'replace' } + ) const overview = useOrganizationSearchOverview(organization.id, { enabled: viewer.isAdmin }) const availability = usePermissionConfig() const approval = useUpdateSearchIntegration() - const [deactivating, setDeactivating] = useState(null) const providers = new Map( overview.data?.providers.map((provider) => [provider.connectorType, provider]) ) + const sources = SEARCH_SOURCE_TYPES.map(([type, meta]) => ({ + type, + meta, + access: getConnectorAccessAvailability(meta, availability.integrationAvailability, { + memberAccessAvailable: searchAccess.memberScoped, + mirroredAccessAvailable: searchAccess.sourceMirrored, + oauthServiceAvailability: availability.oauthServiceAvailability, + isIntegrationAvailabilityReady: availability.isIntegrationAvailabilityReady, + }), + })) const query = search.trim().toLowerCase() - const visible = SEARCH_SOURCE_TYPES.filter(([, meta]) => meta.name.toLowerCase().includes(query)) - const deactivatingName = SEARCH_SOURCE_TYPES.find(([type]) => type === deactivating)?.[1].name - const changeApproval = (connectorType: string, approved: boolean) => { - approval.reset() - if (!approved && (providers.get(connectorType)?.sourceCount ?? 0) > 0) { - setDeactivating(connectorType) + const visible = sources.flatMap((source) => { + const provider = providers.get(source.type) + return provider && + (provider.approved || provider.sourceCount > 0) && + source.meta.name.toLowerCase().includes(query) + ? [{ ...source, provider }] + : [] + }) + const ready = Boolean( + !overview.isPending && + !overview.isError && + availability.isIntegrationAvailabilityReady && + !availability.integrationAvailabilityError + ) + const closePicker = () => { + if (!approval.isPending) void setSetup({ addConnector: null, 'source-access': null }) + } + const selectSource = (type: string, accessMode: 'admin' | 'members') => { + const selectedType = searchSetupParam.parser.parse(type) + if (!selectedType || !ready || approval.isPending) return + const startSetup = () => + void setSetup({ + addConnector: selectedType, + 'source-access': accessMode === 'members' ? 'members' : null, + }) + if (providers.get(type)?.approved) { + startSetup() return } approval.mutate( - { organizationId: organization.id, connectorType, approved }, - { onError: (error) => toast.error(error.message) } + { organizationId: organization.id, connectorType: type, approved: true }, + { onSuccess: startSetup, onError: (error) => toast.error(error.message) } ) } if (!viewer.isAdmin) return null @@ -59,113 +98,94 @@ export function OrganizationIntegrationsSetup() { ) + const feedback = overview.isError ? ( + void overview.refetch()} + variant='inline' + /> + ) : availability.integrationAvailabilityError ? ( + void availability.refetchIntegrationAvailability()} + variant='inline' + /> + ) : null + return ( - - {availability.integrationAvailabilityError && ( - void availability.refetchIntegrationAvailability()} - variant='inline' - /> - )} -
- {overview.isError ? ( - void overview.refetch()} - variant='inline' - /> - ) : overview.isPending ? ( - Loading sources… - ) : visible.length === 0 ? ( - No matching sources - ) : ( - visible.map(([type, meta]) => { - const provider = providers.get(type) - const approved = provider?.approved === true - const sourceCount = provider?.sourceCount ?? 0 - const access = getConnectorAccessAvailability( - meta, - availability.integrationAvailability, - { - memberAccessAvailable: searchAccess.memberScoped, - mirroredAccessAvailable: searchAccess.sourceMirrored, - oauthServiceAvailability: availability.oauthServiceAvailability, - isIntegrationAvailabilityReady: availability.isIntegrationAvailabilityReady, - } - ) - const available = access.admin || access.members - const hasSources = sourceCount > 0 - const manage = hasSources || canConnectWithDefaults(meta) - let description = provider ? organizationSearchStatusLabel(provider) : undefined - if (!hasSources && availability.isIntegrationAvailabilityReady && !available) - description = 'Unavailable in this deployment' - return ( - } - title={meta.name} - description={description} - trailing={ -
- {(hasSources || (approved && available)) && ( - - {manage ? 'Manage' : 'Set up'} - - )} - changeApproval(type, checked)} - /> -
- } - /> - ) - }) - )} -
- { - if (!open && !approval.isPending) setDeactivating(null) - }} - title={`Deactivate ${deactivatingName ?? 'integration'}?`} - text='Its content will be unavailable in Search, Assistant, and MCP. Sources and connected accounts are preserved.' - confirm={{ - label: 'Deactivate', - variant: 'destructive', - pending: approval.isPending, - onClick: () => { - if (!deactivating) return - approval.mutate( - { organizationId: organization.id, connectorType: deactivating, approved: false }, - { onSuccess: () => setDeactivating(null) } - ) + <> + void setSetup({ addConnector: '', 'source-access': null }), }, - }} + ]} + search={{ value: search, onChange: setSearch, placeholder: 'Search sources...' }} > - {approval.error?.message} - - + {setup.addConnector !== '' && feedback} +
+ {overview.isError ? null : overview.isPending ? ( + Loading sources… + ) : visible.length === 0 ? ( + + {query ? 'No matching sources' : 'No sources yet. Add a source to get started.'} + + ) : ( + visible.map(({ type, meta, access, provider }) => { + const available = access.admin || access.members + const status = + provider.approved && ready && !available + ? 'Unavailable in this deployment' + : organizationSearchStatusLabel(provider) + return ( + } + title={meta.name} + description={[ + status, + provider.sourceCount > 0 + ? `${provider.sourceCount} ${provider.sourceCount === 1 ? 'connection' : 'connections'}` + : undefined, + ] + .filter(Boolean) + .join(' · ')} + href={organizationRoutes(organization.id).searchProvider(type)} + clickLabel={`Manage ${meta.name}`} + navigable + /> + ) + }) + )} +
+
+ {setup.addConnector === '' ? ( + + ) : ( + + )} - + ) } diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.test.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.test.tsx new file mode 100644 index 00000000000..c5b62c0626c --- /dev/null +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.test.tsx @@ -0,0 +1,127 @@ +/** @vitest-environment jsdom */ +import { act } from 'react' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { OrganizationSearchStatsPeriod } from '@/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period' + +let root: Root +let container: HTMLDivElement +let originalScroll: typeof HTMLElement.prototype.scrollIntoView +const onChange = vi.fn() + +beforeEach(() => { + vi.clearAllMocks() + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + originalScroll = HTMLElement.prototype.scrollIntoView + HTMLElement.prototype.scrollIntoView = vi.fn() + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) +}) +afterEach(async () => { + await act(async () => root.unmount()) + container.remove() + HTMLElement.prototype.scrollIntoView = originalScroll + vi.unstubAllGlobals() +}) + +async function render() { + await act(async () => + root.render( + + ) + ) +} +async function selectPeriod(label: string) { + const trigger = container.querySelector('[role="combobox"]') + expect(trigger).not.toBeNull() + await act(async () => + trigger?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })) + ) + const option = Array.from(document.querySelectorAll('[role="option"]')).find( + (item) => item.textContent === label + ) + expect(option).toBeDefined() + await act(async () => option?.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))) +} +async function click(label: string) { + const button = Array.from(document.querySelectorAll('button')).find( + (item) => item.textContent === label + ) + expect(button).toBeDefined() + await act(async () => button?.click()) +} + +describe('Stats date selection', () => { + it('keeps the existing range when calendar edits are cancelled', async () => { + await render() + await selectPeriod('Custom range') + expect( + document + .querySelector('[data-radix-popper-content-wrapper]') + ?.contains(document.activeElement) + ).toBe(true) + await click('5') + await click('8') + expect(onChange).not.toHaveBeenCalled() + await click('Cancel') + await vi.waitFor(() => + expect(document.activeElement).toBe(container.querySelector('[role="combobox"]')) + ) + expect(onChange).not.toHaveBeenCalled() + expect(document.body.textContent).not.toContain('Apply') + expect(container.textContent).toContain('Sep 1 – Sep 3') + }) + it('applies both date-only boundaries in one update and closes the calendar', async () => { + await render() + await selectPeriod('Custom range') + await click('5') + await click('8') + await click('Apply') + expect(onChange).toHaveBeenCalledExactlyOnceWith({ + period: 'custom', + startDate: '2024-09-05', + endDate: '2024-09-08', + }) + expect(document.body.textContent).not.toContain('Apply') + }) + it('clears custom boundaries when choosing a preset', async () => { + await render() + await selectPeriod('Past 3 days') + expect(onChange).toHaveBeenCalledExactlyOnceWith({ + period: '3d', + startDate: null, + endDate: null, + }) + }) + it('opens the calendar from the keyboard and restores focus on Escape', async () => { + await render() + const trigger = container.querySelector('[role="combobox"]') + await act(async () => { + trigger?.focus() + trigger?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })) + }) + for (let index = 0; index < 6; index++) { + await act(async () => + trigger?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })) + ) + } + await act(async () => + trigger?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) + ) + expect(document.body.textContent).toContain('Apply') + expect(document.activeElement).not.toBe(trigger) + await act(async () => + document.activeElement?.dispatchEvent( + new KeyboardEvent('keydown', { key: 'Escape', bubbles: true }) + ) + ) + await vi.waitFor(() => expect(document.activeElement).toBe(trigger)) + expect(onChange).not.toHaveBeenCalled() + }) +}) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.tsx new file mode 100644 index 00000000000..cff874b2785 --- /dev/null +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period.tsx @@ -0,0 +1,89 @@ +'use client' + +import { useRef, useState } from 'react' +import { Calendar, ChipCombobox, Popover, PopoverAnchor, PopoverContent, toast } from '@sim/emcn' +import { formatDateShort } from '@/lib/core/utils/date-display' +import { getSearchStatsRangeError, type SEARCH_STATS_PERIODS } from '@/lib/knowledge/search/stats' + +const PERIOD_OPTIONS = [ + { value: 'today', label: 'Today' }, + { value: '3d', label: 'Past 3 days' }, + { value: '7d', label: 'Past 7 days' }, + { value: '14d', label: 'Past 14 days' }, + { value: '30d', label: 'Past 30 days' }, + { value: '90d', label: 'Past 90 days' }, + { value: 'custom', label: 'Custom range' }, +] satisfies { value: (typeof SEARCH_STATS_PERIODS)[number]; label: string }[] + +interface SearchStatsPeriodSelection { + period: (typeof SEARCH_STATS_PERIODS)[number] + startDate: string | null + endDate: string | null +} + +interface OrganizationSearchStatsPeriodProps extends SearchStatsPeriodSelection { + onChange: (selection: SearchStatsPeriodSelection) => void +} + +export function OrganizationSearchStatsPeriod({ + period, + startDate, + endDate, + onChange, +}: OrganizationSearchStatsPeriodProps) { + const triggerContainerRef = useRef(null) + const calendarRef = useRef(null) + const [calendarOpen, setCalendarOpen] = useState(false) + const label = + period === 'custom' && startDate && endDate && !getSearchStatsRangeError({ startDate, endDate }) + ? `${formatDateShort(startDate)} – ${formatDateShort(endDate)}` + : PERIOD_OPTIONS.find((option) => option.value === period)?.label + + return ( +
+ { + const selected = PERIOD_OPTIONS.find((option) => option.value === value) + if (!selected) return + if (selected.value === 'custom') setCalendarOpen(true) + else onChange({ period: selected.value, startDate: null, endDate: null }) + }} + /> + + + calendarRef.current?.focus()} + onCloseAutoFocus={() => + triggerContainerRef.current?.querySelector('[role="combobox"]')?.focus() + } + > + setCalendarOpen(false)} + onRangeChange={(start, end) => { + const error = getSearchStatsRangeError({ startDate: start, endDate: end }) + if (error) { + toast.error(error) + return + } + onChange({ period: 'custom', startDate: start, endDate: end }) + setCalendarOpen(false) + }} + /> + + +
+ ) +} diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.test.ts b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.test.ts index dc1bfa33cfa..90b069f5f44 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.test.ts +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.test.ts @@ -16,13 +16,13 @@ describe('organization source status labels', () => { it('describes the next step instead of calling all empty integrations unconfigured', () => { expect(organizationSearchStatusLabel(provider)).toBe('Waiting for connections') expect(organizationSearchStatusLabel({ ...provider, status: 'needs_setup' })).toBe( - 'Source not configured' + 'Setup required' ) expect( organizationSearchStatusLabel({ ...provider, status: 'needs_setup', sourceCount: 1 }) ).toBe('Waiting for first sync') expect(organizationSearchStatusLabel({ ...provider, status: 'active', sourceCount: 1 })).toBe( - 'Enabled' + 'Ready to search' ) }) it.each([ @@ -50,6 +50,6 @@ describe('organization source status labels', () => { status: 'needs_attention', issue: 'sync_failed', }) - ).toBe('Disabled') + ).toBe('Deactivated') }) }) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.ts b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.ts index 547f0339812..5988b08ce56 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.ts +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-search-status.ts @@ -1,16 +1,16 @@ import type { OrganizationSearchProviderSummary } from '@/lib/api/contracts/knowledge/connectors' const STATUS_LABELS: Record = { - needs_setup: 'Source not configured', + needs_setup: 'Setup required', waiting_for_connections: 'Waiting for connections', indexing: 'Indexing', needs_attention: 'Sync failed', paused: 'Paused', - active: 'Enabled', + active: 'Ready to search', } export function organizationSearchStatusLabel(provider: OrganizationSearchProviderSummary): string { - if (!provider.approved) return 'Disabled' + if (!provider.approved) return 'Deactivated' if (provider.status === 'needs_setup' && provider.sourceCount > 0) return 'Waiting for first sync' if (provider.status === 'needs_attention') { const error = diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-people.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-people.tsx new file mode 100644 index 00000000000..338ba91c5d9 --- /dev/null +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-people.tsx @@ -0,0 +1,79 @@ +'use client' + +import type { ComponentProps, ReactNode } from 'react' +import { ChipSelect } from '@sim/emcn' +import { useQueryState } from 'nuqs' +import type { CredentialGroupOption } from '@/lib/api/contracts/credential-groups' +import { getCredentialGroupIndexingConnector } from '@/lib/credential-groups/indexing' +import { organizationPeopleIntegrationParam } from '@/app/o/[organizationId]/settings/components/integrations/search-params' +import { OrganizationAccountPeople } from '@/ee/credential-groups/components/organization-account-people' + +interface OrganizationSourcePeopleProps + extends Omit, 'searchConnection' | 'filters'> { + options: CredentialGroupOption[] + tabs: ReactNode +} + +export function OrganizationSourcePeople({ + options, + tabs, + ...props +}: OrganizationSourcePeopleProps) { + const [integration, setIntegration] = useQueryState( + organizationPeopleIntegrationParam.key, + organizationPeopleIntegrationParam.parser + ) + const integrations = options + .flatMap((option) => { + const connector = getCredentialGroupIndexingConnector(option.provider) + return option.status === 'active' && connector + ? [ + { + optionId: option.id, + type: connector.type, + name: connector.meta.name, + icon: connector.meta.icon, + needsSetup: option.provider === 'slack' && option.configurationStatus !== 'ready', + }, + ] + : [] + }) + .sort((a, b) => a.name.localeCompare(b.name)) + const selected = integrations.find((item) => item.type === integration) + + return ( + +
+ {tabs} + void setIntegration(value === 'all' ? null : value)} + disabled={props.enabled === false || Boolean(props.setupFallback)} + options={[ + { value: 'all', label: 'All integrations' }, + ...integrations.map((item) => ({ + value: item.type, + label: item.name, + icon: item.icon, + })), + ]} + /> +
+ {selected?.needsSetup && ( +

+ Update the Slack app from Sources before requesting connections. +

+ )} +
+ } + /> + ) +} diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.test.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.test.tsx new file mode 100644 index 00000000000..11481d6a1f4 --- /dev/null +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.test.tsx @@ -0,0 +1,152 @@ +/** @vitest-environment jsdom */ +import { act } from 'react' +import { NuqsTestingAdapter } from 'nuqs/adapters/testing' +import { createRoot, type Root } from 'react-dom/client' +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import type { OrganizationSearchStats } from '@/lib/api/contracts/knowledge/search-stats' + +const mocks = vi.hoisted(() => ({ + query: vi.fn(), + chart: vi.fn(), + refetch: vi.fn(), + updateUrl: vi.fn(), +})) +vi.mock('@/hooks/queries/organization-search-stats', () => ({ + useOrganizationSearchStats: mocks.query, +})) +vi.mock('@/components/charts', () => ({ + BarChart: (props: unknown) => { + mocks.chart(props) + return
Daily chart
+ }, +})) +vi.mock('@/connectors/registry', () => ({ + CONNECTOR_META_REGISTRY: { confluence: { name: 'Confluence' }, jira: { name: 'Jira' } }, +})) +vi.mock('next/navigation', () => ({ useRouter: () => ({}) })) + +import { SettingsHeaderProvider } from '@/components/settings/settings-header' +import { OrganizationSourceStats } from '@/app/o/[organizationId]/settings/components/integrations/organization-source-stats' + +const data: OrganizationSearchStats = { + start: '2026-09-04T00:00:00.000Z', + end: '2026-09-10T20:00:00.000Z', + totals: { invocations: 5, activePeople: 2, results: 8 }, + series: [{ timestamp: '2026-09-10T00:00:00.000Z', invocations: 5 }], + sources: [{ sourceType: 'confluence', invocations: 4 }], + surfaces: [ + { surface: 'dashboard', invocations: 3 }, + { surface: 'mcp', invocations: 2 }, + ], + people: [ + { + userId: 'person', + name: 'Alex', + email: 'alex@example.com', + invocations: 5, + sourceTypes: ['confluence', 'jira'], + }, + ], +} +let root: Root +let container: HTMLDivElement + +beforeEach(() => { + vi.clearAllMocks() + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + mocks.query.mockReturnValue({ data, isError: false, refetch: mocks.refetch }) + container = document.createElement('div') + document.body.appendChild(container) + root = createRoot(container) +}) +afterEach(async () => { + await act(async () => root.unmount()) + container.remove() + vi.unstubAllGlobals() +}) +async function render(searchParams = '') { + await act(async () => + root.render( + + + Sources People Stats} /> + + + ) + ) +} + +describe('organization Search stats', () => { + it('renders request metrics, source labels, people and the canonical daily chart', async () => { + await render() + expect(container.textContent).not.toContain('No-result rate') + expect(container.textContent).toContain('Confluence, Jira') + expect(container.textContent).toContain('alex@example.com') + expect(mocks.chart).toHaveBeenCalledWith( + expect.objectContaining({ data: [{ timestamp: data.series[0].timestamp, value: 5 }] }) + ) + expect(container.textContent).not.toMatch(/citations|clicks|agent runs/i) + }) + it('restores filters from the URL and scopes every metric request consistently', async () => { + await render('?stats-period=7d&stats-surface=mcp') + expect(mocks.query).toHaveBeenLastCalledWith({ + organizationId: 'org', + period: '7d', + surface: 'mcp', + }) + expect(container.textContent).not.toContain('Invocations by surface') + const filter = container.querySelector('button[aria-label="Search surface"]') + const toolbar = filter?.parentElement?.parentElement + expect(toolbar?.textContent).toContain('Sources People Stats') + }) + it('restores a custom UTC range with the surface filter', async () => { + await render( + '?stats-period=custom&stats-start=2026-09-01&stats-end=2026-09-03&stats-surface=slack' + ) + expect(mocks.query).toHaveBeenLastCalledWith({ + organizationId: 'org', + period: 'custom', + startDate: '2026-09-01', + endDate: '2026-09-03', + surface: 'slack', + }) + expect(container.textContent).toContain('Sep 1 – Sep 3') + }) + it('keeps the daily chart mounted with zero-valued buckets when there is no activity', async () => { + mocks.query.mockReturnValue({ + data: { + ...data, + totals: { invocations: 0, activePeople: 0, results: 0 }, + series: data.series.map((point) => ({ ...point, invocations: 0 })), + sources: [], + surfaces: [], + people: [], + }, + isError: false, + }) + await render() + expect(container.textContent).not.toContain('No recorded Search activity') + expect(container.querySelectorAll('dd')).toHaveLength(3) + expect(Array.from(container.querySelectorAll('dd'), (metric) => metric.textContent)).toEqual([ + '0', + '0', + '0', + ]) + expect(mocks.chart).toHaveBeenCalledWith( + expect.objectContaining({ + data: [{ timestamp: data.series[0].timestamp, value: 0 }], + }) + ) + }) + it('offers retry instead of displaying stale successful totals on failure', async () => { + mocks.query.mockReturnValue({ data, isError: true, refetch: mocks.refetch }) + await render() + expect(container.textContent).toContain('Couldn’t load Search stats') + expect(container.textContent).not.toContain('Search invocations') + const retry = Array.from(container.querySelectorAll('button')).find( + (button) => button.textContent === 'Try again' + ) + await act(async () => retry?.click()) + expect(mocks.refetch).toHaveBeenCalledOnce() + }) +}) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.tsx new file mode 100644 index 00000000000..1765187b12d --- /dev/null +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/organization-source-stats.tsx @@ -0,0 +1,227 @@ +'use client' + +import { type ReactNode, useMemo } from 'react' +import { Chip, ChipSelect, Tooltip } from '@sim/emcn' +import { CircleInfo } from '@sim/emcn/icons' +import { useQueryStates } from 'nuqs' +import { BarChart } from '@/components/charts' +import { + SEARCH_STATS_PEOPLE_LIMIT, + SEARCH_STATS_SURFACE_LABELS, + SEARCH_STATS_SURFACES, +} from '@/lib/knowledge/search/stats' +import { OrganizationSearchStatsPeriod } from '@/app/o/[organizationId]/settings/components/integrations/organization-search-stats-period' +import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' +import { SettingsPanel } from '@/app/workspace/[workspaceId]/settings/components/settings-panel' +import { + RESOURCE_LIST_STACK, + SettingsResourceRow, +} from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' +import { SettingsSection } from '@/app/workspace/[workspaceId]/settings/components/settings-section/settings-section' +import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' +import { + organizationSearchStatsParsers, + organizationSearchStatsUrlOptions, +} from '@/ee/organization-search-stats/search-params' +import { useOrganizationSearchStats } from '@/hooks/queries/organization-search-stats' + +const SURFACE_OPTIONS = [ + { value: 'all', label: 'All surfaces' }, + ...SEARCH_STATS_SURFACES.map((surface) => ({ + value: surface, + label: SEARCH_STATS_SURFACE_LABELS[surface], + })), +] + +interface OrganizationSourceStatsProps { + organizationId: string + tabs?: ReactNode +} + +function sourceLabel(sourceType: string) { + return ( + CONNECTOR_META_REGISTRY[sourceType]?.name ?? (sourceType === 'uploads' ? 'Uploads' : sourceType) + ) +} + +export function OrganizationSourceStats({ organizationId, tabs }: OrganizationSourceStatsProps) { + const [{ period, surface, startDate, endDate }, setFilters] = useQueryStates( + organizationSearchStatsParsers, + organizationSearchStatsUrlOptions + ) + const stats = useOrganizationSearchStats({ + organizationId, + period, + surface: surface ?? undefined, + ...(period === 'custom' + ? { startDate: startDate ?? undefined, endDate: endDate ?? undefined } + : {}), + }) + const series = useMemo( + () => + stats.data?.series.map((point) => ({ + timestamp: point.timestamp, + value: point.invocations, + })) ?? [], + [stats.data?.series] + ) + const data = stats.data + const totals = data?.totals + const metrics = totals + ? [ + { label: 'Search invocations', value: totals.invocations.toLocaleString() }, + { label: 'Active people', value: totals.activePeople.toLocaleString() }, + { label: 'Results returned', value: totals.results.toLocaleString() }, + ] + : [] + + return ( + +
+ {tabs} +
+ + void setFilters({ surface: organizationSearchStatsParsers.surface.parse(value) }) + } + /> + void setFilters(selection)} + /> +
+
+ {stats.isError ? ( + + Couldn’t load Search stats. void stats.refetch()}>Try again + + ) : !data || !totals ? ( + Loading Search stats… + ) : ( + <> +
+ {metrics.map((metric) => ( +
+
{metric.label}
+
{metric.value}
+
+ ))} +
+ + + + + + Successful Search requests since tracking was enabled. Assistant and MCP counts + are Search tool calls. Results count each document once per request. One request + can return multiple sources. + + + } + action={ + + {period === 'custom' ? 'UTC' : 'UTC · Includes today'} + + } + > + + + {!surface && totals.invocations > 0 && ( + +
+ {data.surfaces.map((row) => ( + + {row.invocations.toLocaleString()} + + } + /> + ))} +
+
+ )} + + Invocations returning this source + + } + > + {data.sources.length ? ( +
+ {data.sources.map((row) => { + const Icon = CONNECTOR_META_REGISTRY[row.sourceType]?.icon + return ( + : undefined} + title={sourceLabel(row.sourceType)} + badge={ + + {row.invocations.toLocaleString()} + + } + /> + ) + })} +
+ ) : ( + + No sources returned in this period. + + )} +
+ + Top {SEARCH_STATS_PEOPLE_LIMIT} · Invocations + + } + > + {data.people.length ? ( +
+ {data.people.map((person) => ( + + {person.invocations.toLocaleString()} + + } + /> + ))} +
+ ) : ( + + No active people in this period. + + )} +
+ + )} +
+ ) +} diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/search-params.ts b/apps/sim/app/o/[organizationId]/settings/components/integrations/search-params.ts index 30d5f4c5561..ad97007ca37 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/search-params.ts +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/search-params.ts @@ -1,8 +1,8 @@ -import { parseAsStringLiteral } from 'nuqs/server' +import { createSerializer, parseAsString, parseAsStringLiteral } from 'nuqs/server' export const organizationIntegrationsTabParam = { key: 'tab', - parser: parseAsStringLiteral(['providers', 'people']).withDefault('providers'), + parser: parseAsStringLiteral(['providers', 'people', 'stats']).withDefault('providers'), } as const export const connectedAccountsParam = { @@ -10,7 +10,14 @@ export const connectedAccountsParam = { parser: parseAsStringLiteral(['slack']), } as const -export const organizationProviderTabParam = { - key: 'view', - parser: parseAsStringLiteral(['sources', 'accounts']).withDefault('sources'), +/** An absent integration includes connections from all integrations. */ +export const organizationPeopleIntegrationParam = { + key: 'integration', + parser: parseAsString, } as const + +export const serializeOrganizationPeople = createSerializer({ + tab: organizationIntegrationsTabParam.parser, + integration: organizationPeopleIntegrationParam.parser, + 'credential-group-people': parseAsString, +}) diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-removal.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-removal.tsx index 2dff4d17b5f..10dac1eb1bb 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-removal.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-removal.tsx @@ -24,8 +24,8 @@ export function OrganizationSlackAccountRemoval({ onOpenChange={(open) => { if (!open && !update.isPending) onClose() }} - title='Remove Slack account setup?' - text='This disconnects your organization’s Slack accounts and clears their saved app configuration. Remove any sources using these accounts first.' + title='Remove Slack app setup?' + text='This disconnects your organization’s Slack accounts and clears their saved app configuration. Remove any connections using these accounts first.' confirm={{ label: 'Remove', variant: 'destructive', diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.test.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.test.tsx index 1cc0c9b77b9..eef37d52a2f 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.test.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.test.tsx @@ -72,8 +72,57 @@ describe('organization Slack setup continuation', () => { it('prepares a missing container without asking the admin to make an extra choice', async () => { await render() expect(mocks.ensure).toHaveBeenCalledExactlyOnceWith({ organizationId: 'org-a' }) - expect(document.body.textContent).toContain('Loading Slack setup') - expect(document.body.textContent).not.toContain('Continue') + expect(document.querySelector('[role="dialog"]')).toBeNull() + expect(mocks.modal).not.toHaveBeenCalled() + mocks.prepare.mockReturnValue({ mutate: mocks.ensure, isIdle: false, isPending: true }) + await render() + expect(document.querySelector('[role="dialog"]')).toBeNull() + expect(mocks.ensure).toHaveBeenCalledOnce() + mocks.prepare.mockReturnValue({ + mutate: mocks.ensure, + isIdle: false, + isPending: false, + data: { credentialGroup: { id: 'group-a', organizationId: 'org-a', options: [] } }, + }) + await render() + expect(mocks.modal).toHaveBeenCalledWith( + expect.objectContaining({ credentialGroupId: 'group-a' }), + undefined + ) + }) + + it('does not open a temporary modal while discovering accounts', async () => { + mocks.accounts.mockReturnValue({ isSuccess: false, isPending: true }) + await render() + expect(document.querySelector('[role="dialog"]')).toBeNull() + expect(mocks.ensure).not.toHaveBeenCalled() + expect(mocks.modal).not.toHaveBeenCalled() + }) + + it.each(['discovery', 'preparation'])('keeps %s errors recoverable', async (stage) => { + const retry = vi.fn() + if (stage === 'discovery') { + mocks.accounts.mockReturnValue({ + isSuccess: false, + error: new Error('Could not load Slack setup'), + refetch: retry, + }) + } else { + mocks.prepare.mockReturnValue({ + mutate: mocks.ensure, + isIdle: false, + error: new Error('Could not prepare Slack setup'), + }) + } + await render() + expect(document.body.textContent).toContain('Set up Slack app') + const retryButton = Array.from(document.querySelectorAll('button')).find( + (button) => button.textContent === 'Try again' + ) + expect(retryButton).toBeDefined() + await act(async () => retryButton?.click()) + if (stage === 'discovery') expect(retry).toHaveBeenCalledOnce() + else expect(mocks.ensure).toHaveBeenCalledExactlyOnceWith({ organizationId: 'org-a' }) }) it('does not prepare accounts or open admin setup for an ordinary member', async () => { diff --git a/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.tsx b/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.tsx index e5e46838ec2..37d11404811 100644 --- a/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.tsx +++ b/apps/sim/app/o/[organizationId]/settings/components/integrations/slack-account-setup.tsx @@ -15,10 +15,7 @@ import { searchSetupParam, searchSetupReturnParam, } from '@/app/workspace/[workspaceId]/search/search-params' -import { - SettingsEmptyState, - SettingsQueryErrorState, -} from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' +import { SettingsQueryErrorState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' import { SlackManagedUsersModal } from '@/ee/credential-groups/components/slack-managed-users-modal' import { useEnsureOrganizationAccounts, @@ -83,32 +80,30 @@ export function OrganizationSlackAccountSetup() { }} /> ) + const error = accounts.error ?? setupError + if (!error) return null return ( { if (!next) close() }} - srTitle='Connect Slack accounts' + srTitle='Set up Slack app' > - Connect Slack accounts + Set up Slack app - - {accounts.error || setupError ? ( - - accounts.error - ? void accounts.refetch() - : ensureAccounts({ organizationId: organization.id }) - } - variant='inline' - /> - ) : ( - Loading Slack setup… - )} + + + accounts.error + ? void accounts.refetch() + : ensureAccounts({ organizationId: organization.id }) + } + variant='inline' + /> diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.test.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.test.tsx index 25ff75fb3e8..bf09e5c23f9 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.test.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.test.tsx @@ -1,105 +1,81 @@ /** @vitest-environment node */ -import { Suspense } from 'react' -import { beforeEach, describe, expect, it, vi } from 'vitest' +import { beforeEach, expect, it, vi } from 'vitest' -const mocks = vi.hoisted(() => ({ - session: vi.fn(), - authorize: vi.fn(), - redirect: vi.fn(), - notFound: vi.fn(), -})) +const mocks = vi.hoisted(() => ({ session: vi.fn(), authorize: vi.fn(), redirect: vi.fn() })) vi.mock('@/lib/auth', () => ({ getSession: mocks.session })) vi.mock('@/lib/settings/application/organization-section-access', () => ({ authorizeOrganizationSettingsSection: mocks.authorize, })) -vi.mock('@/lib/sim-search/connectors', () => ({ - SEARCH_SOURCE_TYPES: [['google_drive', { name: 'Google Drive' }]], +vi.mock('next/navigation', () => ({ + redirect: (url: string) => { + mocks.redirect(url) + throw new Error('redirect') + }, + notFound: () => { + throw new Error('not found') + }, })) -vi.mock('next/navigation', () => ({ redirect: mocks.redirect, notFound: mocks.notFound })) -vi.mock('@/components/settings/settings-header', () => ({ - SettingsHeaderProvider: 'header-provider', - SettingsHeaderShell: 'header-shell', +vi.mock('@/lib/sim-search/connectors', () => ({ + SEARCH_SOURCE_TYPES: [ + ['jira', { name: 'Jira' }], + ['confluence', { name: 'Confluence' }], + ], })) vi.mock( '@/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail', - () => ({ OrganizationProviderDetail: 'provider-detail' }) + () => ({ OrganizationProviderDetail: () => null }) ) +vi.mock('@/app/workspace/[workspaceId]/settings/components/settings-empty-state', () => ({ + SettingsEmptyState: () => null, +})) -import OrganizationProviderLayout from '@/app/o/[organizationId]/settings/integrations/providers/[connectorType]/layout' -import OrganizationProviderPage, { - generateMetadata, -} from '@/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page' - -const props = { - params: Promise.resolve({ organizationId: 'org-one', connectorType: 'google_drive' }), -} - -describe('organization provider page authorization', () => { - beforeEach(() => { - vi.clearAllMocks() - mocks.session.mockResolvedValue({ user: { id: 'admin-one' } }) - mocks.authorize.mockResolvedValue(true) - mocks.redirect.mockImplementation(() => { - throw new Error('redirect') - }) - mocks.notFound.mockImplementation(() => { - throw new Error('not found') - }) - }) +import OrganizationProviderPage from '@/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page' - it('checks the target organization integration policy before rendering provider management', async () => { - const page = await OrganizationProviderPage(props) - expect(mocks.authorize).toHaveBeenCalledWith({ - organizationId: 'org-one', - userId: 'admin-one', - section: 'integrations', - }) - expect(page.type).toBe(Suspense) - expect(page.props.children).toMatchObject({ - type: 'provider-detail', - props: { connectorType: 'google_drive' }, - }) - }) +beforeEach(() => { + vi.clearAllMocks() + mocks.session.mockResolvedValue({ user: { id: 'admin-1' } }) + mocks.authorize.mockResolvedValue(true) +}) - it('rejects unknown or unsupported providers before loading protected organization state', async () => { +it.each(['jira', 'confluence'])( + 'moves legacy %s Accounts links to filtered People and preserves the search', + async (connectorType) => { await expect( OrganizationProviderPage({ - params: Promise.resolve({ organizationId: 'org-one', connectorType: 'unknown-provider' }), + params: Promise.resolve({ organizationId: 'org-1', connectorType }), + searchParams: Promise.resolve({ + view: 'accounts', + 'credential-group-people': 'alex+qa@example.com', + }), }) - ).rejects.toThrow('not found') - expect(mocks.session).not.toHaveBeenCalled() - expect(mocks.authorize).not.toHaveBeenCalled() - }) - - it('does not render when the admin or feature gate denies access', async () => { - mocks.authorize.mockResolvedValue(false) - await expect(OrganizationProviderPage(props)).rejects.toThrow('not found') - }) - - it('returns signed-out users to the requested provider after login', async () => { - mocks.session.mockResolvedValue(null) - await expect(OrganizationProviderPage(props)).rejects.toThrow('redirect') - const url = new URL(mocks.redirect.mock.calls[0][0], 'https://example.com') - expect(url.pathname).toBe('/login') - expect(url.searchParams.get('callbackUrl')).toBe( - '/o/org-one/settings/integrations/providers/google_drive' - ) - expect(mocks.authorize).not.toHaveBeenCalled() - }) + ).rejects.toThrow('redirect') + const url = new URL(mocks.redirect.mock.lastCall![0], 'https://example.com') + expect(url.pathname).toBe('/o/org-1/settings/integrations') + expect(url.searchParams.get('tab')).toBe('people') + expect(url.searchParams.get('integration')).toBe(connectorType) + expect(url.searchParams.get('credential-group-people')).toBe('alex+qa@example.com') + expect(url.searchParams.has('view')).toBe(false) + } +) - it('keeps the settings header mounted independently of provider authorization', () => { - const layout = OrganizationProviderLayout({ children: Loading integration }) - expect(layout.type).toBe('header-provider') - expect(layout.props.children).toMatchObject({ - type: 'header-shell', - props: { meta: { title: 'Integration' } }, +it('authorizes organization settings before redirecting a legacy link', async () => { + mocks.authorize.mockResolvedValue(false) + await expect( + OrganizationProviderPage({ + params: Promise.resolve({ organizationId: 'org-1', connectorType: 'jira' }), + searchParams: Promise.resolve({ view: 'accounts' }), }) - expect(mocks.authorize).not.toHaveBeenCalled() - }) - - it('uses the supported provider name as page metadata', async () => { - expect(await generateMetadata(props)).toEqual({ title: 'Google Drive' }) - expect(mocks.session).not.toHaveBeenCalled() - expect(mocks.authorize).not.toHaveBeenCalled() - }) + ).rejects.toThrow('not found') + expect(mocks.redirect).not.toHaveBeenCalled() }) + +it.each(['jira', ''])( + 'preserves an active setup in a legacy Accounts link (%s)', + async (addConnector) => { + await OrganizationProviderPage({ + params: Promise.resolve({ organizationId: 'org-1', connectorType: 'jira' }), + searchParams: Promise.resolve({ view: 'accounts', addConnector, 'source-access': 'members' }), + }) + expect(mocks.redirect).not.toHaveBeenCalled() + } +) diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.tsx index 8250da53e98..5f0762a0e49 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/page.tsx @@ -6,11 +6,14 @@ import { organizationRoutes } from '@/lib/navigation/paths' import { authorizeOrganizationSettingsSection } from '@/lib/settings/application/organization-section-access' import { SEARCH_SOURCE_TYPES } from '@/lib/sim-search/connectors' import { buildAuthCrossLink } from '@/app/(auth)/auth-redirect' +import { serializeOrganizationPeople } from '@/app/o/[organizationId]/settings/components/integrations/search-params' import { OrganizationProviderDetail } from '@/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail' +import { searchSetupParam } from '@/app/workspace/[workspaceId]/search/search-params' import { SettingsEmptyState } from '@/app/workspace/[workspaceId]/settings/components/settings-empty-state' interface OrganizationProviderPageProps { params: Promise<{ organizationId: string; connectorType: string }> + searchParams: Promise> } export async function generateMetadata({ @@ -22,7 +25,10 @@ export async function generateMetadata({ } } -export default async function OrganizationProviderPage({ params }: OrganizationProviderPageProps) { +export default async function OrganizationProviderPage({ + params, + searchParams, +}: OrganizationProviderPageProps) { const { organizationId, connectorType } = await params if (!SEARCH_SOURCE_TYPES.some(([type]) => type === connectorType)) notFound() const session = await getSession() @@ -41,6 +47,26 @@ export default async function OrganizationProviderPage({ params }: OrganizationP })) ) notFound() + const query = await searchParams + const activeSetup = + typeof query.addConnector === 'string' + ? searchSetupParam.parser.parse(query.addConnector) + : null + if (query.view === 'accounts' && activeSetup === null) { + redirect( + serializeOrganizationPeople( + organizationRoutes(organizationId).settingsSection('integrations'), + { + tab: 'people', + integration: connectorType, + 'credential-group-people': + typeof query['credential-group-people'] === 'string' + ? query['credential-group-people'] + : null, + } + ) + ) + } return ( Loading integration…} diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.test.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.test.tsx index 7dda89df3ff..594914fb52f 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.test.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.test.tsx @@ -116,6 +116,7 @@ vi.mock('@/app/o/[organizationId]/settings/components/integrations/slack-account import { SettingsHeaderProvider, SettingsHeaderShell } from '@/components/settings/settings-header' import { OrganizationProviderDetail } from '@/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail' +import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' const provider = { connectorType: 'google_drive', @@ -221,46 +222,21 @@ describe('organization provider management', () => { } it.each(['gmail', 'google_calendar', 'google_drive'])( - 'lets %s wait for connections without requiring source setup', + 'offers configuration setup directly for %s without an Accounts or Advanced tab', async (connectorType) => { mocks.overview.mockReturnValue({ - data: { - providers: [ - { - connectorType, - approved: true, - status: 'waiting_for_connections', - sourceCount: 0, - issue: null, - isSyncing: false, - }, - ], - }, + data: { providers: [{ ...provider, connectorType, status: 'waiting_for_connections' }] }, }) - mocks.accounts.mockReturnValue({ data: { credentialGroup: null }, isPending: false }) mocks.sources.mockReturnValue({ data: [], isPending: false }) - await render(connectorType, '?view=accounts') + await render(connectorType) expect(container.textContent).toContain('Waiting for connections') expect(container.textContent).toContain( - 'Members connect their accounts from Integrations. Indexing starts automatically.' + `No ${CONNECTOR_META_REGISTRY[connectorType]?.name} connections yet.` ) - expect(container.textContent).not.toContain('Add source') - expect(container.textContent).not.toContain('Add sync configuration') - expect(container.querySelector('a[href="/o/org-one/integrations"]')).toBeNull() - expect(container.textContent).not.toContain('Open Integrations') - expect(mocks.sources).toHaveBeenCalledWith( - expect.any(Object), - expect.objectContaining({ enabled: false }) - ) - await click('Advanced') - expect(container.textContent).toContain('No sync configurations yet.') - expect(container.textContent).toContain('Add sync configuration') - await click('Add sync configuration') + expect(container.querySelector('[role="radio"]')).toBeNull() + await click('Connect service account') await vi.waitFor(() => { - expect(mocks.updateUrl).toHaveBeenLastCalledWith( - expect.objectContaining({ searchParams: expect.any(URLSearchParams) }) - ) - expect(mocks.updateUrl.mock.calls.at(-1)![0].searchParams.get('addConnector')).toBe( + expect(mocks.updateUrl.mock.calls.at(-1)?.[0].searchParams.get('addConnector')).toBe( connectorType ) }) @@ -284,7 +260,7 @@ describe('organization provider management', () => { expect(container.textContent).not.toContain( 'Members connect their accounts from Integrations.' ) - await click('Add sync configuration') + await click('Connect service account') await vi.waitFor(() => { const params = mocks.updateUrl.mock.calls.at(-1)![0].searchParams expect(params.get('addConnector')).toBe(connectorType) @@ -320,29 +296,17 @@ describe('organization provider management', () => { ])('opens configurations for the $name setup', async ({ modes }) => { withSources(modes) await render(connectorType) - expect(container.querySelector('[role="radio"][aria-checked="true"]')).toHaveTextContent( - 'Advanced' - ) + expect(container.querySelector('[role="radio"]')).toBeNull() expect(mocks.sources).toHaveBeenLastCalledWith( expect.any(Object), expect.objectContaining({ enabled: true }) ) expect(mocks.accounts).toHaveBeenLastCalledWith(undefined) - expect(container.textContent).toContain('Add sync configuration') + expect(container.textContent).toContain('Connect service account') if (modes.length === 0) - expect(container.textContent).toContain('No sync configurations yet.') - }) - - it.each(['accounts', 'sources'])('honors explicit %s links', async (view) => { - withSources(['admin']) - await render(connectorType, `?view=${view}`) - expect(mocks.sources).toHaveBeenLastCalledWith( - expect.any(Object), - expect.objectContaining({ enabled: view === 'sources' }) - ) - expect(container.querySelector('[role="radio"][aria-checked="true"]')).toHaveTextContent( - view === 'accounts' ? 'Accounts' : 'Advanced' - ) + expect(container.textContent).toContain( + `No ${CONNECTOR_META_REGISTRY[connectorType]?.name} connections yet.` + ) }) it('loads the configuration list in parallel with its overview and retains the default', async () => { @@ -357,9 +321,7 @@ describe('organization provider management', () => { ) withSources(['members']) await render(connectorType) - expect(container.querySelector('[role="radio"][aria-checked="true"]')).toHaveTextContent( - 'Advanced' - ) + expect(container.querySelector('[role="radio"]')).toBeNull() expect(container.textContent).toContain('Engineering handbook') expect(mocks.sources).toHaveBeenLastCalledWith( expect.any(Object), @@ -367,43 +329,6 @@ describe('organization provider management', () => { ) expect(mocks.accounts).toHaveBeenLastCalledWith(undefined) }) - - it('preserves an explicit Accounts choice when the overview changes', async () => { - withSources(['members']) - await render(connectorType) - await click('Accounts') - await vi.waitFor(() => - expect(mocks.updateUrl.mock.calls.at(-1)?.[0].searchParams.get('view')).toBe('accounts') - ) - withSources(['admin']) - await render(connectorType) - expect(container.querySelector('[role="radio"][aria-checked="true"]')).toHaveTextContent( - 'Accounts' - ) - expect(mocks.sources).toHaveBeenLastCalledWith( - expect.any(Object), - expect.objectContaining({ enabled: false }) - ) - }) - - it.each([ - { accessMode: 'admin', method: 'Service account' }, - { accessMode: 'members', method: 'Member accounts' }, - ])( - 'identifies $method configurations without changing their title or destination', - async ({ accessMode, method }) => { - withSources([accessMode]) - mocks.sources.mockReturnValue({ - data: [{ ...source, connectorType, accessMode }], - isPending: false, - }) - await render(connectorType) - expect(container.textContent).toContain(`${method} · Last synced`) - expect( - container.querySelector('a[aria-label="Open Engineering handbook"]') - ).toHaveAttribute('href', '/o/org-one/settings/integrations/sources/source-one') - } - ) } ) @@ -412,7 +337,15 @@ describe('organization provider management', () => { async (status) => { withSlackAccounts(true, status) await render('slack') - await click('Remove account setup') + const headerRemove = Array.from(container.querySelectorAll('button')).find( + (button) => button.textContent === 'Remove app setup' + ) + const deactivate = Array.from(container.querySelectorAll('button')).find( + (button) => button.textContent === 'Deactivate' + ) + expect(headerRemove?.className).toBe(deactivate?.className) + expect(headerRemove?.querySelector('[class*="text-error"]')).toBeNull() + await click('Remove app setup') expect(mocks.removeAccounts).not.toHaveBeenCalled() expect(document.querySelector('[role="dialog"]')).toHaveTextContent('saved app configuration') await click('Remove') @@ -434,7 +367,7 @@ describe('organization provider management', () => { it('offers removal when Slack is deactivated and allows cancelling without a mutation', async () => { withSlackAccounts(false) await render('slack') - await click('Remove account setup') + await click('Remove app setup') await click('Cancel') expect(document.querySelector('[role="dialog"]')).toBeNull() expect(mocks.removeAccounts).not.toHaveBeenCalled() @@ -444,32 +377,19 @@ describe('organization provider management', () => { withSlackAccounts() mocks.accountRemovalError = new Error('Remove the source using these accounts first.') await render('slack') - await click('Remove account setup') + await click('Remove app setup') await click('Remove') expect(document.querySelector('[role="dialog"] [role="alert"]')).toHaveTextContent( 'Remove the source using these accounts first.' ) }) - it('passes the removal action to the Slack Accounts tab header', async () => { - withSlackAccounts() - await render('slack', '?view=accounts') - const actions = mocks.people.mock.calls.at(-1)![0].panel.actions - expect(actions).toEqual([ - expect.objectContaining({ text: 'Remove account setup', onSelect: expect.any(Function) }), - ]) - await act(async () => actions[0].onSelect()) - expect(document.querySelector('[role="dialog"]')).toHaveTextContent( - 'Remove Slack account setup?' - ) - }) - it('keeps Slack cleanup available even when personal source creation is unavailable', async () => { withSlackAccounts() mocks.personal = false await render('slack') expect(mocks.accounts).toHaveBeenCalledWith('org-one') - await click('Remove account setup') + await click('Remove app setup') expect(document.querySelector('[role="dialog"]')).not.toBeNull() }) @@ -538,14 +458,12 @@ describe('organization provider management', () => { expect(container.textContent).not.toContain('Activate this integration') expect(mocks.people).not.toHaveBeenCalled() expect( - container.querySelector( - `input[placeholder="${params === '?view=accounts' ? 'Search people...' : 'Search sync configurations...'}"]` - ) + container.querySelector('input[placeholder="Search Google Drive connections..."]') ).toBeEnabled() } ) - it('hides cached account content and retries when overview access is revoked', async () => { + it('hides cached source content and retries when overview access is revoked', async () => { const refetch = vi.fn() mocks.overview.mockReturnValue({ data: { providers: [provider] }, @@ -553,21 +471,29 @@ describe('organization provider management', () => { error: new ApiClientError({ status: 403, message: 'Access denied', body: null }), refetch, }) - await render('google_drive', '?view=accounts&credential-group-people=alex') + await render('google_drive', '?search=alex') expect(container.textContent).toContain('Access denied') expect(mocks.people).not.toHaveBeenCalled() - expect(container.querySelector('input[placeholder="Search people..."]')).toHaveValue('alex') - expect(container.querySelector('input[placeholder="Search people..."]')).toBeEnabled() + expect( + container.querySelector('input[placeholder="Search Google Drive connections..."]') + ).toHaveValue('alex') + expect( + container.querySelector('input[placeholder="Search Google Drive connections..."]') + ).toBeEnabled() await click('Try again') expect(refetch).toHaveBeenCalledOnce() }) - it('offers activation from the accounts tab when an existing provider is deactivated', async () => { + it('offers activation when an existing provider is deactivated', async () => { mocks.overview.mockReturnValue({ data: { providers: [{ ...provider, approved: false }] } }) - await render('google_drive', '?view=accounts&credential-group-people=alex') + await render('google_drive', '?search=alex') expect(mocks.people).not.toHaveBeenCalled() - expect(container.querySelector('input[placeholder="Search people..."]')).toHaveValue('alex') - expect(container.querySelector('input[placeholder="Search people..."]')).toBeEnabled() + expect( + container.querySelector('input[placeholder="Search Google Drive connections..."]') + ).toHaveValue('alex') + expect( + container.querySelector('input[placeholder="Search Google Drive connections..."]') + ).toBeEnabled() await click('Activate') expect(mocks.activate).toHaveBeenCalledWith({ organizationId: 'org-one', @@ -576,7 +502,7 @@ describe('organization provider management', () => { }) }) - it('shows activation failures on Accounts and keeps activation available for retry', async () => { + it('shows activation failures and keeps activation available for retry', async () => { mocks.overview.mockReturnValue({ data: { providers: [{ ...provider, approved: false }] } }) mocks.approvalError = new Error('Activation could not be saved') await render('google_drive', '?view=accounts') @@ -590,56 +516,6 @@ describe('organization provider management', () => { }) }) - it.each([ - ['loading', 'Loading accounts…'], - ['error', 'Accounts unavailable'], - [ - 'missing group', - 'Members connect their accounts from Integrations. Indexing starts automatically.', - ], - [ - 'missing provider option', - 'Members connect their accounts from Integrations. Indexing starts automatically.', - ], - ])('preserves Accounts search while %s', async (state, message) => { - const refetch = vi.fn() - mocks.accounts.mockReturnValue( - state === 'loading' - ? { isPending: true } - : state === 'error' - ? { isError: true, error: new Error(message), refetch } - : { - data: { - credentialGroup: - state === 'missing group' ? null : { ...credentialGroup, options: [] }, - }, - isPending: false, - } - ) - await render('google_drive', '?view=accounts&credential-group-people=alex&search=handbook') - - expect(container.textContent).toContain(message) - expect(container.querySelector('input[placeholder="Search people..."]')).toHaveValue('alex') - expect(container.querySelector('input[placeholder="Search people..."]')).toBeEnabled() - expect(container.querySelector('input[placeholder="Search sync configurations..."]')).toBeNull() - expect(mocks.people).not.toHaveBeenCalled() - if (state === 'error') { - await click('Try again') - expect(refetch).toHaveBeenCalledOnce() - } - - const sourcesTab = Array.from( - container.querySelectorAll('[role="radio"]') - ).find((item) => item.textContent === 'Advanced') - expect(sourcesTab).toBeDefined() - await act(async () => sourcesTab!.click()) - expect( - container.querySelector('input[placeholder="Search sync configurations..."]') - ).toHaveValue('handbook') - await click('Accounts') - expect(container.querySelector('input[placeholder="Search people..."]')).toHaveValue('alex') - }) - it('preserves source navigation and retries connection availability failures', async () => { mocks.availabilityError = new Error('Connection availability could not be loaded') await render('google_drive', '?view=sources') @@ -655,6 +531,19 @@ describe('organization provider management', () => { expect(mocks.activate).not.toHaveBeenCalled() }) + it('explains unavailable integrations instead of showing an empty setup dead end', async () => { + mocks.access = { admin: false, members: false } + mocks.overview.mockReturnValue({ + data: { providers: [{ ...provider, connectorType: 'gitlab' }] }, + }) + mocks.sources.mockReturnValue({ data: [], isPending: false }) + await render('gitlab') + expect(container.textContent).toContain('Unavailable in this deployment') + expect(container.textContent).toContain('GitLab must be configured for this deployment') + expect(container.textContent).not.toContain('No GitLab projects added') + expect(container.textContent).not.toContain('Add project') + }) + it('explains and retries Slack account lookup failures without hiding its sources', async () => { const refetch = vi.fn() mocks.access = { admin: false, members: true } @@ -677,20 +566,6 @@ describe('organization provider management', () => { expect(refetch).toHaveBeenCalledOnce() }) - it('scopes account management and connection requests to the current provider option', async () => { - await render('google_drive', '?view=accounts') - expect(mocks.sources).toHaveBeenCalledWith( - expect.any(Object), - expect.objectContaining({ enabled: false }) - ) - expect(mocks.people).toHaveBeenCalledWith( - expect.objectContaining({ - organizationId: 'org-one', - searchConnection: { optionId: 'google-option', providerName: 'Google Drive' }, - }) - ) - }) - it.each([ { type: 'google_drive', access: { admin: true, members: true }, memberParam: false }, { type: 'gmail', access: { admin: false, members: true }, memberParam: true }, @@ -702,8 +577,7 @@ describe('organization provider management', () => { data: { providers: [{ ...provider, connectorType: type }] }, }) await render(type) - await click('Advanced') - await click('Add sync configuration') + await click(memberParam ? 'Set up member accounts' : 'Connect service account') await vi.waitFor(() => { expect(mocks.updateUrl).toHaveBeenCalled() const query = new URLSearchParams(mocks.updateUrl.mock.calls.at(-1)![0].queryString) @@ -740,7 +614,7 @@ describe('organization provider management', () => { slackBotCredentialId: 'slack-bot', configurationStatus: 'needs_update', }, - ])('offers Slack Accounts recovery for an active option with $name', async (option) => { + ])('offers Slack app recovery for an active option with $name', async (option) => { mocks.access = { admin: false, members: true } mocks.overview.mockReturnValue({ data: { providers: [{ ...provider, connectorType: 'slack' }] }, @@ -762,24 +636,21 @@ describe('organization provider management', () => { }, isPending: false, }) - await render('slack', '?view=accounts&credential-group-people=alex') + await render('slack') expect(mocks.people).not.toHaveBeenCalled() - expect(container.textContent).toContain('Set up the Slack app to connect accounts.') - expect(container.querySelector('input[placeholder="Search people..."]')).toHaveValue('alex') + expect(container.textContent).toContain('Set up Slack app') await click('Set up Slack app') await act(async () => { await vi.waitFor(() => expect(mocks.updateUrl).toHaveBeenCalled()) }) const query = new URLSearchParams(mocks.updateUrl.mock.calls.at(-1)![0].queryString) expect(query.get('connectedAccounts')).toBe('slack') - expect(query.get('view')).toBe('accounts') - expect(query.get('credential-group-people')).toBe('alex') expect(query.has('addConnector')).toBe(false) }) it.each([undefined, 'slack-bot'])( - 'uses verified configuration for account management with bot credential %s', + 'allows source setup with verified Slack configuration and bot credential %s', async (slackBotCredentialId) => { mocks.access = { admin: false, members: true } mocks.overview.mockReturnValue({ @@ -804,11 +675,8 @@ describe('organization provider management', () => { }) await render('slack', '?view=accounts') - expect(mocks.people).toHaveBeenCalledWith( - expect.objectContaining({ - searchConnection: { optionId: 'slack-option', providerName: 'Slack' }, - }) - ) + expect(container.textContent).toContain('Add channels or DMs') + expect(mocks.people).not.toHaveBeenCalled() expect(container.textContent).not.toContain('Set up the Slack app to connect accounts.') } ) diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.tsx index cbf18f2f4e0..05b2e177c68 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/providers/[connectorType]/provider-detail.tsx @@ -1,28 +1,20 @@ 'use client' import { useState } from 'react' -import { ChipConfirmModal, ChipModalError, ChipSwitch } from '@sim/emcn' +import { ChipConfirmModal, ChipModalError } from '@sim/emcn' import { ArrowLeft, Plus } from '@sim/emcn/icons' import { format } from 'date-fns' import { useRouter } from 'next/navigation' import { useQueryState, useQueryStates } from 'nuqs' import type { SettingsAction } from '@/components/settings/settings-header' import { SettingsPanel } from '@/components/settings/settings-panel' -import { findCredentialGroupProviderFromProviderId } from '@/lib/credential-groups/providers' import { organizationRoutes } from '@/lib/navigation/paths' -import { getServiceConfigByProviderId, getServiceConfigByServiceId } from '@/lib/oauth' -import { - canConnectPersonally, - canConnectWithDefaults, - getConnectorAccessAvailability, -} from '@/lib/sim-search/connectors' +import { getSearchConnectionLabels } from '@/lib/sim-search/connection-labels' +import { getConnectorAccessAvailability } from '@/lib/sim-search/connectors' import { SEARCH_DEBOUNCE_MS } from '@/lib/url-state' import { useOrganizationContext } from '@/app/o/[organizationId]/providers/organization-provider' import { organizationSearchStatusLabel } from '@/app/o/[organizationId]/settings/components/integrations/organization-search-status' -import { - connectedAccountsParam, - organizationProviderTabParam, -} from '@/app/o/[organizationId]/settings/components/integrations/search-params' +import { connectedAccountsParam } from '@/app/o/[organizationId]/settings/components/integrations/search-params' import { OrganizationSlackAccountRemoval } from '@/app/o/[organizationId]/settings/components/integrations/slack-account-removal' import { OrganizationSlackAccountSetup } from '@/app/o/[organizationId]/settings/components/integrations/slack-account-setup' import { SearchSourcePagination } from '@/app/workspace/[workspaceId]/search/components/search-source-pagination' @@ -41,12 +33,10 @@ import { } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' import { useSettingsSearch } from '@/app/workspace/[workspaceId]/settings/components/use-settings-search' import { CONNECTOR_META_REGISTRY } from '@/connectors/registry' -import { OrganizationAccountPeople } from '@/ee/credential-groups/components/organization-account-people' import { useOrganizationSearchOverview, useSearchSources } from '@/hooks/queries/kb/connectors' import { useOrganizationAccounts } from '@/hooks/queries/organization-accounts' import { useUpdateSearchIntegration } from '@/hooks/queries/search-integrations' import { useDebounce } from '@/hooks/use-debounce' -import { useOrganizationAccountPeopleSearch } from '@/hooks/use-organization-account-people-search' import { usePermissionConfig } from '@/hooks/use-permission-config' interface OrganizationProviderDetailProps { @@ -57,31 +47,21 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid const { organization, viewer, searchAccess } = useOrganizationContext() const router = useRouter() const meta = CONNECTOR_META_REGISTRY[connectorType] - const automaticSetup = Boolean(meta && canConnectWithDefaults(meta) && searchAccess.memberScoped) - const [view, setView] = useQueryState( - organizationProviderTabParam.key, - organizationProviderTabParam.parser - ) const [search, setSearch] = useSettingsSearch() - const [peopleSearch, setPeopleSearch] = useOrganizationAccountPeopleSearch() const sourceSearch = useDebounce(search.trim(), SEARCH_DEBOUNCE_MS) const [deactivating, setDeactivating] = useState(false) const [removingSlackAccounts, setRemovingSlackAccounts] = useState(false) const scope = { kind: 'organization', organizationId: organization.id } as const - const personal = Boolean(meta && canConnectPersonally(meta) && searchAccess.memberScoped) - const showAccounts = view === 'accounts' && personal const overview = useOrganizationSearchOverview(organization.id, { enabled: viewer.isAdmin }) const sources = useSearchSources(scope, { connectorType, search: sourceSearch, - enabled: viewer.isAdmin && !showAccounts, + enabled: viewer.isAdmin, }) const availability = usePermissionConfig() const approval = useUpdateSearchIntegration() const accounts = useOrganizationAccounts( - viewer.isAdmin && (connectorType === 'slack' || (personal && showAccounts)) - ? organization.id - : undefined + viewer.isAdmin && connectorType === 'slack' ? organization.id : undefined ) const [, setSetup] = useQueryStates( { @@ -103,19 +83,11 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid router.push(organizationRoutes(organization.id).settingsSection('integrations')), } if (!viewer.isAdmin || !meta) return null - const searchField = showAccounts - ? { value: peopleSearch, onChange: setPeopleSearch, placeholder: 'Search people...' } - : { - value: search, - onChange: setSearch, - placeholder: automaticSetup ? 'Search sync configurations...' : 'Search sources...', - } - const panel = { - back, - title: meta.name, - description: provider ? organizationSearchStatusLabel(provider) : undefined, - docsLink: meta.searchDocsUrl, - search: searchField, + const labels = getSearchConnectionLabels(connectorType) + const searchField = { + value: search, + onChange: setSearch, + placeholder: labels.searchPlaceholder, } const access = getConnectorAccessAvailability(meta, availability.integrationAvailability, { memberAccessAvailable: searchAccess.memberScoped, @@ -123,16 +95,22 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid oauthServiceAvailability: availability.oauthServiceAvailability, isIntegrationAvailabilityReady: availability.isIntegrationAvailabilityReady, }) - const service = - meta.auth.mode === 'oauth' - ? (getServiceConfigByServiceId(meta.auth.provider) ?? - getServiceConfigByProviderId(meta.auth.provider)) - : undefined - const credentialProvider = service - ? findCredentialGroupProviderFromProviderId(service.providerId) - : undefined + const unavailable = + availability.isIntegrationAvailabilityReady && !access.admin && !access.members + const panel = { + back, + title: meta.name, + description: + approved && unavailable + ? 'Unavailable in this deployment' + : provider + ? organizationSearchStatusLabel(provider) + : undefined, + docsLink: meta.searchDocsUrl, + search: searchField, + } const option = accounts.data?.credentialGroup?.options.find( - (item) => item.provider === credentialProvider && item.status === 'active' + (item) => item.provider === 'slack' && item.status === 'active' ) const group = accounts.data?.credentialGroup const removalActions: SettingsAction[] = @@ -141,8 +119,8 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid group?.options.some((item) => item.provider === 'slack') ? [ { - text: 'Remove account setup', - textTone: 'error', + id: 'delete', + text: 'Remove app setup', disabled: accounts.isFetching, onSelect: () => setRemovingSlackAccounts(true), }, @@ -165,14 +143,13 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid approval.mutate({ organizationId: organization.id, connectorType, approved: true }) const actions: SettingsAction[] = approved ? [ - ...((access.admin || access.members) && (!automaticSetup || !showAccounts) + ...(access.admin || access.members ? [ { text: needsSlackSetup ? 'Set up Slack app' - : automaticSetup - ? 'Add sync configuration' - : 'Add source', + : getSearchConnectionLabels(connectorType, access.admin ? 'admin' : 'members') + .add, icon: Plus, variant: 'primary' as const, disabled: @@ -196,6 +173,7 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid text: provider ? 'Activate' : 'Add integration', variant: 'primary', disabled: pending || (!access.admin && !access.members), + tooltip: unavailable ? 'This integration is unavailable in this deployment.' : undefined, onSelect: activate, }, ] @@ -247,13 +225,13 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid {sources.isError && !sources.isFetchNextPageError ? ( void sources.refetch()} variant='inline' /> ) : sources.isPending ? ( - Loading sources… + Loading connections… ) : (
{sources.data?.map((source) => ( @@ -291,12 +269,12 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid {!sources.data?.length && !sources.hasNextPage && ( {sourceSearch - ? 'No matching sources' - : !approved - ? 'Activate this integration to set up sources.' - : automaticSetup - ? 'No sync configurations yet.' - : 'No sources yet.'} + ? 'No matching connections' + : unavailable + ? `${meta.name} must be configured for this deployment before you can add a connection.` + : !approved + ? 'Activate this integration to add a connection.' + : labels.empty} )} @@ -306,81 +284,7 @@ export function OrganizationProviderDetail({ connectorType }: OrganizationProvid ) return ( <> -
- {personal && ( -
- void setView(value)} - options={ - automaticSetup - ? [ - { value: 'accounts', label: 'Accounts' }, - { value: 'sources', label: 'Advanced' }, - ] - : [ - { value: 'sources', label: 'Sources' }, - { value: 'accounts', label: 'Accounts' }, - ] - } - /> -
- )} - {showAccounts ? ( - accounts.isError ? ( - - void accounts.refetch()} - variant='inline' - /> - - ) : accounts.isPending ? ( - - Loading accounts… - - ) : option && approved && !needsSlackSetup ? ( - - ) : ( - - {approval.error && ( - - {approval.error.message} - - )} - {availability.integrationAvailabilityError && ( - void availability.refetchIntegrationAvailability()} - variant='inline' - /> - )} - - {approved - ? needsSlackSetup - ? 'Set up the Slack app to connect accounts.' - : automaticSetup - ? provider && provider.sourceCount > 0 - ? 'No connected member accounts.' - : 'Members connect their accounts from Integrations. Indexing starts automatically.' - : 'Add a source to set up account connections.' - : 'Activate this integration to set up account connections.'} - - - ) - ) : ( - renderSources() - )} -
+ {renderSources()} { }) await render(searchParams) - expect(container.textContent).toContain('Some source updates are incomplete') - expect(container.textContent).toContain('Review the source settings and try syncing again.') + expect(container.textContent).toContain('Some connection updates are incomplete') + expect(container.textContent).toContain( + 'Review the connection settings and try syncing again.' + ) expect(container.textContent).not.toContain('Provider denied') expect(container.textContent).not.toContain('org-private-id') } @@ -232,8 +234,10 @@ describe('organization source detail navigation', () => { it('keeps a healthy active source quiet', async () => { await render() - expect(container.textContent).not.toContain('Some source updates are incomplete') - expect(container.textContent).not.toContain('Review the source settings and try syncing again.') + expect(container.textContent).not.toContain('Some connection updates are incomplete') + expect(container.textContent).not.toContain( + 'Review the connection settings and try syncing again.' + ) }) it.each(['', '?view=settings', '?view=history'])( @@ -277,7 +281,7 @@ describe('organization source detail navigation', () => { async (status) => { mocks.detail.mockReturnValue({ data: { ...connector, status, lastSyncError: 'Old failure' } }) await render() - expect(container.textContent).not.toContain('Some source updates are incomplete') + expect(container.textContent).not.toContain('Some connection updates are incomplete') } ) @@ -303,7 +307,9 @@ describe('organization source detail navigation', () => { }, }) await render() - expect(container.textContent?.includes('Some source updates are incomplete')).toBe(showNotice) + expect(container.textContent?.includes('Some connection updates are incomplete')).toBe( + showNotice + ) expect(container.textContent).not.toContain('private-account-id') } ) @@ -335,7 +341,7 @@ describe('organization source detail navigation', () => { await render() expect(mocks.actions).not.toHaveBeenCalled() expect(mocks.documents).not.toHaveBeenCalled() - expect(container.textContent).toContain('Loading source') + expect(container.textContent).toContain('Loading connection') }) it('does not load protected source data for non-admins', async () => { mocks.admin = false @@ -352,7 +358,7 @@ describe('organization source detail navigation', () => { mocks.index.mockReturnValue({ data: { knowledgeBaseId: null }, isPending: false }) mocks.detail.mockReturnValue({}) await render() - expect(container.textContent).toContain('This source is no longer available') + expect(container.textContent).toContain('This connection is no longer available') expect(mocks.actions).not.toHaveBeenCalled() await click('Sources') expect(mocks.push).toHaveBeenCalledWith('/o/org-one/settings/integrations') @@ -386,7 +392,7 @@ describe('organization source detail navigation', () => { const sync = Array.from(container.querySelectorAll('button')).find( (item) => item.textContent === 'Sync now' ) - const tabs = container.querySelector('[aria-label="Source views"]') + const tabs = container.querySelector('[aria-label="Connection views"]') expect(sync).toBeTruthy() expect(tabs).toBeTruthy() expect(sync!.compareDocumentPosition(tabs!)).toBe(Node.DOCUMENT_POSITION_FOLLOWING) diff --git a/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx b/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx index 648ca14f1f6..939dfd52563 100644 --- a/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx +++ b/apps/sim/app/o/[organizationId]/settings/integrations/sources/[connectorId]/source-detail.tsx @@ -70,7 +70,7 @@ export function OrganizationSourceDetail({ connectorId }: OrganizationSourceDeta if (!viewer.isAdmin) return ( - + Only organization admins can manage sources. @@ -89,17 +89,17 @@ export function OrganizationSourceDetail({ connectorId }: OrganizationSourceDeta ) if (failedQuery && (!hasCanonicalDetail || accessFailure)) return ( - + {isApiClientError(failedQuery.error) && failedQuery.error.status === 404 ? ( - This source is no longer available. + This connection is no longer available. ) : ( void failedQuery.refetch()} - fallback='Could not load source' + fallback='Could not load connection' variant='inline' /> )} @@ -107,9 +107,9 @@ export function OrganizationSourceDetail({ connectorId }: OrganizationSourceDeta ) if (!index.isPending && !knowledgeBaseId) return ( - + - This source is no longer available. + This connection is no longer available. ) @@ -120,8 +120,8 @@ export function OrganizationSourceDetail({ connectorId }: OrganizationSourceDeta detail.data.knowledgeBaseId !== knowledgeBaseId ) return ( - - Loading source… + + Loading connection… ) return ( @@ -137,7 +137,7 @@ export function OrganizationSourceDetail({ connectorId }: OrganizationSourceDeta error={failedQuery.error} isRetrying={failedQuery.isFetching} onRetry={() => void failedQuery.refetch()} - fallback='Could not refresh source' + fallback='Could not refresh connection' variant='inline' /> ) : undefined @@ -184,7 +184,7 @@ function SourceDetailContent({ const meta = CONNECTOR_META_REGISTRY[connector.connectorType] const title = meta ? describeSearchSource(meta, connector.sourceConfig) || meta.name - : 'Search source' + : 'Connection' const { effectiveStatus, lastSyncError } = getConnectorSyncState(connector) const status = effectiveStatus === 'paused' @@ -209,7 +209,7 @@ function SourceDetailContent({ return ( {effectiveStatus === 'active' && lastSyncError && ( )}
) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx index 9e5cc037fe9..daee1e5c632 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/add-connector-modal/add-connector-modal.test.tsx @@ -162,6 +162,7 @@ vi.mock( - ), })) vi.mock('next/navigation', () => ({ useParams: () => ({ workspaceId: 'workspace-1' }) })) vi.mock('@/hooks/use-debounce', () => ({ useDebounce: (value: string) => value })) @@ -174,35 +171,34 @@ async function renderBulkSelector() { document.body.appendChild(container) const root = createRoot(container) const change = vi.fn() - await act(async () => - root.render( - - - - ) - ) - const button = (label: string) => { - const element = Array.from(container.querySelectorAll('button')).find( - (item) => item.textContent === label + const rerender = (sourceConfig = { domain: 'example.atlassian.net' }) => + act(async () => + root.render( + + + + ) ) - if (!element) throw new Error(`Missing ${label} button`) - return element + await rerender() + const all = () => { + const option = mocks.combobox.mock.lastCall![0].options.find((item) => item.label === 'All') + if (!option) throw new Error('Missing All option') + return option } - await act(async () => - vi.waitFor(() => expect(button('Select all').disabled).toBe(false), { interval: 1 }) - ) + await act(async () => vi.waitFor(() => expect(all().disabled).toBe(false), { interval: 1 })) return { container, change, - button, + all, + rerender, dispose: async () => { await act(async () => root.unmount()) client.clear() @@ -211,7 +207,7 @@ async function renderBulkSelector() { } } -it('selects every complete page, exposes the count, and clears explicitly', async () => { +it('selects every complete page from All without an external toolbar', async () => { mocks.execute.mockImplementation(async ({ request }: { request: SelectorRequest }) => request.kind === 'detail' ? { kind: 'detail', item: null } @@ -221,8 +217,8 @@ it('selects every complete page, exposes the count, and clears explicitly', asyn ) const view = await renderBulkSelector() try { - expect(view.container.textContent).toContain('1 selected') - await act(async () => view.button('Select all').click()) + expect(view.container.textContent).not.toContain('Select all') + await act(async () => view.all().onSelect?.()) await act(async () => vi.waitFor(() => expect(view.change).toHaveBeenCalledWith(['ENG', 'OPS'], options), { interval: 1, @@ -231,7 +227,7 @@ it('selects every complete page, exposes the count, and clears explicitly', asyn expect(mocks.execute.mock.calls.filter(([args]) => args.request.kind === 'list')).toHaveLength( 2 ) - await act(async () => view.button('Clear').click()) + await act(async () => mocks.combobox.mock.lastCall![0].onMultiSelectChange?.([])) expect(view.change).toHaveBeenLastCalledWith([], []) } finally { await view.dispose() @@ -249,17 +245,21 @@ it.each(['partial', 'error'] as const)('preserves the selection on %s results', }) const view = await renderBulkSelector() try { - await act(async () => view.button('Select all').click()) + await act(async () => view.all().onSelect?.()) await act(async () => vi.waitFor(() => expect(view.container.querySelector('[role="alert"]')).not.toBeNull(), { interval: 1, }) ) + await view.rerender() + expect(view.container.querySelector('[role="alert"]')).not.toBeNull() expect(view.change).not.toHaveBeenCalled() - expect(view.container.textContent).toContain('1 selected') + expect(view.container.textContent).not.toContain('Select all') expect(view.container.textContent).toContain( failure === 'error' ? 'Could not load all options' : 'too many results' ) + await view.rerender({ domain: 'another.atlassian.net' }) + expect(view.container.querySelector('[role="alert"]')).toBeNull() } finally { await view.dispose() } @@ -280,15 +280,14 @@ it('disables bulk selection while searching and ignores a completion after the u const view = await renderBulkSelector() try { await act(async () => mocks.combobox.mock.lastCall![0].onSearchChange?.('Eng')) - expect(view.button('Select all').disabled).toBe(true) - expect(view.container.textContent).toContain('Clear search to select all') + expect(view.all().disabled).toBe(true) await act(async () => mocks.combobox.mock.lastCall![0].onSearchChange?.('')) - await act(async () => view.button('Select all').click()) - await act(async () => view.button('Clear').click()) + await act(async () => view.all().onSelect?.()) + await act(async () => mocks.combobox.mock.lastCall![0].onMultiSelectChange?.([])) expect(view.change).toHaveBeenCalledTimes(1) await act(async () => resolvePage({ kind: 'list', items: [options[1]] })) await act(async () => - vi.waitFor(() => expect(view.container.textContent).not.toContain('Selecting…'), { + vi.waitFor(() => expect(view.all().disabled).toBe(false), { interval: 1, }) ) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx index 708cf3c5db0..716589573d0 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.test.tsx @@ -1,5 +1,5 @@ /** @vitest-environment jsdom */ -import { act, type ComponentProps } from 'react' +import { act } from 'react' import { createRoot } from 'react-dom/client' import { beforeEach, expect, it, vi } from 'vitest' import type { ConnectorConfigField } from '@/connectors/types' @@ -13,9 +13,6 @@ const mocks = vi.hoisted(() => ({ vi.mock('@sim/emcn', () => ({ ChipCombobox: mocks.combobox, - Chip: ({ children, ...props }: ComponentProps<'button'>) => ( - - ), })) vi.mock('next/navigation', () => ({ useParams: () => ({ workspaceId: 'workspace-1' }) })) vi.mock('@/lib/selectors/context', () => ({ projectSelectorContext: mocks.projectContext })) @@ -37,7 +34,7 @@ vi.mock('@/hooks/queries/selectors', () => ({ import { ConnectorSelectorField } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field' interface ComboboxCallbacks { - options: { value: string; label: string; hidden?: boolean }[] + options: { value: string; label: string; hidden?: boolean; onSelect?: () => void }[] disabled: boolean onChange?: (value: string) => void onMultiSelectChange?: (value: string[]) => void @@ -219,10 +216,9 @@ it('keeps the prior selection when all personal setup options exceed its source /> ) ) - const button = Array.from(container.querySelectorAll('button')).find( - (item) => item.textContent === 'Select all' - ) - await act(async () => button?.click()) + const all = mocks.combobox.mock.lastCall![0].options.find((item) => item.label === 'All') + expect(container.textContent).not.toContain('Select all') + await act(async () => all?.onSelect?.()) expect(mocks.loadAll).toHaveBeenCalledTimes(1) expect(mocks.change).not.toHaveBeenCalled() expect(container.querySelector('[role="alert"]')?.textContent).toContain( diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx index 88595e6e428..bdd170f7e50 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.tsx @@ -1,7 +1,8 @@ 'use client' import { useEffect, useMemo, useRef, useState } from 'react' -import { Chip, ChipCombobox, type ChipModalFieldAria, type ComboboxOption } from '@sim/emcn' +import { ChipCombobox, type ChipModalFieldAria, type ComboboxOption } from '@sim/emcn' +import { isEqual } from 'es-toolkit' import { useParams } from 'next/navigation' import { type ResourceScope, resourceScopeFromOwner } from '@/lib/core/resource-scope' import { projectSelectorContext } from '@/lib/selectors/context' @@ -125,6 +126,7 @@ export function ConnectorSelectorField({ truncated, loadMore, loadAll, + refetch, error, } = useSelectorOptions(field.selectorKey, { context, @@ -211,8 +213,19 @@ export function ConnectorSelectorField({ } const hasSearch = searchTerm.trim().length > 0 || debouncedSearch.length > 0 + const selectedIdSet = new Set(selectedIds) + const allSelected = + !hasMore && + !truncated && + options.length > 0 && + selectedIds.length === options.length && + options.every((option) => selectedIdSet.has(option.id)) const selectAll = async () => { if (!isEnabled || hasSearch || isFetching || isLoadingAll) return + if (allSelected) { + handleChange([]) + return + } const generation = ++bulkGenerationRef.current setBulkError(null) const result = await loadAll() @@ -251,7 +264,21 @@ export function ConnectorSelectorField({ {...controlAria} aria-label={field.title} multiSelect - options={comboboxOptions} + options={ + field.allowSelectAll && (options.length > 0 || hasMore) + ? [ + { + value: '', + label: 'All', + disabled: !isEnabled || hasSearch || isFetching || isLoadingAll, + onSelect: () => void selectAll(), + keepOpen: true, + selected: allSelected, + }, + ...comboboxOptions, + ] + : comboboxOptions + } multiSelectValues={multiValues} onMultiSelectChange={handleChange} searchable @@ -266,44 +293,19 @@ export function ConnectorSelectorField({ } disabled={disabled || !credentialId || !depsResolved} isLoading={isEnabled && (isLoading || (options.length === 0 && isLoadingSelectedOptions))} - hasMore={hasMore} + hasMore={hasMore || Boolean(error)} isLoadingMore={isFetchingMore} isLoadingAll={isLoadingAll} truncated={truncated} - onLoadMore={loadMore} - onLoadAll={loadAll} + onLoadMore={error ? refetch : loadMore} + onLoadAll={error ? refetch : loadAll} emptyMessage={emptyMessage} + error={error?.message} /> - {field.allowSelectAll && ( - <> -
- void selectAll()} - > - {isLoadingAll ? 'Selecting…' : 'Select all'} - - handleChange([])} - > - Clear - - - {multiValues.length} selected - -
- {hasSearch && ( -

Clear search to select all.

- )} - {bulkError?.context === context && ( -

- {bulkError.message} -

- )} - + {bulkError && isEqual(bulkError.context, context) && ( +

+ {bulkError.message} +

)} ) @@ -328,13 +330,14 @@ export function ConnectorSelectorField({ } disabled={disabled || !credentialId || !depsResolved} isLoading={isEnabled && (isLoading || (options.length === 0 && isLoadingSelectedOptions))} - hasMore={hasMore} + hasMore={hasMore || Boolean(error)} isLoadingMore={isFetchingMore} isLoadingAll={isLoadingAll} truncated={truncated} - onLoadMore={loadMore} - onLoadAll={loadAll} + onLoadMore={error ? refetch : loadMore} + onLoadAll={error ? refetch : loadAll} emptyMessage={emptyMessage} + error={error?.message} /> ) } @@ -346,7 +349,7 @@ function getEmptyMessage( truncated: boolean } ): string { - if (state.error) return 'No match — the list failed to load. Try reopening' + if (state.error) return 'Could not load options. Try again.' if (state.truncated) return 'No match — too many to list. Try a more exact term' return `No ${noun} found` } diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.ui.test.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.ui.test.tsx new file mode 100644 index 00000000000..2f966afe39d --- /dev/null +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field.ui.test.tsx @@ -0,0 +1,179 @@ +/** @vitest-environment jsdom */ +import { act, useState } from 'react' +import { createRoot } from 'react-dom/client' +import { beforeEach, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + loadAll: vi.fn(), + change: vi.fn(), + hasMore: true, + options: null as { id: string; label: string }[] | null, + error: null as Error | null, + refetch: vi.fn(), + loadMore: vi.fn(), +})) +vi.mock('next/navigation', () => ({ useParams: () => ({ organizationId: 'org-1' }) })) +vi.mock('@/hooks/queries/selectors', () => ({ + useSelectorOptions: () => ({ + data: + mocks.options ?? + (mocks.hasMore + ? [{ id: 'ENG', label: 'Engineering' }] + : [ + { id: 'ENG', label: 'Engineering' }, + { id: 'OPS', label: 'Operations' }, + ]), + hasMore: mocks.hasMore, + isLoading: false, + isFetching: false, + isLoadingAll: false, + truncated: false, + loadAll: mocks.loadAll, + loadMore: mocks.loadMore, + refetch: mocks.refetch, + error: mocks.error, + }), + useSelectorOptionDetails: () => ({ data: [] }), + useSelectorOptionDetail: () => ({}), +})) + +import { ConnectorSelectorField } from '@/app/workspace/[workspaceId]/knowledge/[id]/components/connector-selector-field/connector-selector-field' + +function ControlledSelector() { + const [value, setValue] = useState([]) + return ( + { + mocks.change(next, labels) + mocks.hasMore = false + setValue(Array.isArray(next) ? next : []) + }} + sourceConfig={{}} + configFields={[]} + canonicalModes={{}} + /> + ) +} + +beforeEach(() => { + vi.clearAllMocks() + mocks.hasMore = true + mocks.options = null + mocks.error = null +}) + +it('selects all pages with the keyboard, announces selection, and toggles it off', async () => { + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + const originalScroll = HTMLElement.prototype.scrollIntoView + HTMLElement.prototype.scrollIntoView = vi.fn() + mocks.loadAll.mockResolvedValue({ + status: 'complete', + options: [ + { id: 'ENG', label: 'Engineering' }, + { id: 'OPS', label: 'Operations' }, + ], + }) + const container = document.createElement('div') + document.body.appendChild(container) + const root = createRoot(container) + try { + await act(async () => root.render()) + expect(container.textContent).not.toContain('Select all') + expect(container.textContent).not.toContain('Clear') + const trigger = container.querySelector('[role="combobox"]') + expect(trigger).not.toBeNull() + await act(async () => + trigger?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowDown', bubbles: true })) + ) + expect(document.querySelector('[role="option"]')?.textContent).toBe('All') + await act(async () => + trigger?.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', bubbles: true })) + ) + expect(document.querySelector('[role="option"]')?.getAttribute('aria-selected')).toBe('true') + expect(mocks.loadAll).toHaveBeenCalledOnce() + expect(mocks.change).toHaveBeenCalledWith( + ['ENG', 'OPS'], + [ + { id: 'ENG', label: 'Engineering' }, + { id: 'OPS', label: 'Operations' }, + ] + ) + await act(async () => + document + .querySelector('[role="option"]') + ?.dispatchEvent(new MouseEvent('mousedown', { bubbles: true })) + ) + expect(mocks.change).toHaveBeenLastCalledWith([], []) + expect(document.querySelector('[role="option"]')?.getAttribute('aria-selected')).toBe('false') + expect(mocks.loadAll).toHaveBeenCalledOnce() + } finally { + await act(async () => root.unmount()) + container.remove() + HTMLElement.prototype.scrollIntoView = originalScroll + vi.unstubAllGlobals() + } +}) + +it.each(['empty', 'error'] as const)( + 'shows the initial %s state without All and allows failed lists to retry', + async (state) => { + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + const originalScroll = HTMLElement.prototype.scrollIntoView + HTMLElement.prototype.scrollIntoView = vi.fn() + mocks.options = [] + mocks.hasMore = false + mocks.error = state === 'error' ? new Error('Provider unavailable') : null + const container = document.createElement('div') + document.body.appendChild(container) + const root = createRoot(container) + try { + await act(async () => root.render()) + const trigger = container.querySelector('[role="combobox"]') + expect(trigger).not.toBeNull() + await act(async () => trigger?.click()) + expect(document.querySelector('[role="listbox"]')).not.toBeNull() + expect(document.querySelector('[role="option"]')).toBeNull() + expect(mocks.loadAll).not.toHaveBeenCalled() + + const retry = Array.from(document.querySelectorAll('button')).find( + (button) => button.textContent?.trim() === 'Try again' + ) + if (state === 'empty') { + expect(document.body.textContent).toContain('No spaces found') + expect(retry).toBeUndefined() + return + } + expect(document.body.textContent).toContain('Provider unavailable') + expect(retry).toBeDefined() + await act(async () => retry?.click()) + expect(mocks.refetch).toHaveBeenCalledOnce() + expect(mocks.loadMore).not.toHaveBeenCalled() + mocks.error = null + mocks.options = [{ id: 'ENG', label: 'Engineering' }] + await act(async () => root.render()) + expect( + Array.from(document.querySelectorAll('[role="option"]')).map((option) => option.textContent) + ).toEqual(['All', 'Engineering']) + expect( + Array.from(document.querySelectorAll('button')).some( + (button) => button.textContent?.trim() === 'Try again' + ) + ).toBe(false) + } finally { + await act(async () => root.unmount()) + container.remove() + HTMLElement.prototype.scrollIntoView = originalScroll + vi.unstubAllGlobals() + } + } +) diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connector-actions.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connector-actions.tsx index cc2e15757d1..ac30124057f 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connector-actions.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/connectors-section/connector-actions.tsx @@ -73,11 +73,11 @@ export function ConnectorActionFeedback({ state }: ConnectorActionFeedbackProps) { }, ] await render(confluenceConnectorMeta) - expect(container.textContent).toContain('Indexing account') + expect(container.textContent).toContain('Service account') await openAccountChoices() expect( Array.from(document.querySelectorAll('[role="option"]')).map((node) => diff --git a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx index 6e2f1c9612a..ee36b6d49de 100644 --- a/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx +++ b/apps/sim/app/workspace/[workspaceId]/knowledge/[id]/components/edit-connector-modal/connector-settings-fields.tsx @@ -258,7 +258,11 @@ export function ConnectorSettingsFields({ {isSwitchingAccess ? 'Switching…' : isContentCredentialChange - ? 'Change indexing account' + ? isSearchIndex + ? requiresServiceAccount + ? 'Change service account' + : 'Change account' + : 'Change indexing account' : 'Apply connection method'} @@ -269,7 +273,7 @@ export function ConnectorSettingsFields({ {accessSetupHint ?? (isContentCredentialChange ? syncsPerMember - ? 'The next sync uses this indexing account. Members keep their connected accounts and source permissions.' + ? 'The next sync uses this account. Members keep their connected accounts and source permissions.' : 'The next sync uses this account and refreshes source permissions.' : SWITCH_NOTICE[access.accessMode])}

@@ -282,7 +286,13 @@ export function ConnectorSettingsFields({ {connectorConfig && needsWorkspaceCredential && canAdmin && ( void fetchNextPage()} variant='inline' diff --git a/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx b/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx index 41900dd4c2a..90bb6dafcf2 100644 --- a/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx +++ b/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.test.tsx @@ -375,16 +375,16 @@ function organizationSetup() { describe('organization setup entry points', () => { it.each([ - { type: 'google_drive', mode: 'admin', name: 'Google Drive' }, - { type: 'gmail', mode: 'admin', name: 'Gmail' }, - { type: 'google_calendar', mode: 'admin', name: 'Google Calendar' }, - { type: 'confluence', mode: 'admin', name: 'Confluence' }, - { type: 'gitlab', mode: 'admin', name: 'GitLab' }, - { type: 'gmail', mode: 'members', name: 'Gmail' }, - { type: 'google_calendar', mode: 'members', name: 'Google Calendar' }, - { type: 'jira', mode: 'members', name: 'Jira' }, - { type: 'github', mode: 'members', name: 'GitHub' }, - { type: 'slack', mode: 'members', name: 'Slack' }, + { type: 'google_drive', mode: 'admin', name: 'Connect Google Drive service account' }, + { type: 'gmail', mode: 'admin', name: 'Connect Gmail service account' }, + { type: 'google_calendar', mode: 'admin', name: 'Connect Google Calendar service account' }, + { type: 'confluence', mode: 'admin', name: 'Connect Confluence site' }, + { type: 'gitlab', mode: 'admin', name: 'Add GitLab project' }, + { type: 'gmail', mode: 'members', name: 'Set up Gmail member accounts' }, + { type: 'google_calendar', mode: 'members', name: 'Set up Google Calendar member accounts' }, + { type: 'jira', mode: 'members', name: 'Add Jira projects' }, + { type: 'github', mode: 'members', name: 'Add GitHub repository' }, + { type: 'slack', mode: 'members', name: 'Choose Slack channels and DMs' }, ])( 'opens the known $name configuration after preparing its missing index', async ({ type, mode, name }) => { @@ -396,32 +396,36 @@ describe('organization setup entry points', () => { connectorType: type, accessMode: mode, }) - expect(document.body.textContent).toContain(`Configure ${name}`) + expect(document.querySelector('[role="dialog"]')).toBeNull() expect(document.body.textContent).not.toContain('Continue setup') expect(document.body.textContent).not.toContain('Find a source') + mocks.preparePending = true await render(organizationSetup(), query) expect(mocks.prepare).toHaveBeenCalledOnce() + expect(document.querySelector('[role="dialog"]')).toBeNull() + mocks.preparePending = false mocks.bases = [{ id: 'kb-search', name: 'Sim Search', isSearchIndex: true }] await render(organizationSetup(), query) - expect(document.body.textContent).toContain(`Configure ${name}`) + expect(document.body.textContent).toContain(name) expect(document.body.textContent).not.toContain('Loading source setup') expect(document.querySelector('button[aria-label="Choose another source"]')).toBeNull() expect(mocks.prepare).toHaveBeenCalledOnce() } ) - it('waits for index discovery without showing a redundant provider row', async () => { + it('waits for index discovery without opening an interim modal', async () => { mocks.bases = [] mocks.basesPending = true await render(organizationSetup(), '?addConnector=google_drive') expect(mocks.prepare).not.toHaveBeenCalled() - expect(document.body.textContent).toContain('Loading source setup') + expect(document.querySelector('[role="dialog"]')).toBeNull() expect(document.body.textContent).not.toContain('Continue setup') mocks.basesPending = false mocks.bases = [{ id: 'kb-search', name: 'Sim Search', isSearchIndex: true }] await render(organizationSetup(), '?addConnector=google_drive') expect(mocks.prepare).not.toHaveBeenCalled() expect(document.body.textContent).not.toContain('Loading source setup') + expect(document.body.textContent).toContain('Connect Google Drive service account') }) it.each(['loading', 'error'] as const)( @@ -434,6 +438,11 @@ describe('organization setup entry points', () => { await render(organizationSetup(), '?addConnector=google_drive') expect(mocks.prepare).not.toHaveBeenCalled() expect(document.body.textContent).not.toContain('Continue setup') + if (state === 'loading') { + expect(document.querySelector('[role="dialog"]')).toBeNull() + } else { + expect(document.body.textContent).toContain('Availability failed') + } } ) @@ -467,7 +476,7 @@ describe('organization setup entry points', () => { expect(mocks.prepare).not.toHaveBeenCalled() }) - it('uses central mode and its own draft even when the saved draft contains member mode', async () => { + it('honors the central entry point while restoring its draft and offering both sync methods', async () => { mocks.credentials = [ { id: 'cred-source', @@ -478,7 +487,7 @@ describe('organization setup entry points', () => { ] useConnectorSetupStore .getState() - .saveDraft('user-1:organization:org-1:kb-search:confluence:admin', { + .saveDraft('user-1:organization:org-1:kb-search:confluence:choose', { sourceConfig: { domain: 'team.atlassian.net', spaceKey: ['ENG'] }, canonicalModes: { spaceKey: 'advanced' }, accessMode: 'members', @@ -489,7 +498,8 @@ describe('organization setup entry points', () => { }) await render(organizationSetup(), '?addConnector=confluence') - expect(document.body.textContent).not.toContain('Sync using') + expect(button('Member accounts')).toBeEnabled() + expect(button('Service account')).toBeEnabled() expect(document.querySelector('button[aria-label="Choose another source"]')).toBeNull() expect( document.querySelector('input[placeholder="yoursite.atlassian.net"]')?.value @@ -548,12 +558,16 @@ describe('organization setup entry points', () => { mocks.bases = [{ id: 'kb-search', name: 'Sim Search', isSearchIndex: true }] await render(organizationSetup(), `?addConnector=${type}`) expect(button('Connect & Sync')).toBeDisabled() - expect(document.body.textContent).not.toContain('Sync using') + expect(document.body.textContent).toContain('Sync using') + expect(document.querySelector('button[aria-label="Choose another source"]')).toBeNull() + await click(button('Member accounts')) + expect(button('Set up member accounts')).toBeEnabled() + expect(document.body.textContent).not.toContain('Directory administrator email') await render(organizationSetup(), `?addConnector=${type}&source-access=members`) - expect(button('Add source')).toBeEnabled() + expect(button('Set up member accounts')).toBeEnabled() expect(document.body.textContent).not.toContain('Connect & Sync') expect(document.body.textContent).not.toContain('Directory administrator email') - await click(button('Add source')) + await click(button('Set up member accounts')) expect(mocks.create).toHaveBeenCalledWith( expect.objectContaining({ connectorType: type, @@ -614,14 +628,86 @@ describe('organization setup entry points', () => { } ) - it('remounts the locked form when the same provider URL changes connection mode', async () => { + it('resets the form to the requested method when the same provider URL changes connection mode', async () => { await render(organizationSetup(), '?addConnector=confluence&source-access=members') - expect(button('Add source')).toBeDisabled() + expect(button('Add Confluence site')).toBeDisabled() await render(organizationSetup(), '?addConnector=confluence') expect(button('Connect & Sync')).toBeDisabled() expect(document.body.textContent).not.toContain('Add source') - expect(document.body.textContent).not.toContain('Sync using') + expect(button('Member accounts')).toBeEnabled() + expect(button('Service account')).toBeEnabled() }) + + it.each([ + { + type: 'gmail', + placeholder: 'e.g. INBOX, Engineering (comma-separated)', + value: 'QA', + config: { label: ['QA'] }, + manualField: null, + }, + { + type: 'google_drive', + placeholder: 'e.g. 1aBcDeFg…, 2cDeFgHi… (comma-separated for multiple)', + value: 'qa-folder', + config: { folderId: ['qa-folder'] }, + manualField: 'Folders', + }, + { + type: 'google_calendar', + placeholder: 'e.g. primary, team@group.calendar.google.com (comma-separated for multiple)', + value: 'qa@group.calendar.google.com', + config: { calendarId: ['qa@group.calendar.google.com'] }, + manualField: 'Calendars', + }, + { + type: 'confluence', + placeholder: 'e.g. ENG, PRODUCT (comma-separated for multiple)', + value: 'QA', + config: { spaceKey: ['QA'], domain: 'qa.atlassian.net' }, + manualField: 'Spaces', + }, + ])( + 'preserves the $type draft and chosen method when availability fails and recovers', + async ({ type, placeholder, value, config, manualField }) => { + const query = `?addConnector=${type}` + await render(organizationSetup(), query) + await click(button('Member accounts')) + if (type === 'confluence') await fill('yoursite.atlassian.net', 'qa.atlassian.net') + if (manualField) await click(button(`Switch ${manualField} to manual input`)) + await fill(placeholder, value) + const submitLabel = type === 'confluence' ? 'Add Confluence site' : 'Set up member accounts' + expect(button(submitLabel)).toBeEnabled() + + mocks.availabilityReady = false + mocks.availabilityError = new Error('Availability refresh failed') + await render(organizationSetup(), query) + expect( + document.querySelector(`input[placeholder="${placeholder}"]`)?.value + ).toBe(value) + expect(button(submitLabel)).toBeDisabled() + await click(button('Try again')) + expect(mocks.refetchAvailability).toHaveBeenCalledOnce() + expect(mocks.create).not.toHaveBeenCalled() + + mocks.availabilityReady = true + mocks.availabilityError = null + await render(organizationSetup(), query) + expect( + document.querySelector(`input[placeholder="${placeholder}"]`)?.value + ).toBe(value) + expect(button(submitLabel)).toBeEnabled() + await click(button(submitLabel)) + expect(mocks.create).toHaveBeenCalledWith( + expect.objectContaining({ + connectorType: type, + accessMode: 'members', + sourceConfig: expect.objectContaining(config), + }), + expect.any(Object) + ) + } + ) }) describe('Search source setup with real connector dialogs', () => { @@ -1587,9 +1673,9 @@ describe('administrator source prerequisites in real connector dialogs', () => { )! await act(async () => option.dispatchEvent(new MouseEvent('mousedown', { bubbles: true }))) expect(button('Save')).toBeDisabled() - expect(button('Change indexing account')).toBeEnabled() + expect(button('Change service account')).toBeEnabled() - await click(button('Change indexing account')) + await click(button('Change service account')) expect(mocks.applyAccess).toHaveBeenCalledExactlyOnceWith( { @@ -1943,7 +2029,7 @@ describe('resuming Search source setup', () => { await render(setup(), '?search=nothing-matches&addConnector=gitlab&credentialDraftId=draft-1') expect(document.body.textContent).toContain('Admin or service account') expect(document.querySelector('[role="radio"][aria-checked="true"]')).toBeNull() - expect(document.body.textContent).toContain('Configure GitLab') + expect(document.body.textContent).toContain('Add GitLab project') expect(document.body.textContent).not.toContain('Sync Frequency') expect(document.body.textContent).not.toContain('Sync automatically') expect(mocks.prepare).not.toHaveBeenCalled() @@ -1956,7 +2042,7 @@ describe('resuming Search source setup', () => { expect(document.body.textContent).toContain('Add source') await fill('Find a source…', 'confluence') await click(button('Set up')) - expect(document.body.textContent).toContain('Configure Confluence') + expect(document.body.textContent).toContain('Connect Confluence site') }) it('restores the source configuration and content account after an account-settings detour', async () => { diff --git a/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.tsx b/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.tsx index 9c46ae6d391..81f1c9fb562 100644 --- a/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.tsx +++ b/apps/sim/app/workspace/[workspaceId]/search/components/search-source-setup.tsx @@ -22,6 +22,7 @@ import { resourceScopeKey, } from '@/lib/core/resource-scope' import { organizationRoutes } from '@/lib/navigation/paths' +import { getSearchConnectionLabels } from '@/lib/sim-search/connection-labels' import { getConnectorAccessAvailability, SEARCH_SOURCE_TYPES } from '@/lib/sim-search/connectors' import { IntegrationTile } from '@/app/workspace/[workspaceId]/integrations/components/integrations-showcase' import { @@ -240,10 +241,14 @@ export function SearchSourceSetup({ ) { if (selectedType && session?.user?.id) { const accessMode = initialMode(selectedType) - const setupMode = scope.kind === 'organization' ? accessMode : 'choose' + const setupMode = + scope.kind === 'organization' && + !(selectedMeta?.mirrorsSourceAcls && selectedMeta.auth.mode === 'oauth') + ? accessMode + : 'choose' return ( { if (!nextOpen) void setSelectedType(null) @@ -253,7 +258,8 @@ export function SearchSourceSetup({ isSearchIndex initialConnectorType={selectedType} initialAccessMode={accessMode} - lockedAccessMode={scope.kind === 'organization' ? accessMode : undefined} + lockConnectorType={scope.kind === 'organization'} + lockedAccessMode={setupMode === 'choose' ? undefined : setupMode} setupDraftKey={`${session.user.id}:${resourceScopeKey(scope)}:${knowledgeBaseId}:${selectedType}:${setupMode}`} onConnectorTypeChange={(type) => void setSelectedType(type !== null ? searchSetupParam.parser.parse(type) : null) @@ -280,6 +286,16 @@ export function SearchSourceSetup({ } } + if ( + selectedType && + !failedQuery && + !integrationAvailabilityError && + !prepare.error && + (!isIntegrationAvailabilityReady || selectedAvailable) + ) { + return null + } + const normalizedSearch = search.trim().toLowerCase() const visibleTypes = SEARCH_SOURCE_TYPES.filter( ([type, meta]) => @@ -300,7 +316,9 @@ export function SearchSourceSetup({ srTitle='Add source' > - {selectedMeta ? `Configure ${selectedMeta.name}` : 'Add source'} + {selectedType + ? getSearchConnectionLabels(selectedType, selectedAccessMode).title + : 'Add source'} {failedQuery ? ( diff --git a/apps/sim/components/charts/bar-chart.tsx b/apps/sim/components/charts/bar-chart.tsx index 17acfbe4cb9..2e04c6e12e7 100644 --- a/apps/sim/components/charts/bar-chart.tsx +++ b/apps/sim/components/charts/bar-chart.tsx @@ -45,6 +45,8 @@ interface BarChartProps { /** `''` | `'%'` | `'ms'` | `'latency'` | `'credits'` — drives tick and tooltip formatting. */ unit?: string height?: number + /** Display bucket dates in this zone; omitted uses the viewer’s local zone. */ + timeZone?: string /** Bucket drawn at full opacity, e.g. the period in progress. */ highlightIndex?: number } @@ -75,6 +77,7 @@ function BarChartComponent({ unit, height = CHART_DEFAULT_HEIGHT, highlightIndex, + timeZone, }: BarChartProps) { /* `useId`, not `useRef(generateShortId())`: a ref initializer is evaluated on @@ -311,7 +314,7 @@ function BarChartComponent({ textAnchor='middle' fill={CHART_TICK_FILL} > - {Number.isNaN(date.getTime()) ? '' : formatTimeTick(date, spanMs)} + {Number.isNaN(date.getTime()) ? '' : formatTimeTick(date, spanMs, timeZone)} ) })} @@ -352,7 +355,7 @@ function BarChartComponent({ (() => { const bar = bars[hoverIndex] const value = formatBarValue(bar.point.value, unit) - const date = formatChartTimestamp(bar.point.timestamp) + const date = formatChartTimestamp(bar.point.timestamp, timeZone) const { left, top } = positionChartTooltip({ anchorX: hoverPos?.x ?? bar.x, anchorY: hoverPos?.y ?? bar.y, diff --git a/apps/sim/components/charts/chart-format.ts b/apps/sim/components/charts/chart-format.ts index c5b7151814b..fe31db771d2 100644 --- a/apps/sim/components/charts/chart-format.ts +++ b/apps/sim/components/charts/chart-format.ts @@ -16,10 +16,15 @@ export function formatChartLatency(ms: number): string { } /** The tooltip's header line: `MAR 4 3:05 PM`. Empty for an unparseable timestamp. */ -export function formatChartTimestamp(timestamp?: string): string { +export function formatChartTimestamp(timestamp?: string, timeZone?: string): string { if (!timestamp) return '' const date = new Date(timestamp) if (Number.isNaN(date.getTime())) return '' + if (timeZone) { + const day = date.toLocaleDateString('en-US', { timeZone, month: 'short', day: 'numeric' }) + const time = date.toLocaleTimeString('en-US', { timeZone, hour: 'numeric', minute: '2-digit' }) + return `${day.toUpperCase()} ${time}` + } return `${format(date, 'MMM d').toUpperCase()} ${format(date, 'h:mm a')}` } diff --git a/apps/sim/components/charts/chart-geometry.test.ts b/apps/sim/components/charts/chart-geometry.test.ts index 6108dc3386b..735d7f87ac0 100644 --- a/apps/sim/components/charts/chart-geometry.test.ts +++ b/apps/sim/components/charts/chart-geometry.test.ts @@ -118,3 +118,9 @@ describe('resolveChartPadding', () => { expect(padding.bottom).toBe(CHART_PADDING.bottom) }) }) + +it('keeps UTC bucket labels independent of the viewer time zone', () => { + const bucket = new Date('2026-09-10T00:00:00.000Z') + expect(formatTimeTick(bucket, 7 * 24 * 60 * 60 * 1000, 'UTC')).toBe('Sep 10') + expect(formatTimeTick(bucket, 7 * 24 * 60 * 60 * 1000, 'America/Los_Angeles')).toBe('Sep 9') +}) diff --git a/apps/sim/components/charts/chart-geometry.ts b/apps/sim/components/charts/chart-geometry.ts index 3494543c3c2..9c05f7f36c9 100644 --- a/apps/sim/components/charts/chart-geometry.ts +++ b/apps/sim/components/charts/chart-geometry.ts @@ -110,14 +110,19 @@ export function resolveTimeTickIndices(pointCount: number, usableWidth: number): * Tick label whose precision follows the window: clock time within a day and a half, * calendar day within a quarter, month beyond that. */ -export function formatTimeTick(date: Date, spanMs: number): string { +export function formatTimeTick(date: Date, spanMs: number, timeZone?: string): string { if (spanMs <= 36 * 60 * 60 * 1000) { - return date.toLocaleTimeString('en-US', { hour: '2-digit', minute: '2-digit', hour12: false }) + return date.toLocaleTimeString('en-US', { + timeZone, + hour: '2-digit', + minute: '2-digit', + hour12: false, + }) } if (spanMs <= 90 * 24 * 60 * 60 * 1000) { - return date.toLocaleString('en-US', { month: 'short', day: 'numeric' }) + return date.toLocaleString('en-US', { timeZone, month: 'short', day: 'numeric' }) } - return date.toLocaleString('en-US', { month: 'short', year: 'numeric' }) + return date.toLocaleString('en-US', { timeZone, month: 'short', year: 'numeric' }) } /** Milliseconds between the first and last timestamp, or 0 for a degenerate series. */ diff --git a/apps/sim/components/charts/chart-layout.test.tsx b/apps/sim/components/charts/chart-layout.test.tsx index 3ab1c4e4bc8..b095d90426d 100644 --- a/apps/sim/components/charts/chart-layout.test.tsx +++ b/apps/sim/components/charts/chart-layout.test.tsx @@ -76,6 +76,27 @@ describe('BarChart rendered geometry', () => { const widths = [280, 420, 680, 1024] const peaks = [7300, 173_000, 1_234_567] + it('renders date buckets and axes for a zero-only series without a no-data overlay', () => { + const svg = mountAtWidth( + 680, + + ) + expect(container.textContent).not.toContain('No data') + expect(container.textContent).toContain('Jan 1') + expect(container.textContent).toContain('Jan 7') + expect(container.textContent).not.toContain('Dec 31') + expect(svg.querySelectorAll('text').length).toBeGreaterThan(2) + expect(svg.querySelectorAll('rect')).toHaveLength(7) + expect(svg.querySelectorAll('rect[fill^="url"]')).toHaveLength(0) + expect(svg.querySelectorAll('line').length).toBeGreaterThan(0) + }) + it.each(widths.flatMap((width) => peaks.map((peak) => [width, peak] as const)))( 'keeps the y-axis labels inside the box at width %i, peak %i', (width, peak) => { diff --git a/apps/sim/connectors/confluence/meta.ts b/apps/sim/connectors/confluence/meta.ts index 8113c1eace1..b7b3f0782b3 100644 --- a/apps/sim/connectors/confluence/meta.ts +++ b/apps/sim/connectors/confluence/meta.ts @@ -64,7 +64,7 @@ export const confluenceConnectorMeta: ConnectorMeta = { configFields: [ { id: 'domain', - title: 'Confluence Domain', + title: 'Confluence site', type: 'short-input', placeholder: 'yoursite.atlassian.net', required: true, diff --git a/apps/sim/connectors/jira/meta.ts b/apps/sim/connectors/jira/meta.ts index 5afcf1f44ff..d99f48cf0d6 100644 --- a/apps/sim/connectors/jira/meta.ts +++ b/apps/sim/connectors/jira/meta.ts @@ -16,7 +16,7 @@ export const jiraConnectorMeta: ConnectorMeta = { configFields: [ { id: 'domain', - title: 'Jira Domain', + title: 'Jira site', type: 'short-input', placeholder: 'yoursite.atlassian.net', required: true, diff --git a/apps/sim/ee/credential-groups/components/organization-account-people.tsx b/apps/sim/ee/credential-groups/components/organization-account-people.tsx index 8bac323aff8..5648b046e6b 100644 --- a/apps/sim/ee/credential-groups/components/organization-account-people.tsx +++ b/apps/sim/ee/credential-groups/components/organization-account-people.tsx @@ -16,8 +16,8 @@ import { RESOURCE_LIST_STACK, SettingsResourceRow, } from '@/app/workspace/[workspaceId]/settings/components/settings-resource-row' -import { EnrollmentConnections } from '@/ee/credential-groups/components/credential-group-enrollment-connections' import { OrganizationAccountInviteModal } from '@/ee/credential-groups/components/organization-account-invite-modal' +import { OrganizationPersonConnections } from '@/ee/credential-groups/components/organization-person-connections' import { useOrganizationAccountPeople, useResendOrganizationAccountInvitation, @@ -37,6 +37,8 @@ interface OrganizationAccountPeopleProps { actions?: SettingsAction[] } enabled?: boolean + requestDisabled?: boolean + filters?: ReactNode setupFallback?: ReactNode } export function OrganizationAccountPeople({ @@ -45,6 +47,8 @@ export function OrganizationAccountPeople({ panel, enabled = true, setupFallback, + filters, + requestDisabled = false, }: OrganizationAccountPeopleProps) { const resend = useResendOrganizationAccountInvitation() const revoke = useRevokeOrganizationAccountEnrollment() @@ -69,12 +73,13 @@ export function OrganizationAccountPeople({ text: 'Request connections', icon: Plus, variant: 'primary', - disabled: pending || awaitingSetup, + disabled: pending || awaitingSetup || requestDisabled, onSelect: () => setInviteOpen(true), }, ...(panel?.actions ?? []), ]} > + {filters} {awaitingSetup ? ( setupFallback ) : ( @@ -110,38 +115,14 @@ export function OrganizationAccountPeople({ icon={} iconVariant='custom' title={person.email} - description={ - searchConnection && person.status === 'revoked' ? ( - 'Access revoked' - ) : searchConnection && - !person.connections.some( - (connection) => connection.status === 'active' - ) ? ( - person.connections.some( - (connection) => connection.status === 'needs_reauth' - ) ? ( - 'Reconnect required' - ) : person.connections.some( - (connection) => connection.status === 'revoked' - ) ? ( - 'Disconnected' - ) : ( - 'Not connected' - ) - ) : ( - - ) - } + description={} trailing={ resend.mutate( { diff --git a/apps/sim/ee/credential-groups/components/organization-person-connections.tsx b/apps/sim/ee/credential-groups/components/organization-person-connections.tsx new file mode 100644 index 00000000000..1654bbf830a --- /dev/null +++ b/apps/sim/ee/credential-groups/components/organization-person-connections.tsx @@ -0,0 +1,86 @@ +import { ChipTag } from '@sim/emcn' +import type { CredentialGroupEnrollmentDetail } from '@/lib/api/contracts/credential-groups' +import { getCredentialGroupProviderService } from '@/lib/credential-groups/providers' +import { resolveCredentialDisplay } from '@/lib/integrations/credential-display' + +interface OrganizationPersonConnectionsProps { + person: CredentialGroupEnrollmentDetail +} + +const CONNECTION_STATUS_LABELS = { + active: 'Connected', + needs_reauth: 'Reconnect required', + revoked: 'Disconnected', +} as const + +export function OrganizationPersonConnections({ person }: OrganizationPersonConnectionsProps) { + if (person.status === 'revoked') return <>Access revoked + + const connections = person.connections.map((connection) => { + const display = + connection.provider === 'gitlab' + ? resolveCredentialDisplay({ + type: 'personal_token', + providerId: 'gitlab', + displayName: 'GitLab', + }) + : undefined + const service = + connection.provider !== 'gitlab' + ? getCredentialGroupProviderService(connection.provider) + : undefined + return { + key: `${connection.provider}:${connection.status}`, + name: service?.name ?? display?.detailTitle ?? 'GitLab', + icon: service?.icon ?? display?.icon, + status: connection.status, + count: connection.count, + } + }) + const total = + connections.reduce( + (count, connection) => count + (connection.status === 'active' ? connection.count : 0), + 0 + ) + person.mcpConnections.filter((connection) => connection.status === 'active').length + + const statuses = [...connections, ...person.mcpConnections].map(({ status }) => status) + + return ( + + + {total > 0 + ? `${total} ${total === 1 ? 'account' : 'accounts'} connected` + : statuses.includes('needs_reauth') + ? 'Reconnect required' + : statuses.includes('revoked') + ? 'Disconnected' + : person.status === 'delivery_failed' + ? 'Connection request failed' + : person.expired + ? 'Connection request expired' + : 'Not connected'} + + {(connections.length > 0 || person.mcpConnections.length > 0) && ( + + {connections.map(({ key, name, icon: Icon, status, count }) => ( + + {Icon && } + {name} + {count > 1 ? ` (${count})` : ''} + {status !== 'active' && ` · ${CONNECTION_STATUS_LABELS[status]}`} + + ))} + {person.mcpConnections.map((connection) => ( + + {connection.name} · {CONNECTION_STATUS_LABELS[connection.status]} + + ))} + + )} + + ) +} diff --git a/apps/sim/ee/credential-groups/components/slack-managed-users-modal.tsx b/apps/sim/ee/credential-groups/components/slack-managed-users-modal.tsx index aed7460ef51..cd2fd9c6c0b 100644 --- a/apps/sim/ee/credential-groups/components/slack-managed-users-modal.tsx +++ b/apps/sim/ee/credential-groups/components/slack-managed-users-modal.tsx @@ -302,7 +302,7 @@ export function SlackManagedUsersModal({ const noBots = !organizationSetup && !isLoading && bots.length === 0 const needsApp = organizationSetup && apps.isSuccess && availableApps.length === 0 - const title = organizationSetup ? 'Connect Slack accounts' : 'Set up Slack' + const title = organizationSetup ? 'Set up Slack app' : 'Set up Slack' const primaryLabel = isLoading ? 'Loading...' : pending diff --git a/apps/sim/ee/organization-search-stats/search-params.ts b/apps/sim/ee/organization-search-stats/search-params.ts new file mode 100644 index 00000000000..0514a128245 --- /dev/null +++ b/apps/sim/ee/organization-search-stats/search-params.ts @@ -0,0 +1,22 @@ +import { parseAsString, parseAsStringLiteral } from 'nuqs/server' +import { SEARCH_STATS_PERIODS, SEARCH_STATS_SURFACES } from '@/lib/knowledge/search/stats' + +export const organizationSearchStatsParsers = { + period: parseAsStringLiteral(SEARCH_STATS_PERIODS).withDefault('30d'), + /** An absent surface includes every Search entry point. */ + surface: parseAsStringLiteral(SEARCH_STATS_SURFACES), + startDate: parseAsString, + endDate: parseAsString, +} + +export const organizationSearchStatsUrlOptions = { + history: 'replace', + shallow: true, + clearOnDefault: true, + urlKeys: { + period: 'stats-period', + surface: 'stats-surface', + startDate: 'stats-start', + endDate: 'stats-end', + }, +} as const diff --git a/apps/sim/hooks/queries/organization-accounts.test.tsx b/apps/sim/hooks/queries/organization-accounts.test.tsx index b5773eb720d..69f33d1f871 100644 --- a/apps/sim/hooks/queries/organization-accounts.test.tsx +++ b/apps/sim/hooks/queries/organization-accounts.test.tsx @@ -13,6 +13,7 @@ import { ApiClientError } from '@/lib/api/client/errors' import { disconnectPersonalOrganizationAccountContract, listOrganizationAccountPeopleContract, + revokeOrganizationAccountEnrollmentContract, updateOrganizationAccountsContract, } from '@/lib/api/contracts/organization-accounts' import { resourceScopeKey } from '@/lib/core/resource-scope' @@ -20,6 +21,7 @@ import { organizationAccountsKeys, useDisconnectPersonalOrganizationAccount, useOrganizationAccountPeople, + useRevokeOrganizationAccountEnrollment, useUpdateOrganizationAccounts, } from '@/hooks/queries/organization-accounts' import { slackSearchKeys } from '@/hooks/queries/slack-search' @@ -207,6 +209,90 @@ describe('organization account setup updates', () => { ) }) +describe('organization account revocation', () => { + it.each([true, false])( + 'clears Search content and refreshes affected account projections only on success=%s', + async (success) => { + vi.stubGlobal('IS_REACT_ACT_ENVIRONMENT', true) + mocks.request.mockReset() + const response = Promise.withResolvers() + mocks.request.mockReturnValueOnce(response.promise) + const client = new QueryClient() + const root = createRoot(document.createElement('div')) + let mutation: ReturnType + function Probe() { + mutation = useRevokeOrganizationAccountEnrollment() + return null + } + const orgScope = { kind: 'organization', organizationId: 'org-1' } as const + const results = knowledgeKeys.search(resourceScopeKey(orgScope), 'private content') + const documentKey = knowledgeKeys.document('kb-1', 'doc-1') + const sources = searchSourceKeys.pages(orgScope, { mine: true, search: '' }) + const accounts = organizationAccountsKeys.detail('org-1') + const people = organizationAccountsKeys.peopleList('org-1', '', 'jira-option') + const overview = searchSourceKeys.organizationOverview('org-1') + const otherAccounts = organizationAccountsKeys.detail('org-2') + const otherResults = knowledgeKeys.search( + resourceScopeKey({ kind: 'organization', organizationId: 'org-2' }), + 'private content' + ) + for (const key of [ + results, + documentKey, + sources, + accounts, + people, + overview, + otherAccounts, + otherResults, + ]) + client.setQueryData(key, { content: 'cached' }) + try { + await act(async () => + root.render( + + + + ) + ) + let pending: Promise + await act(async () => { + pending = mutation.mutateAsync({ organizationId: 'org-1', enrollmentId: 'person-1' }) + }) + await act(async () => + root.render({null}) + ) + await act(async () => { + if (success) { + response.resolve({}) + await pending + } else { + const rejected = expect(pending).rejects.toThrow('Revocation failed') + response.reject(new Error('Revocation failed')) + await rejected + } + }) + expect(mocks.request).toHaveBeenCalledExactlyOnceWith( + revokeOrganizationAccountEnrollmentContract, + { params: { id: 'org-1', enrollmentId: 'person-1' } } + ) + for (const key of [results, documentKey, sources]) { + if (success) expect(client.getQueryData(key)).toBeUndefined() + else expect(client.getQueryData(key)).toEqual({ content: 'cached' }) + } + for (const key of [accounts, people, overview]) + expect(client.getQueryState(key)?.isInvalidated).toBe(success) + expect(client.getQueryState(otherAccounts)?.isInvalidated).toBe(false) + expect(client.getQueryData(otherResults)).toEqual({ content: 'cached' }) + } finally { + await act(async () => root.unmount()) + client.clear() + vi.unstubAllGlobals() + } + } + ) +}) + describe('organization people search pagination', () => { let root: Root let container: HTMLDivElement diff --git a/apps/sim/hooks/queries/organization-accounts.ts b/apps/sim/hooks/queries/organization-accounts.ts index 65cf2cafef7..7c96859612d 100644 --- a/apps/sim/hooks/queries/organization-accounts.ts +++ b/apps/sim/hooks/queries/organization-accounts.ts @@ -312,7 +312,12 @@ export function useRevokeOrganizationAccountEnrollment() { params: { id: organizationId, enrollmentId }, }), onSuccess: (_, { organizationId }) => - queryClient.invalidateQueries({ queryKey: organizationAccountsKeys.people(organizationId) }), + Promise.all([ + resetOrganizationSearchAccess(queryClient, organizationId), + queryClient.invalidateQueries({ + queryKey: organizationAccountsKeys.detail(organizationId), + }), + ]), }) } export function useAddOrganizationAccountMcpProvider() { diff --git a/apps/sim/hooks/queries/organization-search-stats.ts b/apps/sim/hooks/queries/organization-search-stats.ts new file mode 100644 index 00000000000..a11c471103b --- /dev/null +++ b/apps/sim/hooks/queries/organization-search-stats.ts @@ -0,0 +1,28 @@ +'use client' + +import { useQuery } from '@tanstack/react-query' +import { requestJson } from '@/lib/api/client/request' +import { + type OrganizationSearchStatsQuery, + readOrganizationSearchStatsContract, +} from '@/lib/api/contracts/knowledge/search-stats' + +export const ORGANIZATION_SEARCH_STATS_STALE_TIME = 60_000 + +export const organizationSearchStatsKeys = { + all: ['organization-search-stats'] as const, + summaries: () => [...organizationSearchStatsKeys.all, 'summary'] as const, + summary: (query: OrganizationSearchStatsQuery) => + [...organizationSearchStatsKeys.summaries(), query] as const, +} + +export function useOrganizationSearchStats(query: OrganizationSearchStatsQuery) { + return useQuery({ + queryKey: organizationSearchStatsKeys.summary(query), + queryFn: async ({ signal }) => { + const result = await requestJson(readOrganizationSearchStatsContract, { query, signal }) + return result.data + }, + staleTime: ORGANIZATION_SEARCH_STATS_STALE_TIME, + }) +} diff --git a/apps/sim/lib/api/contracts/knowledge/search-stats.ts b/apps/sim/lib/api/contracts/knowledge/search-stats.ts new file mode 100644 index 00000000000..63f30e2ec8f --- /dev/null +++ b/apps/sim/lib/api/contracts/knowledge/search-stats.ts @@ -0,0 +1,76 @@ +import { z } from 'zod' +import { organizationIdSchema } from '@/lib/api/contracts/primitives' +import { defineRouteContract } from '@/lib/api/contracts/types' +import { + getSearchStatsRangeError, + SEARCH_STATS_MAX_DAYS, + SEARCH_STATS_PEOPLE_LIMIT, + SEARCH_STATS_PERIODS, + SEARCH_STATS_SOURCE_LIMIT, + SEARCH_STATS_SURFACES, +} from '@/lib/knowledge/search/stats' + +export const organizationSearchStatsQuerySchema = z + .object({ + organizationId: organizationIdSchema, + period: z.enum(SEARCH_STATS_PERIODS).default('30d'), + surface: z.enum(SEARCH_STATS_SURFACES).optional(), + startDate: z.string().max(10).optional(), + endDate: z.string().max(10).optional(), + }) + .superRefine((query, context) => { + if (query.period === 'custom') { + const error = getSearchStatsRangeError(query) + if (error) context.addIssue({ code: 'custom', path: ['startDate'], message: error }) + } else if (query.startDate !== undefined || query.endDate !== undefined) { + context.addIssue({ + code: 'custom', + path: ['period'], + message: 'Choose Custom range to use start and end dates.', + }) + } + }) +export type OrganizationSearchStatsQuery = z.input + +const countSchema = z.number().int().nonnegative() +const sourceTypeSchema = z.string().min(1).max(100) +export const organizationSearchStatsSchema = z.object({ + start: z.string().datetime(), + end: z.string().datetime(), + totals: z.object({ + invocations: countSchema, + activePeople: countSchema, + results: countSchema, + }), + series: z + .array(z.object({ timestamp: z.string().datetime(), invocations: countSchema })) + .max(SEARCH_STATS_MAX_DAYS), + surfaces: z + .array(z.object({ surface: z.enum(SEARCH_STATS_SURFACES), invocations: countSchema })) + .max(7), + sources: z + .array(z.object({ sourceType: sourceTypeSchema, invocations: countSchema })) + .max(SEARCH_STATS_SOURCE_LIMIT), + people: z + .array( + z.object({ + userId: z.string().nullable(), + name: z.string().nullable(), + email: z.string().nullable(), + invocations: countSchema, + sourceTypes: z.array(sourceTypeSchema).max(SEARCH_STATS_SOURCE_LIMIT), + }) + ) + .max(SEARCH_STATS_PEOPLE_LIMIT), +}) +export type OrganizationSearchStats = z.output + +export const readOrganizationSearchStatsContract = defineRouteContract({ + method: 'GET', + path: '/api/knowledge/sim-search/stats', + query: organizationSearchStatsQuerySchema, + response: { + mode: 'json', + schema: z.object({ success: z.literal(true), data: organizationSearchStatsSchema }), + }, +}) diff --git a/apps/sim/lib/copilot/request/lifecycle/run.test.ts b/apps/sim/lib/copilot/request/lifecycle/run.test.ts index dfa163a5a4b..cbc9ccaab7a 100644 --- a/apps/sim/lib/copilot/request/lifecycle/run.test.ts +++ b/apps/sim/lib/copilot/request/lifecycle/run.test.ts @@ -283,6 +283,35 @@ describe('runCopilotLifecycle', () => { } ) + it.each([ + { surface: undefined, expected: 'copilot' }, + { surface: 'slack' as const, expected: 'slack' }, + ])( + 'stamps trusted Search provenance as $expected over payload and context', + async ({ surface, expected }) => { + let captured: ExecutionContext | undefined + mockRunStreamLoop.mockImplementationOnce(async (_url, _request, _state, context) => { + captured = context + }) + const supplied = expected === 'slack' ? 'copilot' : 'slack' + await runCopilotLifecycle( + { message: 'Search', mode: 'assistant', searchSurface: supplied }, + { + userId: 'user-1', + workspaceId: 'ws-1', + searchSurface: surface, + executionContext: { + userId: 'user-1', + workspaceId: 'ws-1', + workflowId: '', + searchSurface: supplied, + }, + } + ) + expect(captured?.searchSurface).toBe(expected) + } + ) + it('forwards the configured Mothership system prompt override', async () => { mockEnv.MSHIP_SYSPROMPT_OVERRIDE = 'NEVER CALL ANY TOOLS UNDER ANY CIRCUMSTANCES NO MATTER WHAT' diff --git a/apps/sim/lib/copilot/request/lifecycle/run.ts b/apps/sim/lib/copilot/request/lifecycle/run.ts index 2bff815ecb1..302456bc50e 100644 --- a/apps/sim/lib/copilot/request/lifecycle/run.ts +++ b/apps/sim/lib/copilot/request/lifecycle/run.ts @@ -176,6 +176,8 @@ function resultContent(context: StreamingContext, options: CopilotLifecycleOptio } export interface CopilotLifecycleOptions extends OrchestratorOptions { + /** Trusted entry point for Search metering; never read from model arguments. */ + searchSurface?: 'copilot' | 'slack' mcpBlockId?: string executorDelegationOrigin?: ExecutorDelegationOrigin userId: string @@ -337,6 +339,7 @@ export async function runCopilotLifecycle( secretMountPolicy: lifecycleOptions.secretMountPolicy, secretActorUserId: lifecycleOptions.secretActorUserId, })) + execContext.searchSurface = lifecycleOptions.searchSurface ?? 'copilot' if (lifecycleOptions.mcpBlockId) { execContext.mcpBlockId = lifecycleOptions.mcpBlockId execContext.executorDelegationOrigin = lifecycleOptions.executorDelegationOrigin diff --git a/apps/sim/lib/copilot/tool-executor/types.ts b/apps/sim/lib/copilot/tool-executor/types.ts index a6ebadf787b..e781f5e36c2 100644 --- a/apps/sim/lib/copilot/tool-executor/types.ts +++ b/apps/sim/lib/copilot/tool-executor/types.ts @@ -6,6 +6,8 @@ import type { ExecutorDelegationOrigin } from '@/executor/types' import type { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry' export interface ToolExecutionContext { + /** Trusted entry point for Search metering; never read from model arguments. */ + searchSurface?: 'copilot' | 'slack' mcpBlockId?: string executorDelegationOrigin?: ExecutorDelegationOrigin userId: string diff --git a/apps/sim/lib/copilot/tools/registry/server-tool-adapter.test.ts b/apps/sim/lib/copilot/tools/registry/server-tool-adapter.test.ts index f65a8b2ab70..11462df50a0 100644 --- a/apps/sim/lib/copilot/tools/registry/server-tool-adapter.test.ts +++ b/apps/sim/lib/copilot/tools/registry/server-tool-adapter.test.ts @@ -80,4 +80,24 @@ describe('server tool adapter authority boundary', () => { storageError ) }) + + it('forwards trusted Search provenance independently of model parameters', async () => { + await createServerToolHandler('search_workspace')( + { query: 'policy', searchSurface: 'copilot', surface: 'copilot' }, + { + userId: 'user-1', + workflowId: '', + organizationId: 'org-1', + chatId: 'chat-1', + toolCallId: 'call-1', + copilotToolExecution: true, + searchSurface: 'slack', + } + ) + expect(mocks.routeExecution).toHaveBeenCalledWith( + 'search_workspace', + expect.objectContaining({ query: 'policy' }), + expect.objectContaining({ searchSurface: 'slack', organizationId: 'org-1' }) + ) + }) }) diff --git a/apps/sim/lib/copilot/tools/registry/server-tool-adapter.ts b/apps/sim/lib/copilot/tools/registry/server-tool-adapter.ts index 5742c431148..f7c37bbf2bd 100644 --- a/apps/sim/lib/copilot/tools/registry/server-tool-adapter.ts +++ b/apps/sim/lib/copilot/tools/registry/server-tool-adapter.ts @@ -24,6 +24,7 @@ export function createServerToolHandler(toolId: string): ToolHandler { toolCallId: context.toolCallId, copilotToolExecution: context.copilotToolExecution, requestMode: context.requestMode, + searchSurface: context.searchSurface, assistantSearch: context.assistantSearch, billingAttribution: context.billingAttribution, userPermission: context.userPermission ?? undefined, diff --git a/apps/sim/lib/copilot/tools/server/base-tool.ts b/apps/sim/lib/copilot/tools/server/base-tool.ts index eacf3d152b4..96b6df6f3bd 100644 --- a/apps/sim/lib/copilot/tools/server/base-tool.ts +++ b/apps/sim/lib/copilot/tools/server/base-tool.ts @@ -4,6 +4,8 @@ import type { WorkspaceSearchFilters } from '@/lib/knowledge/search/filters' import type { ResolvedSecretTraceRegistry } from '@/executor/utils/resolved-secret-trace-registry' export interface ServerToolContext { + /** Trusted entry point for Search metering; never read from model arguments. */ + searchSurface?: 'copilot' | 'slack' requestMode?: string assistantSearch?: WorkspaceSearchFilters userId: string diff --git a/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.test.ts b/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.test.ts index 17b3a987c3b..298d5d7f270 100644 --- a/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.test.ts +++ b/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.test.ts @@ -420,6 +420,22 @@ describe('manage_knowledge_base trusted application delegation', () => { expect(mockReadKnowledgeBase).not.toHaveBeenCalled() }) + it('attributes knowledge queries to the trusted Slack context', async () => { + const result = await knowledgeBaseServerTool.execute( + { operation: 'query', args: { knowledgeBaseId: KNOWLEDGE_BASE.id, query: 'query' } }, + { + ...CONTEXT, + resolvedSecretTraceRegistry: new ResolvedSecretTraceRegistry(), + searchSurface: 'slack', + } + ) + + expect(result.success).toBe(true) + expect(mockSearchKnowledge).toHaveBeenCalledWith( + expect.objectContaining({ input: expect.objectContaining({ surface: 'slack' }) }) + ) + }) + it('asks for citations where per-member access is on', async () => { const result = await knowledgeBaseServerTool.execute( { operation: 'query', args: { knowledgeBaseId: KNOWLEDGE_BASE.id, query: 'query' } }, diff --git a/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.ts b/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.ts index 4781eb1ca8a..a610f02b6b2 100644 --- a/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.ts +++ b/apps/sim/lib/copilot/tools/server/knowledge/knowledge-base.ts @@ -449,7 +449,7 @@ export const knowledgeBaseServerTool: BaseServerTool { }) }) + it.each([ + { searchSurface: undefined, expected: 'copilot' }, + { searchSurface: 'slack' as const, expected: 'slack' }, + ])( + 'attributes organization searches to trusted $expected provenance', + async ({ searchSurface, expected }) => { + const result = await searchWorkspaceServerTool.execute( + { query: 'policy', surface: 'api', searchSurface: 'api' }, + { + ...context, + workspaceId: undefined, + organizationId: 'org-1', + chatId: 'chat-1', + requestMode: 'assistant', + searchSurface, + } + ) + expect(result).toMatchObject({ success: true }) + expect(mocks.search).toHaveBeenCalledWith({ + principal: expect.objectContaining({ organizationId: 'org-1', subjectUserId: 'reader' }), + input: expect.objectContaining({ surface: expected, organizationId: 'org-1' }), + }) + } + ) + it('rejects a removed member or another private chat before reading documents', async () => { mocks.authorizeChat.mockRejectedValueOnce(new Error('Conversation not found')) const result = await readDocumentServerTool.execute( diff --git a/apps/sim/lib/copilot/tools/server/knowledge/workspace-search.ts b/apps/sim/lib/copilot/tools/server/knowledge/workspace-search.ts index e5bc7664f7d..4fad2478865 100644 --- a/apps/sim/lib/copilot/tools/server/knowledge/workspace-search.ts +++ b/apps/sim/lib/copilot/tools/server/knowledge/workspace-search.ts @@ -53,7 +53,7 @@ export const searchWorkspaceServerTool: BaseServerTool = { query: projected.value, topK, filters: intersectWorkspaceSearchFilters(requestedFilters, context?.assistantSearch), - surface: 'copilot', + surface: context?.searchSurface ?? 'copilot', resultSecretRegistry: registry, signal: context?.abortSignal, } as const diff --git a/apps/sim/lib/credential-groups/service.ts b/apps/sim/lib/credential-groups/service.ts index 79f2e428378..c33f52a54db 100644 --- a/apps/sim/lib/credential-groups/service.ts +++ b/apps/sim/lib/credential-groups/service.ts @@ -307,7 +307,7 @@ export async function ensureWorkspaceAccountsGroup( throw new OrchestrationError( 'validation', scope.kind === 'organization' - ? `Refresh ${preparedOption.label} in Sources > More > Refresh connection settings, or Connected accounts > Providers > Update configurations when Search is disabled` + ? `Refresh ${preparedOption.label} in Sources > More > Update sign-in settings, or Connected accounts > Providers > Update configurations when Search is disabled` : `Update ${preparedOption.label} in Connected accounts before connecting this source` ) } diff --git a/apps/sim/lib/knowledge/application/operations.test.ts b/apps/sim/lib/knowledge/application/operations.test.ts index 3662a56b263..a2d8f28daaf 100644 --- a/apps/sim/lib/knowledge/application/operations.test.ts +++ b/apps/sim/lib/knowledge/application/operations.test.ts @@ -78,6 +78,7 @@ describe('knowledge operation registry', () => { 'knowledge.search.sources.progress', 'knowledge.search.integrations.list', 'knowledge.search.integrations.overview', + 'knowledge.search.stats.read', 'knowledge.search.integrations.approve', 'knowledge.connectors.members.list', 'knowledge.connectors.members.enroll', diff --git a/apps/sim/lib/knowledge/application/operations.ts b/apps/sim/lib/knowledge/application/operations.ts index 0669abe2c14..87d98e6e53c 100644 --- a/apps/sim/lib/knowledge/application/operations.ts +++ b/apps/sim/lib/knowledge/application/operations.ts @@ -758,6 +758,15 @@ export const knowledgeOperations = { principalKinds: ['session'], }) ), + readOrganizationSearchStats: defineKnowledgeOperation( + defineWorkspaceOperation({ + id: 'knowledge.search.stats.read', + minimumRole: 'admin', + workspaceApiKey: 'deny', + capability: 'knowledge.use', + principalKinds: ['session'], + }) + ), approveSearchIntegration: defineKnowledgeOperation( defineWorkspaceOperation({ id: 'knowledge.search.integrations.approve', diff --git a/apps/sim/lib/knowledge/application/organization-search-stats.test.ts b/apps/sim/lib/knowledge/application/organization-search-stats.test.ts new file mode 100644 index 00000000000..7b7a2b97b30 --- /dev/null +++ b/apps/sim/lib/knowledge/application/organization-search-stats.test.ts @@ -0,0 +1,82 @@ +/** @vitest-environment node */ +import { member } from '@sim/db/schema' +import { queueTableRows, resetDbChainMock } from '@sim/testing' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + context: vi.fn(), + policy: vi.fn(), + available: vi.fn(), + load: vi.fn(), +})) +vi.mock('@/lib/knowledge/application/contexts', () => ({ + resolveKnowledgeOwnerContext: mocks.context, +})) +vi.mock('@/lib/permission-groups/resolve.server', () => ({ + getUserPermissionConfigForOrganization: mocks.policy, +})) +vi.mock('@sim/platform-authz/workspace', () => ({ + isOrgAdminRole: (role: string) => role === 'admin' || role === 'owner', +})) +vi.mock('@/lib/knowledge/access/availability', () => ({ + requireOrganizationSearchAvailable: mocks.available, +})) +vi.mock('@/lib/knowledge/search/activity-stats', () => ({ + loadOrganizationSearchStats: mocks.load, +})) + +import { readOrganizationSearchStats } from '@/lib/knowledge/application/organization-search-stats' + +const principal = { kind: 'session', userId: 'admin', sessionId: 'session' } as const +const input = { organizationId: 'organization', period: '7d', surface: 'mcp' } as const + +beforeEach(() => { + vi.clearAllMocks() + resetDbChainMock() + mocks.context.mockResolvedValue({ organizationId: 'organization' }) + mocks.policy.mockResolvedValue(null) + mocks.available.mockResolvedValue(undefined) + mocks.load.mockResolvedValue({ totals: { invocations: 3 } }) +}) + +describe('organization Search stats authorization', () => { + it.each(['admin', 'owner'])( + 'allows a current %s and forwards the selected scope', + async (role) => { + queueTableRows(member, [{ role }]) + expect(await readOrganizationSearchStats.execute({ principal, input })).toEqual({ + totals: { invocations: 3 }, + }) + expect(mocks.available).toHaveBeenCalledWith('organization') + expect(mocks.load).toHaveBeenCalledWith(input) + } + ) + it.each([ + { rows: [{ role: 'member' }], code: 'forbidden' }, + { rows: [], code: 'not_found' }, + ])('rejects unauthorized access with $code before aggregation', async ({ rows, code }) => { + queueTableRows(member, rows) + await expect(readOrganizationSearchStats.execute({ principal, input })).rejects.toMatchObject({ + code, + }) + expect(mocks.load).not.toHaveBeenCalled() + }) + it('rejects API keys before protected loading', async () => { + await expect( + readOrganizationSearchStats.execute({ + principal: { kind: 'personal_api_key', userId: 'admin', keyId: 'key' }, + input, + }) + ).rejects.toThrow() + expect(mocks.context).not.toHaveBeenCalled() + expect(mocks.load).not.toHaveBeenCalled() + }) + it('fails closed when Search is disabled', async () => { + queueTableRows(member, [{ role: 'admin' }]) + mocks.available.mockRejectedValueOnce(new Error('Search is disabled')) + await expect(readOrganizationSearchStats.execute({ principal, input })).rejects.toThrow( + 'Search is disabled' + ) + expect(mocks.load).not.toHaveBeenCalled() + }) +}) diff --git a/apps/sim/lib/knowledge/application/organization-search-stats.ts b/apps/sim/lib/knowledge/application/organization-search-stats.ts new file mode 100644 index 00000000000..98aabe2973c --- /dev/null +++ b/apps/sim/lib/knowledge/application/organization-search-stats.ts @@ -0,0 +1,21 @@ +import { OrchestrationError } from '@/lib/core/orchestration/types' +import { requireOrganizationSearchAvailable } from '@/lib/knowledge/access/availability' +import { defineAuthorizedKnowledgeUseCase } from '@/lib/knowledge/application/authorized-knowledge-use-case' +import { resolveKnowledgeOwnerContext } from '@/lib/knowledge/application/contexts' +import { knowledgeOperations } from '@/lib/knowledge/application/operations' +import { + loadOrganizationSearchStats, + type SearchStatsInput, +} from '@/lib/knowledge/search/activity-stats' + +export const readOrganizationSearchStats = defineAuthorizedKnowledgeUseCase({ + operation: knowledgeOperations.readOrganizationSearchStats, + resolveContext: ({ input }: { input: SearchStatsInput }) => + resolveKnowledgeOwnerContext({ organizationId: input.organizationId }), + async execute({ context, input }) { + if (!context.organizationId) + throw new OrchestrationError('validation', 'Organization is required') + await requireOrganizationSearchAvailable(context.organizationId) + return loadOrganizationSearchStats({ ...input, organizationId: context.organizationId }) + }, +}) diff --git a/apps/sim/lib/knowledge/application/search.test.ts b/apps/sim/lib/knowledge/application/search.test.ts index abbb70f08f9..49aa6d88584 100644 --- a/apps/sim/lib/knowledge/application/search.test.ts +++ b/apps/sim/lib/knowledge/application/search.test.ts @@ -26,12 +26,17 @@ const mocks = vi.hoisted(() => ({ importProvenance: vi.fn(), rerank: vi.fn(), searched: vi.fn(), + recordActivity: vi.fn(), })) vi.mock('@/lib/core/telemetry', () => ({ PlatformEvents: { knowledgeBaseSearched: mocks.searched }, })) +vi.mock('@/lib/knowledge/search/activity', () => ({ + recordOrganizationSearchActivity: mocks.recordActivity, +})) + vi.mock('@/lib/knowledge/reranker', () => ({ rerank: mocks.rerank, })) @@ -209,6 +214,23 @@ describe('knowledge search application use case', () => { } }) + it('meters only successful organization calls under the acting person', async () => { + await searchKnowledge.execute({ + principal: { kind: 'session', userId: 'user-1', sessionId: 'session-1' }, + input: { knowledgeBaseIds: ['knowledge-1'], query: 'answer', topK: 10, surface: 'mcp' }, + }) + if (scope === 'organization') { + expect(mocks.recordActivity).toHaveBeenCalledExactlyOnceWith({ + organizationId: 'org-canonical', + userId: 'user-1', + surface: 'mcp', + results: expect.any(Array), + }) + } else { + expect(mocks.recordActivity).not.toHaveBeenCalled() + } + }) + const principal = { kind: 'session', userId: 'user-1', sessionId: 'session-1' } as const const input = { knowledgeBaseIds: ['knowledge-1'], query: 'answer', topK: 10 } @@ -274,6 +296,7 @@ describe('knowledge search application use case', () => { input: { knowledgeBaseIds: ['knowledge-1'], query: 'answer', topK: 5 }, }) ).rejects.toThrow('Search is not enabled for this organization') + expect(mocks.recordActivity).not.toHaveBeenCalled() expect(mocks.requireOrganizationSearch).toHaveBeenCalledExactlyOnceWith('org-canonical') expect(mocks.resolveBilling).not.toHaveBeenCalled() expect(mocks.generateEmbedding).not.toHaveBeenCalled() diff --git a/apps/sim/lib/knowledge/application/search.ts b/apps/sim/lib/knowledge/application/search.ts index 7e1d6d0da95..9568e817c9d 100644 --- a/apps/sim/lib/knowledge/application/search.ts +++ b/apps/sim/lib/knowledge/application/search.ts @@ -39,6 +39,7 @@ import { generateSearchEmbedding, type KbEmbeddingTarget } from '@/lib/knowledge import { runWithKnowledgeModelInputProvenance } from '@/lib/knowledge/model-input-provenance' import { rerank } from '@/lib/knowledge/reranker' import type { RerankerStatus } from '@/lib/knowledge/reranker-models' +import { recordOrganizationSearchActivity } from '@/lib/knowledge/search/activity' import { resolveKnowledgeSearchDefaults } from '@/lib/knowledge/search/defaults' import type { WorkspaceSearchFilters } from '@/lib/knowledge/search/filters' import { @@ -687,7 +688,16 @@ export const searchKnowledge = defineAuthorizedKnowledgeUseCase({ resultSecretRegistry: registry, } }, - afterSuccess: ({ principal, context, input, result }) => { + afterSuccess: async ({ principal, context, input, result }) => { + const actorUserId = resolvePrincipalSubjectUserId(principal) + if (context.organizationId && actorUserId) { + await recordOrganizationSearchActivity({ + organizationId: context.organizationId, + userId: actorUserId, + surface: input.surface ?? 'other', + results: result.results, + }) + } PlatformEvents.knowledgeBaseSearched({ knowledgeBaseId: result.knowledgeBaseId, knowledgeBaseIds: result.knowledgeBaseIds, diff --git a/apps/sim/lib/knowledge/application/slack-search/assistant.test.ts b/apps/sim/lib/knowledge/application/slack-search/assistant.test.ts index d2f335c3e08..c57bb19758d 100644 --- a/apps/sim/lib/knowledge/application/slack-search/assistant.test.ts +++ b/apps/sim/lib/knowledge/application/slack-search/assistant.test.ts @@ -258,6 +258,7 @@ describe('organization Assistant from Slack', () => { chatId: 'chat1', goRoute: '/api/mothership', autoExecuteTools: true, + searchSurface: 'slack', billingAttribution: { organizationId: 'org1', actorUserId: 'member1' }, }) ) diff --git a/apps/sim/lib/knowledge/application/slack-search/assistant.ts b/apps/sim/lib/knowledge/application/slack-search/assistant.ts index 552a68ac710..297d7cdb25d 100644 --- a/apps/sim/lib/knowledge/application/slack-search/assistant.ts +++ b/apps/sim/lib/knowledge/application/slack-search/assistant.ts @@ -255,6 +255,7 @@ export async function runSlackSearchAssistant( abortSignal: controller.signal, timeout: SLACK_SEARCH_MAX_DURATION_SECONDS * 1000, autoExecuteTools: true, + searchSurface: 'slack', onEvent: async (event) => { try { await responseStream.onEvent(event) diff --git a/apps/sim/lib/knowledge/application/workspace-search.activity.test.ts b/apps/sim/lib/knowledge/application/workspace-search.activity.test.ts new file mode 100644 index 00000000000..32ecacf0059 --- /dev/null +++ b/apps/sim/lib/knowledge/application/workspace-search.activity.test.ts @@ -0,0 +1,144 @@ +/** @vitest-environment node */ +import { member } from '@sim/db/schema' +import { queueTableRows, resetDbChainMock } from '@sim/testing' +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + context: vi.fn(), + policy: vi.fn(), + findIndex: vi.fn(), + available: vi.fn(), + activity: vi.fn(), + search: vi.fn(), +})) +vi.mock('@/lib/knowledge/application/contexts', () => ({ + resolveKnowledgeOrganizationContext: mocks.context, + resolveKnowledgeOwnerContext: mocks.context, + resolveKnowledgeWorkspaceContext: mocks.context, +})) +vi.mock('@/lib/permission-groups/resolve.server', () => ({ + getUserPermissionConfigForOrganization: mocks.policy, +})) +vi.mock('@sim/platform-authz/workspace', () => ({ + isOrgAdminRole: (role: string) => role === 'admin' || role === 'owner', +})) +vi.mock('@/lib/knowledge/search/search-index', () => ({ + findSearchIndex: mocks.findIndex, + findWorkspaceSearchIndex: mocks.findIndex, +})) +vi.mock('@/lib/knowledge/access/availability', () => ({ + requireOrganizationSearchAvailable: mocks.available, +})) +vi.mock('@/lib/knowledge/search/activity', () => ({ + recordOrganizationSearchActivity: mocks.activity, +})) +vi.mock('@/lib/knowledge/application/search', () => ({ + searchKnowledge: { execute: mocks.search }, +})) + +import { + searchOrganizationKnowledge, + searchScopedKnowledge, +} from '@/lib/knowledge/application/workspace-search' + +const principal = { kind: 'session', userId: 'reader', sessionId: 'session' } as const +const input = { organizationId: 'org', query: 'policy', topK: 20, surface: 'slack' } as const + +beforeEach(() => { + vi.clearAllMocks() + resetDbChainMock() + mocks.context.mockResolvedValue({ organizationId: 'org' }) + mocks.policy.mockResolvedValue(null) + mocks.findIndex.mockResolvedValue(null) + mocks.available.mockResolvedValue(undefined) + mocks.activity.mockResolvedValue(undefined) + mocks.search.mockResolvedValue({ results: [], knowledgeBases: [{ id: 'index' }] }) +}) + +describe.each([ + { name: 'organization Assistant', operation: searchOrganizationKnowledge }, + { name: 'scoped Search', operation: searchScopedKnowledge }, +])('$name activity before an index exists', ({ operation }) => { + it('records an authorized empty invocation for the acting member', async () => { + queueTableRows(member, [{ role: 'member' }]) + expect(await operation.execute({ principal, input })).toEqual({ + results: [], + query: 'policy', + knowledgeBases: [], + }) + expect(mocks.available).toHaveBeenCalledExactlyOnceWith('org') + expect(mocks.activity).toHaveBeenCalledExactlyOnceWith({ + organizationId: 'org', + userId: 'reader', + surface: 'slack', + results: [], + }) + expect(mocks.search).not.toHaveBeenCalled() + }) + + it('leaves indexed invocation metering to the canonical search operation', async () => { + queueTableRows(member, [{ role: 'member' }]) + mocks.findIndex.mockResolvedValueOnce({ id: 'index' }) + await operation.execute({ principal, input }) + expect(mocks.search).toHaveBeenCalledOnce() + expect(mocks.search).toHaveBeenCalledWith({ + principal, + input: expect.objectContaining({ knowledgeBaseIds: ['index'], surface: 'slack' }), + }) + expect(mocks.activity).not.toHaveBeenCalled() + }) + + it('does not meter an unavailable Search request', async () => { + queueTableRows(member, [{ role: 'member' }]) + mocks.available.mockRejectedValueOnce(new Error('Search is disabled')) + await expect(operation.execute({ principal, input })).rejects.toThrow('Search is disabled') + expect(mocks.activity).not.toHaveBeenCalled() + expect(mocks.search).not.toHaveBeenCalled() + }) + + it('does not discover the index or meter a nonmember request', async () => { + queueTableRows(member, []) + await expect(operation.execute({ principal, input })).rejects.toMatchObject({ + code: 'not_found', + }) + expect(mocks.findIndex).not.toHaveBeenCalled() + expect(mocks.activity).not.toHaveBeenCalled() + }) + + it('does not meter a request that was already cancelled', async () => { + queueTableRows(member, [{ role: 'member' }]) + const controller = new AbortController() + controller.abort(new Error('Search cancelled')) + await expect( + operation.execute({ principal, input: { ...input, signal: controller.signal } }) + ).rejects.toThrow('Search cancelled') + expect(mocks.activity).not.toHaveBeenCalled() + expect(mocks.search).not.toHaveBeenCalled() + }) + + it.each(['index', 'availability'] as const)( + 'does not meter a request cancelled during the %s lookup', + async (lookup) => { + queueTableRows(member, [{ role: 'member' }]) + const controller = new AbortController() + const cancel = () => controller.abort(new Error('Search cancelled')) + if (lookup === 'index') { + mocks.findIndex.mockImplementationOnce(async () => { + cancel() + return null + }) + } else { + mocks.available.mockImplementationOnce(async () => { + cancel() + }) + } + + await expect( + operation.execute({ principal, input: { ...input, signal: controller.signal } }) + ).rejects.toThrow('Search cancelled') + expect(mocks.findIndex).toHaveBeenCalledOnce() + expect(mocks.activity).not.toHaveBeenCalled() + expect(mocks.search).not.toHaveBeenCalled() + } + ) +}) diff --git a/apps/sim/lib/knowledge/application/workspace-search.ts b/apps/sim/lib/knowledge/application/workspace-search.ts index 67598b11c7d..4c44f62cf0e 100644 --- a/apps/sim/lib/knowledge/application/workspace-search.ts +++ b/apps/sim/lib/knowledge/application/workspace-search.ts @@ -1,4 +1,6 @@ +import { resolvePrincipalSubjectUserId } from '@sim/auth/principal' import { type ResourceOwner, resourceScopeFromOwner } from '@/lib/core/resource-scope' +import { requireOrganizationSearchAvailable } from '@/lib/knowledge/access/availability' import { defineAuthorizedKnowledgeUseCase } from '@/lib/knowledge/application/authorized-knowledge-use-case' import { resolveKnowledgeOrganizationContext, @@ -7,6 +9,7 @@ import { } from '@/lib/knowledge/application/contexts' import { knowledgeOperations } from '@/lib/knowledge/application/operations' import { type SearchKnowledgeInput, searchKnowledge } from '@/lib/knowledge/application/search' +import { recordOrganizationSearchActivity } from '@/lib/knowledge/search/activity' import { findSearchIndex, findWorkspaceSearchIndex } from '@/lib/knowledge/search/search-index' export type SearchWorkspaceKnowledgeInput = Omit< @@ -22,6 +25,7 @@ export const searchWorkspaceKnowledge = defineAuthorizedKnowledgeUseCase({ resolveContext: ({ input }: { input: SearchWorkspaceKnowledgeInput }) => resolveKnowledgeWorkspaceContext(input), async execute({ principal, input, context }) { + input.signal?.throwIfAborted() const index = await findWorkspaceSearchIndex(context.workspaceId) if (!index) return { results: [], query: input.query ?? '', knowledgeBases: [] } return searchKnowledge.execute({ @@ -42,11 +46,26 @@ export const searchOrganizationKnowledge = defineAuthorizedKnowledgeUseCase({ resolveContext: ({ input }: { input: SearchOrganizationKnowledgeInput }) => resolveKnowledgeOrganizationContext(input), async execute({ principal, input, context }) { + input.signal?.throwIfAborted() const index = await findSearchIndex({ kind: 'organization', organizationId: context.organizationId, }) - if (!index) return { results: [], query: input.query ?? '', knowledgeBases: [] } + if (!index) { + if (context.organizationId) { + await requireOrganizationSearchAvailable(context.organizationId) + input.signal?.throwIfAborted() + const userId = resolvePrincipalSubjectUserId(principal) + if (userId) + await recordOrganizationSearchActivity({ + organizationId: context.organizationId, + userId, + surface: input.surface ?? 'other', + results: [], + }) + } + return { results: [], query: input.query ?? '', knowledgeBases: [] } + } return searchKnowledge.execute({ principal, input: { ...input, knowledgeBaseIds: [index.id] } }) }, }) @@ -63,8 +82,23 @@ export const searchScopedKnowledge = defineAuthorizedKnowledgeUseCase({ resolveContext: ({ input }: { input: SearchScopedKnowledgeInput }) => resolveKnowledgeOwnerContext(input), async execute({ principal, input, context }) { + input.signal?.throwIfAborted() const index = await findSearchIndex(resourceScopeFromOwner(context)) - if (!index) return { results: [], query: input.query ?? '', knowledgeBases: [] } + if (!index) { + if (context.organizationId) { + await requireOrganizationSearchAvailable(context.organizationId) + input.signal?.throwIfAborted() + const userId = resolvePrincipalSubjectUserId(principal) + if (userId) + await recordOrganizationSearchActivity({ + organizationId: context.organizationId, + userId, + surface: input.surface ?? 'other', + results: [], + }) + } + return { results: [], query: input.query ?? '', knowledgeBases: [] } + } return searchKnowledge.execute({ principal, input: { diff --git a/apps/sim/lib/knowledge/search/activity-stats.ts b/apps/sim/lib/knowledge/search/activity-stats.ts new file mode 100644 index 00000000000..29108baa858 --- /dev/null +++ b/apps/sim/lib/knowledge/search/activity-stats.ts @@ -0,0 +1,100 @@ +import { dbReplica } from '@sim/db' +import { organizationSearchInvocation, user } from '@sim/db/schema' +import { sql } from 'drizzle-orm' +import { + getSearchStatsWindow, + SEARCH_STATS_PEOPLE_LIMIT, + type SEARCH_STATS_PERIODS, + SEARCH_STATS_SOURCE_LIMIT, + type SEARCH_STATS_SURFACES, + type SearchStatsDateRange, +} from '@/lib/knowledge/search/stats' + +export interface SearchStatsInput extends SearchStatsDateRange { + organizationId: string + period: (typeof SEARCH_STATS_PERIODS)[number] + surface?: (typeof SEARCH_STATS_SURFACES)[number] +} + +type StatsRow = { + totals: { invocations: number; activePeople: number; results: number } + series: { timestamp: string; invocations: number }[] + surfaces: { surface: (typeof SEARCH_STATS_SURFACES)[number]; invocations: number }[] + sources: { sourceType: string; invocations: number }[] + people: { + userId: string | null + name: string | null + email: string | null + invocations: number + sourceTypes: string[] + }[] +} + +/** One statement snapshot; only bounded aggregates leave Postgres, never individual search records. */ +export async function loadOrganizationSearchStats(input: SearchStatsInput, now = new Date()) { + const { start, end, days } = getSearchStatsWindow(input.period, now, input) + const rows = await dbReplica.transaction( + async (tx) => { + await tx.execute(sql`SET LOCAL statement_timeout = '10s'`) + return tx.execute(sql` + WITH activity AS ( + SELECT id, user_id, surface, source_types, result_count, created_at + FROM ${organizationSearchInvocation} + WHERE organization_id = ${input.organizationId} + AND created_at >= ${start.toISOString()}::timestamptz + AND created_at < ${end.toISOString()}::timestamptz + ${input.surface ? sql`AND surface = ${input.surface}` : sql``} + ), people AS ( + SELECT user_id, count(*)::float8 AS invocations + FROM activity GROUP BY user_id + ORDER BY invocations DESC, user_id NULLS LAST + LIMIT ${SEARCH_STATS_PEOPLE_LIMIT} + ) + SELECT + (SELECT jsonb_build_object( + 'invocations', count(*)::float8, + 'activePeople', count(DISTINCT user_id)::float8, + 'results', coalesce(sum(result_count), 0)::float8 + ) FROM activity) AS totals, + (SELECT coalesce(jsonb_agg(row ORDER BY row.timestamp), '[]'::jsonb) FROM ( + SELECT to_char(created_at AT TIME ZONE 'UTC', 'YYYY-MM-DD') || 'T00:00:00.000Z' AS timestamp, + count(*)::float8 AS invocations + FROM activity GROUP BY 1 + ) row) AS series, + (SELECT coalesce(jsonb_agg(row ORDER BY row.invocations DESC, row.surface), '[]'::jsonb) FROM ( + SELECT surface, count(*)::float8 AS invocations FROM activity GROUP BY surface + ) row) AS surfaces, + (SELECT coalesce(jsonb_agg(row ORDER BY row.invocations DESC, row."sourceType"), '[]'::jsonb) FROM ( + SELECT source_type AS "sourceType", count(*)::float8 AS invocations + FROM activity CROSS JOIN LATERAL unnest(source_types) AS source_type + GROUP BY source_type ORDER BY invocations DESC, source_type + LIMIT ${SEARCH_STATS_SOURCE_LIMIT} + ) row) AS sources, + (SELECT coalesce(jsonb_agg(row ORDER BY row.invocations DESC, row."userId" NULLS LAST), '[]'::jsonb) FROM ( + SELECT people.user_id AS "userId", ${user.name} AS name, ${user.email} AS email, + people.invocations, + ARRAY( + SELECT DISTINCT source_type FROM activity + CROSS JOIN LATERAL unnest(source_types) AS source_type + WHERE activity.user_id IS NOT DISTINCT FROM people.user_id + ORDER BY source_type LIMIT ${SEARCH_STATS_SOURCE_LIMIT} + ) AS "sourceTypes" + FROM people LEFT JOIN ${user} ON ${user.id} = people.user_id + ) row) AS people + `) + }, + { accessMode: 'read only' } + ) + const row = rows[0] + if (!row) throw new Error('Search activity aggregate returned no result') + const byDay = new Map(row.series.map((point) => [point.timestamp, point.invocations])) + return { + ...row, + start: start.toISOString(), + end: end.toISOString(), + series: Array.from({ length: days }, (_, index) => { + const timestamp = new Date(start.getTime() + index * 86_400_000).toISOString() + return { timestamp, invocations: byDay.get(timestamp) ?? 0 } + }), + } +} diff --git a/apps/sim/lib/knowledge/search/activity.test.ts b/apps/sim/lib/knowledge/search/activity.test.ts new file mode 100644 index 00000000000..11eda26b4e9 --- /dev/null +++ b/apps/sim/lib/knowledge/search/activity.test.ts @@ -0,0 +1,98 @@ +/** @vitest-environment node */ +import { beforeEach, describe, expect, it, vi } from 'vitest' + +const mocks = vi.hoisted(() => ({ + values: vi.fn(), + insert: vi.fn(), + execute: vi.fn(), + transaction: vi.fn(), +})) +vi.mock('@sim/db', () => ({ db: { transaction: mocks.transaction } })) + +import { recordOrganizationSearchActivity } from '@/lib/knowledge/search/activity' + +beforeEach(() => { + vi.clearAllMocks() + mocks.insert.mockReturnValue({ values: mocks.values }) + mocks.values.mockResolvedValue(undefined) + mocks.execute.mockResolvedValue(undefined) + mocks.transaction.mockImplementation((callback) => + callback({ execute: mocks.execute, insert: mocks.insert }) + ) +}) + +describe('Search activity metering', () => { + it('counts documents once per invocation and stores no document identity or content', async () => { + await recordOrganizationSearchActivity({ + organizationId: 'org', + userId: 'actor', + surface: 'mcp', + results: [ + { documentId: 'private-document-1', connectorType: 'confluence' }, + { documentId: 'private-document-1', connectorType: 'confluence' }, + { documentId: 'private-document-2', connectorType: 'jira' }, + { documentId: 'private-document-3', connectorType: null }, + ], + }) + expect(mocks.values).toHaveBeenCalledWith({ + id: expect.any(String), + organizationId: 'org', + userId: 'actor', + surface: 'mcp', + sourceTypes: ['confluence', 'jira', 'uploads'], + resultCount: 3, + }) + expect(JSON.stringify(mocks.values.mock.calls)).not.toContain('private-document') + }) + it('records successful empty searches', async () => { + await recordOrganizationSearchActivity({ + organizationId: 'org', + userId: 'actor', + surface: 'dashboard', + results: [], + }) + expect(mocks.values).toHaveBeenCalledWith( + expect.objectContaining({ resultCount: 0, sourceTypes: [] }) + ) + }) + it('applies a transaction-local statement deadline before inserting activity', async () => { + const timeout = Promise.withResolvers() + mocks.execute.mockReturnValueOnce(timeout.promise) + const recorded = recordOrganizationSearchActivity({ + organizationId: 'org', + userId: 'actor', + surface: 'slack', + results: [], + }) + expect(mocks.insert).not.toHaveBeenCalled() + expect(JSON.stringify(mocks.execute.mock.calls[0])).toContain( + "SET LOCAL statement_timeout = '2s'" + ) + timeout.resolve() + await recorded + expect(mocks.insert).toHaveBeenCalledOnce() + }) + it('does not attempt an unbounded insert if setting the deadline fails', async () => { + mocks.execute.mockRejectedValueOnce(new Error('Could not set statement timeout')) + await expect( + recordOrganizationSearchActivity({ + organizationId: 'org', + userId: 'actor', + surface: 'slack', + results: [], + }) + ).resolves.toBeUndefined() + expect(mocks.insert).not.toHaveBeenCalled() + }) + it('does not fail Search when activity storage is unavailable', async () => { + mocks.values.mockRejectedValueOnce(new Error('offline')) + await expect( + recordOrganizationSearchActivity({ + organizationId: 'org', + userId: 'actor', + surface: 'dashboard', + results: [], + }) + ).resolves.toBeUndefined() + }) +}) diff --git a/apps/sim/lib/knowledge/search/activity.ts b/apps/sim/lib/knowledge/search/activity.ts new file mode 100644 index 00000000000..f3a68393de7 --- /dev/null +++ b/apps/sim/lib/knowledge/search/activity.ts @@ -0,0 +1,38 @@ +import { db } from '@sim/db' +import { organizationSearchInvocation } from '@sim/db/schema' +import { createLogger } from '@sim/logger' +import { getErrorMessage } from '@sim/utils/errors' +import { generateId } from '@sim/utils/id' +import { sql } from 'drizzle-orm' +import type { SEARCH_STATS_SURFACES } from '@/lib/knowledge/search/stats' + +const logger = createLogger('OrganizationSearchActivity') + +interface SearchActivityInput { + organizationId: string + userId: string + surface: (typeof SEARCH_STATS_SURFACES)[number] + results: ReadonlyArray<{ documentId: string; connectorType: string | null }> +} + +/** Records completed, authorized searches without query text, document IDs, or content. */ +export async function recordOrganizationSearchActivity(input: SearchActivityInput): Promise { + const sourceTypes = [...new Set(input.results.map((result) => result.connectorType ?? 'uploads'))] + try { + await db.transaction(async (tx) => { + await tx.execute(sql`SET LOCAL statement_timeout = '2s'`) + await tx.insert(organizationSearchInvocation).values({ + id: generateId(), + organizationId: input.organizationId, + userId: input.userId, + surface: input.surface, + sourceTypes, + resultCount: new Set(input.results.map((result) => result.documentId)).size, + }) + }) + } catch (error) { + logger.warn('Failed to record organization Search activity', { + error: getErrorMessage(error), + }) + } +} diff --git a/apps/sim/lib/knowledge/search/stats.test.ts b/apps/sim/lib/knowledge/search/stats.test.ts new file mode 100644 index 00000000000..3e232bc97ab --- /dev/null +++ b/apps/sim/lib/knowledge/search/stats.test.ts @@ -0,0 +1,97 @@ +/** @vitest-environment node */ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' +import { organizationSearchStatsQuerySchema } from '@/lib/api/contracts/knowledge/search-stats' +import { getSearchStatsRangeError, getSearchStatsWindow } from '@/lib/knowledge/search/stats' + +const now = new Date('2026-09-10T20:00:00.000Z') +beforeEach(() => { + vi.useFakeTimers() + vi.setSystemTime(now) +}) +afterEach(() => vi.useRealTimers()) + +describe('Search stats window and contract', () => { + it.each([ + { period: 'today', start: '2026-09-10T00:00:00.000Z', days: 1 }, + { period: '3d', start: '2026-09-08T00:00:00.000Z', days: 3 }, + { period: '7d', start: '2026-09-04T00:00:00.000Z', days: 7 }, + { period: '14d', start: '2026-08-28T00:00:00.000Z', days: 14 }, + { period: '30d', start: '2026-08-12T00:00:00.000Z', days: 30 }, + { period: '90d', start: '2026-06-13T00:00:00.000Z', days: 90 }, + ] as const)('uses $days UTC calendar days including today', ({ period, start, days }) => { + const now = new Date('2026-09-10T20:00:00.000Z') + const window = getSearchStatsWindow(period, now) + expect(window).toEqual({ start: new Date(start), end: now, days }) + }) + it('includes the last custom day with an exclusive next-midnight bound', () => { + expect( + getSearchStatsWindow('custom', now, { startDate: '2026-08-31', endDate: '2026-09-02' }) + ).toEqual({ + start: new Date('2026-08-31T00:00:00.000Z'), + end: new Date('2026-09-03T00:00:00.000Z'), + days: 3, + }) + expect( + getSearchStatsWindow('custom', now, { startDate: '2026-09-10', endDate: '2026-09-10' }) + ).toEqual({ + start: new Date('2026-09-10T00:00:00.000Z'), + end: now, + days: 1, + }) + }) + it.each([ + { startDate: '2026-09-01' }, + { endDate: '2026-09-01' }, + { startDate: '2026-02-29', endDate: '2026-03-01' }, + { startDate: '2026-04-31', endDate: '2026-05-01' }, + { startDate: '2026-9-01', endDate: '2026-09-02' }, + { startDate: '2026-09-03', endDate: '2026-09-02' }, + { startDate: '2026-09-10', endDate: '2026-09-11' }, + { startDate: '2026-06-12', endDate: '2026-09-10' }, + ])('rejects invalid or unbounded custom ranges: %j', (range) => { + expect(getSearchStatsRangeError(range, now)).not.toBeNull() + expect( + organizationSearchStatsQuerySchema.safeParse({ + organizationId: 'org', + period: 'custom', + ...range, + }).success + ).toBe(false) + expect(() => getSearchStatsWindow('custom', now, range)).toThrow() + }) + it('accepts leap days and exactly 90 inclusive days, but rejects dates with a preset', () => { + for (const range of [ + { startDate: '2024-02-29', endDate: '2024-03-01' }, + { startDate: '2026-06-13', endDate: '2026-09-10' }, + ]) { + expect( + organizationSearchStatsQuerySchema.safeParse({ + organizationId: 'org', + period: 'custom', + ...range, + }).success + ).toBe(true) + expect( + organizationSearchStatsQuerySchema.safeParse({ + organizationId: 'org', + period: '7d', + ...range, + }).success + ).toBe(false) + } + }) + it('bounds scans and rejects caller-supplied surfaces', () => { + expect( + organizationSearchStatsQuerySchema.safeParse({ organizationId: 'org', period: '365d' }) + .success + ).toBe(false) + expect( + organizationSearchStatsQuerySchema.safeParse({ organizationId: 'org', surface: 'forged' }) + .success + ).toBe(false) + expect(organizationSearchStatsQuerySchema.parse({ organizationId: 'org' })).toEqual({ + organizationId: 'org', + period: '30d', + }) + }) +}) diff --git a/apps/sim/lib/knowledge/search/stats.ts b/apps/sim/lib/knowledge/search/stats.ts new file mode 100644 index 00000000000..35dbf4ded42 --- /dev/null +++ b/apps/sim/lib/knowledge/search/stats.ts @@ -0,0 +1,74 @@ +export const SEARCH_STATS_PERIODS = ['today', '3d', '7d', '14d', '30d', '90d', 'custom'] as const +export const SEARCH_STATS_SURFACES = [ + 'dashboard', + 'copilot', + 'mcp', + 'slack', + 'api', + 'workflow', + 'other', +] as const +export const SEARCH_STATS_MAX_DAYS = 90 +const DAY_MS = 86_400_000 + +export const SEARCH_STATS_PEOPLE_LIMIT = 20 +export const SEARCH_STATS_SOURCE_LIMIT = 100 + +export const SEARCH_STATS_SURFACE_LABELS: Record<(typeof SEARCH_STATS_SURFACES)[number], string> = { + dashboard: 'Search', + copilot: 'Assistant', + mcp: 'MCP', + slack: 'Slack', + api: 'API', + workflow: 'Workflows', + other: 'Other', +} + +export interface SearchStatsDateRange { + startDate?: string + endDate?: string +} + +/** Checks the date-only UTC range shared by the picker, API, and aggregate query. */ +export function getSearchStatsRangeError( + range: SearchStatsDateRange, + now = new Date() +): string | null { + const { startDate, endDate } = range + if (!startDate || !endDate) return 'Select both a start date and an end date.' + for (const date of [startDate, endDate]) { + if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) return 'Use dates in YYYY-MM-DD format.' + const parsed = new Date(`${date}T00:00:00.000Z`) + if (!Number.isFinite(parsed.getTime()) || parsed.toISOString().slice(0, 10) !== date) { + return 'Select valid calendar dates.' + } + } + if (endDate < startDate) return 'The end date must be on or after the start date.' + if (endDate > now.toISOString().slice(0, 10)) return 'Select dates on or before today (UTC).' + const days = (Date.parse(endDate) - Date.parse(startDate)) / DAY_MS + 1 + if (days > SEARCH_STATS_MAX_DAYS) + return `Select a range of ${SEARCH_STATS_MAX_DAYS} days or fewer.` + return null +} + +/** Daily UTC buckets, with the selected end date included and today capped at the current time. */ +export function getSearchStatsWindow( + period: (typeof SEARCH_STATS_PERIODS)[number], + now = new Date(), + range: SearchStatsDateRange = {} +) { + if (period === 'custom') { + const error = getSearchStatsRangeError(range, now) + if (error) throw new Error(error) + const start = new Date(`${range.startDate}T00:00:00.000Z`) + const endDay = new Date(`${range.endDate}T00:00:00.000Z`) + const end = new Date(Math.min(endDay.getTime() + DAY_MS, now.getTime())) + const days = (endDay.getTime() - start.getTime()) / DAY_MS + 1 + return { start, end, days } + } + const daysByPeriod = { today: 1, '3d': 3, '7d': 7, '14d': 14, '30d': 30, '90d': 90 } as const + const days = daysByPeriod[period] + const start = new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate())) + start.setUTCDate(start.getUTCDate() - days + 1) + return { start, end: now, days } +} diff --git a/apps/sim/lib/sim-search/connection-labels.ts b/apps/sim/lib/sim-search/connection-labels.ts new file mode 100644 index 00000000000..da7ee159a52 --- /dev/null +++ b/apps/sim/lib/sim-search/connection-labels.ts @@ -0,0 +1,71 @@ +interface SearchConnectionLabels { + add: string + title: string + empty: string + searchPlaceholder: string +} + +const CONNECTION_LABELS: Record = { + confluence: { + add: 'Add Confluence site', + title: 'Connect Confluence site', + empty: 'No Confluence sites connected.', + searchPlaceholder: 'Search Confluence sites...', + }, + jira: { + add: 'Add projects', + title: 'Add Jira projects', + empty: 'No Jira projects added.', + searchPlaceholder: 'Search Jira projects...', + }, + github: { + add: 'Add repository', + title: 'Add GitHub repository', + empty: 'No GitHub repositories added.', + searchPlaceholder: 'Search GitHub repositories...', + }, + gitlab: { + add: 'Add project', + title: 'Add GitLab project', + empty: 'No GitLab projects added.', + searchPlaceholder: 'Search GitLab projects...', + }, + slack: { + add: 'Add channels or DMs', + title: 'Choose Slack channels and DMs', + empty: 'No Slack connections yet.', + searchPlaceholder: 'Search Slack connections...', + }, +} +const GOOGLE_NAMES: Record = { + gmail: 'Gmail', + google_calendar: 'Google Calendar', + google_drive: 'Google Drive', +} + +/** Labels describe the connection being configured, not the internal connector record. */ +export function getSearchConnectionLabels( + connectorType: string, + accessMode: 'admin' | 'members' | 'workspace' = 'admin' +): SearchConnectionLabels { + const googleName = GOOGLE_NAMES[connectorType] + if (googleName) { + return { + add: accessMode === 'members' ? 'Set up member accounts' : 'Connect service account', + title: + accessMode === 'members' + ? `Set up ${googleName} member accounts` + : `Connect ${googleName} service account`, + empty: `No ${googleName} connections yet.`, + searchPlaceholder: `Search ${googleName} connections...`, + } + } + return ( + CONNECTION_LABELS[connectorType] ?? { + add: 'Add connection', + title: 'Add connection', + empty: 'No connections yet.', + searchPlaceholder: 'Search connections...', + } + ) +} diff --git a/packages/db/migrations/0338_organization_search_activity.sql b/packages/db/migrations/0338_organization_search_activity.sql new file mode 100644 index 00000000000..54d5a2ee6f8 --- /dev/null +++ b/packages/db/migrations/0338_organization_search_activity.sql @@ -0,0 +1,16 @@ +CREATE TABLE "organization_search_invocation" ( + "id" text PRIMARY KEY NOT NULL, + "organization_id" text NOT NULL, + "user_id" text, + "surface" text NOT NULL, + "source_types" text[] NOT NULL, + "result_count" integer NOT NULL, + "created_at" timestamp with time zone DEFAULT now() NOT NULL, + CONSTRAINT "organization_search_invocation_result_count_bounds" CHECK ("organization_search_invocation"."result_count" BETWEEN 0 AND 100), + CONSTRAINT "organization_search_invocation_source_types_bounds" CHECK (cardinality("organization_search_invocation"."source_types") <= 100) +); +--> statement-breakpoint +ALTER TABLE "organization_search_invocation" ADD CONSTRAINT "organization_search_invocation_organization_id_organization_id_fk" FOREIGN KEY ("organization_id") REFERENCES "public"."organization"("id") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint +ALTER TABLE "organization_search_invocation" ADD CONSTRAINT "organization_search_invocation_user_id_user_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."user"("id") ON DELETE set null ON UPDATE no action;--> statement-breakpoint +CREATE INDEX "organization_search_invocation_org_created_idx" ON "organization_search_invocation" USING btree ("organization_id","created_at");--> statement-breakpoint +CREATE INDEX "organization_search_invocation_user_idx" ON "organization_search_invocation" USING btree ("user_id"); \ No newline at end of file diff --git a/packages/db/migrations/meta/0338_snapshot.json b/packages/db/migrations/meta/0338_snapshot.json new file mode 100644 index 00000000000..04095d33534 --- /dev/null +++ b/packages/db/migrations/meta/0338_snapshot.json @@ -0,0 +1,26162 @@ +{ + "id": "980173df-14ec-401b-89a6-53d1999bc12d", + "prevId": "52816097-17cd-473b-975a-f7b08169445d", + "version": "7", + "dialect": "postgresql", + "tables": { + "public.academy_certificate": { + "name": "academy_certificate", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "course_id": { + "name": "course_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "academy_cert_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "issued_at": { + "name": "issued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "certificate_number": { + "name": "certificate_number", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "academy_certificate_user_id_idx": { + "name": "academy_certificate_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_course_id_idx": { + "name": "academy_certificate_course_id_idx", + "columns": [ + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_user_course_unique": { + "name": "academy_certificate_user_course_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "course_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "academy_certificate_status_idx": { + "name": "academy_certificate_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "academy_certificate_user_id_user_id_fk": { + "name": "academy_certificate_user_id_user_id_fk", + "tableFrom": "academy_certificate", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "academy_certificate_certificate_number_unique": { + "name": "academy_certificate_certificate_number_unique", + "nullsNotDistinct": false, + "columns": ["certificate_number"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.account": { + "name": "account", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_config": { + "name": "oauth_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "account_user_id_idx": { + "name": "account_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_account_on_account_id_provider_id": { + "name": "idx_account_on_account_id_provider_id", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.api_key": { + "name": "api_key", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key_hash": { + "name": "key_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'personal'" + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "api_key_workspace_type_idx": { + "name": "api_key_workspace_type_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_user_type_idx": { + "name": "api_key_user_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "api_key_key_hash_idx": { + "name": "api_key_key_hash_idx", + "columns": [ + { + "expression": "key_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "api_key_user_id_user_id_fk": { + "name": "api_key_user_id_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_workspace_id_workspace_id_fk": { + "name": "api_key_workspace_id_workspace_id_fk", + "tableFrom": "api_key", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "api_key_created_by_user_id_fk": { + "name": "api_key_created_by_user_id_fk", + "tableFrom": "api_key", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "api_key_key_unique": { + "name": "api_key_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": { + "workspace_type_check": { + "name": "workspace_type_check", + "value": "(type = 'workspace' AND workspace_id IS NOT NULL) OR (type = 'personal' AND workspace_id IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.async_jobs": { + "name": "async_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "run_at": { + "name": "run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 3 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "output": { + "name": "output", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "async_jobs_status_started_at_idx": { + "name": "async_jobs_status_started_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_status_completed_at_idx": { + "name": "async_jobs_status_completed_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "completed_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_pending_run_at_idx": { + "name": "async_jobs_schedule_pending_run_at_idx", + "columns": [ + { + "expression": "run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_processing_started_at_idx": { + "name": "async_jobs_schedule_processing_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" = 'processing'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "async_jobs_schedule_unreconciled_terminal_idx": { + "name": "async_jobs_schedule_unreconciled_terminal_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"async_jobs\".\"type\" = 'schedule-execution' AND \"async_jobs\".\"status\" IN ('completed', 'failed', 'cancelled') AND COALESCE(\"async_jobs\".\"metadata\" ->> 'scheduleReconciled', 'false') <> 'true'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.audit_log": { + "name": "audit_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_name": { + "name": "actor_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "actor_email": { + "name": "actor_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_name": { + "name": "resource_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "audit_log_workspace_created_idx": { + "name": "audit_log_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_workspace_created_at_id_idx": { + "name": "audit_log_workspace_created_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"created_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_actor_created_idx": { + "name": "audit_log_actor_created_idx", + "columns": [ + { + "expression": "actor_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_resource_idx": { + "name": "audit_log_resource_idx", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "audit_log_action_idx": { + "name": "audit_log_action_idx", + "columns": [ + { + "expression": "action", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "audit_log_workspace_id_workspace_id_fk": { + "name": "audit_log_workspace_id_workspace_id_fk", + "tableFrom": "audit_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "audit_log_actor_id_user_id_fk": { + "name": "audit_log_actor_id_user_id_fk", + "tableFrom": "audit_log", + "tableTo": "user", + "columnsFrom": ["actor_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.background_work_status": { + "name": "background_work_status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "background_work_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "background_work_status_value", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "message": { + "name": "message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "background_work_status_workspace_status_idx": { + "name": "background_work_status_workspace_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_workflow_status_idx": { + "name": "background_work_status_workflow_status_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_meta_child_ws_idx": { + "name": "background_work_status_meta_child_ws_idx", + "columns": [ + { + "expression": "(\"metadata\" ->> 'childWorkspaceId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "background_work_status_meta_other_ws_idx": { + "name": "background_work_status_meta_other_ws_idx", + "columns": [ + { + "expression": "(\"metadata\" ->> 'otherWorkspaceId')", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "background_work_status_workspace_id_workspace_id_fk": { + "name": "background_work_status_workspace_id_workspace_id_fk", + "tableFrom": "background_work_status", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "background_work_status_workflow_id_workflow_id_fk": { + "name": "background_work_status_workflow_id_workflow_id_fk", + "tableFrom": "background_work_status", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.chat": { + "name": "chat", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "customizations": { + "name": "customizations", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "output_configs": { + "name": "output_configs", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "include_thinking": { + "name": "include_thinking", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "include_tool_calls": { + "name": "include_tool_calls", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "identifier_idx": { + "name": "identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"chat\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "chat_archived_at_partial_idx": { + "name": "chat_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"chat\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_chat_on_workflow_id_archived_at": { + "name": "idx_chat_on_workflow_id_archived_at", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "chat_workflow_id_workflow_id_fk": { + "name": "chat_workflow_id_workflow_id_fk", + "tableFrom": "chat", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "chat_user_id_user_id_fk": { + "name": "chat_user_id_user_id_fk", + "tableFrom": "chat", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_async_tool_calls": { + "name": "copilot_async_tool_calls", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "checkpoint_id": { + "name": "checkpoint_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "tool_call_id": { + "name": "tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "args": { + "name": "args", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "status": { + "name": "status", + "type": "copilot_async_tool_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "result": { + "name": "result", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission_decision": { + "name": "permission_decision", + "type": "copilot_tool_permission_decision", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "permission_decided_at": { + "name": "permission_decided_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "claimed_by": { + "name": "claimed_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_async_tool_calls_run_id_idx": { + "name": "copilot_async_tool_calls_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_checkpoint_id_idx": { + "name": "copilot_async_tool_calls_checkpoint_id_idx", + "columns": [ + { + "expression": "checkpoint_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_status_idx": { + "name": "copilot_async_tool_calls_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_run_status_idx": { + "name": "copilot_async_tool_calls_run_status_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_async_tool_calls_tool_call_id_unique": { + "name": "copilot_async_tool_calls_tool_call_id_unique", + "columns": [ + { + "expression": "tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_async_tool_calls_run_id_copilot_runs_id_fk": { + "name": "copilot_async_tool_calls_run_id_copilot_runs_id_fk", + "tableFrom": "copilot_async_tool_calls", + "tableTo": "copilot_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_async_tool_calls_checkpoint_id_copilot_run_checkpoints_id_fk": { + "name": "copilot_async_tool_calls_checkpoint_id_copilot_run_checkpoints_id_fk", + "tableFrom": "copilot_async_tool_calls", + "tableTo": "copilot_run_checkpoints", + "columnsFrom": ["checkpoint_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_chats": { + "name": "copilot_chats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "chat_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'copilot'" + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'claude-3-7-sonnet-latest'" + }, + "conversation_id": { + "name": "conversation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_conversation_key": { + "name": "external_conversation_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_conversation_metadata": { + "name": "external_conversation_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "preview_yaml": { + "name": "preview_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "plan_artifact": { + "name": "plan_artifact", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "resources": { + "name": "resources", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "auto_allowed_tools": { + "name": "auto_allowed_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "pinned": { + "name": "pinned", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_chats_organization_id_idx": { + "name": "copilot_chats_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_external_conversation_unique": { + "name": "copilot_chats_external_conversation_unique", + "columns": [ + { + "expression": "external_conversation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"copilot_chats\".\"external_conversation_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_org_created_idx": { + "name": "copilot_chats_user_org_created_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_id_idx": { + "name": "copilot_chats_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workflow_id_idx": { + "name": "copilot_chats_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workflow_idx": { + "name": "copilot_chats_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workspace_idx": { + "name": "copilot_chats_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_created_at_idx": { + "name": "copilot_chats_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_updated_at_idx": { + "name": "copilot_chats_updated_at_idx", + "columns": [ + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_workspace_created_at_id_idx": { + "name": "copilot_chats_workspace_created_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"created_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_chats_user_workspace_deleted_partial_idx": { + "name": "copilot_chats_user_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_chats\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_chats_user_id_user_id_fk": { + "name": "copilot_chats_user_id_user_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workflow_id_workflow_id_fk": { + "name": "copilot_chats_workflow_id_workflow_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_workspace_id_workspace_id_fk": { + "name": "copilot_chats_workspace_id_workspace_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_chats_organization_id_organization_id_fk": { + "name": "copilot_chats_organization_id_organization_id_fk", + "tableFrom": "copilot_chats", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "copilot_chats_owner_check": { + "name": "copilot_chats_owner_check", + "value": "num_nonnulls(\"copilot_chats\".\"workspace_id\", \"copilot_chats\".\"organization_id\") <= 1" + }, + "copilot_chats_organization_workflow_check": { + "name": "copilot_chats_organization_workflow_check", + "value": "\"copilot_chats\".\"organization_id\" IS NULL OR \"copilot_chats\".\"workflow_id\" IS NULL" + } + }, + "isRLSEnabled": false + }, + "public.copilot_feedback": { + "name": "copilot_feedback", + "schema": "", + "columns": { + "feedback_id": { + "name": "feedback_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_query": { + "name": "user_query", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent_response": { + "name": "agent_response", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_positive": { + "name": "is_positive", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "feedback": { + "name": "feedback", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_yaml": { + "name": "workflow_yaml", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_feedback_user_id_idx": { + "name": "copilot_feedback_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_chat_id_idx": { + "name": "copilot_feedback_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_user_chat_idx": { + "name": "copilot_feedback_user_chat_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_is_positive_idx": { + "name": "copilot_feedback_is_positive_idx", + "columns": [ + { + "expression": "is_positive", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_feedback_created_at_idx": { + "name": "copilot_feedback_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_feedback_user_id_user_id_fk": { + "name": "copilot_feedback_user_id_user_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_feedback_chat_id_copilot_chats_id_fk": { + "name": "copilot_feedback_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_feedback", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_messages": { + "name": "copilot_messages", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "stream_id": { + "name": "stream_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parent_message_id": { + "name": "parent_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens_in": { + "name": "tokens_in", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "tokens_out": { + "name": "tokens_out", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "seq": { + "name": "seq", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_messages_chat_message_unique": { + "name": "copilot_messages_chat_message_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_created_at_idx": { + "name": "copilot_messages_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_seq_idx": { + "name": "copilot_messages_chat_seq_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "seq", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_chat_stream_idx": { + "name": "copilot_messages_chat_stream_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "stream_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"stream_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_messages_user_created_at_idx": { + "name": "copilot_messages_user_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"copilot_messages\".\"role\" = 'user' AND \"copilot_messages\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_messages_chat_id_copilot_chats_id_fk": { + "name": "copilot_messages_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_messages", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_run_checkpoints": { + "name": "copilot_run_checkpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "run_id": { + "name": "run_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "pending_tool_call_id": { + "name": "pending_tool_call_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_snapshot": { + "name": "conversation_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "agent_state": { + "name": "agent_state", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "provider_request": { + "name": "provider_request", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_run_checkpoints_run_id_idx": { + "name": "copilot_run_checkpoints_run_id_idx", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_run_checkpoints_pending_tool_call_id_idx": { + "name": "copilot_run_checkpoints_pending_tool_call_id_idx", + "columns": [ + { + "expression": "pending_tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_run_checkpoints_run_pending_tool_unique": { + "name": "copilot_run_checkpoints_run_pending_tool_unique", + "columns": [ + { + "expression": "run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "pending_tool_call_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_run_checkpoints_run_id_copilot_runs_id_fk": { + "name": "copilot_run_checkpoints_run_id_copilot_runs_id_fk", + "tableFrom": "copilot_run_checkpoints", + "tableTo": "copilot_runs", + "columnsFrom": ["run_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_runs": { + "name": "copilot_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_run_id": { + "name": "parent_run_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stream_id": { + "name": "stream_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "agent": { + "name": "agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "model": { + "name": "model", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "copilot_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "request_context": { + "name": "request_context", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "copilot_runs_execution_id_idx": { + "name": "copilot_runs_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_parent_run_id_idx": { + "name": "copilot_runs_parent_run_id_idx", + "columns": [ + { + "expression": "parent_run_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_chat_id_idx": { + "name": "copilot_runs_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_user_id_idx": { + "name": "copilot_runs_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workflow_id_idx": { + "name": "copilot_runs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workspace_id_idx": { + "name": "copilot_runs_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_status_idx": { + "name": "copilot_runs_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_chat_execution_idx": { + "name": "copilot_runs_chat_execution_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_execution_started_at_idx": { + "name": "copilot_runs_execution_started_at_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_workspace_completed_at_id_idx": { + "name": "copilot_runs_workspace_completed_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"completed_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_runs_stream_id_unique": { + "name": "copilot_runs_stream_id_unique", + "columns": [ + { + "expression": "stream_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_runs_chat_id_copilot_chats_id_fk": { + "name": "copilot_runs_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_user_id_user_id_fk": { + "name": "copilot_runs_user_id_user_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_workflow_id_workflow_id_fk": { + "name": "copilot_runs_workflow_id_workflow_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_runs_workspace_id_workspace_id_fk": { + "name": "copilot_runs_workspace_id_workspace_id_fk", + "tableFrom": "copilot_runs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.copilot_workflow_read_hashes": { + "name": "copilot_workflow_read_hashes", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "hash": { + "name": "hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "copilot_workflow_read_hashes_chat_id_idx": { + "name": "copilot_workflow_read_hashes_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_workflow_read_hashes_workflow_id_idx": { + "name": "copilot_workflow_read_hashes_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "copilot_workflow_read_hashes_chat_workflow_unique": { + "name": "copilot_workflow_read_hashes_chat_workflow_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "copilot_workflow_read_hashes_chat_id_copilot_chats_id_fk": { + "name": "copilot_workflow_read_hashes_chat_id_copilot_chats_id_fk", + "tableFrom": "copilot_workflow_read_hashes", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "copilot_workflow_read_hashes_workflow_id_workflow_id_fk": { + "name": "copilot_workflow_read_hashes_workflow_id_workflow_id_fk", + "tableFrom": "copilot_workflow_read_hashes", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.credential": { + "name": "credential", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slack_app_id": { + "name": "slack_app_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "credential_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "unredacted": { + "name": "unredacted", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_key": { + "name": "env_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "env_owner_user_id": { + "name": "env_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_service_account_key": { + "name": "encrypted_service_account_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_personal_token": { + "name": "encrypted_personal_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "authorization_app_id": { + "name": "authorization_app_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_enrollment_id": { + "name": "credential_group_enrollment_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_option_id": { + "name": "credential_group_option_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_oauth_config_version": { + "name": "mcp_oauth_config_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "managed_oauth_scope_version": { + "name": "managed_oauth_scope_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "provider_subject_id": { + "name": "provider_subject_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_tenant_id": { + "name": "provider_tenant_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "managed_oauth_status": { + "name": "managed_oauth_status", + "type": "managed_oauth_credential_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "granted_scopes": { + "name": "granted_scopes", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "provider_metadata": { + "name": "provider_metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "encrypted_oauth_token_set": { + "name": "encrypted_oauth_token_set", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mcp_tools": { + "name": "mcp_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "mcp_tools_refreshed_at": { + "name": "mcp_tools_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "granted_at": { + "name": "granted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_organization_id_idx": { + "name": "credential_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_organization_account_unique": { + "name": "credential_organization_account_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"account_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_org_personal_token_unique": { + "name": "credential_org_personal_token_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_subject_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"type\" = 'personal_token'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_id_idx": { + "name": "credential_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_type_idx": { + "name": "credential_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_provider_id_idx": { + "name": "credential_provider_id_idx", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_account_id_idx": { + "name": "credential_account_id_idx", + "columns": [ + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_env_owner_user_id_idx": { + "name": "credential_env_owner_user_id_idx", + "columns": [ + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_idx": { + "name": "credential_group_enrollment_idx", + "columns": [ + { + "expression": "credential_group_enrollment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_mcp_server_idx": { + "name": "credential_mcp_server_idx", + "columns": [ + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_option_unique": { + "name": "credential_group_option_unique", + "columns": [ + { + "expression": "credential_group_enrollment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "credential_group_option_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"type\" = 'managed_oauth'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_managed_mcp_enrollment_server_unique": { + "name": "credential_managed_mcp_enrollment_server_unique", + "columns": [ + { + "expression": "credential_group_enrollment_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential\".\"type\" = 'managed_mcp'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_account_unique": { + "name": "credential_workspace_account_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "account_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "account_id IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_env_unique": { + "name": "credential_workspace_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_workspace'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_workspace_personal_env_unique": { + "name": "credential_workspace_personal_env_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "env_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'env_personal'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_personal_token_identity_unique": { + "name": "credential_personal_token_identity_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_subject_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "type = 'personal_token'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_workspace_id_workspace_id_fk": { + "name": "credential_workspace_id_workspace_id_fk", + "tableFrom": "credential", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_organization_id_organization_id_fk": { + "name": "credential_organization_id_organization_id_fk", + "tableFrom": "credential", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_slack_app_id_slack_app_id_fk": { + "name": "credential_slack_app_id_slack_app_id_fk", + "tableFrom": "credential", + "tableTo": "slack_app", + "columnsFrom": ["slack_app_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "credential_account_id_account_id_fk": { + "name": "credential_account_id_account_id_fk", + "tableFrom": "credential", + "tableTo": "account", + "columnsFrom": ["account_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_env_owner_user_id_user_id_fk": { + "name": "credential_env_owner_user_id_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["env_owner_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_credential_group_enrollment_id_credential_group_enrollment_id_fk": { + "name": "credential_credential_group_enrollment_id_credential_group_enrollment_id_fk", + "tableFrom": "credential", + "tableTo": "credential_group_enrollment", + "columnsFrom": ["credential_group_enrollment_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_mcp_server_id_mcp_servers_id_fk": { + "name": "credential_mcp_server_id_mcp_servers_id_fk", + "tableFrom": "credential", + "tableTo": "mcp_servers", + "columnsFrom": ["mcp_server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_created_by_user_id_fk": { + "name": "credential_created_by_user_id_fk", + "tableFrom": "credential", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_owner_check": { + "name": "credential_owner_check", + "value": "num_nonnulls(\"credential\".\"workspace_id\", \"credential\".\"organization_id\") = 1" + }, + "credential_organization_type_check": { + "name": "credential_organization_type_check", + "value": "\"credential\".\"organization_id\" IS NULL OR \"credential\".\"type\" IN ('oauth', 'managed_oauth', 'managed_mcp', 'service_account', 'personal_token')" + }, + "credential_personal_token_source_check": { + "name": "credential_personal_token_source_check", + "value": "(type::text <> 'personal_token') OR (\n created_by IS NOT NULL\n AND provider_id IS NOT NULL\n AND provider_id = 'gitlab'\n AND provider_subject_id IS NOT NULL\n AND provider_tenant_id IS NOT NULL\n AND encrypted_personal_token IS NOT NULL\n AND granted_scopes IS NOT NULL\n AND cardinality(granted_scopes) > 0\n AND account_id IS NULL\n AND env_key IS NULL\n AND env_owner_user_id IS NULL\n AND authorization_app_id IS NULL\n AND encrypted_oauth_token_set IS NULL\n AND encrypted_service_account_key IS NULL\n AND unredacted = false\n )" + }, + "credential_oauth_source_check": { + "name": "credential_oauth_source_check", + "value": "(type <> 'oauth') OR (account_id IS NOT NULL AND provider_id IS NOT NULL)" + }, + "credential_managed_oauth_source_check": { + "name": "credential_managed_oauth_source_check", + "value": "(type::text <> 'managed_oauth') OR (\n account_id IS NULL\n AND provider_id IS NOT NULL\n AND authorization_app_id IS NOT NULL\n AND provider_subject_id IS NOT NULL\n AND managed_oauth_status IS NOT NULL\n AND granted_scopes IS NOT NULL\n AND encrypted_oauth_token_set IS NOT NULL\n AND granted_at IS NOT NULL\n )" + }, + "credential_managed_oauth_group_binding_check": { + "name": "credential_managed_oauth_group_binding_check", + "value": "(type::text <> 'managed_oauth') OR (\n credential_group_enrollment_id IS NOT NULL\n AND credential_group_option_id IS NOT NULL\n AND managed_oauth_scope_version IS NOT NULL\n AND managed_oauth_scope_version > 0\n )" + }, + "credential_managed_mcp_source_check": { + "name": "credential_managed_mcp_source_check", + "value": "(type::text <> 'managed_mcp') OR (\n id LIKE 'mcp-cg-%'\n AND account_id IS NULL\n AND provider_id IS NULL\n AND authorization_app_id IS NULL\n AND credential_group_enrollment_id IS NOT NULL\n AND credential_group_option_id IS NULL\n AND mcp_server_id IS NOT NULL\n AND managed_oauth_status IS NOT NULL\n AND (managed_oauth_status <> 'active' OR (\n encrypted_oauth_token_set IS NOT NULL\n AND mcp_tools IS NOT NULL\n ))\n AND granted_at IS NOT NULL\n AND managed_oauth_scope_version IS NULL\n AND provider_subject_id IS NULL\n AND provider_tenant_id IS NULL\n AND granted_scopes IS NULL\n AND provider_metadata IS NULL\n AND created_by IS NULL\n AND env_key IS NULL\n AND env_owner_user_id IS NULL\n AND encrypted_service_account_key IS NULL\n AND unredacted = false\n )" + }, + "credential_creator_source_check": { + "name": "credential_creator_source_check", + "value": "(type::text = 'managed_mcp') OR created_by IS NOT NULL" + }, + "credential_workspace_env_source_check": { + "name": "credential_workspace_env_source_check", + "value": "(type <> 'env_workspace') OR (env_key IS NOT NULL AND env_owner_user_id IS NULL)" + }, + "credential_personal_env_source_check": { + "name": "credential_personal_env_source_check", + "value": "(type <> 'env_personal') OR (env_key IS NOT NULL AND env_owner_user_id IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.credential_group": { + "name": "credential_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "public_id": { + "name": "public_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "options": { + "name": "options", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "encrypted_provider_configuration": { + "name": "encrypted_provider_configuration", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "credential_group_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_group_organization_id_idx": { + "name": "credential_group_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_organization_unique": { + "name": "credential_group_organization_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_public_id_unique": { + "name": "credential_group_public_id_unique", + "columns": [ + { + "expression": "public_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_workspace_unique": { + "name": "credential_group_workspace_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_group_workspace_id_workspace_id_fk": { + "name": "credential_group_workspace_id_workspace_id_fk", + "tableFrom": "credential_group", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_organization_id_organization_id_fk": { + "name": "credential_group_organization_id_organization_id_fk", + "tableFrom": "credential_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_created_by_user_id_fk": { + "name": "credential_group_created_by_user_id_fk", + "tableFrom": "credential_group", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_group_owner_check": { + "name": "credential_group_owner_check", + "value": "num_nonnulls(\"credential_group\".\"workspace_id\", \"credential_group\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.credential_group_enrollment": { + "name": "credential_group_enrollment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_group_id": { + "name": "credential_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "credential_group_enrollment_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'invited'" + }, + "invitation_token_hash": { + "name": "invitation_token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invitation_expires_at": { + "name": "invitation_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "invited_at": { + "name": "invited_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "sent_at": { + "name": "sent_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_delivery_error": { + "name": "last_delivery_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_group_enrollment_group_user_unique": { + "name": "credential_group_enrollment_group_user_unique", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"credential_group_enrollment\".\"user_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_user_id_idx": { + "name": "credential_group_enrollment_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_group_email_unique": { + "name": "credential_group_enrollment_group_email_unique", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_invitation_token_hash_unique": { + "name": "credential_group_enrollment_invitation_token_hash_unique", + "columns": [ + { + "expression": "invitation_token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_group_status_idx": { + "name": "credential_group_enrollment_group_status_idx", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_group_enrollment_group_invited_at_id_idx": { + "name": "credential_group_enrollment_group_invited_at_id_idx", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "invited_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_group_enrollment_credential_group_id_credential_group_id_fk": { + "name": "credential_group_enrollment_credential_group_id_credential_group_id_fk", + "tableFrom": "credential_group_enrollment", + "tableTo": "credential_group", + "columnsFrom": ["credential_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_enrollment_user_id_user_id_fk": { + "name": "credential_group_enrollment_user_id_user_id_fk", + "tableFrom": "credential_group_enrollment", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_group_enrollment_created_by_user_id_fk": { + "name": "credential_group_enrollment_created_by_user_id_fk", + "tableFrom": "credential_group_enrollment", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "credential_group_enrollment_normalized_email_check": { + "name": "credential_group_enrollment_normalized_email_check", + "value": "\"credential_group_enrollment\".\"email\" = lower(btrim(\"credential_group_enrollment\".\"email\")) AND length(\"credential_group_enrollment\".\"email\") BETWEEN 3 AND 320" + }, + "credential_group_enrollment_invitation_token_hash_length_check": { + "name": "credential_group_enrollment_invitation_token_hash_length_check", + "value": "length(\"credential_group_enrollment\".\"invitation_token_hash\") = 64" + } + }, + "isRLSEnabled": false + }, + "public.credential_member": { + "name": "credential_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "credential_member_role", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'member'" + }, + "status": { + "name": "status", + "type": "credential_member_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "joined_at": { + "name": "joined_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "credential_member_user_id_idx": { + "name": "credential_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_role_idx": { + "name": "credential_member_role_idx", + "columns": [ + { + "expression": "role", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_status_idx": { + "name": "credential_member_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "credential_member_unique": { + "name": "credential_member_unique", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "credential_member_credential_id_credential_id_fk": { + "name": "credential_member_credential_id_credential_id_fk", + "tableFrom": "credential_member", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_user_id_user_id_fk": { + "name": "credential_member_user_id_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "credential_member_invited_by_user_id_fk": { + "name": "credential_member_invited_by_user_id_fk", + "tableFrom": "credential_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_block": { + "name": "custom_block", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inputs": { + "name": "inputs", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "outputs": { + "name": "outputs", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "trace_child_runs": { + "name": "trace_child_runs", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "custom_block_organization_id_idx": { + "name": "custom_block_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_block_workflow_id_idx": { + "name": "custom_block_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_block_organization_type_unique": { + "name": "custom_block_organization_type_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_block_organization_id_organization_id_fk": { + "name": "custom_block_organization_id_organization_id_fk", + "tableFrom": "custom_block", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_block_workflow_id_workflow_id_fk": { + "name": "custom_block_workflow_id_workflow_id_fk", + "tableFrom": "custom_block", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_block_created_by_user_id_fk": { + "name": "custom_block_created_by_user_id_fk", + "tableFrom": "custom_block", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.custom_tools": { + "name": "custom_tools", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schema": { + "name": "schema", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "custom_tools_workspace_id_idx": { + "name": "custom_tools_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "custom_tools_workspace_title_unique": { + "name": "custom_tools_workspace_title_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "title", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "custom_tools_workspace_id_workspace_id_fk": { + "name": "custom_tools_workspace_id_workspace_id_fk", + "tableFrom": "custom_tools", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "custom_tools_user_id_user_id_fk": { + "name": "custom_tools_user_id_user_id_fk", + "tableFrom": "custom_tools", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_drain_runs": { + "name": "data_drain_runs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "drain_id": { + "name": "drain_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "data_drain_run_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "trigger": { + "name": "trigger", + "type": "data_drain_run_trigger", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "finished_at": { + "name": "finished_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "rows_exported": { + "name": "rows_exported", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "bytes_written": { + "name": "bytes_written", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "cursor_before": { + "name": "cursor_before", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cursor_after": { + "name": "cursor_after", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locators": { + "name": "locators", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + } + }, + "indexes": { + "data_drain_runs_drain_started_idx": { + "name": "data_drain_runs_drain_started_idx", + "columns": [ + { + "expression": "drain_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_drain_runs_drain_id_data_drains_id_fk": { + "name": "data_drain_runs_drain_id_data_drains_id_fk", + "tableFrom": "data_drain_runs", + "tableTo": "data_drains", + "columnsFrom": ["drain_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.data_drains": { + "name": "data_drains", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "data_drain_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "destination_type": { + "name": "destination_type", + "type": "data_drain_destination", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "destination_config": { + "name": "destination_config", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "destination_credentials": { + "name": "destination_credentials", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "schedule_cadence": { + "name": "schedule_cadence", + "type": "data_drain_cadence", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "cursor": { + "name": "cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_success_at": { + "name": "last_success_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "data_drains_org_idx": { + "name": "data_drains_org_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "data_drains_due_idx": { + "name": "data_drains_due_idx", + "columns": [ + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "data_drains_org_name_unique": { + "name": "data_drains_org_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "data_drains_organization_id_organization_id_fk": { + "name": "data_drains_organization_id_organization_id_fk", + "tableFrom": "data_drains", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "data_drains_created_by_user_id_fk": { + "name": "data_drains_created_by_user_id_fk", + "tableFrom": "data_drains", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.docs_embeddings": { + "name": "docs_embeddings", + "schema": "", + "columns": { + "chunk_id": { + "name": "chunk_id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "chunk_text": { + "name": "chunk_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_document": { + "name": "source_document", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_link": { + "name": "source_link", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_text": { + "name": "header_text", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header_level": { + "name": "header_level", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": true + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "chunk_text_tsv": { + "name": "chunk_text_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"docs_embeddings\".\"chunk_text\")", + "type": "stored" + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "docs_emb_source_document_idx": { + "name": "docs_emb_source_document_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_header_level_idx": { + "name": "docs_emb_header_level_idx", + "columns": [ + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_source_header_idx": { + "name": "docs_emb_source_header_idx", + "columns": [ + { + "expression": "source_document", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "header_level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_model_idx": { + "name": "docs_emb_model_idx", + "columns": [ + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_emb_created_at_idx": { + "name": "docs_emb_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "docs_embedding_vector_hnsw_idx": { + "name": "docs_embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "docs_emb_metadata_gin_idx": { + "name": "docs_emb_metadata_gin_idx", + "columns": [ + { + "expression": "metadata", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "docs_emb_chunk_text_fts_idx": { + "name": "docs_emb_chunk_text_fts_idx", + "columns": [ + { + "expression": "chunk_text_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "docs_embedding_not_null_check": { + "name": "docs_embedding_not_null_check", + "value": "\"embedding\" IS NOT NULL" + }, + "docs_header_level_check": { + "name": "docs_header_level_check", + "value": "\"header_level\" >= 1 AND \"header_level\" <= 6" + } + }, + "isRLSEnabled": false + }, + "public.document": { + "name": "document", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "filename": { + "name": "filename", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_url": { + "name": "file_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_key": { + "name": "storage_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_size": { + "name": "file_size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_count": { + "name": "chunk_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "character_count": { + "name": "character_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processing_status": { + "name": "processing_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "processing_attempts": { + "name": "processing_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "processing_queued_at": { + "name": "processing_queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_queue_token": { + "name": "processing_queue_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_deferred_until": { + "name": "processing_deferred_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_completed_at": { + "name": "processing_completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "processing_error": { + "name": "processing_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processing_recovery_after": { + "name": "processing_recovery_after", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "user_excluded": { + "name": "user_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_url": { + "name": "source_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "acl": { + "name": "acl", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{ws}'::text[]" + }, + "acl_requirements": { + "name": "acl_requirements", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "acl_verified_at": { + "name": "acl_verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_modified_at": { + "name": "source_modified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_seen_at": { + "name": "source_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "doc_kb_id_idx": { + "name": "doc_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_acl_gin_idx": { + "name": "doc_acl_gin_idx", + "columns": [ + { + "expression": "acl", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "array_ops" + } + ], + "isUnique": false, + "where": "\"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "gin", + "with": {} + }, + "doc_filename_idx": { + "name": "doc_filename_idx", + "columns": [ + { + "expression": "filename", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_processing_status_idx": { + "name": "doc_processing_status_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "processing_status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_processing_recovery_idx": { + "name": "doc_processing_recovery_idx", + "columns": [ + { + "expression": "uploaded_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"processing_status\" IN ('pending', 'processing', 'failed') AND \"document\".\"connector_id\" IS NOT NULL AND \"document\".\"content_hash\" IS NOT NULL AND \"document\".\"storage_key\" IS NOT NULL AND \"document\".\"user_excluded\" = false AND \"document\".\"archived_at\" IS NULL AND \"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_external_id_idx": { + "name": "doc_connector_external_id_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_source_lookup_idx": { + "name": "doc_connector_source_lookup_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_connector_reconciliation_idx": { + "name": "doc_connector_reconciliation_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "COALESCE(\"source_seen_at\", '-infinity'::timestamp)", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"user_excluded\" = false AND \"document\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_active_kb_token_count_idx": { + "name": "doc_active_kb_token_count_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "token_count", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"user_excluded\" = false AND \"document\".\"archived_at\" IS NULL AND \"document\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_storage_key_idx": { + "name": "doc_storage_key_idx", + "columns": [ + { + "expression": "storage_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"storage_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_archived_at_partial_idx": { + "name": "doc_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_deleted_at_partial_idx": { + "name": "doc_deleted_at_partial_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"document\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag1_lower_idx": { + "name": "doc_kb_tag1_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag1\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag2_lower_idx": { + "name": "doc_kb_tag2_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag2\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag3_lower_idx": { + "name": "doc_kb_tag3_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag3\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag4_lower_idx": { + "name": "doc_kb_tag4_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag4\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag5_lower_idx": { + "name": "doc_kb_tag5_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag5\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag6_lower_idx": { + "name": "doc_kb_tag6_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag6\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_kb_tag7_lower_idx": { + "name": "doc_kb_tag7_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag7\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number1_idx": { + "name": "doc_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number2_idx": { + "name": "doc_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number3_idx": { + "name": "doc_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number4_idx": { + "name": "doc_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_number5_idx": { + "name": "doc_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date1_idx": { + "name": "doc_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_date2_idx": { + "name": "doc_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean1_idx": { + "name": "doc_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean2_idx": { + "name": "doc_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "doc_boolean3_idx": { + "name": "doc_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "document_knowledge_base_id_knowledge_base_id_fk": { + "name": "document_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "document_connector_id_knowledge_connector_id_fk": { + "name": "document_connector_id_knowledge_connector_id_fk", + "tableFrom": "document", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "document_uploaded_by_user_id_fk": { + "name": "document_uploaded_by_user_id_fk", + "tableFrom": "document", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "doc_acl_token_shape_check": { + "name": "doc_acl_token_shape_check", + "value": "array_position(\"document\".\"acl\", NULL) IS NULL AND (cardinality(\"document\".\"acl\") = 0 OR (cardinality(\"document\".\"acl\") = array_length(string_to_array(array_to_string(\"document\".\"acl\", E'\\n'), E'\\n'), 1) AND array_to_string(\"document\".\"acl\", E'\\n') ~ '^((ws|pub|link|u:[^\\nA-Z]+@[^\\nA-Z]+|[gs]:[^\\n:]+:[^\\n:]+:[^\\n]+)(\\n(ws|pub|link|u:[^\\nA-Z]+@[^\\nA-Z]+|[gs]:[^\\n:]+:[^\\n:]+:[^\\n]+))*)$'))" + } + }, + "isRLSEnabled": false + }, + "public.document_secret_provenance": { + "name": "document_secret_provenance", + "schema": "", + "columns": { + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "source_hash": { + "name": "source_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "document_secret_provenance_document_id_document_id_fk": { + "name": "document_secret_provenance_document_id_document_id_fk", + "tableFrom": "document_secret_provenance", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "document_secret_provenance_status_check": { + "name": "document_secret_provenance_status_check", + "value": "\"document_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.embedding": { + "name": "embedding", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chunk_index": { + "name": "chunk_index", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "chunk_hash": { + "name": "chunk_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "content_length": { + "name": "content_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "embedding": { + "name": "embedding", + "type": "vector(1536)", + "primaryKey": false, + "notNull": false + }, + "embedding_384": { + "name": "embedding_384", + "type": "vector(384)", + "primaryKey": false, + "notNull": false + }, + "embedding_768": { + "name": "embedding_768", + "type": "vector(768)", + "primaryKey": false, + "notNull": false + }, + "embedding_1024": { + "name": "embedding_1024", + "type": "vector(1024)", + "primaryKey": false, + "notNull": false + }, + "embedding_3072": { + "name": "embedding_3072", + "type": "vector(3072)", + "primaryKey": false, + "notNull": false + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "start_offset": { + "name": "start_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "end_offset": { + "name": "end_offset", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "tag1": { + "name": "tag1", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag2": { + "name": "tag2", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag3": { + "name": "tag3", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag4": { + "name": "tag4", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag5": { + "name": "tag5", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag6": { + "name": "tag6", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tag7": { + "name": "tag7", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "number1": { + "name": "number1", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number2": { + "name": "number2", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number3": { + "name": "number3", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number4": { + "name": "number4", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "number5": { + "name": "number5", + "type": "double precision", + "primaryKey": false, + "notNull": false + }, + "date1": { + "name": "date1", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "date2": { + "name": "date2", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "boolean1": { + "name": "boolean1", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean2": { + "name": "boolean2", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "boolean3": { + "name": "boolean3", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "content_tsv": { + "name": "content_tsv", + "type": "tsvector", + "primaryKey": false, + "notNull": false, + "generated": { + "as": "to_tsvector('english', \"embedding\".\"content\")", + "type": "stored" + } + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "emb_kb_id_idx": { + "name": "emb_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_id_idx": { + "name": "emb_doc_id_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_chunk_idx": { + "name": "emb_doc_chunk_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chunk_index", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_model_idx": { + "name": "emb_kb_model_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "embedding_model", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_enabled_idx": { + "name": "emb_kb_enabled_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_doc_enabled_idx": { + "name": "emb_doc_enabled_idx", + "columns": [ + { + "expression": "document_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "embedding_vector_hnsw_idx": { + "name": "embedding_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_384_vector_hnsw_idx": { + "name": "embedding_384_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding_384", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_768_vector_hnsw_idx": { + "name": "embedding_768_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding_768", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_1024_vector_hnsw_idx": { + "name": "embedding_1024_vector_hnsw_idx", + "columns": [ + { + "expression": "embedding_1024", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "vector_cosine_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "embedding_3072_vector_hnsw_idx": { + "name": "embedding_3072_vector_hnsw_idx", + "columns": [ + { + "expression": "(\"embedding_3072\"::halfvec(3072)) halfvec_cosine_ops", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "hnsw", + "with": { + "m": 16, + "ef_construction": 64 + } + }, + "emb_kb_tag1_lower_idx": { + "name": "emb_kb_tag1_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag1\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag2_lower_idx": { + "name": "emb_kb_tag2_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag2\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag3_lower_idx": { + "name": "emb_kb_tag3_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag3\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag4_lower_idx": { + "name": "emb_kb_tag4_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag4\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag5_lower_idx": { + "name": "emb_kb_tag5_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag5\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag6_lower_idx": { + "name": "emb_kb_tag6_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag6\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_kb_tag7_lower_idx": { + "name": "emb_kb_tag7_lower_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(\"tag7\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number1_idx": { + "name": "emb_number1_idx", + "columns": [ + { + "expression": "number1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number2_idx": { + "name": "emb_number2_idx", + "columns": [ + { + "expression": "number2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number3_idx": { + "name": "emb_number3_idx", + "columns": [ + { + "expression": "number3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number4_idx": { + "name": "emb_number4_idx", + "columns": [ + { + "expression": "number4", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_number5_idx": { + "name": "emb_number5_idx", + "columns": [ + { + "expression": "number5", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date1_idx": { + "name": "emb_date1_idx", + "columns": [ + { + "expression": "date1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_date2_idx": { + "name": "emb_date2_idx", + "columns": [ + { + "expression": "date2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean1_idx": { + "name": "emb_boolean1_idx", + "columns": [ + { + "expression": "boolean1", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean2_idx": { + "name": "emb_boolean2_idx", + "columns": [ + { + "expression": "boolean2", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_boolean3_idx": { + "name": "emb_boolean3_idx", + "columns": [ + { + "expression": "boolean3", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "emb_content_fts_idx": { + "name": "emb_content_fts_idx", + "columns": [ + { + "expression": "content_tsv", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "embedding_knowledge_base_id_knowledge_base_id_fk": { + "name": "embedding_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "embedding", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "embedding_document_id_document_id_fk": { + "name": "embedding_document_id_document_id_fk", + "tableFrom": "embedding", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_width_check": { + "name": "embedding_width_check", + "value": "num_nonnulls(\"embedding\", \"embedding_384\", \"embedding_768\", \"embedding_1024\", \"embedding_3072\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.embedding_secret_provenance": { + "name": "embedding_secret_provenance", + "schema": "", + "columns": { + "embedding_id": { + "name": "embedding_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "embedding_secret_provenance_embedding_id_embedding_id_fk": { + "name": "embedding_secret_provenance_embedding_id_embedding_id_fk", + "tableFrom": "embedding_secret_provenance", + "tableTo": "embedding", + "columnsFrom": ["embedding_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "embedding_secret_provenance_status_check": { + "name": "embedding_secret_provenance_status_check", + "value": "\"embedding_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.environment": { + "name": "environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "environment_user_id_user_id_fk": { + "name": "environment_user_id_user_id_fk", + "tableFrom": "environment", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "environment_user_id_unique": { + "name": "environment_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_value_dependencies": { + "name": "execution_large_value_dependencies", + "schema": "", + "columns": { + "parent_key": { + "name": "parent_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_key": { + "name": "child_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "execution_large_value_dependencies_workspace_parent_key_idx": { + "name": "execution_large_value_dependencies_workspace_parent_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_value_dependencies_workspace_child_key_idx": { + "name": "execution_large_value_dependencies_workspace_child_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_value_dependencies_workspace_id_workspace_id_fk": { + "name": "execution_large_value_dependencies_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_value_dependencies", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "execution_large_value_dependencies_parent_key_child_key_pk": { + "name": "execution_large_value_dependencies_parent_key_child_key_pk", + "columns": ["parent_key", "child_key"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_value_references": { + "name": "execution_large_value_references", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "execution_large_value_reference_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "execution_large_value_references_workspace_execution_source_idx": { + "name": "execution_large_value_references_workspace_execution_source_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_value_references_workflow_id_idx": { + "name": "execution_large_value_references_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_value_references_workspace_id_workspace_id_fk": { + "name": "execution_large_value_references_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_value_references", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "execution_large_value_references_workflow_id_workflow_id_fk": { + "name": "execution_large_value_references_workflow_id_workflow_id_fk", + "tableFrom": "execution_large_value_references", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "execution_large_value_references_key_execution_id_source_pk": { + "name": "execution_large_value_references_key_execution_id_source_pk", + "columns": ["key", "execution_id", "source"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.execution_large_values": { + "name": "execution_large_values", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_execution_id": { + "name": "owner_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "execution_large_values_owner_execution_id_idx": { + "name": "execution_large_values_owner_execution_id_idx", + "columns": [ + { + "expression": "owner_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_cleanup_idx": { + "name": "execution_large_values_cleanup_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"execution_large_values\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_tombstone_cleanup_idx": { + "name": "execution_large_values_tombstone_cleanup_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"execution_large_values\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "execution_large_values_workflow_id_idx": { + "name": "execution_large_values_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "execution_large_values_workspace_id_workspace_id_fk": { + "name": "execution_large_values_workspace_id_workspace_id_fk", + "tableFrom": "execution_large_values", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "execution_large_values_workflow_id_workflow_id_fk": { + "name": "execution_large_values_workflow_id_workflow_id_fk", + "tableFrom": "execution_large_values", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.folder": { + "name": "folder", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "folder_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_id": { + "name": "parent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "folder_user_idx": { + "name": "folder_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_workspace_resource_parent_idx": { + "name": "folder_workspace_resource_parent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_parent_sort_idx": { + "name": "folder_parent_sort_idx", + "columns": [ + { + "expression": "parent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_deleted_at_idx": { + "name": "folder_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_workspace_deleted_partial_idx": { + "name": "folder_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"folder\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "folder_workspace_resource_parent_name_active_unique": { + "name": "folder_workspace_resource_parent_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"parent_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"folder\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "folder_user_id_user_id_fk": { + "name": "folder_user_id_user_id_fk", + "tableFrom": "folder", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "folder_workspace_id_workspace_id_fk": { + "name": "folder_workspace_id_workspace_id_fk", + "tableFrom": "folder", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "folder_parent_id_folder_id_fk": { + "name": "folder_parent_id_folder_id_fk", + "tableFrom": "folder", + "tableTo": "folder", + "columnsFrom": ["parent_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.idempotency_key": { + "name": "idempotency_key", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "result": { + "name": "result", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "idempotency_key_created_at_idx": { + "name": "idempotency_key_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation": { + "name": "invitation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "invitation_kind", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'organization'" + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inviter_id": { + "name": "inviter_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "membership_intent": { + "name": "membership_intent", + "type": "invitation_membership_intent", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'internal'" + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "invitation_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "invitation_email_idx": { + "name": "invitation_email_idx", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_organization_id_idx": { + "name": "invitation_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_status_idx": { + "name": "invitation_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_pending_email_org_unique": { + "name": "invitation_pending_email_org_unique", + "columns": [ + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"invitation\".\"status\" = 'pending' AND \"invitation\".\"organization_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_inviter_id_user_id_fk": { + "name": "invitation_inviter_id_user_id_fk", + "tableFrom": "invitation", + "tableTo": "user", + "columnsFrom": ["inviter_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_organization_id_organization_id_fk": { + "name": "invitation_organization_id_organization_id_fk", + "tableFrom": "invitation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "invitation_token_unique": { + "name": "invitation_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.invitation_workspace_grant": { + "name": "invitation_workspace_grant", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "invitation_id": { + "name": "invitation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission": { + "name": "permission", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "invitation_workspace_grant_unique": { + "name": "invitation_workspace_grant_unique", + "columns": [ + { + "expression": "invitation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "invitation_workspace_grant_workspace_id_idx": { + "name": "invitation_workspace_grant_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "invitation_workspace_grant_invitation_id_invitation_id_fk": { + "name": "invitation_workspace_grant_invitation_id_invitation_id_fk", + "tableFrom": "invitation_workspace_grant", + "tableTo": "invitation", + "columnsFrom": ["invitation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "invitation_workspace_grant_workspace_id_workspace_id_fk": { + "name": "invitation_workspace_grant_workspace_id_workspace_id_fk", + "tableFrom": "invitation_workspace_grant", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.job_execution_logs": { + "name": "job_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "schedule_id": { + "name": "schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "job_execution_logs_schedule_id_idx": { + "name": "job_execution_logs_schedule_id_idx", + "columns": [ + { + "expression": "schedule_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_started_at_idx": { + "name": "job_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_workspace_ended_at_id_idx": { + "name": "job_execution_logs_workspace_ended_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"ended_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_execution_id_unique": { + "name": "job_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "job_execution_logs_trigger_idx": { + "name": "job_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "job_execution_logs_schedule_id_workflow_schedule_id_fk": { + "name": "job_execution_logs_schedule_id_workflow_schedule_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workflow_schedule", + "columnsFrom": ["schedule_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "job_execution_logs_workspace_id_workspace_id_fk": { + "name": "job_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "job_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_base": { + "name": "knowledge_base", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_search_index": { + "name": "is_search_index", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "token_count": { + "name": "token_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "embedding_model": { + "name": "embedding_model", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text-embedding-3-small'" + }, + "embedding_dimension": { + "name": "embedding_dimension", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1536 + }, + "chunking_config": { + "name": "chunking_config", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{\"maxSize\": 1024, \"minSize\": 1, \"overlap\": 200}'" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kb_organization_id_idx": { + "name": "kb_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_organization_search_index_unique": { + "name": "kb_organization_search_index_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"is_search_index\" = true AND \"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_organization_name_active_unique": { + "name": "kb_organization_name_active_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_user_id_idx": { + "name": "kb_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_id_idx": { + "name": "kb_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_user_workspace_idx": { + "name": "kb_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_folder_id_idx": { + "name": "kb_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_deleted_at_idx": { + "name": "kb_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_deleted_partial_idx": { + "name": "kb_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_base\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_name_active_unique": { + "name": "kb_workspace_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_workspace_search_index_unique": { + "name": "kb_workspace_search_index_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"knowledge_base\".\"is_search_index\" = true AND \"knowledge_base\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_user_id_user_id_fk": { + "name": "knowledge_base_user_id_user_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_workspace_id_workspace_id_fk": { + "name": "knowledge_base_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_organization_id_organization_id_fk": { + "name": "knowledge_base_organization_id_organization_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_base_folder_id_folder_id_fk": { + "name": "knowledge_base_folder_id_folder_id_fk", + "tableFrom": "knowledge_base", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kb_owner_check": { + "name": "kb_owner_check", + "value": "num_nonnulls(\"knowledge_base\".\"workspace_id\", \"knowledge_base\".\"organization_id\") = 1" + }, + "kb_organization_search_index_check": { + "name": "kb_organization_search_index_check", + "value": "\"knowledge_base\".\"organization_id\" IS NULL OR \"knowledge_base\".\"is_search_index\"" + }, + "kb_organization_folder_check": { + "name": "kb_organization_folder_check", + "value": "\"knowledge_base\".\"organization_id\" IS NULL OR \"knowledge_base\".\"folder_id\" IS NULL" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_base_tag_definitions": { + "name": "knowledge_base_tag_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tag_slot": { + "name": "tag_slot", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "field_type": { + "name": "field_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kb_tag_definitions_kb_slot_idx": { + "name": "kb_tag_definitions_kb_slot_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tag_slot", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_display_name_idx": { + "name": "kb_tag_definitions_kb_display_name_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kb_tag_definitions_kb_id_idx": { + "name": "kb_tag_definitions_kb_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_base_tag_definitions_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_base_tag_definitions", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_connector": { + "name": "knowledge_connector", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_type": { + "name": "connector_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_config": { + "name": "source_config", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "sync_mode": { + "name": "sync_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'full'" + }, + "sync_interval_minutes": { + "name": "sync_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1440 + }, + "access_mode": { + "name": "access_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'workspace'" + }, + "credential_group_id": { + "name": "credential_group_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_option_id": { + "name": "credential_group_option_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_sync_status": { + "name": "member_sync_status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'idle'" + }, + "member_sync_lock_token": { + "name": "member_sync_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_sync_lock_lease_at": { + "name": "member_sync_lock_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_member_sync_at": { + "name": "next_member_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_member_sync_at": { + "name": "last_member_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_member_sync_error": { + "name": "last_member_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_sync_consecutive_failures": { + "name": "member_sync_consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "access_rewrite_pending": { + "name": "access_rewrite_pending", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_sync_error": { + "name": "last_sync_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_sync_doc_count": { + "name": "last_sync_doc_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "listing_checkpoint": { + "name": "listing_checkpoint", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "directory_checkpoint": { + "name": "directory_checkpoint", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "next_sync_at": { + "name": "next_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_directory_sync_at": { + "name": "next_directory_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "consecutive_failures": { + "name": "consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "sync_lock_token": { + "name": "sync_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_lock_lease_at": { + "name": "sync_lock_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kc_knowledge_base_id_idx": { + "name": "kc_knowledge_base_id_idx", + "columns": [ + { + "expression": "knowledge_base_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_status_next_sync_idx": { + "name": "kc_status_next_sync_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_archived_at_partial_idx": { + "name": "kc_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_deleted_at_partial_idx": { + "name": "kc_deleted_at_partial_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_member_sync_due_idx": { + "name": "kc_member_sync_due_idx", + "columns": [ + { + "expression": "member_sync_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_member_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"access_mode\" = 'members' AND \"knowledge_connector\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "kc_directory_sync_due_idx": { + "name": "kc_directory_sync_due_idx", + "columns": [ + { + "expression": "next_directory_sync_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector\".\"access_mode\" = 'admin' AND \"knowledge_connector\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_knowledge_base_id_knowledge_base_id_fk": { + "name": "knowledge_connector_knowledge_base_id_knowledge_base_id_fk", + "tableFrom": "knowledge_connector", + "tableTo": "knowledge_base", + "columnsFrom": ["knowledge_base_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_credential_group_id_credential_group_id_fk": { + "name": "knowledge_connector_credential_group_id_credential_group_id_fk", + "tableFrom": "knowledge_connector", + "tableTo": "credential_group", + "columnsFrom": ["credential_group_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kc_access_mode_check": { + "name": "kc_access_mode_check", + "value": "\"knowledge_connector\".\"access_mode\" IN ('workspace', 'members', 'admin')" + }, + "kc_member_sync_status_check": { + "name": "kc_member_sync_status_check", + "value": "\"knowledge_connector\".\"member_sync_status\" IN ('idle', 'pending', 'running', 'error', 'disabled')" + }, + "kc_sync_lock_exclusive_check": { + "name": "kc_sync_lock_exclusive_check", + "value": "NOT (\"knowledge_connector\".\"sync_lock_token\" IS NOT NULL AND \"knowledge_connector\".\"member_sync_lock_token\" IS NOT NULL)" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_member": { + "name": "knowledge_connector_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_token": { + "name": "subject_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "consecutive_failures": { + "name": "consecutive_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "next_attempt_at": { + "name": "next_attempt_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_started_at": { + "name": "last_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_complete_listing_at": { + "name": "last_complete_listing_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_listed_count": { + "name": "last_listed_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "member_synced_through": { + "name": "member_synced_through", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "change_cursor": { + "name": "change_cursor", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "listing_checkpoint": { + "name": "listing_checkpoint", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kcm_organization_id_idx": { + "name": "kcm_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcm_connector_credential_unique": { + "name": "kcm_connector_credential_unique", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcm_connector_queue_idx": { + "name": "kcm_connector_queue_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "next_attempt_at", + "isExpression": false, + "asc": true, + "nulls": "first" + }, + { + "expression": "last_started_at", + "isExpression": false, + "asc": true, + "nulls": "first" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcm_credential_idx": { + "name": "kcm_credential_idx", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_member_workspace_id_workspace_id_fk": { + "name": "knowledge_connector_member_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_member_organization_id_organization_id_fk": { + "name": "knowledge_connector_member_organization_id_organization_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_member_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_member_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_connector_member_credential_id_credential_id_fk": { + "name": "knowledge_connector_member_credential_id_credential_id_fk", + "tableFrom": "knowledge_connector_member", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kcm_owner_check": { + "name": "kcm_owner_check", + "value": "num_nonnulls(\"knowledge_connector_member\".\"workspace_id\", \"knowledge_connector_member\".\"organization_id\") = 1" + }, + "kcm_status_check": { + "name": "kcm_status_check", + "value": "\"knowledge_connector_member\".\"status\" IN ('active', 'suspended', 'disabled')" + }, + "kcm_subject_token_shape_check": { + "name": "kcm_subject_token_shape_check", + "value": "\"knowledge_connector_member\".\"subject_token\" ~ '^s:[^:]+:[^:]+:.+$'" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_member_sync_log": { + "name": "knowledge_connector_member_sync_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "members_claimed": { + "name": "members_claimed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "members_completed": { + "name": "members_completed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "members_incomplete": { + "name": "members_incomplete", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "members_failed": { + "name": "members_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_listed": { + "name": "docs_listed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_added": { + "name": "docs_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_updated": { + "name": "docs_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_unchanged": { + "name": "docs_unchanged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_hydrated_once": { + "name": "docs_hydrated_once", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "observations_added": { + "name": "observations_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "observations_removed": { + "name": "observations_removed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_tombstoned": { + "name": "docs_tombstoned", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_resurrected": { + "name": "docs_resurrected", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_purged": { + "name": "docs_purged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "credentials_audited": { + "name": "credentials_audited", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kcmsl_connector_started_at_idx": { + "name": "kcmsl_connector_started_at_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcmsl_started_at_partial_idx": { + "name": "kcmsl_started_at_partial_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector_member_sync_log\".\"status\" = 'started'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_member_sync_log_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_member_sync_log_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_member_sync_log", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "kcmsl_status_check": { + "name": "kcmsl_status_check", + "value": "\"knowledge_connector_member_sync_log\".\"status\" IN ('started', 'partial', 'completed', 'failed')" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_connector_sync_log": { + "name": "knowledge_connector_sync_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connector_id": { + "name": "connector_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "docs_added": { + "name": "docs_added", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_updated": { + "name": "docs_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_deleted": { + "name": "docs_deleted", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_unchanged": { + "name": "docs_unchanged", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_skipped": { + "name": "docs_skipped", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "docs_failed": { + "name": "docs_failed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "listed_count": { + "name": "listed_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "kcsl_connector_started_at_idx": { + "name": "kcsl_connector_started_at_idx", + "columns": [ + { + "expression": "connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "kcsl_started_at_partial_idx": { + "name": "kcsl_started_at_partial_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"knowledge_connector_sync_log\".\"status\" = 'started'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk": { + "name": "knowledge_connector_sync_log_connector_id_knowledge_connector_id_fk", + "tableFrom": "knowledge_connector_sync_log", + "tableTo": "knowledge_connector", + "columnsFrom": ["connector_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_document_observation": { + "name": "knowledge_document_observation", + "schema": "", + "columns": { + "document_id": { + "name": "document_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "member_id": { + "name": "member_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "run_id": { + "name": "run_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "kdo_member_idx": { + "name": "kdo_member_idx", + "columns": [ + { + "expression": "member_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_document_observation_document_id_document_id_fk": { + "name": "knowledge_document_observation_document_id_document_id_fk", + "tableFrom": "knowledge_document_observation", + "tableTo": "document", + "columnsFrom": ["document_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_document_observation_member_id_knowledge_connector_member_id_fk": { + "name": "knowledge_document_observation_member_id_knowledge_connector_member_id_fk", + "tableFrom": "knowledge_document_observation", + "tableTo": "knowledge_connector_member", + "columnsFrom": ["member_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "knowledge_document_observation_document_id_member_id_pk": { + "name": "knowledge_document_observation_document_id_member_id_pk", + "columns": ["document_id", "member_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.knowledge_external_directory": { + "name": "knowledge_external_directory", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenant_id": { + "name": "tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sync_lock_token": { + "name": "sync_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sync_lock_lease_at": { + "name": "sync_lock_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_started_at": { + "name": "last_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_complete_sync_at": { + "name": "last_complete_sync_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "ked_organization_id_idx": { + "name": "ked_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ked_workspace_identity_unique": { + "name": "ked_workspace_identity_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "ked_organization_identity_unique": { + "name": "ked_organization_identity_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_external_directory_workspace_id_workspace_id_fk": { + "name": "knowledge_external_directory_workspace_id_workspace_id_fk", + "tableFrom": "knowledge_external_directory", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "knowledge_external_directory_organization_id_organization_id_fk": { + "name": "knowledge_external_directory_organization_id_organization_id_fk", + "tableFrom": "knowledge_external_directory", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "ked_owner_check": { + "name": "ked_owner_check", + "value": "num_nonnulls(\"knowledge_external_directory\".\"workspace_id\", \"knowledge_external_directory\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_external_group": { + "name": "knowledge_external_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tenant_id": { + "name": "tenant_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_group_id": { + "name": "external_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_synced_at": { + "name": "last_synced_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "keg_organization_id_idx": { + "name": "keg_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_organization_identity_unique": { + "name": "keg_organization_identity_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_organization_synced_idx": { + "name": "keg_organization_synced_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_synced_at", + "isExpression": false, + "asc": true, + "nulls": "first" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_identity_unique": { + "name": "keg_identity_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "tenant_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "keg_workspace_synced_idx": { + "name": "keg_workspace_synced_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_synced_at", + "isExpression": false, + "asc": true, + "nulls": "first" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "knowledge_external_group_organization_id_organization_id_fk": { + "name": "knowledge_external_group_organization_id_organization_id_fk", + "tableFrom": "knowledge_external_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "keg_workspace_fk": { + "name": "keg_workspace_fk", + "tableFrom": "knowledge_external_group", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "keg_owner_check": { + "name": "keg_owner_check", + "value": "num_nonnulls(\"knowledge_external_group\".\"workspace_id\", \"knowledge_external_group\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.knowledge_external_group_member": { + "name": "knowledge_external_group_member", + "schema": "", + "columns": { + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "subject_token": { + "name": "subject_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "kegm_subject_token_idx": { + "name": "kegm_subject_token_idx", + "columns": [ + { + "expression": "subject_token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "kegm_group_fk": { + "name": "kegm_group_fk", + "tableFrom": "knowledge_external_group_member", + "tableTo": "knowledge_external_group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "knowledge_external_group_member_group_id_subject_token_pk": { + "name": "knowledge_external_group_member_group_id_subject_token_pk", + "columns": ["group_id", "subject_token"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mcp_server_oauth": { + "name": "mcp_server_oauth", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mcp_server_id": { + "name": "mcp_server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_information": { + "name": "client_information", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "tokens": { + "name": "tokens", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "code_verifier": { + "name": "code_verifier", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_created_at": { + "name": "state_created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_refreshed_at": { + "name": "last_refreshed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_server_oauth_server_unique": { + "name": "mcp_server_oauth_server_unique", + "columns": [ + { + "expression": "mcp_server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_server_oauth_state_idx": { + "name": "mcp_server_oauth_state_idx", + "columns": [ + { + "expression": "state", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_server_oauth_mcp_server_id_mcp_servers_id_fk": { + "name": "mcp_server_oauth_mcp_server_id_mcp_servers_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "mcp_servers", + "columnsFrom": ["mcp_server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_server_oauth_user_id_user_id_fk": { + "name": "mcp_server_oauth_user_id_user_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "mcp_server_oauth_workspace_id_workspace_id_fk": { + "name": "mcp_server_oauth_workspace_id_workspace_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_server_oauth_organization_id_organization_id_fk": { + "name": "mcp_server_oauth_organization_id_organization_id_fk", + "tableFrom": "mcp_server_oauth", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "mcp_server_oauth_owner_check": { + "name": "mcp_server_oauth_owner_check", + "value": "num_nonnulls(\"mcp_server_oauth\".\"workspace_id\", \"mcp_server_oauth\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.mcp_servers": { + "name": "mcp_servers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_group_id": { + "name": "credential_group_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "managed_connector_id": { + "name": "managed_connector_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_config_version": { + "name": "oauth_config_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "transport": { + "name": "transport", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'headers'" + }, + "oauth_client_id": { + "name": "oauth_client_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_client_secret": { + "name": "oauth_client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "headers": { + "name": "headers", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "timeout": { + "name": "timeout", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 30000 + }, + "retries": { + "name": "retries", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 3 + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "last_connected": { + "name": "last_connected", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "connection_status": { + "name": "connection_status", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'disconnected'" + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status_config": { + "name": "status_config", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "tool_count": { + "name": "tool_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_tools_refresh": { + "name": "last_tools_refresh", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_requests": { + "name": "total_requests", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_used": { + "name": "last_used", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "mcp_servers_organization_id_idx": { + "name": "mcp_servers_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_workspace_enabled_idx": { + "name": "mcp_servers_workspace_enabled_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "enabled", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_credential_group_idx": { + "name": "mcp_servers_credential_group_idx", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_credential_group_managed_connector_unique": { + "name": "mcp_servers_credential_group_managed_connector_unique", + "columns": [ + { + "expression": "credential_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "managed_connector_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"mcp_servers\".\"credential_group_id\" IS NOT NULL AND \"mcp_servers\".\"managed_connector_id\" IS NOT NULL AND \"mcp_servers\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "mcp_servers_workspace_deleted_partial_idx": { + "name": "mcp_servers_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"mcp_servers\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mcp_servers_workspace_id_workspace_id_fk": { + "name": "mcp_servers_workspace_id_workspace_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_servers_organization_id_organization_id_fk": { + "name": "mcp_servers_organization_id_organization_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mcp_servers_credential_group_id_credential_group_id_fk": { + "name": "mcp_servers_credential_group_id_credential_group_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "credential_group", + "columnsFrom": ["credential_group_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "mcp_servers_created_by_user_id_fk": { + "name": "mcp_servers_created_by_user_id_fk", + "tableFrom": "mcp_servers", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "mcp_servers_owner_check": { + "name": "mcp_servers_owner_check", + "value": "num_nonnulls(\"mcp_servers\".\"workspace_id\", \"mcp_servers\".\"organization_id\") = 1" + }, + "mcp_servers_organization_managed_check": { + "name": "mcp_servers_organization_managed_check", + "value": "\"mcp_servers\".\"organization_id\" IS NULL OR \"mcp_servers\".\"credential_group_id\" IS NOT NULL" + }, + "mcp_servers_credential_group_managed_connector_check": { + "name": "mcp_servers_credential_group_managed_connector_check", + "value": "\"mcp_servers\".\"credential_group_id\" IS NULL OR \"mcp_servers\".\"managed_connector_id\" IS NOT NULL" + }, + "mcp_servers_managed_connector_oauth_check": { + "name": "mcp_servers_managed_connector_oauth_check", + "value": "\"mcp_servers\".\"managed_connector_id\" IS NULL OR \"mcp_servers\".\"auth_type\" = 'oauth'" + } + }, + "isRLSEnabled": false + }, + "public.member": { + "name": "member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "member_user_id_unique": { + "name": "member_user_id_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "member_organization_id_idx": { + "name": "member_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "member_user_id_user_id_fk": { + "name": "member_user_id_user_id_fk", + "tableFrom": "member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "member_organization_id_organization_id_fk": { + "name": "member_organization_id_organization_id_fk", + "tableFrom": "member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory": { + "name": "memory", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "memory_key_idx": { + "name": "memory_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_idx": { + "name": "memory_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_key_idx": { + "name": "memory_workspace_key_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "memory_workspace_deleted_partial_idx": { + "name": "memory_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"memory\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "memory_workspace_id_workspace_id_fk": { + "name": "memory_workspace_id_workspace_id_fk", + "tableFrom": "memory", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.memory_secret_provenance": { + "name": "memory_secret_provenance", + "schema": "", + "columns": { + "memory_id": { + "name": "memory_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_hash": { + "name": "content_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "memory_secret_provenance_memory_id_memory_id_fk": { + "name": "memory_secret_provenance_memory_id_memory_id_fk", + "tableFrom": "memory_secret_provenance", + "tableTo": "memory", + "columnsFrom": ["memory_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "memory_secret_provenance_status_check": { + "name": "memory_secret_provenance_status_check", + "value": "\"memory_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.mothership_inbox_allowed_sender": { + "name": "mothership_inbox_allowed_sender", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "label": { + "name": "label", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "added_by": { + "name": "added_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "inbox_sender_ws_email_idx": { + "name": "inbox_sender_ws_email_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "email", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_allowed_sender_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_allowed_sender_added_by_user_id_fk": { + "name": "mothership_inbox_allowed_sender_added_by_user_id_fk", + "tableFrom": "mothership_inbox_allowed_sender", + "tableTo": "user", + "columnsFrom": ["added_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_task": { + "name": "mothership_inbox_task", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_email": { + "name": "from_email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "from_name": { + "name": "from_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "subject": { + "name": "subject", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "body_preview": { + "name": "body_preview", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_text": { + "name": "body_text", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "body_html": { + "name": "body_html", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_message_id": { + "name": "email_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "in_reply_to": { + "name": "in_reply_to", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "response_message_id": { + "name": "response_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "agentmail_message_id": { + "name": "agentmail_message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'received'" + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "trigger_job_id": { + "name": "trigger_job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "result_summary": { + "name": "result_summary", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "rejection_reason": { + "name": "rejection_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "has_attachments": { + "name": "has_attachments", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "cc_recipients": { + "name": "cc_recipients", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processing_started_at": { + "name": "processing_started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "inbox_task_ws_created_at_idx": { + "name": "inbox_task_ws_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_ws_status_idx": { + "name": "inbox_task_ws_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_response_msg_id_idx": { + "name": "inbox_task_response_msg_id_idx", + "columns": [ + { + "expression": "response_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "inbox_task_email_msg_id_idx": { + "name": "inbox_task_email_msg_id_idx", + "columns": [ + { + "expression": "email_message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "mothership_inbox_task_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_task_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "mothership_inbox_task_chat_id_copilot_chats_id_fk": { + "name": "mothership_inbox_task_chat_id_copilot_chats_id_fk", + "tableFrom": "mothership_inbox_task", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_inbox_webhook": { + "name": "mothership_inbox_webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "webhook_id": { + "name": "webhook_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mothership_inbox_webhook_workspace_id_workspace_id_fk": { + "name": "mothership_inbox_webhook_workspace_id_workspace_id_fk", + "tableFrom": "mothership_inbox_webhook", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mothership_inbox_webhook_workspace_id_unique": { + "name": "mothership_inbox_webhook_workspace_id_unique", + "nullsNotDistinct": false, + "columns": ["workspace_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.mothership_settings": { + "name": "mothership_settings", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "mcp_tool_refs": { + "name": "mcp_tool_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "custom_tool_refs": { + "name": "custom_tool_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "skill_refs": { + "name": "skill_refs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "mothership_settings_workspace_id_workspace_id_fk": { + "name": "mothership_settings_workspace_id_workspace_id_fk", + "tableFrom": "mothership_settings", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_access_token": { + "name": "oauth_access_token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "refresh_id": { + "name": "refresh_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "resource": { + "name": "resource", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "oauth_access_token_client_id_idx": { + "name": "oauth_access_token_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_session_id_idx": { + "name": "oauth_access_token_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_refresh_id_idx": { + "name": "oauth_access_token_refresh_id_idx", + "columns": [ + { + "expression": "refresh_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_user_client_idx": { + "name": "oauth_access_token_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_access_token_expires_at_idx": { + "name": "oauth_access_token_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_access_token_client_id_oauth_client_client_id_fk": { + "name": "oauth_access_token_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_access_token_session_id_session_id_fk": { + "name": "oauth_access_token_session_id_session_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "session", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauth_access_token_user_id_user_id_fk": { + "name": "oauth_access_token_user_id_user_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_access_token_refresh_id_oauth_refresh_token_id_fk": { + "name": "oauth_access_token_refresh_id_oauth_refresh_token_id_fk", + "tableFrom": "oauth_access_token", + "tableTo": "oauth_refresh_token", + "columnsFrom": ["refresh_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_access_token_token_unique": { + "name": "oauth_access_token_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": { + "oauth_access_token_search_resource_check": { + "name": "oauth_access_token_search_resource_check", + "value": "NOT ('search:read' = ANY(\"oauth_access_token\".\"scopes\")) OR \"oauth_access_token\".\"resource\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.oauth_client": { + "name": "oauth_client", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_secret": { + "name": "client_secret", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "disabled": { + "name": "disabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "skip_consent": { + "name": "skip_consent", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "enable_end_session": { + "name": "enable_end_session", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "subject_type": { + "name": "subject_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "contacts": { + "name": "contacts", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "tos": { + "name": "tos", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "policy": { + "name": "policy", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_id": { + "name": "software_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_version": { + "name": "software_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "software_statement": { + "name": "software_statement", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "post_logout_redirect_uris": { + "name": "post_logout_redirect_uris", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "token_endpoint_auth_method": { + "name": "token_endpoint_auth_method", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "grant_types": { + "name": "grant_types", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "response_types": { + "name": "response_types", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "public": { + "name": "public", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "require_pkce": { + "name": "require_pkce", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "oauth_client_user_id_idx": { + "name": "oauth_client_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_client_user_id_user_id_fk": { + "name": "oauth_client_user_id_user_id_fk", + "tableFrom": "oauth_client", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_client_client_id_unique": { + "name": "oauth_client_client_id_unique", + "nullsNotDistinct": false, + "columns": ["client_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_consent": { + "name": "oauth_consent", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_consent_client_id_idx": { + "name": "oauth_consent_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_consent_client_id_oauth_client_client_id_fk": { + "name": "oauth_consent_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_consent", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_consent_user_id_user_id_fk": { + "name": "oauth_consent_user_id_user_id_fk", + "tableFrom": "oauth_consent", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_consent_user_client_reference_unique": { + "name": "oauth_consent_user_client_reference_unique", + "nullsNotDistinct": true, + "columns": ["user_id", "client_id", "reference_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.oauth_refresh_token": { + "name": "oauth_refresh_token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "revoked": { + "name": "revoked", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "auth_time": { + "name": "auth_time", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "scopes": { + "name": "scopes", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "resource": { + "name": "resource", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "family_id": { + "name": "family_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_refresh_token_client_id_idx": { + "name": "oauth_refresh_token_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_refresh_token_session_id_idx": { + "name": "oauth_refresh_token_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_refresh_token_user_client_idx": { + "name": "oauth_refresh_token_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_refresh_token_expires_at_idx": { + "name": "oauth_refresh_token_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_refresh_token_client_id_oauth_client_client_id_fk": { + "name": "oauth_refresh_token_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_refresh_token_session_id_session_id_fk": { + "name": "oauth_refresh_token_session_id_session_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "session", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauth_refresh_token_user_id_user_id_fk": { + "name": "oauth_refresh_token_user_id_user_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_refresh_token_family_id_oauth_token_family_id_fk": { + "name": "oauth_refresh_token_family_id_oauth_token_family_id_fk", + "tableFrom": "oauth_refresh_token", + "tableTo": "oauth_token_family", + "columnsFrom": ["family_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "oauth_refresh_token_token_unique": { + "name": "oauth_refresh_token_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + }, + "oauth_refresh_token_family_generation_unique": { + "name": "oauth_refresh_token_family_generation_unique", + "nullsNotDistinct": false, + "columns": ["family_id", "generation"] + } + }, + "policies": {}, + "checkConstraints": { + "oauth_refresh_token_generation_check": { + "name": "oauth_refresh_token_generation_check", + "value": "\"oauth_refresh_token\".\"generation\" BETWEEN 0 AND 1000" + }, + "oauth_refresh_token_search_resource_check": { + "name": "oauth_refresh_token_search_resource_check", + "value": "NOT ('search:read' = ANY(\"oauth_refresh_token\".\"scopes\")) OR \"oauth_refresh_token\".\"resource\" IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.oauth_token_family": { + "name": "oauth_token_family", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "session_id": { + "name": "session_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "consent_id": { + "name": "consent_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "current_generation": { + "name": "current_generation", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "oauth_token_family_client_id_idx": { + "name": "oauth_token_family_client_id_idx", + "columns": [ + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_session_id_idx": { + "name": "oauth_token_family_session_id_idx", + "columns": [ + { + "expression": "session_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_user_client_idx": { + "name": "oauth_token_family_user_client_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "client_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_consent_id_idx": { + "name": "oauth_token_family_consent_id_idx", + "columns": [ + { + "expression": "consent_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "oauth_token_family_expires_at_idx": { + "name": "oauth_token_family_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "oauth_token_family_client_id_oauth_client_client_id_fk": { + "name": "oauth_token_family_client_id_oauth_client_client_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "oauth_client", + "columnsFrom": ["client_id"], + "columnsTo": ["client_id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_token_family_session_id_session_id_fk": { + "name": "oauth_token_family_session_id_session_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "session", + "columnsFrom": ["session_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "oauth_token_family_user_id_user_id_fk": { + "name": "oauth_token_family_user_id_user_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "oauth_token_family_consent_id_oauth_consent_id_fk": { + "name": "oauth_token_family_consent_id_oauth_consent_id_fk", + "tableFrom": "oauth_token_family", + "tableTo": "oauth_consent", + "columnsFrom": ["consent_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "oauth_token_family_generation_check": { + "name": "oauth_token_family_generation_check", + "value": "\"oauth_token_family\".\"current_generation\" BETWEEN 0 AND 1000" + } + }, + "isRLSEnabled": false + }, + "public.organization": { + "name": "organization", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "session_policy_settings": { + "name": "session_policy_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "security_policy_version": { + "name": "security_policy_version", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "whitelabel_settings": { + "name": "whitelabel_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "data_retention_settings": { + "name": "data_retention_settings", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "org_usage_limit": { + "name": "org_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "limit_notifications": { + "name": "limit_notifications", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "departed_member_usage": { + "name": "departed_member_usage", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_byok_keys": { + "name": "organization_byok_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "organization_byok_organization_provider_idx": { + "name": "organization_byok_organization_provider_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_byok_keys_organization_id_organization_id_fk": { + "name": "organization_byok_keys_organization_id_organization_id_fk", + "tableFrom": "organization_byok_keys", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_byok_keys_created_by_user_id_fk": { + "name": "organization_byok_keys_created_by_user_id_fk", + "tableFrom": "organization_byok_keys", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_member_usage_limit": { + "name": "organization_member_usage_limit", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "usage_limit": { + "name": "usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "set_by": { + "name": "set_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "org_member_usage_limit_org_user_unique": { + "name": "org_member_usage_limit_org_user_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "org_member_usage_limit_organization_id_idx": { + "name": "org_member_usage_limit_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_member_usage_limit_organization_id_organization_id_fk": { + "name": "organization_member_usage_limit_organization_id_organization_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_member_usage_limit_user_id_user_id_fk": { + "name": "organization_member_usage_limit_user_id_user_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_member_usage_limit_set_by_user_id_fk": { + "name": "organization_member_usage_limit_set_by_user_id_fk", + "tableFrom": "organization_member_usage_limit", + "tableTo": "user", + "columnsFrom": ["set_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_search_integration": { + "name": "organization_search_integration", + "schema": "", + "columns": { + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "connector_type": { + "name": "connector_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "approved": { + "name": "approved", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "organization_search_integration_organization_id_organization_id_fk": { + "name": "organization_search_integration_organization_id_organization_id_fk", + "tableFrom": "organization_search_integration", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "organization_search_integration_organization_id_connector_type_pk": { + "name": "organization_search_integration_organization_id_connector_type_pk", + "columns": ["organization_id", "connector_type"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.organization_search_invocation": { + "name": "organization_search_invocation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "surface": { + "name": "surface", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_types": { + "name": "source_types", + "type": "text[]", + "primaryKey": false, + "notNull": true + }, + "result_count": { + "name": "result_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "organization_search_invocation_org_created_idx": { + "name": "organization_search_invocation_org_created_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "organization_search_invocation_user_idx": { + "name": "organization_search_invocation_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "organization_search_invocation_organization_id_organization_id_fk": { + "name": "organization_search_invocation_organization_id_organization_id_fk", + "tableFrom": "organization_search_invocation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "organization_search_invocation_user_id_user_id_fk": { + "name": "organization_search_invocation_user_id_user_id_fk", + "tableFrom": "organization_search_invocation", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "organization_search_invocation_result_count_bounds": { + "name": "organization_search_invocation_result_count_bounds", + "value": "\"organization_search_invocation\".\"result_count\" BETWEEN 0 AND 100" + }, + "organization_search_invocation_source_types_bounds": { + "name": "organization_search_invocation_source_types_bounds", + "value": "cardinality(\"organization_search_invocation\".\"source_types\") <= 100" + } + }, + "isRLSEnabled": false + }, + "public.outbox_event": { + "name": "outbox_event", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "event_type": { + "name": "event_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "max_attempts": { + "name": "max_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10 + }, + "available_at": { + "name": "available_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "locked_at": { + "name": "locked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_error": { + "name": "last_error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "processed_at": { + "name": "processed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "outbox_event_status_available_idx": { + "name": "outbox_event_status_available_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "available_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_pending_type_available_idx": { + "name": "outbox_event_pending_type_available_idx", + "columns": [ + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "available_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"outbox_event\".\"status\" = 'pending'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_locked_at_idx": { + "name": "outbox_event_locked_at_idx", + "columns": [ + { + "expression": "locked_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "outbox_event_type_created_idx": { + "name": "outbox_event_type_created_idx", + "columns": [ + { + "expression": "event_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.paused_executions": { + "name": "paused_executions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_snapshot": { + "name": "execution_snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "pause_points": { + "name": "pause_points", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "total_pause_count": { + "name": "total_pause_count", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "resumed_count": { + "name": "resumed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "automatic_resume_retry_count": { + "name": "automatic_resume_retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'paused'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "paused_at": { + "name": "paused_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "next_resume_at": { + "name": "next_resume_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "paused_executions_workflow_id_idx": { + "name": "paused_executions_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_status_idx": { + "name": "paused_executions_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_execution_id_unique": { + "name": "paused_executions_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "paused_executions_next_resume_at_idx": { + "name": "paused_executions_next_resume_at_idx", + "columns": [ + { + "expression": "next_resume_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'paused' AND next_resume_at IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "paused_executions_workflow_id_workflow_id_fk": { + "name": "paused_executions_workflow_id_workflow_id_fk", + "tableFrom": "paused_executions", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pending_credential_draft": { + "name": "pending_credential_draft", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "oauth_config": { + "name": "oauth_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pending_draft_organization_id_idx": { + "name": "pending_draft_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pending_draft_user_provider_org": { + "name": "pending_draft_user_provider_org", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pending_draft_user_provider_ws": { + "name": "pending_draft_user_provider_ws", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pending_credential_draft_user_id_user_id_fk": { + "name": "pending_credential_draft_user_id_user_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_workspace_id_workspace_id_fk": { + "name": "pending_credential_draft_workspace_id_workspace_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_organization_id_organization_id_fk": { + "name": "pending_credential_draft_organization_id_organization_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pending_credential_draft_credential_id_credential_id_fk": { + "name": "pending_credential_draft_credential_id_credential_id_fk", + "tableFrom": "pending_credential_draft", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "pending_draft_owner_check": { + "name": "pending_draft_owner_check", + "value": "num_nonnulls(\"pending_credential_draft\".\"workspace_id\", \"pending_credential_draft\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.permission_group": { + "name": "permission_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "membership_mode": { + "name": "membership_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'inherit'" + } + }, + "indexes": { + "permission_group_created_by_idx": { + "name": "permission_group_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_organization_name_unique": { + "name": "permission_group_organization_name_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_organization_default_unique": { + "name": "permission_group_organization_default_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_organization_id_organization_id_fk": { + "name": "permission_group_organization_id_organization_id_fk", + "tableFrom": "permission_group", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_created_by_user_id_fk": { + "name": "permission_group_created_by_user_id_fk", + "tableFrom": "permission_group", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_member": { + "name": "permission_group_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "assigned_by": { + "name": "assigned_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "assigned_at": { + "name": "assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_member_group_id_idx": { + "name": "permission_group_member_group_id_idx", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_group_user_unique": { + "name": "permission_group_member_group_user_unique", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_member_organization_user_idx": { + "name": "permission_group_member_organization_user_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_member_permission_group_id_permission_group_id_fk": { + "name": "permission_group_member_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_organization_id_organization_id_fk": { + "name": "permission_group_member_organization_id_organization_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_user_id_user_id_fk": { + "name": "permission_group_member_user_id_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_member_assigned_by_user_id_fk": { + "name": "permission_group_member_assigned_by_user_id_fk", + "tableFrom": "permission_group_member", + "tableTo": "user", + "columnsFrom": ["assigned_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permission_group_workspace": { + "name": "permission_group_workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permission_group_workspace_workspace_id_idx": { + "name": "permission_group_workspace_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permission_group_workspace_group_workspace_unique": { + "name": "permission_group_workspace_group_workspace_unique", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permission_group_workspace_permission_group_id_permission_group_id_fk": { + "name": "permission_group_workspace_permission_group_id_permission_group_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_workspace_workspace_id_workspace_id_fk": { + "name": "permission_group_workspace_workspace_id_workspace_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "permission_group_workspace_organization_id_organization_id_fk": { + "name": "permission_group_workspace_organization_id_organization_id_fk", + "tableFrom": "permission_group_workspace", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.permissions": { + "name": "permissions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_type": { + "name": "entity_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entity_id": { + "name": "entity_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "permissions_user_id_idx": { + "name": "permissions_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_entity_idx": { + "name": "permissions_entity_idx", + "columns": [ + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_type_idx": { + "name": "permissions_user_entity_type_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_user_entity_permission_idx": { + "name": "permissions_user_entity_permission_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "permission_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "permissions_unique_constraint": { + "name": "permissions_unique_constraint", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "permissions_user_id_user_id_fk": { + "name": "permissions_user_id_user_id_fk", + "tableFrom": "permissions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.pinned_item": { + "name": "pinned_item", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "pinned_at": { + "name": "pinned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "pinned_item_user_workspace_idx": { + "name": "pinned_item_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pinned_item_resource_idx": { + "name": "pinned_item_resource_idx", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "pinned_item_user_resource_unique": { + "name": "pinned_item_user_resource_unique", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "pinned_item_user_id_user_id_fk": { + "name": "pinned_item_user_id_user_id_fk", + "tableFrom": "pinned_item", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "pinned_item_workspace_id_workspace_id_fk": { + "name": "pinned_item_workspace_id_workspace_id_fk", + "tableFrom": "pinned_item", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.public_share": { + "name": "public_share", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auth_type": { + "name": "auth_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'public'" + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "allowed_emails": { + "name": "allowed_emails", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'[]'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "public_share_token_unique": { + "name": "public_share_token_unique", + "columns": [ + { + "expression": "token", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_resource_unique": { + "name": "public_share_resource_unique", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_resource_id_idx": { + "name": "public_share_resource_id_idx", + "columns": [ + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "public_share_workspace_id_idx": { + "name": "public_share_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "public_share_workspace_id_workspace_id_fk": { + "name": "public_share_workspace_id_workspace_id_fk", + "tableFrom": "public_share", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "public_share_created_by_user_id_fk": { + "name": "public_share_created_by_user_id_fk", + "tableFrom": "public_share", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.rate_limit_bucket": { + "name": "rate_limit_bucket", + "schema": "", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "tokens": { + "name": "tokens", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "last_refill_at": { + "name": "last_refill_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "blocked_until": { + "name": "blocked_until", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capacity_state": { + "name": "capacity_state", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.resource_policy": { + "name": "resource_policy", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "resource_type": { + "name": "resource_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_id": { + "name": "resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 1 + }, + "document": { + "name": "document", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_by": { + "name": "updated_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "resource_policy_organization_id_idx": { + "name": "resource_policy_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resource_policy_resource_unique": { + "name": "resource_policy_resource_unique", + "columns": [ + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resource_policy_workspace_id_idx": { + "name": "resource_policy_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resource_policy_workspace_id_workspace_id_fk": { + "name": "resource_policy_workspace_id_workspace_id_fk", + "tableFrom": "resource_policy", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "resource_policy_organization_id_organization_id_fk": { + "name": "resource_policy_organization_id_organization_id_fk", + "tableFrom": "resource_policy", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "resource_policy_created_by_user_id_fk": { + "name": "resource_policy_created_by_user_id_fk", + "tableFrom": "resource_policy", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "resource_policy_updated_by_user_id_fk": { + "name": "resource_policy_updated_by_user_id_fk", + "tableFrom": "resource_policy", + "tableTo": "user", + "columnsFrom": ["updated_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "resource_policy_owner_check": { + "name": "resource_policy_owner_check", + "value": "num_nonnulls(\"resource_policy\".\"workspace_id\", \"resource_policy\".\"organization_id\") = 1" + } + }, + "isRLSEnabled": false + }, + "public.resume_queue": { + "name": "resume_queue", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "paused_execution_id": { + "name": "paused_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_execution_id": { + "name": "parent_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "new_execution_id": { + "name": "new_execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "context_id": { + "name": "context_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resume_input": { + "name": "resume_input", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "queued_at": { + "name": "queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "claimed_at": { + "name": "claimed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "resume_queue_parent_status_idx": { + "name": "resume_queue_parent_status_idx", + "columns": [ + { + "expression": "parent_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "resume_queue_new_execution_idx": { + "name": "resume_queue_new_execution_idx", + "columns": [ + { + "expression": "new_execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "resume_queue_paused_execution_id_paused_executions_id_fk": { + "name": "resume_queue_paused_execution_id_paused_executions_id_fk", + "tableFrom": "resume_queue", + "tableTo": "paused_executions", + "columnsFrom": ["paused_execution_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sandbox_image": { + "name": "sandbox_image", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "spec_hash": { + "name": "spec_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "spec": { + "name": "spec", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "sandbox_image_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "image_ref": { + "name": "image_ref", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_image_id": { + "name": "provider_image_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "build_id": { + "name": "build_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "materialization_generation": { + "name": "materialization_generation", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_detail": { + "name": "error_detail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sandbox_image_provider_spec_unique": { + "name": "sandbox_image_provider_spec_unique", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "spec_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_image_status_idx": { + "name": "sandbox_image_status_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sandbox_image_last_used_idx": { + "name": "sandbox_image_last_used_idx", + "columns": [ + { + "expression": "last_used_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_connection": { + "name": "scim_connection", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "settings": { + "name": "settings", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "last_request_at": { + "name": "last_request_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "reconcile_lock_token": { + "name": "reconcile_lock_token", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "reconcile_lease_at": { + "name": "reconcile_lease_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "reconciled_at": { + "name": "reconciled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_connection_organization_unique": { + "name": "scim_connection_organization_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_connection_reconcile_due_idx": { + "name": "scim_connection_reconcile_due_idx", + "columns": [ + { + "expression": "reconciled_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_connection_organization_id_organization_id_fk": { + "name": "scim_connection_organization_id_organization_id_fk", + "tableFrom": "scim_connection", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_connection_created_by_user_id_fk": { + "name": "scim_connection_created_by_user_id_fk", + "tableFrom": "scim_connection", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_credential": { + "name": "scim_credential", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "token_prefix": { + "name": "token_prefix", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_at": { + "name": "revoked_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "revoked_by": { + "name": "revoked_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_credential_token_hash_unique": { + "name": "scim_credential_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_credential_connection_idx": { + "name": "scim_credential_connection_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_credential_connection_id_scim_connection_id_fk": { + "name": "scim_credential_connection_id_scim_connection_id_fk", + "tableFrom": "scim_credential", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_credential_revoked_by_user_id_fk": { + "name": "scim_credential_revoked_by_user_id_fk", + "tableFrom": "scim_credential", + "tableTo": "user", + "columnsFrom": ["revoked_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "scim_credential_created_by_user_id_fk": { + "name": "scim_credential_created_by_user_id_fk", + "tableFrom": "scim_credential", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_group": { + "name": "scim_group", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name_key": { + "name": "display_name_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "order_key": { + "name": "order_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_group_connection_display_name_unique": { + "name": "scim_group_connection_display_name_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_connection_external_id_unique": { + "name": "scim_group_connection_external_id_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "external_id is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_connection_order_idx": { + "name": "scim_group_connection_order_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_group_connection_id_scim_connection_id_fk": { + "name": "scim_group_connection_id_scim_connection_id_fk", + "tableFrom": "scim_group", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_group_mapping": { + "name": "scim_group_mapping", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_kind": { + "name": "target_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_group_id": { + "name": "permission_group_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'manual'" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_group_mapping_group_idx": { + "name": "scim_group_mapping_group_idx", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_mapping_permission_group_idx": { + "name": "scim_group_mapping_permission_group_idx", + "columns": [ + { + "expression": "permission_group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_mapping_workspace_idx": { + "name": "scim_group_mapping_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_mapping_group_target_unique": { + "name": "scim_group_mapping_group_target_unique", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"permission_group_id\", \"workspace_id\", \"role\")", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_group_mapping_group_id_scim_group_id_fk": { + "name": "scim_group_mapping_group_id_scim_group_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "scim_group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_mapping_permission_group_id_permission_group_id_fk": { + "name": "scim_group_mapping_permission_group_id_permission_group_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "permission_group", + "columnsFrom": ["permission_group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_mapping_workspace_id_workspace_id_fk": { + "name": "scim_group_mapping_workspace_id_workspace_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_mapping_created_by_user_id_fk": { + "name": "scim_group_mapping_created_by_user_id_fk", + "tableFrom": "scim_group_mapping", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "scim_group_mapping_target_shape": { + "name": "scim_group_mapping_target_shape", + "value": "(\n (\"scim_group_mapping\".\"target_kind\" = 'permission_group' AND \"scim_group_mapping\".\"permission_group_id\" IS NOT NULL AND \"scim_group_mapping\".\"workspace_id\" IS NULL AND \"scim_group_mapping\".\"permission_type\" IS NULL AND \"scim_group_mapping\".\"role\" IS NULL)\n OR (\"scim_group_mapping\".\"target_kind\" = 'workspace' AND \"scim_group_mapping\".\"workspace_id\" IS NOT NULL AND \"scim_group_mapping\".\"permission_type\" IS NOT NULL AND \"scim_group_mapping\".\"permission_group_id\" IS NULL AND \"scim_group_mapping\".\"role\" IS NULL)\n OR (\"scim_group_mapping\".\"target_kind\" = 'org_role' AND \"scim_group_mapping\".\"role\" IS NOT NULL AND \"scim_group_mapping\".\"permission_group_id\" IS NULL AND \"scim_group_mapping\".\"workspace_id\" IS NULL AND \"scim_group_mapping\".\"permission_type\" IS NULL)\n )" + } + }, + "isRLSEnabled": false + }, + "public.scim_group_member": { + "name": "scim_group_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scim_user_id": { + "name": "scim_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_group_member_group_user_unique": { + "name": "scim_group_member_group_user_unique", + "columns": [ + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "scim_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_group_member_scim_user_idx": { + "name": "scim_group_member_scim_user_idx", + "columns": [ + { + "expression": "scim_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_group_member_group_id_scim_group_id_fk": { + "name": "scim_group_member_group_id_scim_group_id_fk", + "tableFrom": "scim_group_member", + "tableTo": "scim_group", + "columnsFrom": ["group_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_group_member_scim_user_id_scim_user_id_fk": { + "name": "scim_group_member_scim_user_id_scim_user_id_fk", + "tableFrom": "scim_group_member", + "tableTo": "scim_user", + "columnsFrom": ["scim_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_projection_grant": { + "name": "scim_projection_grant", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scim_user_id": { + "name": "scim_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_kind": { + "name": "target_kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_id": { + "name": "target_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "permission_type": { + "name": "permission_type", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "baseline_permission": { + "name": "baseline_permission", + "type": "permission_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "origin": { + "name": "origin", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'directory'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_projection_grant_user_target_unique": { + "name": "scim_projection_grant_user_target_unique", + "columns": [ + { + "expression": "scim_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_kind", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_projection_grant_connection_idx": { + "name": "scim_projection_grant_connection_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_projection_grant_connection_id_scim_connection_id_fk": { + "name": "scim_projection_grant_connection_id_scim_connection_id_fk", + "tableFrom": "scim_projection_grant", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_projection_grant_scim_user_id_scim_user_id_fk": { + "name": "scim_projection_grant_scim_user_id_scim_user_id_fk", + "tableFrom": "scim_projection_grant", + "tableTo": "scim_user", + "columnsFrom": ["scim_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_request_log": { + "name": "scim_request_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "scim_type": { + "name": "scim_type", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "detail": { + "name": "detail", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_request_log_connection_created_idx": { + "name": "scim_request_log_connection_created_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_request_log_connection_id_scim_connection_id_fk": { + "name": "scim_request_log_connection_id_scim_connection_id_fk", + "tableFrom": "scim_request_log", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_user": { + "name": "scim_user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_name": { + "name": "user_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active": { + "name": "active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "attributes": { + "name": "attributes", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "order_key": { + "name": "order_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_user_connection_user_unique": { + "name": "scim_user_connection_user_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_connection_user_name_unique": { + "name": "scim_user_connection_user_name_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_connection_external_id_unique": { + "name": "scim_user_connection_external_id_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "external_id is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_connection_order_idx": { + "name": "scim_user_connection_order_idx", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_user_idx": { + "name": "scim_user_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_user_connection_id_scim_connection_id_fk": { + "name": "scim_user_connection_id_scim_connection_id_fk", + "tableFrom": "scim_user", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_user_user_id_user_id_fk": { + "name": "scim_user_user_id_user_id_fk", + "tableFrom": "scim_user", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.scim_user_tombstone": { + "name": "scim_user_tombstone", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "connection_id": { + "name": "connection_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "scim_user_tombstone_connection_external_id_unique": { + "name": "scim_user_tombstone_connection_external_id_unique", + "columns": [ + { + "expression": "connection_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "external_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "scim_user_tombstone_user_idx": { + "name": "scim_user_tombstone_user_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "scim_user_tombstone_connection_id_scim_connection_id_fk": { + "name": "scim_user_tombstone_connection_id_scim_connection_id_fk", + "tableFrom": "scim_user_tombstone", + "tableTo": "scim_connection", + "columnsFrom": ["connection_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "scim_user_tombstone_user_id_user_id_fk": { + "name": "scim_user_tombstone_user_id_user_id_fk", + "tableFrom": "scim_user_tombstone", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.secret_usage": { + "name": "secret_usage", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret_name": { + "name": "secret_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret_scope": { + "name": "secret_scope", + "type": "secret_usage_scope", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "secret_owner_user_id": { + "name": "secret_owner_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "source": { + "name": "source", + "type": "secret_usage_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "actor_user_id": { + "name": "actor_user_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "usage_date": { + "name": "usage_date", + "type": "date", + "primaryKey": false, + "notNull": true + }, + "use_count": { + "name": "use_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_used_at": { + "name": "last_used_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "last_execution_id": { + "name": "last_execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_trigger": { + "name": "last_trigger", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "secret_usage_bucket_unique": { + "name": "secret_usage_bucket_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_scope", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "actor_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "usage_date", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "secret_usage_secret_recent_idx": { + "name": "secret_usage_secret_recent_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_name", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_scope", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "secret_owner_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_used_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "secret_usage_workspace_id_workspace_id_fk": { + "name": "secret_usage_workspace_id_workspace_id_fk", + "tableFrom": "secret_usage", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.session": { + "name": "session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "active_organization_id": { + "name": "active_organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "session_user_id_idx": { + "name": "session_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "session_active_organization_id_organization_id_fk": { + "name": "session_active_organization_id_organization_id_fk", + "tableFrom": "session", + "tableTo": "organization", + "columnsFrom": ["active_organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "session_token_unique": { + "name": "session_token_unique", + "nullsNotDistinct": false, + "columns": ["token"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.settings": { + "name": "settings", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'system'" + }, + "auto_connect": { + "name": "auto_connect", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "telemetry_enabled": { + "name": "telemetry_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "email_preferences": { + "name": "email_preferences", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "billing_usage_notifications_enabled": { + "name": "billing_usage_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "show_training_controls": { + "name": "show_training_controls", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "super_user_mode_enabled": { + "name": "super_user_mode_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "mothership_environment": { + "name": "mothership_environment", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'default'" + }, + "error_notifications_enabled": { + "name": "error_notifications_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "snap_to_grid_size": { + "name": "snap_to_grid_size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "show_action_bar": { + "name": "show_action_bar", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "auto_focus_on_click": { + "name": "auto_focus_on_click", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "copilot_enabled_models": { + "name": "copilot_enabled_models", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "copilot_auto_allowed_tools": { + "name": "copilot_auto_allowed_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'" + }, + "last_active_workspace_id": { + "name": "last_active_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "settings_user_id_user_id_fk": { + "name": "settings_user_id_user_id_fk", + "tableFrom": "settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "settings_user_id_unique": { + "name": "settings_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sim_trigger_state": { + "name": "sim_trigger_state", + "schema": "", + "columns": { + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope_key": { + "name": "scope_key", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "last_fired_at": { + "name": "last_fired_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "sim_trigger_state_workflow_id_workflow_id_fk": { + "name": "sim_trigger_state_workflow_id_workflow_id_fk", + "tableFrom": "sim_trigger_state", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "sim_trigger_state_workflow_id_block_id_scope_key_pk": { + "name": "sim_trigger_state_workflow_id_block_id_scope_key_pk", + "columns": ["workflow_id", "block_id", "scope_key"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.skill": { + "name": "skill", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "skill_workspace_name_unique": { + "name": "skill_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "skill_workspace_id_workspace_id_fk": { + "name": "skill_workspace_id_workspace_id_fk", + "tableFrom": "skill", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_user_id_user_id_fk": { + "name": "skill_user_id_user_id_fk", + "tableFrom": "skill", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.skill_member": { + "name": "skill_member", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "skill_id": { + "name": "skill_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "invited_by": { + "name": "invited_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "skill_member_user_id_idx": { + "name": "skill_member_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "skill_member_unique": { + "name": "skill_member_unique", + "columns": [ + { + "expression": "skill_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "skill_member_skill_id_skill_id_fk": { + "name": "skill_member_skill_id_skill_id_fk", + "tableFrom": "skill_member", + "tableTo": "skill", + "columnsFrom": ["skill_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_member_user_id_user_id_fk": { + "name": "skill_member_user_id_user_id_fk", + "tableFrom": "skill_member", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "skill_member_invited_by_user_id_fk": { + "name": "skill_member_invited_by_user_id_fk", + "tableFrom": "skill_member", + "tableTo": "user", + "columnsFrom": ["invited_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_app": { + "name": "slack_app", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_client_secret": { + "name": "encrypted_client_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_signing_secret": { + "name": "encrypted_signing_secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "slack_app_organization_id_organization_id_fk": { + "name": "slack_app_organization_id_organization_id_fk", + "tableFrom": "slack_app", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "slack_app_owner_check": { + "name": "slack_app_owner_check", + "value": "(\"slack_app\".\"kind\" = 'custom' AND \"slack_app\".\"organization_id\" IS NOT NULL) OR (\"slack_app\".\"kind\" = 'shared' AND \"slack_app\".\"organization_id\" IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.slack_search_installation": { + "name": "slack_search_installation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "credential_id": { + "name": "credential_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "app_id": { + "name": "app_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "slack_app_id": { + "name": "slack_app_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "team_id": { + "name": "team_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "team_name": { + "name": "team_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "bot_user_id": { + "name": "bot_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "enterprise_id": { + "name": "enterprise_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "credential_version": { + "name": "credential_version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "revision": { + "name": "revision", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "last_outcome": { + "name": "last_outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_event_at": { + "name": "last_event_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_search_installation_organization_idx": { + "name": "slack_search_installation_organization_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_installation_credential_unique": { + "name": "slack_search_installation_credential_unique", + "columns": [ + { + "expression": "credential_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_installation_app_team_unique": { + "name": "slack_search_installation_app_team_unique", + "columns": [ + { + "expression": "app_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_installation_active_team_unique": { + "name": "slack_search_installation_active_team_unique", + "columns": [ + { + "expression": "team_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"slack_search_installation\".\"enabled\" = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_search_installation_organization_id_organization_id_fk": { + "name": "slack_search_installation_organization_id_organization_id_fk", + "tableFrom": "slack_search_installation", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slack_search_installation_credential_id_credential_id_fk": { + "name": "slack_search_installation_credential_id_credential_id_fk", + "tableFrom": "slack_search_installation", + "tableTo": "credential", + "columnsFrom": ["credential_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "slack_search_installation_slack_app_id_slack_app_id_fk": { + "name": "slack_search_installation_slack_app_id_slack_app_id_fk", + "tableFrom": "slack_search_installation", + "tableTo": "slack_app", + "columnsFrom": ["slack_app_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.slack_search_turn": { + "name": "slack_search_turn", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "ordinal": { + "name": "ordinal", + "type": "integer", + "primaryKey": false, + "notNull": true, + "identity": { + "type": "always", + "name": "slack_search_turn_ordinal_seq", + "schema": "public", + "increment": "1", + "startWith": "1", + "minValue": "1", + "maxValue": "2147483647", + "cache": "1", + "cycle": false + } + }, + "installation_id": { + "name": "installation_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "conversation_key": { + "name": "conversation_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "event_id": { + "name": "event_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "lease_id": { + "name": "lease_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lease_expires_at": { + "name": "lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "outcome": { + "name": "outcome", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "slack_search_turn_event_unique": { + "name": "slack_search_turn_event_unique", + "columns": [ + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "event_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_turn_pending_idx": { + "name": "slack_search_turn_pending_idx", + "columns": [ + { + "expression": "installation_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_turn_thread_idx": { + "name": "slack_search_turn_thread_idx", + "columns": [ + { + "expression": "conversation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "slack_search_turn_active_thread_unique": { + "name": "slack_search_turn_active_thread_unique", + "columns": [ + { + "expression": "conversation_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"slack_search_turn\".\"status\" = 'running'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "slack_search_turn_installation_id_slack_search_installation_id_fk": { + "name": "slack_search_turn_installation_id_slack_search_installation_id_fk", + "tableFrom": "slack_search_turn", + "tableTo": "slack_search_installation", + "columnsFrom": ["installation_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sso_domain": { + "name": "sso_domain", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "verification_token": { + "name": "verification_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "verified_at": { + "name": "verified_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "sso_domain_organization_id_idx": { + "name": "sso_domain_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_domain_domain_idx": { + "name": "sso_domain_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_domain_org_domain_unique": { + "name": "sso_domain_org_domain_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_domain_verified_unique": { + "name": "sso_domain_verified_unique", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "status = 'verified'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sso_domain_organization_id_organization_id_fk": { + "name": "sso_domain_organization_id_organization_id_fk", + "tableFrom": "sso_domain", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sso_domain_created_by_user_id_fk": { + "name": "sso_domain_created_by_user_id_fk", + "tableFrom": "sso_domain", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.sso_provider": { + "name": "sso_provider", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "issuer": { + "name": "issuer", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "oidc_config": { + "name": "oidc_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "saml_config": { + "name": "saml_config", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "domain_verified": { + "name": "domain_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "jit_provisioning_enabled": { + "name": "jit_provisioning_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + } + }, + "indexes": { + "sso_provider_provider_id_unique": { + "name": "sso_provider_provider_id_unique", + "columns": [ + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_org_domain_unique": { + "name": "sso_provider_org_domain_unique", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "lower(regexp_replace(btrim(\"domain\"), '^\\*\\.', ''))", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"sso_provider\".\"organization_id\" is not null", + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_domain_idx": { + "name": "sso_provider_domain_idx", + "columns": [ + { + "expression": "domain", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_user_id_idx": { + "name": "sso_provider_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "sso_provider_organization_id_idx": { + "name": "sso_provider_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "sso_provider_user_id_user_id_fk": { + "name": "sso_provider_user_id_user_id_fk", + "tableFrom": "sso_provider", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "sso_provider_organization_id_organization_id_fk": { + "name": "sso_provider_organization_id_organization_id_fk", + "tableFrom": "sso_provider", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.subscription": { + "name": "subscription", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "reference_id": { + "name": "reference_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_subscription_id": { + "name": "stripe_subscription_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "period_start": { + "name": "period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "period_end": { + "name": "period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancel_at_period_end": { + "name": "cancel_at_period_end", + "type": "boolean", + "primaryKey": false, + "notNull": false + }, + "cancel_at": { + "name": "cancel_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "canceled_at": { + "name": "canceled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "seats": { + "name": "seats", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "trial_start": { + "name": "trial_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trial_end": { + "name": "trial_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_interval": { + "name": "billing_interval", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "stripe_schedule_id": { + "name": "stripe_schedule_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "metadata": { + "name": "metadata", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "last_closed_period_start": { + "name": "last_closed_period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "subscription_reference_status_idx": { + "name": "subscription_reference_status_idx", + "columns": [ + { + "expression": "reference_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "subscription_cycle_close_lagging_idx": { + "name": "subscription_cycle_close_lagging_idx", + "columns": [ + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"subscription\".\"status\" in ('active', 'past_due') and \"subscription\".\"period_start\" is not null and (\"subscription\".\"last_closed_period_start\" is null or \"subscription\".\"last_closed_period_start\" < \"subscription\".\"period_start\")", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "check_enterprise_metadata": { + "name": "check_enterprise_metadata", + "value": "plan != 'enterprise' OR metadata IS NOT NULL" + } + }, + "isRLSEnabled": false + }, + "public.table_jobs": { + "name": "table_jobs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "payload": { + "name": "payload", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "rows_processed": { + "name": "rows_processed", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "table_jobs_one_active_per_table": { + "name": "table_jobs_one_active_per_table", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"table_jobs\".\"status\" = 'running' AND \"table_jobs\".\"type\" <> 'export'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_jobs_watchdog_idx": { + "name": "table_jobs_watchdog_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_jobs_table_started_idx": { + "name": "table_jobs_table_started_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_jobs_table_id_user_table_definitions_id_fk": { + "name": "table_jobs_table_id_user_table_definitions_id_fk", + "tableFrom": "table_jobs", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_jobs_workspace_id_workspace_id_fk": { + "name": "table_jobs_workspace_id_workspace_id_fk", + "tableFrom": "table_jobs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_row_executions": { + "name": "table_row_executions", + "schema": "", + "columns": { + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "row_id": { + "name": "row_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "group_id": { + "name": "group_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "job_id": { + "name": "job_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "running_block_ids": { + "name": "running_block_ids", + "type": "text[]", + "primaryKey": false, + "notNull": true, + "default": "'{}'::text[]" + }, + "block_errors": { + "name": "block_errors", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "capability_governed_user_id": { + "name": "capability_governed_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "enrichment_details": { + "name": "enrichment_details", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "table_row_executions_table_status_idx": { + "name": "table_row_executions_table_status_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_row_executions\".\"status\" IN ('queued', 'running', 'pending')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_row_executions_execution_id_idx": { + "name": "table_row_executions_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_row_executions\".\"execution_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_row_executions_table_group_idx": { + "name": "table_row_executions_table_group_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "group_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_row_executions_table_id_user_table_definitions_id_fk": { + "name": "table_row_executions_table_id_user_table_definitions_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_row_executions_row_id_user_table_rows_id_fk": { + "name": "table_row_executions_row_id_user_table_rows_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user_table_rows", + "columnsFrom": ["row_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_row_executions_capability_governed_user_id_user_id_fk": { + "name": "table_row_executions_capability_governed_user_id_user_id_fk", + "tableFrom": "table_row_executions", + "tableTo": "user", + "columnsFrom": ["capability_governed_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "table_row_executions_row_id_group_id_pk": { + "name": "table_row_executions_row_id_group_id_pk", + "columns": ["row_id", "group_id"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_run_dispatches": { + "name": "table_run_dispatches", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "mode": { + "name": "mode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "cursor": { + "name": "cursor", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "limit": { + "name": "limit", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "processed_count": { + "name": "processed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "is_manual_run": { + "name": "is_manual_run", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "triggered_by_user_id": { + "name": "triggered_by_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "capability_governed_user_id": { + "name": "capability_governed_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "requested_at": { + "name": "requested_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "heartbeat_at": { + "name": "heartbeat_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "cancelled_at": { + "name": "cancelled_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "table_run_dispatches_active_idx": { + "name": "table_run_dispatches_active_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_run_dispatches_watchdog_idx": { + "name": "table_run_dispatches_watchdog_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "requested_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_run_dispatches_governed_active_idx": { + "name": "table_run_dispatches_governed_active_idx", + "columns": [ + { + "expression": "capability_governed_user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"table_run_dispatches\".\"status\" IN ('pending', 'dispatching')", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_run_dispatches_table_id_user_table_definitions_id_fk": { + "name": "table_run_dispatches_table_id_user_table_definitions_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_run_dispatches_workspace_id_workspace_id_fk": { + "name": "table_run_dispatches_workspace_id_workspace_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_run_dispatches_triggered_by_user_id_user_id_fk": { + "name": "table_run_dispatches_triggered_by_user_id_user_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user", + "columnsFrom": ["triggered_by_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "table_run_dispatches_capability_governed_user_id_user_id_fk": { + "name": "table_run_dispatches_capability_governed_user_id_user_id_fk", + "tableFrom": "table_run_dispatches", + "tableTo": "user", + "columnsFrom": ["capability_governed_user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.table_views": { + "name": "table_views", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "is_default": { + "name": "is_default", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "table_views_table_created_idx": { + "name": "table_views_table_created_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_views_workspace_created_idx": { + "name": "table_views_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "table_views_table_default_unique": { + "name": "table_views_table_default_unique", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "is_default = true", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "table_views_table_id_user_table_definitions_id_fk": { + "name": "table_views_table_id_user_table_definitions_id_fk", + "tableFrom": "table_views", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_views_workspace_id_workspace_id_fk": { + "name": "table_views_workspace_id_workspace_id_fk", + "tableFrom": "table_views", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "table_views_created_by_user_id_fk": { + "name": "table_views_created_by_user_id_fk", + "tableFrom": "table_views", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.upload_session": { + "name": "upload_session", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "token_hash": { + "name": "token_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "knowledge_base_id": { + "name": "knowledge_base_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "purpose": { + "name": "purpose", + "type": "upload_session_purpose", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "method": { + "name": "method", + "type": "upload_session_method", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "storage_context": { + "name": "storage_context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "final_key": { + "name": "final_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_provider": { + "name": "storage_provider", + "type": "upload_session_provider", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "provider_upload_id": { + "name": "provider_upload_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_object_version": { + "name": "provider_object_version", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "file_name": { + "name": "file_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "file_size": { + "name": "file_size", + "type": "bigint", + "primaryKey": false, + "notNull": true + }, + "part_size": { + "name": "part_size", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "part_count": { + "name": "part_count", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "status": { + "name": "status", + "type": "upload_session_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'uploading'" + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "processing_lease_id": { + "name": "processing_lease_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "processing_lease_expires_at": { + "name": "processing_lease_expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "completed_file_id": { + "name": "completed_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error": { + "name": "error", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "upload_session_token_hash_unique": { + "name": "upload_session_token_hash_unique", + "columns": [ + { + "expression": "token_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "upload_session_final_key_unique": { + "name": "upload_session_final_key_unique", + "columns": [ + { + "expression": "final_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "upload_session_status_expires_at_idx": { + "name": "upload_session_status_expires_at_idx", + "columns": [ + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.usage_log": { + "name": "usage_log", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "category": { + "name": "category", + "type": "usage_log_category", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "source": { + "name": "source", + "type": "usage_log_source", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost": { + "name": "cost", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "event_key": { + "name": "event_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_entity_type": { + "name": "billing_entity_type", + "type": "billing_entity_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "billing_entity_id": { + "name": "billing_entity_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "billing_period_start": { + "name": "billing_period_start", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "billing_period_end": { + "name": "billing_period_end", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "usage_log_user_created_at_idx": { + "name": "usage_log_user_created_at_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_source_idx": { + "name": "usage_log_source_idx", + "columns": [ + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_id_idx": { + "name": "usage_log_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workflow_id_idx": { + "name": "usage_log_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_event_key_unique": { + "name": "usage_log_event_key_unique", + "columns": [ + { + "expression": "event_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"usage_log\".\"event_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_entity_period_idx": { + "name": "usage_log_billing_entity_period_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_period_cost_idx": { + "name": "usage_log_billing_period_cost_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_start", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_period_end", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_billing_entity_created_at_cost_idx": { + "name": "usage_log_billing_entity_created_at_cost_idx", + "columns": [ + { + "expression": "billing_entity_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "billing_entity_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"usage_log\".\"billing_entity_type\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_workspace_created_at_idx": { + "name": "usage_log_workspace_created_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "usage_log_execution_id_idx": { + "name": "usage_log_execution_id_idx", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "usage_log_user_id_user_id_fk": { + "name": "usage_log_user_id_user_id_fk", + "tableFrom": "usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "usage_log_workspace_id_workspace_id_fk": { + "name": "usage_log_workspace_id_workspace_id_fk", + "tableFrom": "usage_log", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "usage_log_workflow_id_workflow_id_fk": { + "name": "usage_log_workflow_id_workflow_id_fk", + "tableFrom": "usage_log", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "usage_log_billing_scope_all_or_none": { + "name": "usage_log_billing_scope_all_or_none", + "value": "(\n (\"usage_log\".\"billing_entity_type\" IS NULL AND \"usage_log\".\"billing_entity_id\" IS NULL AND \"usage_log\".\"billing_period_start\" IS NULL AND \"usage_log\".\"billing_period_end\" IS NULL)\n OR\n (\"usage_log\".\"billing_entity_type\" IS NOT NULL AND \"usage_log\".\"billing_entity_id\" IS NOT NULL AND \"usage_log\".\"billing_period_start\" IS NOT NULL AND \"usage_log\".\"billing_period_end\" IS NOT NULL AND \"usage_log\".\"billing_period_start\" < \"usage_log\".\"billing_period_end\")\n )" + } + }, + "isRLSEnabled": false + }, + "public.user": { + "name": "user", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "normalized_email": { + "name": "normalized_email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email_verified": { + "name": "email_verified", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "stripe_customer_id": { + "name": "stripe_customer_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'user'" + }, + "banned": { + "name": "banned", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "suspended_at": { + "name": "suspended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "suspension_source": { + "name": "suspension_source", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_email_lower_idx": { + "name": "user_email_lower_idx", + "columns": [ + { + "expression": "lower(btrim(\"email\"))", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_email_unique": { + "name": "user_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + }, + "user_normalized_email_unique": { + "name": "user_normalized_email_unique", + "nullsNotDistinct": false, + "columns": ["normalized_email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_stats": { + "name": "user_stats", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "total_manual_executions": { + "name": "total_manual_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_api_calls": { + "name": "total_api_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_webhook_triggers": { + "name": "total_webhook_triggers", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_scheduled_executions": { + "name": "total_scheduled_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_chat_executions": { + "name": "total_chat_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_executions": { + "name": "total_mcp_executions", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_tokens_used": { + "name": "total_tokens_used", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_cost": { + "name": "total_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_usage_limit": { + "name": "current_usage_limit", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'5'" + }, + "usage_limit_updated_at": { + "name": "usage_limit_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false, + "default": "now()" + }, + "current_period_cost": { + "name": "current_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_cost": { + "name": "last_period_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "billed_overage_this_period": { + "name": "billed_overage_this_period", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "pro_period_cost_snapshot": { + "name": "pro_period_cost_snapshot", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "pro_period_cost_snapshot_at": { + "name": "pro_period_cost_snapshot_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "credit_balance": { + "name": "credit_balance", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "total_copilot_cost": { + "name": "total_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_copilot_cost": { + "name": "current_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "last_period_copilot_cost": { + "name": "last_period_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": false, + "default": "'0'" + }, + "total_copilot_tokens": { + "name": "total_copilot_tokens", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_copilot_calls": { + "name": "total_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_calls": { + "name": "total_mcp_copilot_calls", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "total_mcp_copilot_cost": { + "name": "total_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "current_period_mcp_copilot_cost": { + "name": "current_period_mcp_copilot_cost", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_active": { + "name": "last_active", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "billing_blocked": { + "name": "billing_blocked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "billing_blocked_reason": { + "name": "billing_blocked_reason", + "type": "billing_blocked_reason", + "typeSchema": "public", + "primaryKey": false, + "notNull": false + }, + "limit_notifications": { + "name": "limit_notifications", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + } + }, + "indexes": {}, + "foreignKeys": { + "user_stats_user_id_user_id_fk": { + "name": "user_stats_user_id_user_id_fk", + "tableFrom": "user_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_stats_user_id_unique": { + "name": "user_stats_user_id_unique", + "nullsNotDistinct": false, + "columns": ["user_id"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_definitions": { + "name": "user_table_definitions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "schema": { + "name": "schema", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "metadata": { + "name": "metadata", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "max_rows": { + "name": "max_rows", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 10000 + }, + "row_count": { + "name": "row_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "rows_version": { + "name": "rows_version", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "schema_locked": { + "name": "schema_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "insert_locked": { + "name": "insert_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "update_locked": { + "name": "update_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "delete_locked": { + "name": "delete_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "user_table_def_workspace_id_idx": { + "name": "user_table_def_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_folder_id_idx": { + "name": "user_table_def_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_name_unique": { + "name": "user_table_def_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"user_table_definitions\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_archived_at_idx": { + "name": "user_table_def_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_def_workspace_archived_partial_idx": { + "name": "user_table_def_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"user_table_definitions\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_definitions_workspace_id_workspace_id_fk": { + "name": "user_table_definitions_workspace_id_workspace_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_definitions_folder_id_folder_id_fk": { + "name": "user_table_definitions_folder_id_folder_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "user_table_definitions_created_by_user_id_fk": { + "name": "user_table_definitions_created_by_user_id_fk", + "tableFrom": "user_table_definitions", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.user_table_row_secret_provenance": { + "name": "user_table_row_secret_provenance", + "schema": "", + "columns": { + "row_id": { + "name": "row_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_updated_at": { + "name": "content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_table_row_secret_provenance_row_id_user_table_rows_id_fk": { + "name": "user_table_row_secret_provenance_row_id_user_table_rows_id_fk", + "tableFrom": "user_table_row_secret_provenance", + "tableTo": "user_table_rows", + "columnsFrom": ["row_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "user_table_row_secret_provenance_status_check": { + "name": "user_table_row_secret_provenance_status_check", + "value": "\"user_table_row_secret_provenance\".\"status\" IN ('exact', 'unknown')" + } + }, + "isRLSEnabled": false + }, + "public.user_table_rows": { + "name": "user_table_rows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "table_id": { + "name": "table_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "position": { + "name": "position", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "order_key": { + "name": "order_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "user_table_rows_tenant_data_gin_idx": { + "name": "user_table_rows_tenant_data_gin_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"data\" jsonb_path_ops", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "user_table_rows_workspace_table_idx": { + "name": "user_table_rows_workspace_table_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_position_idx": { + "name": "user_table_rows_table_position_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "position", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_order_key_idx": { + "name": "user_table_rows_table_order_key_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "order_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_created_id_idx": { + "name": "user_table_rows_table_created_id_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "user_table_rows_table_id_id_idx": { + "name": "user_table_rows_table_id_id_idx", + "columns": [ + { + "expression": "table_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "user_table_rows_table_id_user_table_definitions_id_fk": { + "name": "user_table_rows_table_id_user_table_definitions_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user_table_definitions", + "columnsFrom": ["table_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_workspace_id_workspace_id_fk": { + "name": "user_table_rows_workspace_id_workspace_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_table_rows_created_by_user_id_fk": { + "name": "user_table_rows_created_by_user_id_fk", + "tableFrom": "user_table_rows", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.verification": { + "name": "verification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "verification_identifier_idx": { + "name": "verification_identifier_idx", + "columns": [ + { + "expression": "identifier", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "verification_expires_at_idx": { + "name": "verification_expires_at_idx", + "columns": [ + { + "expression": "expires_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.waitlist": { + "name": "waitlist", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "waitlist_email_unique": { + "name": "waitlist_email_unique", + "nullsNotDistinct": false, + "columns": ["email"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.webhook": { + "name": "webhook", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registration_status": { + "name": "registration_status", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "registration_generation": { + "name": "registration_generation", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "config_fingerprint": { + "name": "config_fingerprint", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prepared_at": { + "name": "prepared_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "path": { + "name": "path", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "routing_key": { + "name": "routing_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "provider_config": { + "name": "provider_config", + "type": "json", + "primaryKey": false, + "notNull": false + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "path_deployment_unique": { + "name": "path_deployment_unique", + "columns": [ + { + "expression": "path", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_workflow_deployment_idx": { + "name": "webhook_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_routing_key_active_idx": { + "name": "webhook_routing_key_active_idx", + "columns": [ + { + "expression": "routing_key", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"archived_at\" IS NULL AND \"webhook\".\"routing_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_archived_at_partial_idx": { + "name": "webhook_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"webhook\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_provider_is_active_workflow_id_deploym_bdeed5468": { + "name": "idx_webhook_on_provider_is_active_workflow_id_deploym_bdeed5468", + "columns": [ + { + "expression": "provider", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_webhook_on_workflow_id_block_id_updated_at_desc": { + "name": "idx_webhook_on_workflow_id_block_id_updated_at_desc", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_active_registration_unique": { + "name": "webhook_active_registration_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"registration_status\" = 'active' AND \"webhook\".\"block_id\" IS NOT NULL AND \"webhook\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_candidate_registration_unique": { + "name": "webhook_candidate_registration_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"webhook\".\"registration_status\" = 'candidate' AND \"webhook\".\"block_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "webhook_registration_status_generation_idx": { + "name": "webhook_registration_status_generation_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "registration_status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "registration_generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_workflow_id_workflow_id_fk": { + "name": "webhook_workflow_id_workflow_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "webhook_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "webhook_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "webhook", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhook_registration_status_check": { + "name": "webhook_registration_status_check", + "value": "\"webhook\".\"registration_status\" IS NULL OR \"webhook\".\"registration_status\" IN ('active', 'candidate', 'retired', 'orphaned')" + }, + "webhook_registration_generation_check": { + "name": "webhook_registration_generation_check", + "value": "\"webhook\".\"registration_generation\" IS NULL OR \"webhook\".\"registration_generation\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.webhook_path_claim": { + "name": "webhook_path_claim", + "schema": "", + "columns": { + "path": { + "name": "path", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "webhook_path_claim_workflow_idx": { + "name": "webhook_path_claim_workflow_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "webhook_path_claim_workflow_id_workflow_id_fk": { + "name": "webhook_path_claim_workflow_id_workflow_id_fk", + "tableFrom": "webhook_path_claim", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "webhook_path_claim_generation_check": { + "name": "webhook_path_claim_generation_check", + "value": "\"webhook_path_claim\".\"generation\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.workflow": { + "name": "workflow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sort_order": { + "name": "sort_order", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_synced": { + "name": "last_synced", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "is_deployed": { + "name": "is_deployed", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deployed_at": { + "name": "deployed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "is_public_api": { + "name": "is_public_api", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "fork_sync_excluded": { + "name": "fork_sync_excluded", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "last_run_at": { + "name": "last_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_user_id_idx": { + "name": "workflow_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_id_idx": { + "name": "workflow_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_user_workspace_idx": { + "name": "workflow_user_workspace_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_folder_name_active_unique": { + "name": "workflow_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_folder_sort_idx": { + "name": "workflow_folder_sort_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_active_workspace_sort_idx": { + "name": "workflow_active_workspace_sort_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sort_order", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_archived_at_idx": { + "name": "workflow_archived_at_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_workspace_archived_partial_idx": { + "name": "workflow_workspace_archived_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_user_id_user_id_fk": { + "name": "workflow_user_id_user_id_fk", + "tableFrom": "workflow", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_workspace_id_workspace_id_fk": { + "name": "workflow_workspace_id_workspace_id_fk", + "tableFrom": "workflow", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_folder_id_folder_id_fk": { + "name": "workflow_folder_id_folder_id_fk", + "tableFrom": "workflow", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_blocks": { + "name": "workflow_blocks", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "position_x": { + "name": "position_x", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "position_y": { + "name": "position_y", + "type": "numeric", + "primaryKey": false, + "notNull": true + }, + "enabled": { + "name": "enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "horizontal_handles": { + "name": "horizontal_handles", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "is_wide": { + "name": "is_wide", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "advanced_mode": { + "name": "advanced_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "trigger_mode": { + "name": "trigger_mode", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "error_enabled": { + "name": "error_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "retry": { + "name": "retry", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "locked": { + "name": "locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "height": { + "name": "height", + "type": "numeric", + "primaryKey": false, + "notNull": true, + "default": "'0'" + }, + "sub_blocks": { + "name": "sub_blocks", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "outputs": { + "name": "outputs", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "data": { + "name": "data", + "type": "jsonb", + "primaryKey": false, + "notNull": false, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_blocks_workflow_id_idx": { + "name": "workflow_blocks_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_blocks_type_idx": { + "name": "workflow_blocks_type_idx", + "columns": [ + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_blocks_workflow_id_workflow_id_fk": { + "name": "workflow_blocks_workflow_id_workflow_id_fk", + "tableFrom": "workflow_blocks", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_checkpoints": { + "name": "workflow_checkpoints", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workflow_state": { + "name": "workflow_state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_checkpoints_user_id_idx": { + "name": "workflow_checkpoints_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_id_idx": { + "name": "workflow_checkpoints_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_id_idx": { + "name": "workflow_checkpoints_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_message_id_idx": { + "name": "workflow_checkpoints_message_id_idx", + "columns": [ + { + "expression": "message_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_user_workflow_idx": { + "name": "workflow_checkpoints_user_workflow_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_workflow_chat_idx": { + "name": "workflow_checkpoints_workflow_chat_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_created_at_idx": { + "name": "workflow_checkpoints_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_checkpoints_chat_created_at_idx": { + "name": "workflow_checkpoints_chat_created_at_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_checkpoints_user_id_user_id_fk": { + "name": "workflow_checkpoints_user_id_user_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_workflow_id_workflow_id_fk": { + "name": "workflow_checkpoints_workflow_id_workflow_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_checkpoints_chat_id_copilot_chats_id_fk": { + "name": "workflow_checkpoints_chat_id_copilot_chats_id_fk", + "tableFrom": "workflow_checkpoints", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_deployment_operation": { + "name": "workflow_deployment_operation", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "previous_active_version_id": { + "name": "previous_active_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "protocol_version": { + "name": "protocol_version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "generation": { + "name": "generation", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'preparing'" + }, + "component_readiness": { + "name": "component_readiness", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'::jsonb" + }, + "error_code": { + "name": "error_code", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "error_message": { + "name": "error_message", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "idempotency_key": { + "name": "idempotency_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "actor_id": { + "name": "actor_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_deployment_operation_workflow_generation_unique": { + "name": "workflow_deployment_operation_workflow_generation_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_idempotency_unique": { + "name": "workflow_deployment_operation_workflow_idempotency_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "idempotency_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_deployment_operation\".\"idempotency_key\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_in_flight_unique": { + "name": "workflow_deployment_operation_workflow_in_flight_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_deployment_operation\".\"status\" IN ('preparing', 'activating')", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_status_idx": { + "name": "workflow_deployment_operation_workflow_status_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_deployment_version_idx": { + "name": "workflow_deployment_operation_deployment_version_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_operation_workflow_version_generation_idx": { + "name": "workflow_deployment_operation_workflow_version_generation_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "generation", + "isExpression": false, + "asc": false, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_operation_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_operation_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_deployment_operation_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_deployment_operation_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_deployment_operation_previous_active_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_deployment_operation_previous_active_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_deployment_operation", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["previous_active_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workflow_deployment_operation_action_check": { + "name": "workflow_deployment_operation_action_check", + "value": "\"workflow_deployment_operation\".\"action\" IN ('deploy', 'activate')" + }, + "workflow_deployment_operation_status_check": { + "name": "workflow_deployment_operation_status_check", + "value": "\"workflow_deployment_operation\".\"status\" IN ('preparing', 'activating', 'active', 'failed', 'superseded')" + }, + "workflow_deployment_operation_generation_check": { + "name": "workflow_deployment_operation_generation_check", + "value": "\"workflow_deployment_operation\".\"generation\" > 0" + }, + "workflow_deployment_operation_protocol_version_check": { + "name": "workflow_deployment_operation_protocol_version_check", + "value": "\"workflow_deployment_operation\".\"protocol_version\" > 0" + } + }, + "isRLSEnabled": false + }, + "public.workflow_deployment_version": { + "name": "workflow_deployment_version", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state": { + "name": "state", + "type": "json", + "primaryKey": false, + "notNull": true + }, + "is_active": { + "name": "is_active", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workflow_deployment_version_workflow_version_unique": { + "name": "workflow_deployment_version_workflow_version_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "version", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_workflow_active_idx": { + "name": "workflow_deployment_version_workflow_active_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "is_active", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_deployment_version_created_at_idx": { + "name": "workflow_deployment_version_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_deployment_version_workflow_id_workflow_id_fk": { + "name": "workflow_deployment_version_workflow_id_workflow_id_fk", + "tableFrom": "workflow_deployment_version", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_edges": { + "name": "workflow_edges", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_block_id": { + "name": "source_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_handle": { + "name": "source_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "target_handle": { + "name": "target_handle", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_edges_workflow_id_idx": { + "name": "workflow_edges_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_source_idx": { + "name": "workflow_edges_workflow_source_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_edges_workflow_target_idx": { + "name": "workflow_edges_workflow_target_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_edges_workflow_id_workflow_id_fk": { + "name": "workflow_edges_workflow_id_workflow_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_source_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_source_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["source_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_edges_target_block_id_workflow_blocks_id_fk": { + "name": "workflow_edges_target_block_id_workflow_blocks_id_fk", + "tableFrom": "workflow_edges", + "tableTo": "workflow_blocks", + "columnsFrom": ["target_block_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_logs": { + "name": "workflow_execution_logs", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "execution_id": { + "name": "execution_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_snapshot_id": { + "name": "state_snapshot_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "level": { + "name": "level", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'running'" + }, + "trigger": { + "name": "trigger", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "started_at": { + "name": "started_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "execution_deadline_at": { + "name": "execution_deadline_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "ended_at": { + "name": "ended_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "total_duration_ms": { + "name": "total_duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "execution_data": { + "name": "execution_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "cost": { + "name": "cost", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "cost_total": { + "name": "cost_total", + "type": "numeric", + "primaryKey": false, + "notNull": false + }, + "models_used": { + "name": "models_used", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "files": { + "name": "files", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_execution_logs_workflow_id_idx": { + "name": "workflow_execution_logs_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_state_snapshot_id_idx": { + "name": "workflow_execution_logs_state_snapshot_id_idx", + "columns": [ + { + "expression": "state_snapshot_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_deployment_version_id_idx": { + "name": "workflow_execution_logs_deployment_version_id_idx", + "columns": [ + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_trigger_idx": { + "name": "workflow_execution_logs_trigger_idx", + "columns": [ + { + "expression": "trigger", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_level_idx": { + "name": "workflow_execution_logs_level_idx", + "columns": [ + { + "expression": "level", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_started_at_idx": { + "name": "workflow_execution_logs_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_execution_id_unique": { + "name": "workflow_execution_logs_execution_id_unique", + "columns": [ + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workflow_started_at_idx": { + "name": "workflow_execution_logs_workflow_started_at_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_idx": { + "name": "workflow_execution_logs_workspace_started_at_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_started_at_id_desc_idx": { + "name": "workflow_execution_logs_workspace_started_at_id_desc_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "\"started_at\" DESC NULLS LAST", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "\"id\" DESC", + "asc": true, + "isExpression": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_workspace_cost_total_idx": { + "name": "workflow_execution_logs_workspace_cost_total_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "cost_total", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_models_used_idx": { + "name": "workflow_execution_logs_models_used_idx", + "columns": [ + { + "expression": "models_used", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + }, + "workflow_execution_logs_workspace_ended_at_id_idx": { + "name": "workflow_execution_logs_workspace_ended_at_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "date_trunc('milliseconds', \"ended_at\")", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_running_started_at_idx": { + "name": "workflow_execution_logs_running_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'running'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_running_deadline_idx": { + "name": "workflow_execution_logs_running_deadline_idx", + "columns": [ + { + "expression": "execution_deadline_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'running' AND \"workflow_execution_logs\".\"execution_deadline_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_redacting_started_at_idx": { + "name": "workflow_execution_logs_redacting_started_at_idx", + "columns": [ + { + "expression": "started_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "status = 'redacting'", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_redacting_deadline_idx": { + "name": "workflow_execution_logs_redacting_deadline_idx", + "columns": [ + { + "expression": "execution_deadline_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'redacting' AND \"workflow_execution_logs\".\"execution_deadline_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_execution_logs_completed_ended_at_idx": { + "name": "workflow_execution_logs_completed_ended_at_idx", + "columns": [ + { + "expression": "ended_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "execution_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_execution_logs\".\"status\" = 'completed' AND \"workflow_execution_logs\".\"level\" = 'info' AND \"workflow_execution_logs\".\"ended_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_logs_workflow_id_workflow_id_fk": { + "name": "workflow_execution_logs_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_execution_logs_workspace_id_workspace_id_fk": { + "name": "workflow_execution_logs_workspace_id_workspace_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk": { + "name": "workflow_execution_logs_state_snapshot_id_workflow_execution_snapshots_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_execution_snapshots", + "columnsFrom": ["state_snapshot_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_execution_logs_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_execution_logs", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_execution_snapshots": { + "name": "workflow_execution_snapshots", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "state_hash": { + "name": "state_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "state_data": { + "name": "state_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_snapshots_workflow_id_idx": { + "name": "workflow_snapshots_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_hash_idx": { + "name": "workflow_snapshots_hash_idx", + "columns": [ + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_workflow_hash_idx": { + "name": "workflow_snapshots_workflow_hash_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "state_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_snapshots_created_at_idx": { + "name": "workflow_snapshots_created_at_idx", + "columns": [ + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_execution_snapshots_workflow_id_workflow_id_fk": { + "name": "workflow_execution_snapshots_workflow_id_workflow_id_fk", + "tableFrom": "workflow_execution_snapshots", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_server": { + "name": "workflow_mcp_server", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "is_public": { + "name": "is_public", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_mcp_server_workspace_id_idx": { + "name": "workflow_mcp_server_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_created_by_idx": { + "name": "workflow_mcp_server_created_by_idx", + "columns": [ + { + "expression": "created_by", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_deleted_at_idx": { + "name": "workflow_mcp_server_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_server_workspace_deleted_partial_idx": { + "name": "workflow_mcp_server_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_mcp_server\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_server_workspace_id_workspace_id_fk": { + "name": "workflow_mcp_server_workspace_id_workspace_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_server_created_by_user_id_fk": { + "name": "workflow_mcp_server_created_by_user_id_fk", + "tableFrom": "workflow_mcp_server", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_mcp_tool": { + "name": "workflow_mcp_tool", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_name": { + "name": "tool_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "tool_description": { + "name": "tool_description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "parameter_schema": { + "name": "parameter_schema", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "parameter_description_overrides": { + "name": "parameter_description_overrides", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'::json" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_mcp_tool_server_id_idx": { + "name": "workflow_mcp_tool_server_id_idx", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_workflow_id_idx": { + "name": "workflow_mcp_tool_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_server_workflow_unique": { + "name": "workflow_mcp_tool_server_workflow_unique", + "columns": [ + { + "expression": "server_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_mcp_tool_archived_at_partial_idx": { + "name": "workflow_mcp_tool_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_mcp_tool\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk": { + "name": "workflow_mcp_tool_server_id_workflow_mcp_server_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow_mcp_server", + "columnsFrom": ["server_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_mcp_tool_workflow_id_workflow_id_fk": { + "name": "workflow_mcp_tool_workflow_id_workflow_id_fk", + "tableFrom": "workflow_mcp_tool", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_schedule": { + "name": "workflow_schedule", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_version_id": { + "name": "deployment_version_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "deployment_operation_id": { + "name": "deployment_operation_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "block_id": { + "name": "block_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "cron_expression": { + "name": "cron_expression", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "next_run_at": { + "name": "next_run_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_ran_at": { + "name": "last_ran_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "last_queued_at": { + "name": "last_queued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "trigger_type": { + "name": "trigger_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "timezone": { + "name": "timezone", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'UTC'" + }, + "failed_count": { + "name": "failed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "infra_retry_count": { + "name": "infra_retry_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'active'" + }, + "last_failed_at": { + "name": "last_failed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "source_type": { + "name": "source_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'workflow'" + }, + "job_title": { + "name": "job_title", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "prompt": { + "name": "prompt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "lifecycle": { + "name": "lifecycle", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'persistent'" + }, + "success_condition": { + "name": "success_condition", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "max_runs": { + "name": "max_runs", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "run_count": { + "name": "run_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "source_chat_id": { + "name": "source_chat_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_task_name": { + "name": "source_task_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_user_id": { + "name": "source_user_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "secret_scope": { + "name": "secret_scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'all'" + }, + "mounted_secrets": { + "name": "mounted_secrets", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "job_history": { + "name": "job_history", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "contexts": { + "name": "contexts", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "excluded_dates": { + "name": "excluded_dates", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "ends_at": { + "name": "ends_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_schedule_workflow_block_deployment_unique": { + "name": "workflow_schedule_workflow_block_deployment_unique", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_workflow_deployment_idx": { + "name": "workflow_schedule_workflow_deployment_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_archived_at_partial_idx": { + "name": "workflow_schedule_archived_at_partial_idx", + "columns": [ + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "idx_workflow_schedule_on_source_workspace_id_source_t_c07f3bba6": { + "name": "idx_workflow_schedule_on_source_workspace_id_source_t_c07f3bba6", + "columns": [ + { + "expression": "source_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "archived_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_due_workflow_idx": { + "name": "workflow_schedule_due_workflow_idx", + "columns": [ + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deployment_version_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL AND \"workflow_schedule\".\"status\" NOT IN ('disabled', 'completed') AND (\"workflow_schedule\".\"source_type\" = 'workflow' OR \"workflow_schedule\".\"source_type\" IS NULL)", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_schedule_due_job_idx": { + "name": "workflow_schedule_due_job_idx", + "columns": [ + { + "expression": "next_run_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "last_queued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workflow_schedule\".\"archived_at\" IS NULL AND \"workflow_schedule\".\"status\" NOT IN ('disabled', 'completed') AND \"workflow_schedule\".\"source_type\" = 'job'", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_schedule_workflow_id_workflow_id_fk": { + "name": "workflow_schedule_workflow_id_workflow_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk": { + "name": "workflow_schedule_deployment_version_id_workflow_deployment_version_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_version", + "columnsFrom": ["deployment_version_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_deployment_operation_id_workflow_deployment_operation_id_fk": { + "name": "workflow_schedule_deployment_operation_id_workflow_deployment_operation_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workflow_deployment_operation", + "columnsFrom": ["deployment_operation_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workflow_schedule_source_user_id_user_id_fk": { + "name": "workflow_schedule_source_user_id_user_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "user", + "columnsFrom": ["source_user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workflow_schedule_source_workspace_id_workspace_id_fk": { + "name": "workflow_schedule_source_workspace_id_workspace_id_fk", + "tableFrom": "workflow_schedule", + "tableTo": "workspace", + "columnsFrom": ["source_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workflow_subflows": { + "name": "workflow_subflows", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workflow_id": { + "name": "workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "config": { + "name": "config", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workflow_subflows_workflow_id_idx": { + "name": "workflow_subflows_workflow_id_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workflow_subflows_workflow_type_idx": { + "name": "workflow_subflows_workflow_type_idx", + "columns": [ + { + "expression": "workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workflow_subflows_workflow_id_workflow_id_fk": { + "name": "workflow_subflows_workflow_id_workflow_id_fk", + "tableFrom": "workflow_subflows", + "tableTo": "workflow", + "columnsFrom": ["workflow_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace": { + "name": "workspace", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'#33C482'" + }, + "logo_url": { + "name": "logo_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "owner_id": { + "name": "owner_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "workspace_mode": { + "name": "workspace_mode", + "type": "workspace_mode", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'grandfathered_shared'" + }, + "billed_account_user_id": { + "name": "billed_account_user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "storage_used_bytes": { + "name": "storage_used_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "allow_personal_api_keys": { + "name": "allow_personal_api_keys", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": true + }, + "inbox_enabled": { + "name": "inbox_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "inbox_address": { + "name": "inbox_address", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_provider_id": { + "name": "inbox_provider_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "inbox_secret_scope": { + "name": "inbox_secret_scope", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'all'" + }, + "inbox_mounted_secrets": { + "name": "inbox_mounted_secrets", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "archived_at": { + "name": "archived_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "organization_assigned_at": { + "name": "organization_assigned_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "forked_from_workspace_id": { + "name": "forked_from_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_owner_id_idx": { + "name": "workspace_owner_id_idx", + "columns": [ + { + "expression": "owner_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_organization_id_idx": { + "name": "workspace_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_mode_idx": { + "name": "workspace_mode_idx", + "columns": [ + { + "expression": "workspace_mode", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_forked_from_workspace_id_idx": { + "name": "workspace_forked_from_workspace_id_idx", + "columns": [ + { + "expression": "forked_from_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_inbox_provider_id_idx": { + "name": "workspace_inbox_provider_id_idx", + "columns": [ + { + "expression": "inbox_provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace\".\"inbox_provider_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_owner_id_user_id_fk": { + "name": "workspace_owner_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["owner_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_organization_id_organization_id_fk": { + "name": "workspace_organization_id_organization_id_fk", + "tableFrom": "workspace", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workspace_billed_account_user_id_user_id_fk": { + "name": "workspace_billed_account_user_id_user_id_fk", + "tableFrom": "workspace", + "tableTo": "user", + "columnsFrom": ["billed_account_user_id"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + }, + "workspace_forked_from_workspace_id_workspace_id_fk": { + "name": "workspace_forked_from_workspace_id_workspace_id_fk", + "tableFrom": "workspace", + "tableTo": "workspace", + "columnsFrom": ["forked_from_workspace_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_storage_used_bytes_non_negative": { + "name": "workspace_storage_used_bytes_non_negative", + "value": "\"workspace\".\"storage_used_bytes\" >= 0" + } + }, + "isRLSEnabled": false + }, + "public.workspace_byok_keys": { + "name": "workspace_byok_keys", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "encrypted_api_key": { + "name": "encrypted_api_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_byok_workspace_provider_idx": { + "name": "workspace_byok_workspace_provider_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "provider_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_byok_keys_workspace_id_workspace_id_fk": { + "name": "workspace_byok_keys_workspace_id_workspace_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_byok_keys_created_by_user_id_fk": { + "name": "workspace_byok_keys_created_by_user_id_fk", + "tableFrom": "workspace_byok_keys", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_environment": { + "name": "workspace_environment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "variables": { + "name": "variables", + "type": "json", + "primaryKey": false, + "notNull": true, + "default": "'{}'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_environment_workspace_unique": { + "name": "workspace_environment_workspace_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_environment_workspace_id_workspace_id_fk": { + "name": "workspace_environment_workspace_id_workspace_id_fk", + "tableFrom": "workspace_environment", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file": { + "name": "workspace_file", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uploaded_by": { + "name": "uploaded_by", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_workspace_id_idx": { + "name": "workspace_file_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_deleted_at_idx": { + "name": "workspace_file_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_workspace_deleted_partial_idx": { + "name": "workspace_file_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_workspace_id_workspace_id_fk": { + "name": "workspace_file_workspace_id_workspace_id_fk", + "tableFrom": "workspace_file", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_uploaded_by_user_id_fk": { + "name": "workspace_file_uploaded_by_user_id_fk", + "tableFrom": "workspace_file", + "tableTo": "user", + "columnsFrom": ["uploaded_by"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "workspace_file_key_unique": { + "name": "workspace_file_key_unique", + "nullsNotDistinct": false, + "columns": ["key"] + } + }, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_collab_state": { + "name": "workspace_file_collab_state", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "doc_state": { + "name": "doc_state", + "type": "bytea", + "primaryKey": false, + "notNull": true + }, + "source_hash": { + "name": "source_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_file_collab_state_file_id_workspace_files_id_fk": { + "name": "workspace_file_collab_state_file_id_workspace_files_id_fk", + "tableFrom": "workspace_file_collab_state", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_backfill": { + "name": "workspace_file_search_backfill", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "after_workspace_id": { + "name": "after_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "after_file_id": { + "name": "after_file_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "completed_at": { + "name": "completed_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_dispatch_queue": { + "name": "workspace_file_search_dispatch_queue", + "schema": "", + "columns": { + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "enqueued_at": { + "name": "enqueued_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "last_dispatched_at": { + "name": "last_dispatched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_search_dispatch_queue_schedule_idx": { + "name": "workspace_file_search_dispatch_queue_schedule_idx", + "columns": [ + { + "expression": "last_dispatched_at", + "isExpression": false, + "asc": true, + "nulls": "first" + }, + { + "expression": "enqueued_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_search_queue_workspace_fk": { + "name": "workspace_file_search_queue_workspace_fk", + "tableFrom": "workspace_file_search_dispatch_queue", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_index": { + "name": "workspace_file_search_index", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_content_updated_at": { + "name": "source_content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "workspace_file_search_index_status", + "typeSchema": "public", + "primaryKey": false, + "notNull": true, + "default": "'pending'" + }, + "partial": { + "name": "partial", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "failure_reason": { + "name": "failure_reason", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "line_count": { + "name": "line_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "indexed_bytes": { + "name": "indexed_bytes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "dispatched_at": { + "name": "dispatched_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_file_search_index_workspace_status_idx": { + "name": "workspace_file_search_index_workspace_status_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "status", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_content_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_search_index_pending_dispatch_idx": { + "name": "workspace_file_search_index_pending_dispatch_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "file_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_content_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file_search_index\".\"status\" = 'pending' AND \"workspace_file_search_index\".\"dispatched_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_search_index_active_dispatch_idx": { + "name": "workspace_file_search_index_active_dispatch_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "dispatched_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_file_search_index\".\"status\" = 'pending' AND \"workspace_file_search_index\".\"dispatched_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_search_index_file_fk": { + "name": "workspace_file_search_index_file_fk", + "tableFrom": "workspace_file_search_index", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_search_index_workspace_fk": { + "name": "workspace_file_search_index_workspace_fk", + "tableFrom": "workspace_file_search_index", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "workspace_file_search_index_pk": { + "name": "workspace_file_search_index_pk", + "columns": ["file_id", "source_content_updated_at"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_search_segment": { + "name": "workspace_file_search_segment", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_content_updated_at": { + "name": "source_content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "line_number": { + "name": "line_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "segment_number": { + "name": "segment_number", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "segment_start": { + "name": "segment_start", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "line_length": { + "name": "line_length", + "type": "integer", + "primaryKey": false, + "notNull": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "workspace_file_search_segment_workspace_revision_idx": { + "name": "workspace_file_search_segment_workspace_revision_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "file_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "source_content_updated_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_file_search_segment_workspace_content_trgm_idx": { + "name": "workspace_file_search_segment_workspace_content_trgm_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "text_ops" + }, + { + "expression": "content", + "isExpression": false, + "asc": true, + "nulls": "last", + "opclass": "gin_trgm_ops" + } + ], + "isUnique": false, + "concurrently": false, + "method": "gin", + "with": {} + } + }, + "foreignKeys": { + "workspace_file_search_segment_file_fk": { + "name": "workspace_file_search_segment_file_fk", + "tableFrom": "workspace_file_search_segment", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_file_search_segment_workspace_fk": { + "name": "workspace_file_search_segment_workspace_fk", + "tableFrom": "workspace_file_search_segment", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "workspace_file_search_segment_pk": { + "name": "workspace_file_search_segment_pk", + "columns": ["file_id", "source_content_updated_at", "line_number", "segment_number"] + } + }, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_file_secret_provenance": { + "name": "workspace_file_secret_provenance", + "schema": "", + "columns": { + "file_id": { + "name": "file_id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "content_updated_at": { + "name": "content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true + }, + "status": { + "name": "status", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "entries": { + "name": "entries", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "workspace_file_secret_provenance_file_id_workspace_files_id_fk": { + "name": "workspace_file_secret_provenance_file_id_workspace_files_id_fk", + "tableFrom": "workspace_file_secret_provenance", + "tableTo": "workspace_files", + "columnsFrom": ["file_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_file_secret_provenance_status_check": { + "name": "workspace_file_secret_provenance_status_check", + "value": "\"workspace_file_secret_provenance\".\"status\" IN ('exact', 'unknown', 'unrecorded')" + } + }, + "isRLSEnabled": false + }, + "public.workspace_files": { + "name": "workspace_files", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "key": { + "name": "key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "organization_id": { + "name": "organization_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "folder_id": { + "name": "folder_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "context": { + "name": "context", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "chat_id": { + "name": "chat_id", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "message_id": { + "name": "message_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "original_name": { + "name": "original_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": true, + "default": 0 + }, + "size_bytes": { + "name": "size_bytes", + "type": "bigint", + "primaryKey": false, + "notNull": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "deleted_at": { + "name": "deleted_at", + "type": "timestamp", + "primaryKey": false, + "notNull": false + }, + "uploaded_at": { + "name": "uploaded_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "content_updated_at": { + "name": "content_updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "secret_provenance_version": { + "name": "secret_provenance_version", + "type": "integer", + "primaryKey": false, + "notNull": false + } + }, + "indexes": { + "workspace_files_key_active_unique": { + "name": "workspace_files_key_active_unique", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_folder_name_active_unique": { + "name": "workspace_files_workspace_folder_name_active_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "coalesce(\"folder_id\", '')", + "asc": true, + "isExpression": true, + "nulls": "last" + }, + { + "expression": "original_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"deleted_at\" IS NULL AND \"workspace_files\".\"context\" = 'workspace' AND \"workspace_files\".\"workspace_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_display_name_unique": { + "name": "workspace_files_chat_display_name_unique", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "display_name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "where": "\"workspace_files\".\"context\" = 'mothership' AND \"workspace_files\".\"chat_id\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_organization_id_idx": { + "name": "workspace_files_organization_id_idx", + "columns": [ + { + "expression": "organization_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_key_idx": { + "name": "workspace_files_key_idx", + "columns": [ + { + "expression": "key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_user_id_idx": { + "name": "workspace_files_user_id_idx", + "columns": [ + { + "expression": "user_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_id_idx": { + "name": "workspace_files_workspace_id_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_folder_id_idx": { + "name": "workspace_files_folder_id_idx", + "columns": [ + { + "expression": "folder_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_context_idx": { + "name": "workspace_files_context_idx", + "columns": [ + { + "expression": "context", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_chat_id_idx": { + "name": "workspace_files_chat_id_idx", + "columns": [ + { + "expression": "chat_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_deleted_at_idx": { + "name": "workspace_files_deleted_at_idx", + "columns": [ + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_files_workspace_deleted_partial_idx": { + "name": "workspace_files_workspace_deleted_partial_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "deleted_at", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "where": "\"workspace_files\".\"deleted_at\" IS NOT NULL", + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_files_user_id_user_id_fk": { + "name": "workspace_files_user_id_user_id_fk", + "tableFrom": "workspace_files", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_workspace_id_workspace_id_fk": { + "name": "workspace_files_workspace_id_workspace_id_fk", + "tableFrom": "workspace_files", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_organization_id_organization_id_fk": { + "name": "workspace_files_organization_id_organization_id_fk", + "tableFrom": "workspace_files", + "tableTo": "organization", + "columnsFrom": ["organization_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_files_folder_id_folder_id_fk": { + "name": "workspace_files_folder_id_folder_id_fk", + "tableFrom": "workspace_files", + "tableTo": "folder", + "columnsFrom": ["folder_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + }, + "workspace_files_chat_id_copilot_chats_id_fk": { + "name": "workspace_files_chat_id_copilot_chats_id_fk", + "tableFrom": "workspace_files", + "tableTo": "copilot_chats", + "columnsFrom": ["chat_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": { + "workspace_files_organization_binding_check": { + "name": "workspace_files_organization_binding_check", + "value": "\"workspace_files\".\"organization_id\" IS NULL OR (\"workspace_files\".\"workspace_id\" IS NULL AND \"workspace_files\".\"context\" = 'knowledge-base' AND \"workspace_files\".\"folder_id\" IS NULL AND \"workspace_files\".\"chat_id\" IS NULL)" + } + }, + "isRLSEnabled": false + }, + "public.workspace_fork_block_map": { + "name": "workspace_fork_block_map", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_workflow_id": { + "name": "parent_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "parent_block_id": { + "name": "parent_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_workflow_id": { + "name": "child_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_block_id": { + "name": "child_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_block_map_child_ws_parent_unique": { + "name": "workspace_fork_block_map_child_ws_parent_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_child_unique": { + "name": "workspace_fork_block_map_child_ws_child_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_parent_wf_idx": { + "name": "workspace_fork_block_map_child_ws_parent_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_block_map_child_ws_child_wf_idx": { + "name": "workspace_fork_block_map_child_ws_child_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "child_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_block_map_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_block_map_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_block_map", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_dependent_value": { + "name": "workspace_fork_dependent_value", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_workflow_id": { + "name": "target_workflow_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_block_id": { + "name": "target_block_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "sub_block_key": { + "name": "sub_block_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_dependent_value_child_ws_wf_idx": { + "name": "workspace_fork_dependent_value_child_ws_wf_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_dependent_value_field_unique": { + "name": "workspace_fork_dependent_value_field_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workflow_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_block_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "sub_block_key", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_dependent_value_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_dependent_value_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_dependent_value", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_promote_run": { + "name": "workspace_fork_promote_run", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "source_workspace_id": { + "name": "source_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "target_workspace_id": { + "name": "target_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "direction": { + "name": "direction", + "type": "workspace_fork_promote_direction", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "snapshot": { + "name": "snapshot", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_promote_run_child_ws_target_unique": { + "name": "workspace_fork_promote_run_child_ws_target_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "target_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_promote_run_target_ws_idx": { + "name": "workspace_fork_promote_run_target_ws_idx", + "columns": [ + { + "expression": "target_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_promote_run_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_promote_run_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_promote_run", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_fork_promote_run_created_by_user_id_fk": { + "name": "workspace_fork_promote_run_created_by_user_id_fk", + "tableFrom": "workspace_fork_promote_run", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_fork_resource_map": { + "name": "workspace_fork_resource_map", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "child_workspace_id": { + "name": "child_workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "resource_type": { + "name": "resource_type", + "type": "workspace_fork_resource_type", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "parent_resource_id": { + "name": "parent_resource_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "child_resource_id": { + "name": "child_resource_id", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_fork_resource_map_child_ws_idx": { + "name": "workspace_fork_resource_map_child_ws_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_resource_map_child_ws_type_idx": { + "name": "workspace_fork_resource_map_child_ws_type_idx", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_fork_resource_map_child_type_parent_unique": { + "name": "workspace_fork_resource_map_child_type_parent_unique", + "columns": [ + { + "expression": "child_workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "resource_type", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "parent_resource_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_fork_resource_map_child_workspace_id_workspace_id_fk": { + "name": "workspace_fork_resource_map_child_workspace_id_workspace_id_fk", + "tableFrom": "workspace_fork_resource_map", + "tableTo": "workspace", + "columnsFrom": ["child_workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_fork_resource_map_created_by_user_id_fk": { + "name": "workspace_fork_resource_map_created_by_user_id_fk", + "tableFrom": "workspace_fork_resource_map", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_operation_receipt": { + "name": "workspace_operation_receipt", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_id": { + "name": "request_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "request_hash": { + "name": "request_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "kind": { + "name": "kind", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "report": { + "name": "report", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_operation_receipt_request_unique": { + "name": "workspace_operation_receipt_request_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "request_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_operation_receipt_workspace_created_idx": { + "name": "workspace_operation_receipt_workspace_created_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "created_at", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_operation_receipt_workspace_id_workspace_id_fk": { + "name": "workspace_operation_receipt_workspace_id_workspace_id_fk", + "tableFrom": "workspace_operation_receipt", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + }, + "public.workspace_sandbox": { + "name": "workspace_sandbox", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "workspace_id": { + "name": "workspace_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "language": { + "name": "language", + "type": "sandbox_language", + "typeSchema": "public", + "primaryKey": false, + "notNull": true + }, + "dependencies": { + "name": "dependencies", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "cli_tools": { + "name": "cli_tools", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "system_packages": { + "name": "system_packages", + "type": "jsonb", + "primaryKey": false, + "notNull": true, + "default": "'[]'::jsonb" + }, + "spec_hash": { + "name": "spec_hash", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_by": { + "name": "created_by", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "workspace_sandbox_workspace_name_unique": { + "name": "workspace_sandbox_workspace_name_unique", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + }, + { + "expression": "name", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": true, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_sandbox_workspace_idx": { + "name": "workspace_sandbox_workspace_idx", + "columns": [ + { + "expression": "workspace_id", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + }, + "workspace_sandbox_spec_hash_idx": { + "name": "workspace_sandbox_spec_hash_idx", + "columns": [ + { + "expression": "spec_hash", + "isExpression": false, + "asc": true, + "nulls": "last" + } + ], + "isUnique": false, + "concurrently": false, + "method": "btree", + "with": {} + } + }, + "foreignKeys": { + "workspace_sandbox_workspace_id_workspace_id_fk": { + "name": "workspace_sandbox_workspace_id_workspace_id_fk", + "tableFrom": "workspace_sandbox", + "tableTo": "workspace", + "columnsFrom": ["workspace_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "workspace_sandbox_created_by_user_id_fk": { + "name": "workspace_sandbox_created_by_user_id_fk", + "tableFrom": "workspace_sandbox", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "policies": {}, + "checkConstraints": {}, + "isRLSEnabled": false + } + }, + "enums": { + "public.academy_cert_status": { + "name": "academy_cert_status", + "schema": "public", + "values": ["active", "revoked", "expired"] + }, + "public.background_work_kind": { + "name": "background_work_kind", + "schema": "public", + "values": ["deployment_side_effects", "fork_content_copy", "fork_sync", "fork_rollback"] + }, + "public.background_work_status_value": { + "name": "background_work_status_value", + "schema": "public", + "values": ["pending", "processing", "completed", "completed_with_warnings", "failed"] + }, + "public.billing_blocked_reason": { + "name": "billing_blocked_reason", + "schema": "public", + "values": ["payment_failed", "dispute"] + }, + "public.billing_entity_type": { + "name": "billing_entity_type", + "schema": "public", + "values": ["user", "organization"] + }, + "public.chat_type": { + "name": "chat_type", + "schema": "public", + "values": ["mothership", "copilot"] + }, + "public.copilot_async_tool_status": { + "name": "copilot_async_tool_status", + "schema": "public", + "values": ["pending", "running", "completed", "failed", "cancelled", "delivered"] + }, + "public.copilot_run_status": { + "name": "copilot_run_status", + "schema": "public", + "values": ["active", "paused_waiting_for_tool", "resuming", "complete", "error", "cancelled"] + }, + "public.copilot_tool_permission_decision": { + "name": "copilot_tool_permission_decision", + "schema": "public", + "values": ["allow", "allow_chat", "always_allow", "skip"] + }, + "public.credential_group_enrollment_status": { + "name": "credential_group_enrollment_status", + "schema": "public", + "values": ["invited", "delivery_failed", "in_progress", "completed", "revoked"] + }, + "public.credential_group_status": { + "name": "credential_group_status", + "schema": "public", + "values": ["active", "disabled"] + }, + "public.credential_member_role": { + "name": "credential_member_role", + "schema": "public", + "values": ["admin", "member"] + }, + "public.credential_member_status": { + "name": "credential_member_status", + "schema": "public", + "values": ["active", "pending", "revoked"] + }, + "public.credential_type": { + "name": "credential_type", + "schema": "public", + "values": [ + "oauth", + "managed_oauth", + "managed_mcp", + "env_workspace", + "env_personal", + "service_account", + "personal_token" + ] + }, + "public.data_drain_cadence": { + "name": "data_drain_cadence", + "schema": "public", + "values": ["hourly", "daily"] + }, + "public.data_drain_destination": { + "name": "data_drain_destination", + "schema": "public", + "values": ["s3", "gcs", "azure_blob", "datadog", "bigquery", "snowflake", "webhook"] + }, + "public.data_drain_run_status": { + "name": "data_drain_run_status", + "schema": "public", + "values": ["running", "success", "failed"] + }, + "public.data_drain_run_trigger": { + "name": "data_drain_run_trigger", + "schema": "public", + "values": ["cron", "manual"] + }, + "public.data_drain_source": { + "name": "data_drain_source", + "schema": "public", + "values": ["workflow_logs", "job_logs", "audit_logs", "copilot_chats", "copilot_runs"] + }, + "public.execution_large_value_reference_source": { + "name": "execution_large_value_reference_source", + "schema": "public", + "values": ["execution_log", "paused_snapshot"] + }, + "public.folder_resource_type": { + "name": "folder_resource_type", + "schema": "public", + "values": ["workflow", "file", "knowledge_base", "table"] + }, + "public.invitation_kind": { + "name": "invitation_kind", + "schema": "public", + "values": ["organization", "workspace"] + }, + "public.invitation_membership_intent": { + "name": "invitation_membership_intent", + "schema": "public", + "values": ["internal", "external"] + }, + "public.invitation_status": { + "name": "invitation_status", + "schema": "public", + "values": ["pending", "accepted", "rejected", "cancelled", "expired"] + }, + "public.managed_oauth_credential_status": { + "name": "managed_oauth_credential_status", + "schema": "public", + "values": ["active", "needs_reauth", "revoked"] + }, + "public.permission_type": { + "name": "permission_type", + "schema": "public", + "values": ["admin", "write", "read"] + }, + "public.sandbox_image_status": { + "name": "sandbox_image_status", + "schema": "public", + "values": ["pending", "building", "ready", "failed"] + }, + "public.sandbox_language": { + "name": "sandbox_language", + "schema": "public", + "values": ["javascript", "python"] + }, + "public.secret_usage_scope": { + "name": "secret_usage_scope", + "schema": "public", + "values": ["workspace", "personal"] + }, + "public.secret_usage_source": { + "name": "secret_usage_source", + "schema": "public", + "values": ["workflow", "copilot", "mcp"] + }, + "public.upload_session_method": { + "name": "upload_session_method", + "schema": "public", + "values": ["put", "multipart"] + }, + "public.upload_session_provider": { + "name": "upload_session_provider", + "schema": "public", + "values": ["local", "s3", "blob", "gcs"] + }, + "public.upload_session_purpose": { + "name": "upload_session_purpose", + "schema": "public", + "values": [ + "workspace_file", + "table_import", + "knowledge_document", + "profile_picture", + "workspace_logo", + "mothership_attachment", + "execution_attachment" + ] + }, + "public.upload_session_status": { + "name": "upload_session_status", + "schema": "public", + "values": [ + "uploading", + "completing", + "finalizing", + "completed", + "aborting", + "aborted", + "failed", + "expired" + ] + }, + "public.usage_log_category": { + "name": "usage_log_category", + "schema": "public", + "values": ["model", "fixed", "tool", "model_unbilled"] + }, + "public.usage_log_source": { + "name": "usage_log_source", + "schema": "public", + "values": [ + "workflow", + "wand", + "copilot", + "workspace-chat", + "mcp_copilot", + "mothership_block", + "knowledge-base", + "voice-input", + "enrichment", + "voice-output", + "api-tool" + ] + }, + "public.workspace_file_search_index_status": { + "name": "workspace_file_search_index_status", + "schema": "public", + "values": ["pending", "ready", "skipped", "failed"] + }, + "public.workspace_fork_promote_direction": { + "name": "workspace_fork_promote_direction", + "schema": "public", + "values": ["push", "pull"] + }, + "public.workspace_fork_resource_type": { + "name": "workspace_fork_resource_type", + "schema": "public", + "values": [ + "workflow", + "oauth_credential", + "service_account_credential", + "env_var", + "table", + "knowledge_base", + "knowledge_document", + "file", + "file_folder", + "mcp_server", + "workflow_mcp_server", + "custom_block", + "custom_tool", + "skill", + "sandbox" + ] + }, + "public.workspace_mode": { + "name": "workspace_mode", + "schema": "public", + "values": ["personal", "organization", "grandfathered_shared"] + } + }, + "schemas": {}, + "sequences": {}, + "roles": {}, + "policies": {}, + "views": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} diff --git a/packages/db/migrations/meta/_journal.json b/packages/db/migrations/meta/_journal.json index 660164f99d0..f8f91eff92f 100644 --- a/packages/db/migrations/meta/_journal.json +++ b/packages/db/migrations/meta/_journal.json @@ -2360,6 +2360,13 @@ "when": 1788986020651, "tag": "0337_colossal_the_renegades", "breakpoints": true + }, + { + "idx": 338, + "version": "7", + "when": 1789076658450, + "tag": "0338_organization_search_activity", + "breakpoints": true } ] } diff --git a/packages/db/schema.ts b/packages/db/schema.ts index 89375ccdb66..8d1b2746844 100644 --- a/packages/db/schema.ts +++ b/packages/db/schema.ts @@ -4550,6 +4550,37 @@ export const usageLogSourceEnum = pgEnum('usage_log_source', [ 'api-tool', ]) +/** Content-free organization Search activity, independent of billable model usage. */ +export const organizationSearchInvocation = pgTable( + 'organization_search_invocation', + { + id: text('id').primaryKey(), + organizationId: text('organization_id') + .notNull() + .references(() => organization.id, { onDelete: 'cascade' }), + userId: text('user_id').references(() => user.id, { onDelete: 'set null' }), + surface: text('surface').notNull(), + sourceTypes: text('source_types').array().notNull(), + resultCount: integer('result_count').notNull(), + createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(), + }, + (table) => ({ + organizationCreatedAtIdx: index('organization_search_invocation_org_created_idx').on( + table.organizationId, + table.createdAt + ), + userIdIdx: index('organization_search_invocation_user_idx').on(table.userId), + resultCountBounds: check( + 'organization_search_invocation_result_count_bounds', + sql`${table.resultCount} BETWEEN 0 AND 100` + ), + sourceTypesBounds: check( + 'organization_search_invocation_source_types_bounds', + sql`cardinality(${table.sourceTypes}) <= 100` + ), + }) +) + export const usageLog = pgTable( 'usage_log', { diff --git a/packages/emcn/src/components/combobox/combobox.tsx b/packages/emcn/src/components/combobox/combobox.tsx index 42757411481..39858f47f67 100644 --- a/packages/emcn/src/components/combobox/combobox.tsx +++ b/packages/emcn/src/components/combobox/combobox.tsx @@ -59,6 +59,8 @@ export type ComboboxOption = { iconElement?: ReactNode /** Custom select handler - when provided, this is called instead of onChange */ onSelect?: () => void + /** Explicit selection state for action options whose values are not stored in the selection. */ + selected?: boolean /** Whether this option is disabled */ disabled?: boolean /** When true, keep the dropdown open after selecting this option */ @@ -738,9 +740,11 @@ const Combobox = memo( ) : null const renderFlatOption = (option: ComboboxOption, index: number) => { - const isSelected = multiSelect - ? multiSelectValues?.includes(option.value) - : effectiveSelectedValue === option.value + const isSelected = + option.selected ?? + (multiSelect + ? multiSelectValues?.includes(option.value) + : effectiveSelectedValue === option.value) const isHighlighted = index === effectiveHighlightedIndex const OptionIcon = option.icon @@ -988,7 +992,7 @@ const Combobox = memo( Loading options... - ) : error && filteredOptions.length === 0 && !hasMore ? ( + ) : error && filteredOptions.length === 0 ? (
{error}
@@ -1009,9 +1013,11 @@ const Combobox = memo( )} {group.items.map((option) => { - const isSelected = multiSelect - ? multiSelectValues?.includes(option.value) - : effectiveSelectedValue === option.value + const isSelected = + option.selected ?? + (multiSelect + ? multiSelectValues?.includes(option.value) + : effectiveSelectedValue === option.value) const globalIndex = filteredOptions.findIndex( (o) => o.value === option.value ) diff --git a/packages/testing/src/mocks/schema.mock.ts b/packages/testing/src/mocks/schema.mock.ts index 5f7427e14b9..8d951f74c6c 100644 --- a/packages/testing/src/mocks/schema.mock.ts +++ b/packages/testing/src/mocks/schema.mock.ts @@ -1629,6 +1629,15 @@ export const schemaMock = { approved: 'organizationSearchIntegration.approved', updatedAt: 'organizationSearchIntegration.updatedAt', }, + organizationSearchInvocation: { + id: 'organizationSearchInvocation.id', + organizationId: 'organizationSearchInvocation.organizationId', + userId: 'organizationSearchInvocation.userId', + surface: 'organizationSearchInvocation.surface', + sourceTypes: 'organizationSearchInvocation.sourceTypes', + resultCount: 'organizationSearchInvocation.resultCount', + createdAt: 'organizationSearchInvocation.createdAt', + }, knowledgeConnector: { id: 'knowledgeConnector.id', knowledgeBaseId: 'knowledgeConnector.knowledgeBaseId',