orcheo-studio 0.21.2 → 0.22.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.bumpversion.cfg +1 -1
- package/dist/assets/{arc-CpXJ41cG.js → arc-De9dLqyl.js} +1 -1
- package/dist/assets/{architectureDiagram-VXUJARFQ-Bnj1Z3kt.js → architectureDiagram-VXUJARFQ-hEslfmYm.js} +1 -1
- package/dist/assets/{blockDiagram-VD42YOAC-DSxmIebP.js → blockDiagram-VD42YOAC-CyWSMWJa.js} +1 -1
- package/dist/assets/{c4Diagram-YG6GDRKO-wk2snQI8.js → c4Diagram-YG6GDRKO-CxoTVJ47.js} +1 -1
- package/dist/assets/channel-CzCzGn0f.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-B0ZkMnbv.js → chunk-4BX2VUAB-twftUw9o.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-BVFWf_lK.js → chunk-55IACEB6-DQZDNQUo.js} +1 -1
- package/dist/assets/{chunk-B4BG7PRW-DnR7oQ4g.js → chunk-B4BG7PRW-BYGOoNB5.js} +1 -1
- package/dist/assets/{chunk-DI55MBZ5-CNFww0wO.js → chunk-DI55MBZ5-qyPhcZF3.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-kqvlp-gm.js → chunk-FMBD7UC4-BgUDHGEG.js} +1 -1
- package/dist/assets/{chunk-QN33PNHL-CwF-7kEP.js → chunk-QN33PNHL-DHlMh8NC.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-DVLEC_l5.js → chunk-QZHKN3VN-Bfc8IV0O.js} +1 -1
- package/dist/assets/{chunk-TZMSLE5B-rwpYb83b.js → chunk-TZMSLE5B-BqwdftTm.js} +1 -1
- package/dist/assets/classDiagram-2ON5EDUG-ekNI5d_4.js +1 -0
- package/dist/assets/classDiagram-v2-WZHVMYZB-ekNI5d_4.js +1 -0
- package/dist/assets/clone-DowBu1Kh.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-BG5vo_BU.js → cose-bilkent-S5V4N54A-g5agH7fS.js} +1 -1
- package/dist/assets/{dagre-6UL2VRFP-DNS8secx.js → dagre-6UL2VRFP-ajLMaXPP.js} +1 -1
- package/dist/assets/{diagram-PSM6KHXK-DhkTaeY-.js → diagram-PSM6KHXK-BndVcBhB.js} +1 -1
- package/dist/assets/{diagram-QEK2KX5R-juugDR85.js → diagram-QEK2KX5R-BFiIYeu7.js} +1 -1
- package/dist/assets/{diagram-S2PKOQOG-BfwDPXhp.js → diagram-S2PKOQOG-DXy-A9pn.js} +1 -1
- package/dist/assets/{erDiagram-Q2GNP2WA-Dcz1rPHi.js → erDiagram-Q2GNP2WA-D_Bac_58.js} +1 -1
- package/dist/assets/{flowDiagram-NV44I4VS-CCfthK8j.js → flowDiagram-NV44I4VS-DhEi8qtz.js} +1 -1
- package/dist/assets/{ganttDiagram-JELNMOA3-Qm12KTag.js → ganttDiagram-JELNMOA3-BtpUvOuc.js} +1 -1
- package/dist/assets/{gitGraphDiagram-V2S2FVAM-CjyU6Twb.js → gitGraphDiagram-V2S2FVAM-MBES60cx.js} +1 -1
- package/dist/assets/{graph-DThnWdhX.js → graph-BcwvIN-m.js} +1 -1
- package/dist/assets/index-DLYzf0K-.js +775 -0
- package/dist/assets/index-DebsXgfj.css +1 -0
- package/dist/assets/{infoDiagram-HS3SLOUP-h3Nrkige.js → infoDiagram-HS3SLOUP-vaIFYyC9.js} +1 -1
- package/dist/assets/{isUndefined-yP-9UF2N.js → isUndefined-DVO6xakl.js} +1 -1
- package/dist/assets/{journeyDiagram-XKPGCS4Q-BSbwRc84.js → journeyDiagram-XKPGCS4Q-D-_q99If.js} +1 -1
- package/dist/assets/{kanban-definition-3W4ZIXB7-CARNrGlf.js → kanban-definition-3W4ZIXB7-i_AZcs_J.js} +1 -1
- package/dist/assets/{layout-pp8XWeO7.js → layout-CPJ9nR_z.js} +1 -1
- package/dist/assets/{linear-WDZxKeGm.js → linear-KBGpPBiH.js} +1 -1
- package/dist/assets/{min-rK5lTeBA.js → min-By5f7YdD.js} +1 -1
- package/dist/assets/{mindmap-definition-VGOIOE7T-BzF1XeHx.js → mindmap-definition-VGOIOE7T-DRjtRxFS.js} +1 -1
- package/dist/assets/{pieDiagram-ADFJNKIX-C5j6lI7D.js → pieDiagram-ADFJNKIX-BkkSglWM.js} +1 -1
- package/dist/assets/{quadrantDiagram-AYHSOK5B-CMaUda4E.js → quadrantDiagram-AYHSOK5B-DY-Ng2qt.js} +1 -1
- package/dist/assets/{requirementDiagram-UZGBJVZJ-BxOFsm2a.js → requirementDiagram-UZGBJVZJ-B5w0etXG.js} +1 -1
- package/dist/assets/{sankeyDiagram-TZEHDZUN-CGR0hfi8.js → sankeyDiagram-TZEHDZUN-BWntUp8b.js} +1 -1
- package/dist/assets/{sequenceDiagram-WL72ISMW-QLQiFJnI.js → sequenceDiagram-WL72ISMW-Cl77fd7y.js} +1 -1
- package/dist/assets/{stateDiagram-FKZM4ZOC-CebVOHmS.js → stateDiagram-FKZM4ZOC-B8_DoPW6.js} +1 -1
- package/dist/assets/stateDiagram-v2-4FDKWEC3-DHL7p-md.js +1 -0
- package/dist/assets/{timeline-definition-IT6M3QCI-CR6Zjm9F.js → timeline-definition-IT6M3QCI-udvNLTe_.js} +1 -1
- package/dist/assets/{treemap-GDKQZRPO-C0ItD1QK.js → treemap-GDKQZRPO-BSvoMl74.js} +1 -1
- package/dist/assets/{xychartDiagram-PRI3JC2R-T_ak7rrn.js → xychartDiagram-PRI3JC2R-CTdy-FCX.js} +1 -1
- package/dist/index.html +2 -7
- package/index.html +0 -5
- package/package.json +1 -1
- package/src/App.tsx +20 -0
- package/src/features/chatkit/pages/public-chat.tsx +7 -3
- package/src/features/workflow/data/templates/candidate-badges.ts +5 -0
- package/src/features/workflow/data/workflow-types.ts +1 -0
- package/src/features/workflow/lib/workflow-storage-api.ts +35 -4
- package/src/features/workflow/lib/workflow-storage-helpers.ts +10 -3
- package/src/features/workflow/lib/workflow-storage.ts +2 -1
- package/src/features/workflow/lib/workflow-storage.types.ts +9 -0
- package/src/features/workflow/pages/workflow/components/workflow-config-sheet.tsx +2 -66
- package/src/features/workflow/pages/workflow/components/workflow-config-sheet.utils.ts +0 -40
- package/src/features/workflow/pages/workflow-gallery/create-team-dialog.tsx +137 -0
- package/src/features/workflow/pages/workflow-gallery/onboard-team-dialog.tsx +57 -0
- package/src/features/workflow/pages/workflow-gallery/team-section.tsx +58 -0
- package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-actions.ts +124 -21
- package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery-state.ts +22 -2
- package/src/features/workflow/pages/workflow-gallery/use-workflow-gallery.ts +2 -0
- package/src/features/workflow/pages/workflow-gallery/workflow-card.tsx +26 -5
- package/src/features/workflow/pages/workflow-gallery/workflow-gallery-tabs.tsx +91 -16
- package/src/features/workflow/pages/workflow-gallery.tsx +45 -1
- package/src/lib/api.ts +13 -1
- package/src/lib/workspace-routing.ts +15 -0
- package/src/main.tsx +7 -0
- package/dist/assets/channel-D5aHOnKn.js +0 -1
- package/dist/assets/classDiagram-2ON5EDUG-BsnXw08J.js +0 -1
- package/dist/assets/classDiagram-v2-WZHVMYZB-BsnXw08J.js +0 -1
- package/dist/assets/clone-B8_btpeA.js +0 -1
- package/dist/assets/index-B0_h2wCA.css +0 -1
- package/dist/assets/index-nbmIZFkh.js +0 -775
- package/dist/assets/stateDiagram-v2-4FDKWEC3-Be2We9pM.js +0 -1
package/dist/assets/{xychartDiagram-PRI3JC2R-T_ak7rrn.js → xychartDiagram-PRI3JC2R-CTdy-FCX.js}
RENAMED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{s as gi,g as xi,q as Xt,p as di,a as fi,b as pi,_ as a,l as Nt,H as mi,e as yi,y as bi,F as St,i as Ai,D as Yt,E as wi,K as Ci,aI as Si,R as Wt}from"./index-
|
|
1
|
+
import{s as gi,g as xi,q as Xt,p as di,a as fi,b as pi,_ as a,l as Nt,H as mi,e as yi,y as bi,F as St,i as Ai,D as Yt,E as wi,K as Ci,aI as Si,R as Wt}from"./index-DLYzf0K-.js";import{i as _i}from"./init-Gi6I4Gst.js";import{o as ki}from"./ordinal-Cboi1Yqb.js";import{l as zt}from"./linear-KBGpPBiH.js";import"./defaultLocale-C4B-KCzX.js";function Ri(e,t,i){e=+e,t=+t,i=(n=arguments.length)<2?(t=e,e=0,1):n<3?1:+i;for(var s=-1,n=Math.max(0,Math.ceil((t-e)/i))|0,o=new Array(n);++s<n;)o[s]=e+s*i;return o}function yt(){var e=ki().unknown(void 0),t=e.domain,i=e.range,s=0,n=1,o,g,m=!1,p=0,k=0,v=.5;delete e.unknown;function C(){var b=t().length,E=n<s,D=E?n:s,P=E?s:n;o=(P-D)/Math.max(1,b-p+k*2),m&&(o=Math.floor(o)),D+=(P-D-o*(b-p))*v,g=o*(1-p),m&&(D=Math.round(D),g=Math.round(g));var I=Ri(b).map(function(y){return D+o*y});return i(E?I.reverse():I)}return e.domain=function(b){return arguments.length?(t(b),C()):t()},e.range=function(b){return arguments.length?([s,n]=b,s=+s,n=+n,C()):[s,n]},e.rangeRound=function(b){return[s,n]=b,s=+s,n=+n,m=!0,C()},e.bandwidth=function(){return g},e.step=function(){return o},e.round=function(b){return arguments.length?(m=!!b,C()):m},e.padding=function(b){return arguments.length?(p=Math.min(1,k=+b),C()):p},e.paddingInner=function(b){return arguments.length?(p=Math.min(1,b),C()):p},e.paddingOuter=function(b){return arguments.length?(k=+b,C()):k},e.align=function(b){return arguments.length?(v=Math.max(0,Math.min(1,b)),C()):v},e.copy=function(){return yt(t(),[s,n]).round(m).paddingInner(p).paddingOuter(k).align(v)},_i.apply(C(),arguments)}var bt=(function(){var e=a(function(F,h,u,x){for(u=u||{},x=F.length;x--;u[F[x]]=h);return u},"o"),t=[1,10,12,14,16,18,19,21,23],i=[2,6],s=[1,3],n=[1,5],o=[1,6],g=[1,7],m=[1,5,10,12,14,16,18,19,21,23,34,35,36],p=[1,25],k=[1,26],v=[1,28],C=[1,29],b=[1,30],E=[1,31],D=[1,32],P=[1,33],I=[1,34],y=[1,35],_=[1,36],c=[1,37],W=[1,43],z=[1,42],U=[1,47],X=[1,50],l=[1,10,12,14,16,18,19,21,23,34,35,36],L=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36],S=[1,10,12,14,16,18,19,21,23,24,26,27,28,34,35,36,41,42,43,44,45,46,47,48,49,50],R=[1,64],$={trace:a(function(){},"trace"),yy:{},symbols_:{error:2,start:3,eol:4,XYCHART:5,chartConfig:6,document:7,CHART_ORIENTATION:8,statement:9,title:10,text:11,X_AXIS:12,parseXAxis:13,Y_AXIS:14,parseYAxis:15,LINE:16,plotData:17,BAR:18,acc_title:19,acc_title_value:20,acc_descr:21,acc_descr_value:22,acc_descr_multiline_value:23,SQUARE_BRACES_START:24,commaSeparatedNumbers:25,SQUARE_BRACES_END:26,NUMBER_WITH_DECIMAL:27,COMMA:28,xAxisData:29,bandData:30,ARROW_DELIMITER:31,commaSeparatedTexts:32,yAxisData:33,NEWLINE:34,SEMI:35,EOF:36,alphaNum:37,STR:38,MD_STR:39,alphaNumToken:40,AMP:41,NUM:42,ALPHA:43,PLUS:44,EQUALS:45,MULT:46,DOT:47,BRKT:48,MINUS:49,UNDERSCORE:50,$accept:0,$end:1},terminals_:{2:"error",5:"XYCHART",8:"CHART_ORIENTATION",10:"title",12:"X_AXIS",14:"Y_AXIS",16:"LINE",18:"BAR",19:"acc_title",20:"acc_title_value",21:"acc_descr",22:"acc_descr_value",23:"acc_descr_multiline_value",24:"SQUARE_BRACES_START",26:"SQUARE_BRACES_END",27:"NUMBER_WITH_DECIMAL",28:"COMMA",31:"ARROW_DELIMITER",34:"NEWLINE",35:"SEMI",36:"EOF",38:"STR",39:"MD_STR",41:"AMP",42:"NUM",43:"ALPHA",44:"PLUS",45:"EQUALS",46:"MULT",47:"DOT",48:"BRKT",49:"MINUS",50:"UNDERSCORE"},productions_:[0,[3,2],[3,3],[3,2],[3,1],[6,1],[7,0],[7,2],[9,2],[9,2],[9,2],[9,2],[9,2],[9,3],[9,2],[9,3],[9,2],[9,2],[9,1],[17,3],[25,3],[25,1],[13,1],[13,2],[13,1],[29,1],[29,3],[30,3],[32,3],[32,1],[15,1],[15,2],[15,1],[33,3],[4,1],[4,1],[4,1],[11,1],[11,1],[11,1],[37,1],[37,2],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1],[40,1]],performAction:a(function(h,u,x,d,w,r,at){var f=r.length-1;switch(w){case 5:d.setOrientation(r[f]);break;case 9:d.setDiagramTitle(r[f].text.trim());break;case 12:d.setLineData({text:"",type:"text"},r[f]);break;case 13:d.setLineData(r[f-1],r[f]);break;case 14:d.setBarData({text:"",type:"text"},r[f]);break;case 15:d.setBarData(r[f-1],r[f]);break;case 16:this.$=r[f].trim(),d.setAccTitle(this.$);break;case 17:case 18:this.$=r[f].trim(),d.setAccDescription(this.$);break;case 19:this.$=r[f-1];break;case 20:this.$=[Number(r[f-2]),...r[f]];break;case 21:this.$=[Number(r[f])];break;case 22:d.setXAxisTitle(r[f]);break;case 23:d.setXAxisTitle(r[f-1]);break;case 24:d.setXAxisTitle({type:"text",text:""});break;case 25:d.setXAxisBand(r[f]);break;case 26:d.setXAxisRangeData(Number(r[f-2]),Number(r[f]));break;case 27:this.$=r[f-1];break;case 28:this.$=[r[f-2],...r[f]];break;case 29:this.$=[r[f]];break;case 30:d.setYAxisTitle(r[f]);break;case 31:d.setYAxisTitle(r[f-1]);break;case 32:d.setYAxisTitle({type:"text",text:""});break;case 33:d.setYAxisRangeData(Number(r[f-2]),Number(r[f]));break;case 37:this.$={text:r[f],type:"text"};break;case 38:this.$={text:r[f],type:"text"};break;case 39:this.$={text:r[f],type:"markdown"};break;case 40:this.$=r[f];break;case 41:this.$=r[f-1]+""+r[f];break}},"anonymous"),table:[e(t,i,{3:1,4:2,7:4,5:s,34:n,35:o,36:g}),{1:[3]},e(t,i,{4:2,7:4,3:8,5:s,34:n,35:o,36:g}),e(t,i,{4:2,7:4,6:9,3:10,5:s,8:[1,11],34:n,35:o,36:g}),{1:[2,4],9:12,10:[1,13],12:[1,14],14:[1,15],16:[1,16],18:[1,17],19:[1,18],21:[1,19],23:[1,20]},e(m,[2,34]),e(m,[2,35]),e(m,[2,36]),{1:[2,1]},e(t,i,{4:2,7:4,3:21,5:s,34:n,35:o,36:g}),{1:[2,3]},e(m,[2,5]),e(t,[2,7],{4:22,34:n,35:o,36:g}),{11:23,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},{11:39,13:38,24:W,27:z,29:40,30:41,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},{11:45,15:44,27:U,33:46,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},{11:49,17:48,24:X,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},{11:52,17:51,24:X,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},{20:[1,53]},{22:[1,54]},e(l,[2,18]),{1:[2,2]},e(l,[2,8]),e(l,[2,9]),e(L,[2,37],{40:55,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c}),e(L,[2,38]),e(L,[2,39]),e(S,[2,40]),e(S,[2,42]),e(S,[2,43]),e(S,[2,44]),e(S,[2,45]),e(S,[2,46]),e(S,[2,47]),e(S,[2,48]),e(S,[2,49]),e(S,[2,50]),e(S,[2,51]),e(l,[2,10]),e(l,[2,22],{30:41,29:56,24:W,27:z}),e(l,[2,24]),e(l,[2,25]),{31:[1,57]},{11:59,32:58,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},e(l,[2,11]),e(l,[2,30],{33:60,27:U}),e(l,[2,32]),{31:[1,61]},e(l,[2,12]),{17:62,24:X},{25:63,27:R},e(l,[2,14]),{17:65,24:X},e(l,[2,16]),e(l,[2,17]),e(S,[2,41]),e(l,[2,23]),{27:[1,66]},{26:[1,67]},{26:[2,29],28:[1,68]},e(l,[2,31]),{27:[1,69]},e(l,[2,13]),{26:[1,70]},{26:[2,21],28:[1,71]},e(l,[2,15]),e(l,[2,26]),e(l,[2,27]),{11:59,32:72,37:24,38:p,39:k,40:27,41:v,42:C,43:b,44:E,45:D,46:P,47:I,48:y,49:_,50:c},e(l,[2,33]),e(l,[2,19]),{25:73,27:R},{26:[2,28]},{26:[2,20]}],defaultActions:{8:[2,1],10:[2,3],21:[2,2],72:[2,28],73:[2,20]},parseError:a(function(h,u){if(u.recoverable)this.trace(h);else{var x=new Error(h);throw x.hash=u,x}},"parseError"),parse:a(function(h){var u=this,x=[0],d=[],w=[null],r=[],at=this.table,f="",lt=0,It=0,hi=2,Mt=1,li=r.slice.call(arguments,1),T=Object.create(this.lexer),Y={yy:{}};for(var dt in this.yy)Object.prototype.hasOwnProperty.call(this.yy,dt)&&(Y.yy[dt]=this.yy[dt]);T.setInput(h,Y.yy),Y.yy.lexer=T,Y.yy.parser=this,typeof T.yylloc>"u"&&(T.yylloc={});var ft=T.yylloc;r.push(ft);var ci=T.options&&T.options.ranges;typeof Y.yy.parseError=="function"?this.parseError=Y.yy.parseError:this.parseError=Object.getPrototypeOf(this).parseError;function ui(V){x.length=x.length-2*V,w.length=w.length-V,r.length=r.length-V}a(ui,"popStack");function Vt(){var V;return V=d.pop()||T.lex()||Mt,typeof V!="number"&&(V instanceof Array&&(d=V,V=d.pop()),V=u.symbols_[V]||V),V}a(Vt,"lex");for(var M,H,B,pt,q={},ct,O,Bt,ut;;){if(H=x[x.length-1],this.defaultActions[H]?B=this.defaultActions[H]:((M===null||typeof M>"u")&&(M=Vt()),B=at[H]&&at[H][M]),typeof B>"u"||!B.length||!B[0]){var mt="";ut=[];for(ct in at[H])this.terminals_[ct]&&ct>hi&&ut.push("'"+this.terminals_[ct]+"'");T.showPosition?mt="Parse error on line "+(lt+1)+`:
|
|
2
2
|
`+T.showPosition()+`
|
|
3
3
|
Expecting `+ut.join(", ")+", got '"+(this.terminals_[M]||M)+"'":mt="Parse error on line "+(lt+1)+": Unexpected "+(M==Mt?"end of input":"'"+(this.terminals_[M]||M)+"'"),this.parseError(mt,{text:T.match,token:this.terminals_[M]||M,line:T.yylineno,loc:ft,expected:ut})}if(B[0]instanceof Array&&B.length>1)throw new Error("Parse Error: multiple actions possible at state: "+H+", token: "+M);switch(B[0]){case 1:x.push(M),w.push(T.yytext),r.push(T.yylloc),x.push(B[1]),M=null,It=T.yyleng,f=T.yytext,lt=T.yylineno,ft=T.yylloc;break;case 2:if(O=this.productions_[B[1]][1],q.$=w[w.length-O],q._$={first_line:r[r.length-(O||1)].first_line,last_line:r[r.length-1].last_line,first_column:r[r.length-(O||1)].first_column,last_column:r[r.length-1].last_column},ci&&(q._$.range=[r[r.length-(O||1)].range[0],r[r.length-1].range[1]]),pt=this.performAction.apply(q,[f,It,lt,Y.yy,B[1],w,r].concat(li)),typeof pt<"u")return pt;O&&(x=x.slice(0,-1*O*2),w=w.slice(0,-1*O),r=r.slice(0,-1*O)),x.push(this.productions_[B[1]][0]),w.push(q.$),r.push(q._$),Bt=at[x[x.length-2]][x[x.length-1]],x.push(Bt);break;case 3:return!0}}return!0},"parse")},Et=(function(){var F={EOF:1,parseError:a(function(u,x){if(this.yy.parser)this.yy.parser.parseError(u,x);else throw new Error(u)},"parseError"),setInput:a(function(h,u){return this.yy=u||this.yy||{},this._input=h,this._more=this._backtrack=this.done=!1,this.yylineno=this.yyleng=0,this.yytext=this.matched=this.match="",this.conditionStack=["INITIAL"],this.yylloc={first_line:1,first_column:0,last_line:1,last_column:0},this.options.ranges&&(this.yylloc.range=[0,0]),this.offset=0,this},"setInput"),input:a(function(){var h=this._input[0];this.yytext+=h,this.yyleng++,this.offset++,this.match+=h,this.matched+=h;var u=h.match(/(?:\r\n?|\n).*/g);return u?(this.yylineno++,this.yylloc.last_line++):this.yylloc.last_column++,this.options.ranges&&this.yylloc.range[1]++,this._input=this._input.slice(1),h},"input"),unput:a(function(h){var u=h.length,x=h.split(/(?:\r\n?|\n)/g);this._input=h+this._input,this.yytext=this.yytext.substr(0,this.yytext.length-u),this.offset-=u;var d=this.match.split(/(?:\r\n?|\n)/g);this.match=this.match.substr(0,this.match.length-1),this.matched=this.matched.substr(0,this.matched.length-1),x.length-1&&(this.yylineno-=x.length-1);var w=this.yylloc.range;return this.yylloc={first_line:this.yylloc.first_line,last_line:this.yylineno+1,first_column:this.yylloc.first_column,last_column:x?(x.length===d.length?this.yylloc.first_column:0)+d[d.length-x.length].length-x[0].length:this.yylloc.first_column-u},this.options.ranges&&(this.yylloc.range=[w[0],w[0]+this.yyleng-u]),this.yyleng=this.yytext.length,this},"unput"),more:a(function(){return this._more=!0,this},"more"),reject:a(function(){if(this.options.backtrack_lexer)this._backtrack=!0;else return this.parseError("Lexical error on line "+(this.yylineno+1)+`. You can only invoke reject() in the lexer when the lexer is of the backtracking persuasion (options.backtrack_lexer = true).
|
|
4
4
|
`+this.showPosition(),{text:"",token:null,line:this.yylineno});return this},"reject"),less:a(function(h){this.unput(this.match.slice(h))},"less"),pastInput:a(function(){var h=this.matched.substr(0,this.matched.length-this.match.length);return(h.length>20?"...":"")+h.substr(-20).replace(/\n/g,"")},"pastInput"),upcomingInput:a(function(){var h=this.match;return h.length<20&&(h+=this._input.substr(0,20-h.length)),(h.substr(0,20)+(h.length>20?"...":"")).replace(/\n/g,"")},"upcomingInput"),showPosition:a(function(){var h=this.pastInput(),u=new Array(h.length+1).join("-");return h+this.upcomingInput()+`
|
package/dist/index.html
CHANGED
|
@@ -5,15 +5,10 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.ico" />
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
7
|
<title>Orcheo</title>
|
|
8
|
-
<script type="module" crossorigin src="/assets/index-
|
|
9
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
8
|
+
<script type="module" crossorigin src="/assets/index-DLYzf0K-.js"></script>
|
|
9
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DebsXgfj.css">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|
|
13
|
-
<script
|
|
14
|
-
async
|
|
15
|
-
src="%VITE_ORCHEO_BACKEND_URL%/api/chatkit/assets/chatkit.js"
|
|
16
|
-
crossorigin="anonymous"
|
|
17
|
-
></script>
|
|
18
13
|
</body>
|
|
19
14
|
</html>
|
package/index.html
CHANGED
package/package.json
CHANGED
package/src/App.tsx
CHANGED
|
@@ -2,6 +2,7 @@ import { useLayoutEffect } from "react";
|
|
|
2
2
|
import {
|
|
3
3
|
BrowserRouter as Router,
|
|
4
4
|
Navigate,
|
|
5
|
+
Outlet,
|
|
5
6
|
Route,
|
|
6
7
|
Routes,
|
|
7
8
|
useParams,
|
|
@@ -22,6 +23,7 @@ import {
|
|
|
22
23
|
setSelectedWorkspaceSlug,
|
|
23
24
|
} from "@/lib/workspace-session";
|
|
24
25
|
import { getWorkspaceGalleryPath } from "@/lib/workspace-routing";
|
|
26
|
+
import { WorkspaceBootstrapGate } from "@features/shared/components/workspace-bootstrap-gate";
|
|
25
27
|
|
|
26
28
|
const syncWorkspaceSlug = (workspaceSlug?: string) => {
|
|
27
29
|
if (!workspaceSlug) {
|
|
@@ -56,9 +58,18 @@ function WorkspaceManagementRoute() {
|
|
|
56
58
|
return <WorkspaceManagement />;
|
|
57
59
|
}
|
|
58
60
|
|
|
61
|
+
function RequireWorkspace() {
|
|
62
|
+
return (
|
|
63
|
+
<WorkspaceBootstrapGate>
|
|
64
|
+
<Outlet />
|
|
65
|
+
</WorkspaceBootstrapGate>
|
|
66
|
+
);
|
|
67
|
+
}
|
|
68
|
+
|
|
59
69
|
function WorkspaceWorkflowRoute() {
|
|
60
70
|
const { workspaceSlug, workflowId } = useParams<{
|
|
61
71
|
workspaceSlug?: string;
|
|
72
|
+
teamSlug?: string;
|
|
62
73
|
workflowId?: string;
|
|
63
74
|
}>();
|
|
64
75
|
useLayoutEffect(() => {
|
|
@@ -81,8 +92,12 @@ export default function OrcheoStudioApp() {
|
|
|
81
92
|
|
|
82
93
|
<Route path="/auth/callback" element={<OAuthCallback />} />
|
|
83
94
|
<Route path="/chat/:workflowId" element={<PublicChatPage />} />
|
|
95
|
+
<Route path="/chat/team/:teamSlug/:workflowId" element={<PublicChatPage />} />
|
|
96
|
+
<Route path="/chat/:workspaceSlug/:workflowId" element={<PublicChatPage />} />
|
|
97
|
+
<Route path="/chat/:workspaceSlug/team/:teamSlug/:workflowId" element={<PublicChatPage />} />
|
|
84
98
|
|
|
85
99
|
<Route element={<RequireAuth />}>
|
|
100
|
+
<Route element={<RequireWorkspace />}>
|
|
86
101
|
<Route path="/" element={<WorkspaceHomeRedirect />} />
|
|
87
102
|
<Route
|
|
88
103
|
path="/:workspaceSlug"
|
|
@@ -98,6 +113,10 @@ export default function OrcheoStudioApp() {
|
|
|
98
113
|
path="/:workspaceSlug/new"
|
|
99
114
|
element={<WorkspaceWorkflowRoute />}
|
|
100
115
|
/>
|
|
116
|
+
<Route
|
|
117
|
+
path="/:workspaceSlug/team/:teamSlug/:workflowId"
|
|
118
|
+
element={<WorkspaceWorkflowRoute />}
|
|
119
|
+
/>
|
|
101
120
|
<Route
|
|
102
121
|
path="/:workspaceSlug/:workflowId"
|
|
103
122
|
element={<WorkspaceWorkflowRoute />}
|
|
@@ -106,6 +125,7 @@ export default function OrcheoStudioApp() {
|
|
|
106
125
|
<Route path="/profile" element={<Profile />} />
|
|
107
126
|
|
|
108
127
|
<Route path="/settings" element={<Settings />} />
|
|
128
|
+
</Route>
|
|
109
129
|
</Route>
|
|
110
130
|
</Routes>
|
|
111
131
|
<Toaster />
|
|
@@ -34,7 +34,11 @@ const sanitizeWorkflowNameForEmail = (value: string): string =>
|
|
|
34
34
|
.trim();
|
|
35
35
|
|
|
36
36
|
export default function PublicChatPage() {
|
|
37
|
-
const { workflowId } = useParams<{
|
|
37
|
+
const { workflowId, workspaceSlug, teamSlug } = useParams<{
|
|
38
|
+
workflowId: string;
|
|
39
|
+
workspaceSlug?: string;
|
|
40
|
+
teamSlug?: string;
|
|
41
|
+
}>();
|
|
38
42
|
const location = useLocation();
|
|
39
43
|
const [workflowState, setWorkflowState] = useState<WorkflowState>({
|
|
40
44
|
status: workflowId ? "loading" : "error",
|
|
@@ -67,7 +71,7 @@ export default function PublicChatPage() {
|
|
|
67
71
|
let cancelled = false;
|
|
68
72
|
setWorkflowState({ status: "loading" });
|
|
69
73
|
|
|
70
|
-
fetchPublicWorkflow(workflowId)
|
|
74
|
+
fetchPublicWorkflow(workflowId, { workspaceSlug, teamSlug })
|
|
71
75
|
.then((workflow) => {
|
|
72
76
|
if (cancelled) {
|
|
73
77
|
return;
|
|
@@ -118,7 +122,7 @@ export default function PublicChatPage() {
|
|
|
118
122
|
return () => {
|
|
119
123
|
cancelled = true;
|
|
120
124
|
};
|
|
121
|
-
}, [workflowId]);
|
|
125
|
+
}, [workflowId, workspaceSlug, teamSlug]);
|
|
122
126
|
|
|
123
127
|
const contactHref = useMemo(() => {
|
|
124
128
|
if (workflowState.status !== "ready") {
|
|
@@ -132,6 +132,11 @@ export const getCandidateBadgeDefinition = (
|
|
|
132
132
|
): CandidateBadgeDefinition | undefined =>
|
|
133
133
|
candidateBadges.find((badge) => badge.workflow.id === workflowId);
|
|
134
134
|
|
|
135
|
+
export const getCandidateBadgeByHandle = (
|
|
136
|
+
handle: string,
|
|
137
|
+
): CandidateBadgeDefinition | undefined =>
|
|
138
|
+
candidateBadges.find((badge) => badge.handle === handle);
|
|
139
|
+
|
|
135
140
|
export const getCandidateTemplateDefinition = (
|
|
136
141
|
templateId: string,
|
|
137
142
|
): WorkflowTemplateDefinition | undefined =>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { authFetch } from "@/lib/auth-fetch";
|
|
2
2
|
import { buildBackendHttpUrl, getBackendBaseUrl } from "@/lib/config";
|
|
3
3
|
import type {
|
|
4
|
+
ApiTeam,
|
|
4
5
|
ApiWorkflow,
|
|
5
6
|
ApiWorkflowPagePayload,
|
|
6
7
|
ApiWorkflowRun,
|
|
@@ -105,11 +106,19 @@ export const fetchWorkflowPageData = async (
|
|
|
105
106
|
|
|
106
107
|
export const fetchPublicWorkflow = async (
|
|
107
108
|
workflowId: string,
|
|
109
|
+
context?: { workspaceSlug?: string; teamSlug?: string },
|
|
108
110
|
): Promise<PublicWorkflowMetadata | undefined> => {
|
|
109
111
|
try {
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
112
|
+
const params = new URLSearchParams();
|
|
113
|
+
if (context?.workspaceSlug) {
|
|
114
|
+
params.set("workspace_slug", context.workspaceSlug);
|
|
115
|
+
}
|
|
116
|
+
if (context?.teamSlug) {
|
|
117
|
+
params.set("team_slug", context.teamSlug);
|
|
118
|
+
}
|
|
119
|
+
const queryString = params.toString();
|
|
120
|
+
const url = `${PUBLIC_WORKFLOW_PATH}/${workflowId}/public${queryString ? `?${queryString}` : ""}`;
|
|
121
|
+
return await request<PublicWorkflowMetadata>(url);
|
|
113
122
|
} catch (error) {
|
|
114
123
|
if (
|
|
115
124
|
error instanceof ApiRequestError &&
|
|
@@ -175,12 +184,34 @@ export interface ApiCandidate {
|
|
|
175
184
|
export const fetchCandidates = async (): Promise<ApiCandidate[]> =>
|
|
176
185
|
request<ApiCandidate[]>("/api/candidates");
|
|
177
186
|
|
|
187
|
+
export const fetchTeams = async (): Promise<ApiTeam[]> =>
|
|
188
|
+
request<ApiTeam[]>("/api/teams");
|
|
189
|
+
|
|
190
|
+
export const createTeam = async (input: {
|
|
191
|
+
name: string;
|
|
192
|
+
slug: string;
|
|
193
|
+
}): Promise<ApiTeam> =>
|
|
194
|
+
request<ApiTeam>("/api/teams", {
|
|
195
|
+
method: "POST",
|
|
196
|
+
body: JSON.stringify(input),
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
export const deleteTeam = async (teamId: string): Promise<void> =>
|
|
200
|
+
request<void>(`/api/teams/${teamId}`, {
|
|
201
|
+
method: "DELETE",
|
|
202
|
+
expectJson: false,
|
|
203
|
+
});
|
|
204
|
+
|
|
178
205
|
export const onboardCandidate = async (
|
|
179
206
|
candidateId: string,
|
|
207
|
+
teamId?: string,
|
|
180
208
|
): Promise<ApiWorkflow> =>
|
|
181
209
|
request<ApiWorkflow>("/api/candidates/onboard", {
|
|
182
210
|
method: "POST",
|
|
183
|
-
body: JSON.stringify({
|
|
211
|
+
body: JSON.stringify({
|
|
212
|
+
id: candidateId,
|
|
213
|
+
...(teamId ? { team_id: teamId } : {}),
|
|
214
|
+
}),
|
|
184
215
|
});
|
|
185
216
|
|
|
186
217
|
export const fetchWorkflowListeners = async (
|
|
@@ -135,9 +135,15 @@ export const toFlowEdges = (edges: WorkflowEdge[]): FlowEdge[] =>
|
|
|
135
135
|
|
|
136
136
|
export const getWorkflowRouteRef = (
|
|
137
137
|
workflow:
|
|
138
|
-
| Pick<ApiWorkflow, "id" | "handle">
|
|
139
|
-
| Pick<Workflow, "id" | "handle">,
|
|
140
|
-
): string =>
|
|
138
|
+
| Pick<ApiWorkflow, "id" | "handle" | "team_id">
|
|
139
|
+
| Pick<Workflow, "id" | "handle" | "teamId">,
|
|
140
|
+
): string => {
|
|
141
|
+
const teamId = "team_id" in workflow ? workflow.team_id : workflow.teamId;
|
|
142
|
+
if (teamId) {
|
|
143
|
+
return workflow.id;
|
|
144
|
+
}
|
|
145
|
+
return workflow.handle ?? workflow.id;
|
|
146
|
+
};
|
|
141
147
|
|
|
142
148
|
export const resolveWorkflowVersionMermaidSource = (
|
|
143
149
|
version:
|
|
@@ -351,6 +357,7 @@ export const toStoredWorkflow = (
|
|
|
351
357
|
return {
|
|
352
358
|
id: workflow.id,
|
|
353
359
|
handle: workflow.handle ?? undefined,
|
|
360
|
+
teamId: workflow.team_id ?? undefined,
|
|
354
361
|
name: workflow.name,
|
|
355
362
|
description: workflow.description ?? undefined,
|
|
356
363
|
avatarEmoji,
|
|
@@ -458,8 +458,9 @@ export const deleteWorkflow = async (
|
|
|
458
458
|
|
|
459
459
|
export const onboardCandidateAsWorkflow = async (
|
|
460
460
|
candidateId: string,
|
|
461
|
+
teamId?: string,
|
|
461
462
|
): Promise<StoredWorkflow> => {
|
|
462
|
-
const apiWorkflow = await onboardCandidate(candidateId);
|
|
463
|
+
const apiWorkflow = await onboardCandidate(candidateId, teamId);
|
|
463
464
|
invalidateWorkflowCache(apiWorkflow.id);
|
|
464
465
|
const stored = await ensureWorkflow(apiWorkflow.id);
|
|
465
466
|
if (!stored) {
|
|
@@ -6,9 +6,17 @@ import type {
|
|
|
6
6
|
import type { WorkflowDiffResult, WorkflowSnapshot } from "./workflow-diff";
|
|
7
7
|
import type { RJSFSchema } from "@rjsf/utils";
|
|
8
8
|
|
|
9
|
+
export interface ApiTeam {
|
|
10
|
+
id: string;
|
|
11
|
+
slug: string;
|
|
12
|
+
name: string;
|
|
13
|
+
is_default: boolean;
|
|
14
|
+
}
|
|
15
|
+
|
|
9
16
|
export interface ApiWorkflow {
|
|
10
17
|
id: string;
|
|
11
18
|
handle?: string | null;
|
|
19
|
+
team_id?: string | null;
|
|
12
20
|
name: string;
|
|
13
21
|
slug: string;
|
|
14
22
|
description: string | null;
|
|
@@ -237,6 +245,7 @@ export interface WorkflowVersionRecord {
|
|
|
237
245
|
|
|
238
246
|
export interface StoredWorkflow extends Workflow {
|
|
239
247
|
versions: WorkflowVersionRecord[];
|
|
248
|
+
teamId?: string | null;
|
|
240
249
|
draftAccess?: "personal" | "authenticated" | "workspace";
|
|
241
250
|
isArchived?: boolean;
|
|
242
251
|
isPublic?: boolean;
|
|
@@ -29,73 +29,17 @@ const baseWorkflowConfigSchema: RJSFSchema = {
|
|
|
29
29
|
additionalProperties: true,
|
|
30
30
|
default: {},
|
|
31
31
|
},
|
|
32
|
-
run_name: {
|
|
33
|
-
type: "string",
|
|
34
|
-
title: "Run name",
|
|
35
|
-
},
|
|
36
|
-
tags: {
|
|
37
|
-
type: "array",
|
|
38
|
-
title: "Tags",
|
|
39
|
-
items: {
|
|
40
|
-
type: "string",
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
metadata: {
|
|
44
|
-
type: "object",
|
|
45
|
-
title: "Metadata",
|
|
46
|
-
additionalProperties: true,
|
|
47
|
-
default: {},
|
|
48
|
-
},
|
|
49
|
-
callbacks: {
|
|
50
|
-
type: "array",
|
|
51
|
-
title: "Callbacks",
|
|
52
|
-
items: {
|
|
53
|
-
type: ["object", "array", "string", "number", "integer", "boolean"],
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
32
|
recursion_limit: {
|
|
57
33
|
type: "integer",
|
|
58
34
|
title: "Recursion limit",
|
|
59
35
|
minimum: 1,
|
|
36
|
+
description: "Maximum graph recursion depth allowed for this run.",
|
|
60
37
|
},
|
|
61
38
|
max_concurrency: {
|
|
62
39
|
type: "integer",
|
|
63
40
|
title: "Max concurrency",
|
|
64
41
|
minimum: 1,
|
|
65
|
-
|
|
66
|
-
prompts: {
|
|
67
|
-
type: "object",
|
|
68
|
-
title: "Prompts",
|
|
69
|
-
additionalProperties: {
|
|
70
|
-
type: "object",
|
|
71
|
-
properties: {
|
|
72
|
-
template: {
|
|
73
|
-
type: "string",
|
|
74
|
-
title: "Template",
|
|
75
|
-
},
|
|
76
|
-
input_variables: {
|
|
77
|
-
type: "array",
|
|
78
|
-
title: "Input variables",
|
|
79
|
-
items: {
|
|
80
|
-
type: "string",
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
optional_variables: {
|
|
84
|
-
type: "array",
|
|
85
|
-
title: "Optional variables",
|
|
86
|
-
items: {
|
|
87
|
-
type: "string",
|
|
88
|
-
},
|
|
89
|
-
},
|
|
90
|
-
partial_variables: {
|
|
91
|
-
type: "object",
|
|
92
|
-
title: "Partial variables",
|
|
93
|
-
additionalProperties: true,
|
|
94
|
-
},
|
|
95
|
-
},
|
|
96
|
-
required: ["template", "input_variables"],
|
|
97
|
-
},
|
|
98
|
-
default: {},
|
|
42
|
+
description: "Maximum number of concurrent tasks allowed for this run.",
|
|
99
43
|
},
|
|
100
44
|
},
|
|
101
45
|
};
|
|
@@ -106,14 +50,6 @@ const workflowConfigUiSchema: UiSchema = {
|
|
|
106
50
|
"ui:field": "jsonObject",
|
|
107
51
|
},
|
|
108
52
|
},
|
|
109
|
-
run_name: {
|
|
110
|
-
"ui:placeholder": "Optional run label",
|
|
111
|
-
},
|
|
112
|
-
tags: {
|
|
113
|
-
"ui:options": {
|
|
114
|
-
orderable: false,
|
|
115
|
-
},
|
|
116
|
-
},
|
|
117
53
|
};
|
|
118
54
|
|
|
119
55
|
interface WorkflowConfigSheetProps {
|
|
@@ -208,37 +208,6 @@ export const toWorkflowConfig = (
|
|
|
208
208
|
next.configurable = formData.configurable;
|
|
209
209
|
}
|
|
210
210
|
|
|
211
|
-
if (typeof formData.run_name === "string") {
|
|
212
|
-
const runName = formData.run_name.trim();
|
|
213
|
-
if (runName.length > 0) {
|
|
214
|
-
next.run_name = runName;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
if (Array.isArray(formData.tags)) {
|
|
219
|
-
const tags = formData.tags
|
|
220
|
-
.filter((item): item is string => typeof item === "string")
|
|
221
|
-
.map((item) => item.trim())
|
|
222
|
-
.filter(
|
|
223
|
-
(item, index, array) =>
|
|
224
|
-
item.length > 0 && array.indexOf(item) === index,
|
|
225
|
-
);
|
|
226
|
-
if (tags.length > 0) {
|
|
227
|
-
next.tags = tags;
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
|
|
231
|
-
if (
|
|
232
|
-
isRecord(formData.metadata) &&
|
|
233
|
-
Object.keys(formData.metadata).length > 0
|
|
234
|
-
) {
|
|
235
|
-
next.metadata = formData.metadata;
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
if (Array.isArray(formData.callbacks) && formData.callbacks.length > 0) {
|
|
239
|
-
next.callbacks = formData.callbacks;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
211
|
const recursionLimit = toPositiveInteger(formData.recursion_limit);
|
|
243
212
|
if (recursionLimit) {
|
|
244
213
|
next.recursion_limit = recursionLimit;
|
|
@@ -249,10 +218,6 @@ export const toWorkflowConfig = (
|
|
|
249
218
|
next.max_concurrency = maxConcurrency;
|
|
250
219
|
}
|
|
251
220
|
|
|
252
|
-
if (isRecord(formData.prompts) && Object.keys(formData.prompts).length > 0) {
|
|
253
|
-
next.prompts = formData.prompts;
|
|
254
|
-
}
|
|
255
|
-
|
|
256
221
|
return Object.keys(next).length > 0 ? next : null;
|
|
257
222
|
};
|
|
258
223
|
|
|
@@ -265,11 +230,6 @@ export const toFormData = (
|
|
|
265
230
|
config: WorkflowRunnableConfig | null,
|
|
266
231
|
): Record<string, unknown> => ({
|
|
267
232
|
configurable: config?.configurable ?? {},
|
|
268
|
-
run_name: config?.run_name ?? "",
|
|
269
|
-
tags: config?.tags ?? [],
|
|
270
|
-
metadata: config?.metadata ?? {},
|
|
271
|
-
callbacks: config?.callbacks ?? [],
|
|
272
233
|
recursion_limit: config?.recursion_limit,
|
|
273
234
|
max_concurrency: config?.max_concurrency,
|
|
274
|
-
prompts: config?.prompts ?? {},
|
|
275
235
|
});
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { useEffect, useState } from "react";
|
|
2
|
+
import { Button } from "@/design-system/ui/button";
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogContent,
|
|
6
|
+
DialogDescription,
|
|
7
|
+
DialogFooter,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
} from "@/design-system/ui/dialog";
|
|
11
|
+
import { Input } from "@/design-system/ui/input";
|
|
12
|
+
import { Label } from "@/design-system/ui/label";
|
|
13
|
+
|
|
14
|
+
interface CreateTeamDialogProps {
|
|
15
|
+
open: boolean;
|
|
16
|
+
onOpenChange: (open: boolean) => void;
|
|
17
|
+
onCreate: (name: string, slug: string) => Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
const toSlug = (name: string): string =>
|
|
21
|
+
name
|
|
22
|
+
.trim()
|
|
23
|
+
.toLowerCase()
|
|
24
|
+
.replace(/[^a-z0-9_-]+/g, "-")
|
|
25
|
+
.replace(/^-+|-+$/g, "");
|
|
26
|
+
|
|
27
|
+
export const CreateTeamDialog = ({
|
|
28
|
+
open,
|
|
29
|
+
onOpenChange,
|
|
30
|
+
onCreate,
|
|
31
|
+
}: CreateTeamDialogProps) => {
|
|
32
|
+
const [name, setName] = useState("");
|
|
33
|
+
const [slug, setSlug] = useState("");
|
|
34
|
+
const [slugDirty, setSlugDirty] = useState(false);
|
|
35
|
+
const [error, setError] = useState<string | null>(null);
|
|
36
|
+
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
37
|
+
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
if (!open) {
|
|
40
|
+
setName("");
|
|
41
|
+
setSlug("");
|
|
42
|
+
setSlugDirty(false);
|
|
43
|
+
setError(null);
|
|
44
|
+
setIsSubmitting(false);
|
|
45
|
+
}
|
|
46
|
+
}, [open]);
|
|
47
|
+
|
|
48
|
+
const handleNameChange = (value: string) => {
|
|
49
|
+
setName(value);
|
|
50
|
+
if (!slugDirty) {
|
|
51
|
+
setSlug(toSlug(value));
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const handleSlugChange = (value: string) => {
|
|
56
|
+
setSlugDirty(true);
|
|
57
|
+
setSlug(value.toLowerCase().replace(/[^a-z0-9_-]/g, ""));
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
const handleSubmit = async () => {
|
|
61
|
+
const trimmedName = name.trim();
|
|
62
|
+
const trimmedSlug = slug.trim();
|
|
63
|
+
if (!trimmedName || !trimmedSlug) {
|
|
64
|
+
setError("Both name and slug are required.");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
setError(null);
|
|
68
|
+
setIsSubmitting(true);
|
|
69
|
+
try {
|
|
70
|
+
await onCreate(trimmedName, trimmedSlug);
|
|
71
|
+
onOpenChange(false);
|
|
72
|
+
} catch (err) {
|
|
73
|
+
setError(
|
|
74
|
+
err instanceof Error ? err.message : "Failed to create team.",
|
|
75
|
+
);
|
|
76
|
+
} finally {
|
|
77
|
+
setIsSubmitting(false);
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<Dialog open={open} onOpenChange={onOpenChange}>
|
|
83
|
+
<DialogContent>
|
|
84
|
+
<DialogHeader>
|
|
85
|
+
<DialogTitle>New team</DialogTitle>
|
|
86
|
+
<DialogDescription>
|
|
87
|
+
Create a team to group colleagues under a shared label.
|
|
88
|
+
</DialogDescription>
|
|
89
|
+
</DialogHeader>
|
|
90
|
+
|
|
91
|
+
<div className="flex flex-col gap-4 py-2">
|
|
92
|
+
<div className="flex flex-col gap-1.5">
|
|
93
|
+
<Label htmlFor="team-name">Name</Label>
|
|
94
|
+
<Input
|
|
95
|
+
id="team-name"
|
|
96
|
+
placeholder="e.g. Sales"
|
|
97
|
+
value={name}
|
|
98
|
+
onChange={(e) => handleNameChange(e.target.value)}
|
|
99
|
+
onKeyDown={(e) => {
|
|
100
|
+
if (e.key === "Enter") void handleSubmit();
|
|
101
|
+
}}
|
|
102
|
+
autoFocus
|
|
103
|
+
/>
|
|
104
|
+
</div>
|
|
105
|
+
<div className="flex flex-col gap-1.5">
|
|
106
|
+
<Label htmlFor="team-slug">Slug</Label>
|
|
107
|
+
<Input
|
|
108
|
+
id="team-slug"
|
|
109
|
+
placeholder="e.g. sales"
|
|
110
|
+
value={slug}
|
|
111
|
+
onChange={(e) => handleSlugChange(e.target.value)}
|
|
112
|
+
onKeyDown={(e) => {
|
|
113
|
+
if (e.key === "Enter") void handleSubmit();
|
|
114
|
+
}}
|
|
115
|
+
/>
|
|
116
|
+
<p className="text-xs text-muted-foreground">
|
|
117
|
+
Used in API references. Lowercase letters, numbers, hyphens, and
|
|
118
|
+
underscores only.
|
|
119
|
+
</p>
|
|
120
|
+
</div>
|
|
121
|
+
{error ? (
|
|
122
|
+
<p className="text-sm text-destructive">{error}</p>
|
|
123
|
+
) : null}
|
|
124
|
+
</div>
|
|
125
|
+
|
|
126
|
+
<DialogFooter>
|
|
127
|
+
<Button variant="outline" onClick={() => onOpenChange(false)}>
|
|
128
|
+
Cancel
|
|
129
|
+
</Button>
|
|
130
|
+
<Button onClick={() => void handleSubmit()} disabled={isSubmitting}>
|
|
131
|
+
{isSubmitting ? "Creating…" : "Create team"}
|
|
132
|
+
</Button>
|
|
133
|
+
</DialogFooter>
|
|
134
|
+
</DialogContent>
|
|
135
|
+
</Dialog>
|
|
136
|
+
);
|
|
137
|
+
};
|