@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-06b7d4e → 0.0.2-dev-b0a6833

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.
@@ -0,0 +1,2 @@
1
+ "use strict";(self.webpackChunkinternal_plugin_kuadrant=self.webpackChunkinternal_plugin_kuadrant||[]).push([[532],{63221:(e,a,t)=>{t.d(a,{K:()=>v});var s=t(31085),l=t(95478),n=t(76891),r=t(61477),i=t(10394),o=t(46805),d=t(59461),c=t(72501),u=t(16249),p=t(93453),m=t(64947),h=t(78467),x=t(77225);const v=({open:e,title:a,description:t,confirmText:v,severity:A="normal",deleting:g=!1,onConfirm:j,onCancel:f})=>{const[y,b]=(0,l.useState)("");(0,l.useEffect)(()=>{e||b("")},[e]);const P="high"===A&&v,S=!P||y===v;return(0,s.jsxs)(n.A,{open:e,onClose:g?void 0:f,maxWidth:"sm",fullWidth:!0,children:[(0,s.jsxs)(r.A,{children:["high"===A&&(0,s.jsxs)(i.A,{display:"flex",alignItems:"center",style:{gap:8},children:[(0,s.jsx)(x.A,{color:"error"}),(0,s.jsx)("span",{children:a})]}),"high"!==A&&a]}),(0,s.jsxs)(o.A,{children:[(0,s.jsx)(d.A,{style:{whiteSpace:"pre-line"},children:t}),P&&(0,s.jsxs)(i.A,{mt:2,children:[(0,s.jsxs)(c.A,{variant:"body2",color:"textSecondary",gutterBottom:!0,children:["Type ",(0,s.jsx)("strong",{children:v})," to confirm:"]}),(0,s.jsx)(u.A,{fullWidth:!0,variant:"outlined",size:"small",value:y,onChange:e=>b(e.target.value),disabled:g,autoFocus:!0,placeholder:v})]})]}),(0,s.jsxs)(p.A,{children:[(0,s.jsx)(m.A,{onClick:f,disabled:g,children:"Cancel"}),(0,s.jsx)(m.A,{onClick:()=>{S&&j()},color:"secondary",variant:"contained",disabled:g||!S,startIcon:g?(0,s.jsx)(h.A,{size:16,color:"inherit"}):void 0,children:g?"Deleting...":"Delete"})]})]})}},80532:(e,a,t)=>{t.r(a),t.d(a,{KuadrantPage:()=>se});var s=t(31085),l=t(95478),n=t.n(l),r=t(67720),i=t(10394),o=t(29365),d=t(72501),c=t(42899),u=t(64947),p=t(18466),m=t(39590),h=t(75625),x=t(37725),v=t(25010),A=t(289),g=t(55639),j=t(45210),f=t(46681),y=t(86687),b=t(42367),P=t(96040),S=t(91638),w=t(22097),k=t(16281),C=t(71677),T=t(78467),R=t(31653),I=t(38605),$=t(37757),q=t(26343),W=t(32269),E=t(61524),M=t(71407),N=t(84189),D=t(63221);const z=()=>{var e,a;const t=(0,w.useApi)(w.configApiRef),n=(0,w.useApi)(w.fetchApiRef),c=(0,w.useApi)(w.identityApiRef),u=(0,w.useApi)(w.alertApiRef),p=t.getString("backend.baseUrl"),[m,h]=(0,l.useState)(0),[,A]=(0,l.useState)(""),[g,j]=(0,l.useState)(new Set),[f,b]=(0,l.useState)(null),[k,z]=(0,l.useState)(null),[L,K]=(0,l.useState)({open:!1,request:null,plans:[]}),[U,B]=(0,l.useState)(0),[H,F]=(0,l.useState)(null),[O,_]=(0,l.useState)({open:!1,request:null}),[V,Y]=(0,l.useState)(new Map),[J,X]=(0,l.useState)(new Set);(0,S.A)(async()=>{const e=await c.getBackstageIdentity(),a=e.userEntityRef.split("/")[1]||"guest";console.log(`MyApiKeysCard: setting userId from userEntityRef: ${e.userEntityRef} -> "${a}"`),A(a)},[c]);const[G,Q]=(0,l.useState)(new Set),{value:Z,loading:ee,error:ae}=(0,S.A)(async()=>{const e=await n.fetch(`${p}/api/kuadrant/requests/my`);if(!e.ok)throw new Error("failed to fetch requests");return(await e.json()).items||[]},[p,n,U]);if(ee)return(0,s.jsx)(P.n,{title:"My API Keys",children:(0,s.jsx)(y.k,{})});if(ae)return(0,s.jsx)(P.n,{title:"My API Keys",children:(0,s.jsxs)(d.A,{color:"error",children:["Error loading API keys: ",ae.message]})});const te=(Z||[]).filter(e=>!G.has(e.metadata.name)),se=te.filter(e=>{var a;return"Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)}),le=te.filter(e=>{var a;return!(null===(a=e.status)||void 0===a?void 0:a.phase)||"Pending"===e.status.phase}),ne=te.filter(e=>{var a;return"Rejected"===(null===(a=e.status)||void 0===a?void 0:a.phase)}),re=e=>{j(a=>{const t=new Set(a);return t.has(e)?t.delete(e):t.add(e),t})},ie=()=>{b(null),z(null)},oe=async()=>{if(!k)return;const e=k;ie();try{var a;const s=null===(a=e.spec.apiProductRef)||void 0===a?void 0:a.name,l=e.metadata.namespace,r=await n.fetch(`${p}/api/kuadrant/apiproducts/${l}/${s}`);if(r.ok){var t;const a=(null===(t=(await r.json()).spec)||void 0===t?void 0:t.plans)||[];K({open:!0,request:e,plans:a})}else console.error("Failed to fetch API product"),K({open:!0,request:e,plans:[]})}catch(a){console.error("Error fetching plans:",a),K({open:!0,request:e,plans:[]})}},de=()=>{if(!k)return;const e=k;ie(),_({open:!0,request:e})},ce=[{title:"API Product",field:"spec.apiProductRef.name",render:e=>{var a;const t=(null===(a=e.spec.apiProductRef)||void 0===a?void 0:a.name)||"unknown";return(0,s.jsx)(x.N_,{to:`/catalog/default/api/${t}/api-keys`,children:(0,s.jsx)("strong",{children:t})})}},{title:"Tier",field:"spec.planTier",render:e=>{const a="gold"===e.spec.planTier?"primary":"silver"===e.spec.planTier?"default":"secondary";return(0,s.jsx)(r.A,{label:e.spec.planTier,color:a,size:"small"})}},{title:"Use Case",field:"spec.useCase",render:e=>e.spec.useCase?(0,s.jsx)(C.Ay,{title:e.spec.useCase,placement:"top",children:(0,s.jsx)(d.A,{variant:"body2",style:{maxWidth:"200px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.spec.useCase})}):(0,s.jsx)(d.A,{variant:"body2",children:"-"})},{title:"Status",field:"status.phase",render:e=>{var a;const t=(null===(a=e.status)||void 0===a?void 0:a.phase)||"Pending",l="Approved"===t?"primary":"Rejected"===t?"secondary":"default";return(0,s.jsx)(r.A,{label:t,color:l,size:"small"})}},{title:"Reviewed By",field:"status.reviewedBy",render:e=>{var a,t;if(("Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)||"Rejected"===(null===(t=e.status)||void 0===t?void 0:t.phase))&&e.status.reviewedBy){const a=e.status.reviewedAt?new Date(e.status.reviewedAt).toLocaleDateString():"";return(0,s.jsxs)(i.A,{children:[(0,s.jsx)(d.A,{variant:"body2",children:e.status.reviewedBy}),a&&(0,s.jsx)(d.A,{variant:"caption",color:"textSecondary",children:a})]})}return(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"-"})}},{title:"API Key",field:"status.secretRef",filtering:!1,render:e=>{var a,t,l;if("Approved"!==(null===(a=e.status)||void 0===a?void 0:a.phase))return(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"-"});const r=`${e.metadata.namespace}/${e.metadata.name}`,c=null===(l=e.status)||void 0===l||null===(t=l.secretRef)||void 0===t?void 0:t.name,u=g.has(e.metadata.name),m=J.has(r),h=V.get(r);return c?(0,s.jsxs)(i.A,{display:"flex",alignItems:"center",style:{gap:8},children:[(0,s.jsx)(i.A,{fontFamily:"monospace",fontSize:"0.875rem",children:m?"Loading...":u&&h?h:"•".repeat(20)+"..."}),(0,s.jsx)(C.Ay,{title:u?"hide key":"show key",children:(0,s.jsx)(o.A,{size:"small",onClick:()=>{u?(((e,a)=>{const t=`${e}/${a}`;Y(e=>{const a=new Map(e);return a.delete(t),a})})(e.metadata.namespace,e.metadata.name),re(e.metadata.name)):((async(e,a)=>{const t=`${e}/${a}`;if(!J.has(t)){X(e=>new Set(e).add(t));try{const s=await n.fetch(`${p}/api/kuadrant/requests/${e}/${a}/secret`);if(s.ok){const e=await s.json();Y(a=>new Map(a).set(t,e.apiKey))}}catch(e){console.error("failed to fetch api key:",e)}finally{X(e=>{const a=new Set(e);return a.delete(t),a})}}})(e.metadata.namespace,e.metadata.name),re(e.metadata.name))},disabled:m,children:u?(0,s.jsx)(E.A,{fontSize:"small"}):(0,s.jsx)(W.A,{fontSize:"small"})})})]}):(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"Awaiting secret..."})}},{title:"Requested",field:"metadata.creationTimestamp",render:e=>{if(!e.metadata.creationTimestamp)return(0,s.jsx)(d.A,{variant:"body2",children:"-"});const a=new Date(e.metadata.creationTimestamp);return(0,s.jsx)(d.A,{variant:"body2",children:a.toLocaleDateString()})}},{title:"",filtering:!1,render:e=>H===e.metadata.name?(0,s.jsx)(T.A,{size:20}):(0,s.jsx)(o.A,{size:"small",onClick:a=>{a.stopPropagation();const t=a.currentTarget.getBoundingClientRect();b({top:t.bottom,left:t.left}),z(e)},"aria-controls":f?"myapikeys-menu":void 0,"aria-haspopup":"true",children:(0,s.jsx)(M.A,{})})}],ue=(()=>{switch(m){case 0:return se;case 1:return le;case 2:return ne;default:return te}})(),pe=(()=>{switch(m){case 0:return ce.filter(e=>"Reason"!==e.title);case 1:return ce.filter(e=>"Reason"!==e.title&&"Reviewed By"!==e.title&&"API Key"!==e.title);case 2:return ce.filter(e=>"API Key"!==e.title);default:return ce}})();return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(P.n,{title:"My API Keys",subheader:`${se.length} active, ${le.length} pending`,children:[(0,s.jsx)(i.A,{mb:2,children:(0,s.jsxs)(R.A,{value:m,onChange:(e,a)=>h(a),indicatorColor:"primary",textColor:"primary",children:[(0,s.jsx)(I.A,{label:`Active (${se.length})`}),(0,s.jsx)(I.A,{label:`Pending (${le.length})`}),(0,s.jsx)(I.A,{label:`Rejected (${ne.length})`})]})}),0===ue.length?(0,s.jsx)(i.A,{p:3,textAlign:"center",children:(0,s.jsxs)(d.A,{variant:"body1",color:"textSecondary",children:[0===m&&"No active API keys. Request access to an API to get started.",1===m&&"No pending requests.",2===m&&"No rejected requests."]})}):(0,s.jsx)(v.X,{options:{paging:ue.length>5,pageSize:20,search:!0,filtering:!0,debounceInterval:300,toolbar:!0,emptyRowsWhenPaging:!1},columns:pe,data:ue.map(e=>({...e,id:e.metadata.name}))})]}),(0,s.jsx)($.A,{id:"myapikeys-menu",open:Boolean(f),onClose:ie,anchorReference:"anchorPosition",anchorPosition:f||{top:0,left:0},children:k&&(()=>{const e=[];var a;return(a=k).status&&"Pending"!==a.status.phase||e.push((0,s.jsx)(q.A,{onClick:oe,children:"Edit"},"edit")),e.push((0,s.jsx)(q.A,{onClick:de,children:"Delete"},"delete")),e})()}),L.request&&(0,s.jsx)(N.n,{open:L.open,request:L.request,availablePlans:L.plans,onClose:()=>K({open:!1,request:null,plans:[]}),onSuccess:()=>{K({open:!1,request:null,plans:[]}),B(e=>e+1)}}),(0,s.jsx)(D.K,{open:O.open,title:"Delete API Key Request",description:`Are you sure you want to delete the API key request for ${(null===(a=O.request)||void 0===a||null===(e=a.spec.apiProductRef)||void 0===e?void 0:e.name)||"this API"}?`,deleting:null!==H,onConfirm:async()=>{if(!O.request)return;const e=O.request,a=e.metadata.name;Q(e=>new Set(e).add(a)),F(a);try{if(!(await n.fetch(`${p}/api/kuadrant/requests/${e.metadata.namespace}/${e.metadata.name}`,{method:"DELETE"})).ok)throw new Error("Failed to delete request");B(e=>e+1),u.post({message:"Request deleted",severity:"success",display:"transient"}),_({open:!1,request:null})}catch(e){console.error("Error deleting request:",e),Q(e=>{const t=new Set(e);return t.delete(a),t}),u.post({message:"Failed to delete request",severity:"error",display:"transient"})}finally{F(null)}},onCancel:()=>{_({open:!1,request:null})}})]})};var L=t(46205);const K=({children:e,permission:a,fallback:t,errorMessage:l})=>{const{allowed:n,loading:r,error:o}=(0,L.l)(a);return r?(0,s.jsx)(y.k,{}):o?(0,s.jsxs)(i.A,{p:4,children:[(0,s.jsxs)(d.A,{color:"error",children:["Unable to check permissions: ",o.message]}),(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"Please try again or contact your administrator"})]}):n?(0,s.jsx)(s.Fragment,{children:e}):t?(0,s.jsx)(s.Fragment,{children:t}):(0,s.jsxs)(i.A,{p:4,children:[(0,s.jsx)(d.A,{color:"textSecondary",children:l||"You don't have permission to view this page"}),(0,s.jsx)(i.A,{mt:1,children:(0,s.jsxs)(d.A,{variant:"caption",color:"textSecondary",children:["Required permission: ",a.name]})})]})};var U=t(58837),B=t(76891),H=t(61477),F=t(46805),O=t(16249),_=t(93453),V=t(84441);const Y=({selectedPolicy:e,alertSeverity:a="warning",alertMessage:t="No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.",includeTopMargin:l=!0})=>(0,s.jsx)(i.A,{mt:l?1:0,p:2,bgcolor:"#f5f5f5",borderRadius:1,border:"1px solid #e0e0e0",children:e?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(d.A,{variant:"subtitle2",gutterBottom:!0,style:{fontWeight:600},children:["Associated PlanPolicy: ",(0,s.jsx)("strong",{children:e.metadata.name})]}),e.plans&&e.plans.length>0?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(d.A,{variant:"caption",display:"block",gutterBottom:!0,color:"textSecondary",style:{marginTop:8},children:"Available Plans:"}),(0,s.jsx)(i.A,{display:"flex",flexWrap:"wrap",mt:1,style:{gap:8},children:e.plans.map((e,a)=>{var t,l,n;const i=(null===(t=e.limits)||void 0===t?void 0:t.daily)?`${e.limits.daily}/day`:(null===(l=e.limits)||void 0===l?void 0:l.monthly)?`${e.limits.monthly}/month`:(null===(n=e.limits)||void 0===n?void 0:n.yearly)?`${e.limits.yearly}/year`:"No limit";return(0,s.jsx)(r.A,{label:`${e.tier}: ${i}`,size:"small",variant:"outlined",color:"primary"},a)})}),e.plans.some(e=>e.description)&&(0,s.jsx)(i.A,{mt:1,children:e.plans.filter(e=>e.description).map((e,a)=>(0,s.jsxs)(d.A,{variant:"caption",display:"block",color:"textSecondary",children:["• ",(0,s.jsxs)("strong",{children:[e.tier,":"]})," ",e.description]},a))})]}):(0,s.jsx)(d.A,{variant:"caption",color:"textSecondary",children:"No plans defined in this PlanPolicy"})]}):(0,s.jsx)(V.A,{severity:a,children:t})}),J=e=>e?/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(e)?null:"Must be a valid email address":null,X=e=>{if(!e)return null;try{const a=new URL(e);return["http:","https:"].includes(a.protocol)?null:"Must be a valid HTTP or HTTPS URL"}catch{return"Must be a valid URL"}},G=(0,U.A)({asterisk:{color:"#f44336"}}),Q=({open:e,onClose:a,onSuccess:t})=>{const n=G(),o=(0,w.useApi)(w.configApiRef),p=(0,w.useApi)(w.fetchApiRef),m=o.getString("backend.baseUrl"),[h,x]=(0,l.useState)(""),[v,A]=(0,l.useState)(""),[g,j]=(0,l.useState)(""),[f,y]=(0,l.useState)("v1"),[b,P]=(0,l.useState)("manual"),[k,C]=(0,l.useState)("Published"),[R,I]=(0,l.useState)([]),[$,W]=(0,l.useState)(""),[E,M]=(0,l.useState)(""),[N,D]=(0,l.useState)(""),[z,L]=(0,l.useState)(""),[K,U]=(0,l.useState)(""),[Q,Z]=(0,l.useState)(""),[ee,ae]=(0,l.useState)(""),[te,se]=(0,l.useState)(!1),[le,ne]=(0,l.useState)(0),[re,ie]=(0,l.useState)(null),[oe,de]=(0,l.useState)(null),[ce,ue]=(0,l.useState)(null),[pe,me]=(0,l.useState)(null),{value:he,loading:xe,error:ve}=(0,S.A)(async()=>{const e=await p.fetch(`${m}/api/kuadrant/httproutes`);return((await e.json()).items||[]).filter(e=>{var a;return"true"===(null===(a=e.metadata.annotations)||void 0===a?void 0:a["backstage.io/expose"])})},[m,p,e,le]),{value:Ae,error:ge}=(0,S.A)(async()=>{const e=await p.fetch(`${m}/api/kuadrant/planpolicies`);return await e.json()},[m,p,e]),je=E?E.split("/"):null,fe=je?(ye=je[0],be=je[1],(null==Ae?void 0:Ae.items)?Ae.items.find(e=>{const a=e.targetRef;return"HTTPRoute"===(null==a?void 0:a.kind)&&(null==a?void 0:a.name)===be&&(!(null==a?void 0:a.namespace)||(null==a?void 0:a.namespace)===ye)}):null):null;var ye,be;(0,l.useEffect)(()=>{e&&(ie(null),de(null),ue(null),me(null))},[e]);const Pe=()=>{$.trim()&&!R.includes($.trim())&&(I([...R,$.trim()]),W(""))},Se=()=>{x(""),A(""),j(""),y("v1"),P("manual"),C("Published"),I([]),W(""),M(""),D(""),L(""),U(""),Z(""),ae(""),ie(null),de(null),ue(null),me(null),a()},we=!!(re||oe||ce||pe);return(0,s.jsxs)(B.A,{open:e,onClose:Se,maxWidth:"md",fullWidth:!0,children:[(0,s.jsx)(H.A,{children:"Create API Product"}),(0,s.jsxs)(F.A,{children:[ee&&(0,s.jsx)(V.A,{severity:"error",style:{marginBottom:16},children:ee}),ve&&(0,s.jsxs)(V.A,{severity:"error",style:{marginBottom:16},children:[(0,s.jsx)("strong",{children:"Failed to load HTTPRoutes:"})," ",ve.message,(0,s.jsx)(i.A,{mt:1,children:(0,s.jsx)(u.A,{size:"small",variant:"outlined",onClick:()=>ne(e=>e+1),children:"Retry"})})]}),ge&&(0,s.jsxs)(V.A,{severity:"warning",style:{marginBottom:16},children:[(0,s.jsx)("strong",{children:"Failed to load PlanPolicies:"})," ",ge.message,(0,s.jsx)(d.A,{variant:"body2",style:{marginTop:8},children:"You can still create the API Product, but plan information may be incomplete."})]}),(0,s.jsxs)(c.A,{container:!0,spacing:2,children:[(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Name",value:h,onChange:e=>{return a=e.target.value,x(a),void ie((e=>e&&e.trim()?e.length>253?"Must be 253 characters or less":/^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/.test(e)?null:"Must be lowercase alphanumeric with hyphens, start and end with alphanumeric":"Name is required")(a));var a},placeholder:"my-api",helperText:re||"Kubernetes resource name (lowercase, hyphens)",error:!!re,margin:"normal",required:!0,disabled:te,InputLabelProps:{classes:{asterisk:n.asterisk}}})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Display Name",value:v,onChange:e=>A(e.target.value),placeholder:"My API",margin:"normal",required:!0,disabled:te,InputLabelProps:{classes:{asterisk:n.asterisk}}})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Version",value:f,onChange:e=>y(e.target.value),placeholder:"v1",margin:"normal",disabled:te})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsxs)(O.A,{fullWidth:!0,select:!0,label:"Approval Mode",value:b,onChange:e=>P(e.target.value),margin:"normal",helperText:"Automatic: keys are created immediately. Manual: requires approval.",disabled:te,children:[(0,s.jsx)(q.A,{value:"manual",children:"Manual"}),(0,s.jsx)(q.A,{value:"automatic",children:"Automatic"})]})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsxs)(O.A,{fullWidth:!0,select:!0,label:"Publish Status",value:k,onChange:e=>C(e.target.value),margin:"normal",helperText:"Draft: hidden from catalog. Published: visible to consumers.",disabled:te,children:[(0,s.jsx)(q.A,{value:"Draft",children:"Draft"}),(0,s.jsx)(q.A,{value:"Published",children:"Published"})]})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Description",value:g,onChange:e=>j(e.target.value),placeholder:"API description",margin:"normal",multiline:!0,rows:2,required:!0,disabled:te,InputLabelProps:{classes:{asterisk:n.asterisk}}})}),(0,s.jsxs)(c.A,{item:!0,xs:12,children:[(0,s.jsx)(d.A,{variant:"subtitle2",gutterBottom:!0,style:{marginTop:16},children:"Tags"}),(0,s.jsx)(i.A,{display:"flex",flexWrap:"wrap",marginBottom:1,style:{gap:8},children:R.map(e=>(0,s.jsx)(r.A,{label:e,onDelete:te?void 0:()=>{return a=e,void I(R.filter(e=>e!==a));var a},size:"small",disabled:te},e))}),(0,s.jsxs)(i.A,{display:"flex",style:{gap:8},children:[(0,s.jsx)(O.A,{fullWidth:!0,size:"small",value:$,onChange:e=>W(e.target.value),onKeyPress:e=>"Enter"===e.key&&Pe(),placeholder:"Add tag",disabled:te}),(0,s.jsx)(u.A,{onClick:Pe,variant:"outlined",size:"small",disabled:te,children:"Add"})]})]}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsxs)(O.A,{fullWidth:!0,select:!0,label:"HTTPRoute",value:E,onChange:e=>M(e.target.value),margin:"normal",required:!0,helperText:ve?"Unable to load HTTPRoutes. Please retry.":"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.",error:!!ve,disabled:xe||te||!!ve,InputLabelProps:{classes:{asterisk:n.asterisk}},children:[xe&&(0,s.jsx)(q.A,{value:"",children:"Loading..."}),ve&&(0,s.jsx)(q.A,{value:"",children:"Error loading routes"}),!xe&&!ve&&he&&0===he.length&&(0,s.jsx)(q.A,{value:"",children:"No HTTPRoutes available"}),!xe&&!ve&&he&&he.map(e=>(0,s.jsxs)(q.A,{value:`${e.metadata.namespace}/${e.metadata.name}`,children:[e.metadata.name," (",e.metadata.namespace,")"]},`${e.metadata.namespace}/${e.metadata.name}`))]})}),E&&(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(Y,{selectedPolicy:fe,alertSeverity:"warning",alertMessage:"No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.",includeTopMargin:!0})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Contact Email",value:N,onChange:e=>{return a=e.target.value,D(a),void de(J(a));var a},placeholder:"api-team@example.com",helperText:oe||"Contact email for API support",error:!!oe,margin:"normal",disabled:te})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Contact Team",value:z,onChange:e=>L(e.target.value),placeholder:"platform-team",margin:"normal",disabled:te})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Docs URL",value:K,onChange:e=>{return a=e.target.value,U(a),void ue(X(a));var a},placeholder:"https://api.example.com/docs",helperText:ce||"Link to API documentation",error:!!ce,margin:"normal",disabled:te})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"OpenAPI Spec URL",value:Q,onChange:e=>{return a=e.target.value,Z(a),void me(X(a));var a},placeholder:"https://api.example.com/openapi.json",helperText:pe||"Link to OpenAPI specification",error:!!pe,margin:"normal",disabled:te})})]})]}),(0,s.jsxs)(_.A,{children:[(0,s.jsx)(u.A,{onClick:Se,disabled:te,children:"Cancel"}),(0,s.jsx)(u.A,{onClick:async()=>{ae(""),se(!0);try{if(!E)throw new Error("Please select an HTTPRoute");const[e,a]=E.split("/"),s={apiVersion:"devportal.kuadrant.io/v1alpha1",kind:"APIProduct",metadata:{name:h,namespace:e},spec:{displayName:v,description:g,version:f,approvalMode:b,publishStatus:k,tags:R,targetRef:{group:"gateway.networking.k8s.io",kind:"HTTPRoute",name:a,namespace:e},...N||z?{contact:{...N&&{email:N},...z&&{team:z}}}:{},...K||Q?{documentation:{...K&&{docsURL:K},...Q&&{openAPISpec:Q}}}:{}}},l=await p.fetch(`${m}/api/kuadrant/apiproducts`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!l.ok){const e=await l.json();throw new Error(e.error||"failed to create apiproduct")}t(),Se()}catch(e){ae(e instanceof Error?e.message:String(e))}finally{se(!1)}},color:"primary",variant:"contained",disabled:te||!h||!v||!g||!E||we,startIcon:te?(0,s.jsx)(T.A,{size:16,color:"inherit"}):void 0,children:te?"Creating...":"Create"})]})]})};var Z=t(34955);const ee=(0,U.A)({asterisk:{color:"#f44336"}}),ae=({open:e,onClose:a,onSuccess:t,namespace:o,name:p})=>{const m=ee(),h=(0,w.useApi)(w.configApiRef),x=(0,w.useApi)(w.fetchApiRef),v=h.getString("backend.baseUrl"),[A,g]=(0,l.useState)(!1),[j,f]=(0,l.useState)(""),[b,P]=(0,l.useState)(""),[k,C]=(0,l.useState)("v1"),[R,I]=(0,l.useState)("Draft"),[$,W]=(0,l.useState)("manual"),[E,M]=(0,l.useState)([]),[N,D]=(0,l.useState)(null),[z,L]=(0,l.useState)(""),[K,U]=(0,l.useState)(""),[G,Q]=(0,l.useState)(""),[Z,ae]=(0,l.useState)(""),[te,se]=(0,l.useState)(""),[le,ne]=(0,l.useState)(""),[re,ie]=(0,l.useState)(!1),[oe,de]=(0,l.useState)(null),[ce,ue]=(0,l.useState)(null),[pe,me]=(0,l.useState)(null);(0,l.useEffect)(()=>{e&&o&&p&&(g(!0),ne(""),x.fetch(`${v}/api/kuadrant/apiproducts/${o}/${p}`).then(async e=>{if(!e.ok){const a=await e.json();throw new Error(a.error||`Failed to fetch API product: ${e.status}`)}return e.json()}).then(e=>{var a,t,s,l;f(e.spec.displayName||""),P(e.spec.description||""),C(e.spec.version||"v1"),I(e.spec.publishStatus||"Draft"),W(e.spec.approvalMode||"manual"),M(e.spec.tags||[]),D(e.spec.targetRef||null),U((null===(a=e.spec.contact)||void 0===a?void 0:a.email)||""),Q((null===(t=e.spec.contact)||void 0===t?void 0:t.team)||""),ae((null===(s=e.spec.documentation)||void 0===s?void 0:s.docsURL)||""),se((null===(l=e.spec.documentation)||void 0===l?void 0:l.openAPISpec)||""),de(null),ue(null),me(null),g(!1)}).catch(e=>{ne(e.message||"Failed to load API product"),g(!1)}))},[e,o,p,v,x]);const{value:he,error:xe}=(0,S.A)(async()=>{if(!e)return null;const a=await x.fetch(`${v}/api/kuadrant/planpolicies`);return await a.json()},[v,x,e]),ve=n().useMemo(()=>(null==he?void 0:he.items)&&N?he.items.find(e=>{const a=e.targetRef;return"HTTPRoute"===(null==a?void 0:a.kind)&&(null==a?void 0:a.name)===N.name&&(!(null==a?void 0:a.namespace)||(null==a?void 0:a.namespace)===(N.namespace||o))}):null,[he,N,o]);(0,l.useEffect)(()=>{e&&(de(null),ue(null),me(null))},[e]);const Ae=()=>{z.trim()&&!E.includes(z.trim())&&(M([...E,z.trim()]),L(""))};return(0,s.jsxs)(B.A,{open:e,onClose:a,maxWidth:"md",fullWidth:!0,children:[(0,s.jsx)(H.A,{children:"Edit API Product"}),(0,s.jsxs)(F.A,{children:[le&&(0,s.jsx)(V.A,{severity:"error",style:{marginBottom:16},children:le}),xe&&(0,s.jsxs)(V.A,{severity:"warning",style:{marginBottom:16},children:[(0,s.jsx)("strong",{children:"Failed to load PlanPolicies:"})," ",xe.message,(0,s.jsx)(d.A,{variant:"body2",style:{marginTop:8},children:"Plan information may be incomplete."})]}),A?(0,s.jsx)(y.k,{}):(0,s.jsxs)(c.A,{container:!0,spacing:2,children:[(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Name",value:p,disabled:!0,helperText:"Kubernetes resource name (immutable)",margin:"normal"})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Namespace",value:o,disabled:!0,helperText:"Derived from HTTPRoute (immutable)",margin:"normal"})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Display Name",value:j,onChange:e=>f(e.target.value),placeholder:"My API",margin:"normal",required:!0,disabled:re,InputLabelProps:{classes:{asterisk:m.asterisk}}})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Version",value:k,onChange:e=>C(e.target.value),placeholder:"v1",margin:"normal",disabled:re})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsxs)(O.A,{fullWidth:!0,select:!0,label:"Publish Status",value:R,onChange:e=>I(e.target.value),margin:"normal",helperText:"Draft: Hidden from catalog. Published: Visible in catalog.",disabled:re,children:[(0,s.jsx)(q.A,{value:"Draft",children:"Draft (Hidden)"}),(0,s.jsx)(q.A,{value:"Published",children:"Published (Visible)"})]})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsxs)(O.A,{fullWidth:!0,select:!0,label:"Approval Mode",value:$,onChange:e=>W(e.target.value),margin:"normal",helperText:"Automatic: keys created immediately. Manual: requires approval.",disabled:re,children:[(0,s.jsx)(q.A,{value:"manual",children:"Manual"}),(0,s.jsx)(q.A,{value:"automatic",children:"Automatic"})]})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Description",value:b,onChange:e=>P(e.target.value),placeholder:"API description",margin:"normal",multiline:!0,rows:2,required:!0,disabled:re,InputLabelProps:{classes:{asterisk:m.asterisk}}})}),(0,s.jsxs)(c.A,{item:!0,xs:12,children:[(0,s.jsx)(d.A,{variant:"subtitle2",gutterBottom:!0,style:{marginTop:16},children:"Tags"}),(0,s.jsx)(i.A,{display:"flex",flexWrap:"wrap",marginBottom:1,style:{gap:8},children:E.map(e=>(0,s.jsx)(r.A,{label:e,onDelete:re?void 0:()=>{return a=e,void M(E.filter(e=>e!==a));var a},size:"small",disabled:re},e))}),(0,s.jsxs)(i.A,{display:"flex",style:{gap:8},children:[(0,s.jsx)(O.A,{fullWidth:!0,size:"small",value:z,onChange:e=>L(e.target.value),onKeyPress:e=>"Enter"===e.key&&Ae(),placeholder:"Add tag",disabled:re}),(0,s.jsx)(u.A,{onClick:Ae,variant:"outlined",size:"small",disabled:re,children:"Add"})]})]}),N&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"HTTPRoute",value:`${N.namespace||o}/${N.name}`,disabled:!0,helperText:"Target HTTPRoute (immutable)",margin:"normal"})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(Y,{selectedPolicy:ve,alertSeverity:"info",alertMessage:"No PlanPolicy found for this HTTPRoute.",includeTopMargin:!1})})]}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Contact Email",value:K,onChange:e=>{return a=e.target.value,U(a),void de(J(a));var a},placeholder:"api-team@example.com",helperText:oe||"Contact email for API support",error:!!oe,margin:"normal",disabled:re})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Contact Team",value:G,onChange:e=>Q(e.target.value),placeholder:"platform-team",margin:"normal",disabled:re})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"Docs URL",value:Z,onChange:e=>{return a=e.target.value,ae(a),void ue(X(a));var a},placeholder:"https://api.example.com/docs",helperText:ce||"Link to API documentation",error:!!ce,margin:"normal",disabled:re})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(O.A,{fullWidth:!0,label:"OpenAPI Spec URL",value:te,onChange:e=>{return a=e.target.value,se(a),void me(X(a));var a},placeholder:"https://api.example.com/openapi.json",helperText:pe||"Link to OpenAPI specification",error:!!pe,margin:"normal",disabled:re})})]})]}),(0,s.jsxs)(_.A,{children:[(0,s.jsx)(u.A,{onClick:a,disabled:re,children:"Cancel"}),(0,s.jsx)(u.A,{onClick:async()=>{ne(""),ie(!0);try{const e={spec:{displayName:j,description:b,version:k,publishStatus:R,approvalMode:$,tags:E,targetRef:N,...K||G?{contact:{...K&&{email:K},...G&&{team:G}}}:{},...Z||te?{documentation:{...Z&&{docsURL:Z},...te&&{openAPISpec:te}}}:{}}},s=await x.fetch(`${v}/api/kuadrant/apiproducts/${o}/${p}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){const e=await s.json();throw new Error(e.error||"failed to update apiproduct")}t(),a()}catch(e){ne(e instanceof Error?e.message:String(e))}finally{ie(!1)}},color:"primary",variant:"contained",disabled:re||A||!j||!b||!!oe||!!ce||!!pe,startIcon:re?(0,s.jsx)(T.A,{size:16,color:"inherit"}):void 0,children:re?"Saving...":"Save"})]})]})},te=()=>{const e=(0,w.useApi)(w.configApiRef),a=(0,w.useApi)(w.fetchApiRef),t=(0,w.useApi)(w.alertApiRef),n=(0,w.useApi)(w.identityApiRef),C=e.getString("backend.baseUrl"),[T,R]=(0,l.useState)(""),[I,$]=(0,l.useState)(!1),[q,W]=(0,l.useState)(!1),[E,M]=(0,l.useState)(0),[N,K]=(0,l.useState)(!1),[U,B]=(0,l.useState)(null),[H,F]=(0,l.useState)(null),[O,_]=(0,l.useState)(!1),[V,Y]=(0,l.useState)(null),{allowed:J,loading:X,error:G}=(0,L.l)(Z.FL),{allowed:ee,loading:te}=(0,L.l)(Z.TE),{allowed:se,loading:le,error:ne}=(0,L.l)(Z.SU),re=ee||se,ie=te||le,{allowed:oe,loading:de}=(0,L.l)(Z.EM),{allowed:ce,loading:ue,error:pe}=(0,L.l)(Z.R_),{allowed:me}=(0,L.l)(Z.U3),{allowed:he}=(0,L.l)(Z.v_),xe=de||ue,{allowed:ve,loading:Ae,error:ge}=(0,L.l)(Z.J);(0,S.A)(async()=>{const e=await n.getBackstageIdentity();R(e.userEntityRef)},[n]);const{value:je,loading:fe,error:ye}=(0,S.A)(async()=>{const e=await a.fetch(`${C}/api/kuadrant/apiproducts`);return await e.json()},[C,a,E]),{value:be,loading:Pe,error:Se}=(0,S.A)(async()=>{const e=await a.fetch(`${C}/api/kuadrant/planpolicies`);return await e.json()},[C,a,E]),we=fe||Pe||X||ie||xe||Ae,ke=ye||Se,Ce=G||ne||pe||ge,Te=[{title:"Name",field:"spec.displayName",render:e=>{var a,t;const l="Published"===(null===(a=e.spec)||void 0===a?void 0:a.publishStatus);var n;const r=null!==(n=null===(t=e.spec)||void 0===t?void 0:t.displayName)&&void 0!==n?n:e.metadata.name;return l?(0,s.jsx)(x.N_,{to:`/catalog/default/api/${e.metadata.name}/api-product`,children:(0,s.jsx)("strong",{children:r})}):(0,s.jsx)("span",{className:"text-muted",children:(0,s.jsx)("strong",{children:r})})},customFilterAndSearch:(e,a)=>{var t;return((null===(t=a.spec)||void 0===t?void 0:t.displayName)||a.metadata.name||"").toLowerCase().includes(e.toLowerCase())}},{title:"Resource Name",field:"metadata.name"},{title:"Version",field:"spec.version",render:e=>{var a;return(null===(a=e.spec)||void 0===a?void 0:a.version)||"-"}},{title:"HTTPRoute",field:"spec.targetRef.name",render:e=>{var a,t;return(null===(t=e.spec)||void 0===t||null===(a=t.targetRef)||void 0===a?void 0:a.name)||"-"}},{title:"Publish Status",field:"spec.publishStatus",render:e=>{var a;const t=(null===(a=e.spec)||void 0===a?void 0:a.publishStatus)||"Draft";return(0,s.jsx)(r.A,{label:t,size:"small",color:"Published"===t?"primary":"default"})}},{title:"Approval Mode",field:"spec.approvalMode",render:e=>{var a;const t=(null===(a=e.spec)||void 0===a?void 0:a.approvalMode)||"manual";return(0,s.jsx)(r.A,{label:t,size:"small",color:"automatic"===t?"secondary":"default"})}},{title:"Namespace",field:"metadata.namespace"},{title:"Created",field:"metadata.creationTimestamp",render:e=>{return a=e.metadata.creationTimestamp,new Date(a).toLocaleDateString("en-GB",{year:"numeric",month:"short",day:"numeric"});var a}},{title:"Actions",field:"actions",filtering:!1,render:e=>{var t,l;const n=(null===(l=e.metadata)||void 0===l||null===(t=l.annotations)||void 0===t?void 0:t["backstage.io/owner"])===T,r=he||me&&n,d=ce||oe&&n;return r||d?(0,s.jsxs)(i.A,{display:"flex",style:{gap:4},children:[r&&(0,s.jsx)(o.A,{size:"small",onClick:()=>{return a=e.metadata.namespace,t=e.metadata.name,F({namespace:a,name:t}),void W(!0);var a,t},title:"Edit API Product",children:(0,s.jsx)(h.A,{fontSize:"small"})}),d&&(0,s.jsx)(o.A,{size:"small",onClick:()=>(async(e,t)=>{B({namespace:e,name:t}),Y(null);try{const s=await a.fetch(`${C}/api/kuadrant/requests?namespace=${e}`);if(s.ok){const a=((await s.json()).items||[]).filter(a=>a.spec.apiName===t&&a.spec.apiNamespace===e),l=a.filter(e=>{var a;return"Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)}).length;Y({requests:a.length,secrets:l})}}catch(e){console.warn("Failed to fetch delete stats:",e)}K(!0)})(e.metadata.namespace,e.metadata.name),title:"Delete API Product",children:(0,s.jsx)(m.A,{fontSize:"small"})})]}):null}}],Re=[{title:"Name",field:"metadata.name",render:e=>(0,s.jsx)(x.N_,{to:`/kuadrant/planpolicy/${e.metadata.namespace}/${e.metadata.name}`,children:(0,s.jsx)("strong",{children:e.metadata.name})})},{title:"Namespace",field:"metadata.namespace"}];return(0,s.jsxs)(A.Y,{themeId:"tool",children:[(0,s.jsx)(g.Y,{title:"Kuadrant",subtitle:"API management for Kubernetes",children:(0,s.jsx)(j.Y,{children:"Manage API products and access requests"})}),(0,s.jsxs)(f.U,{children:[we&&(0,s.jsx)(y.k,{}),ke&&(0,s.jsx)(b._,{error:ke}),Ce&&(0,s.jsxs)(i.A,{p:2,children:[(0,s.jsxs)(d.A,{color:"error",children:["unable to check permissions: ",Ce.message]}),(0,s.jsxs)(d.A,{variant:"body2",color:"textSecondary",children:["permission: ",G?"kuadrant.apiproduct.create":pe?"kuadrant.apiproduct.delete":ne?"kuadrant.apikeyrequest.read.all":ge?"kuadrant.planpolicy.list":"unknown"]}),(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"please try again or contact your administrator"})]}),!we&&!ke&&!Ce&&(0,s.jsxs)(c.A,{container:!0,spacing:3,direction:"column",children:[(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(z,{})}),(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(P.n,{title:"API Products",action:J?(0,s.jsx)(i.A,{display:"flex",alignItems:"center",height:"100%",mt:1,children:(0,s.jsx)(u.A,{variant:"contained",color:"primary",size:"small",startIcon:(0,s.jsx)(p.A,{}),onClick:()=>$(!0),children:"Create API Product"})}):void 0,children:(Ie=null==je?void 0:je.items,Ie&&0!==Ie.length?(0,s.jsx)(v.X,{options:{paging:Ie.length>5,pageSize:20,search:!0,filtering:!0,debounceInterval:300,toolbar:!0,emptyRowsWhenPaging:!1},columns:Te,data:Ie}):(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"No API products found"}))})}),ve&&(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(P.n,{title:"Plan Policies",children:(e=>e&&0!==e.length?(0,s.jsx)(v.X,{options:{paging:!1,search:!1,toolbar:!1},columns:Re,data:e}):(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"No plan policies found"}))(null==be?void 0:be.items)})}),re&&(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(k.d,{})})]}),(0,s.jsx)(Q,{open:I,onClose:()=>$(!1),onSuccess:()=>{M(e=>e+1),t.post({message:"API Product created",severity:"success",display:"transient"})}}),(0,s.jsx)(ae,{open:q,onClose:()=>W(!1),onSuccess:()=>{M(e=>e+1),t.post({message:"API Product updated",severity:"success",display:"transient"})},namespace:(null==H?void 0:H.namespace)||"",name:(null==H?void 0:H.name)||""}),(0,s.jsx)(D.K,{open:N,title:"Delete API Product",description:V?`Deleting "${null==U?void 0:U.name}" will also remove:\n\n• ${V.requests} API Key Request(s)\n• ${V.secrets} API Key Secret(s)\n\nThis action cannot be undone.`:`Deleting "${null==U?void 0:U.name}" will also remove all associated API Key Requests and Secrets.\nThis action cannot be undone.`,confirmText:null==U?void 0:U.name,severity:"high",deleting:O,onConfirm:async()=>{if(U){_(!0);try{if(!(await a.fetch(`${C}/api/kuadrant/apiproducts/${U.namespace}/${U.name}`,{method:"DELETE"})).ok)throw new Error("failed to delete apiproduct");M(e=>e+1),t.post({message:"API Product deleted",severity:"success",display:"transient"})}catch(e){console.error("error deleting apiproduct:",e),t.post({message:"Failed to delete API Product",severity:"error",display:"transient"})}finally{_(!1),K(!1),B(null)}}},onCancel:()=>{K(!1),B(null)}})]})]});var Ie},se=()=>(0,s.jsx)(K,{permission:Z.OP,errorMessage:"you don't have permission to view the Kuadrant page",children:(0,s.jsx)(te,{})})},84189:(e,a,t)=>{t.d(a,{n:()=>j});var s=t(31085),l=t(95478),n=t(76891),r=t(61477),i=t(46805),o=t(10394),d=t(72501),c=t(95061),u=t(48543),p=t(81215),m=t(26343),h=t(16249),x=t(93453),v=t(64947),A=t(78467),g=t(22097);const j=({open:e,onClose:a,onSuccess:t,request:j,availablePlans:f})=>{const y=(0,g.useApi)(g.configApiRef),b=(0,g.useApi)(g.fetchApiRef),P=y.getString("backend.baseUrl"),[S,w]=(0,l.useState)(""),[k,C]=(0,l.useState)(""),[T,R]=(0,l.useState)(!1),[I,$]=(0,l.useState)("");(0,l.useEffect)(()=>{e&&j&&(w(j.spec.planTier||""),C(j.spec.useCase||""),$(""))},[e,j]);const q=()=>{T||($(""),a())};return(0,s.jsxs)(n.A,{open:e,onClose:q,maxWidth:"sm",fullWidth:!0,children:[(0,s.jsx)(r.A,{children:"Edit API Access Request"}),(0,s.jsxs)(i.A,{children:[I&&(0,s.jsx)(o.A,{mb:2,p:2,bgcolor:"error.main",color:"error.contrastText",borderRadius:1,children:(0,s.jsx)(d.A,{variant:"body2",children:I})}),(0,s.jsxs)(c.A,{fullWidth:!0,margin:"normal",children:[(0,s.jsx)(u.A,{children:"Tier"}),(0,s.jsx)(p.A,{value:S,onChange:e=>w(e.target.value),disabled:T,children:f.map(e=>{const a=Object.entries(e.limits||{}).map(([e,a])=>`${a} per ${e}`).join(", ");return(0,s.jsxs)(m.A,{value:e.tier,children:[e.tier," ",a?`(${a})`:""]},e.tier)})})]}),(0,s.jsx)(h.A,{label:"Use Case",placeholder:"Describe how you plan to use this API",multiline:!0,rows:3,fullWidth:!0,margin:"normal",value:k,onChange:e=>C(e.target.value),disabled:T,helperText:"Explain your intended use of this API for admin review"})]}),(0,s.jsxs)(x.A,{children:[(0,s.jsx)(v.A,{onClick:q,disabled:T,children:"Cancel"}),(0,s.jsx)(v.A,{onClick:async()=>{if(S){$(""),R(!0);try{const e={spec:{planTier:S,useCase:k.trim()}},s=await b.fetch(`${P}/api/kuadrant/requests/${j.metadata.namespace}/${j.metadata.name}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){const e=await s.json().catch(()=>({}));throw new Error(e.error||`Failed to update request: ${s.status}`)}t(),a()}catch(e){console.error("Error updating API key request:",e),$(e instanceof Error?e.message:"Unknown error occurred")}finally{R(!1)}}else $("Please select a tier")},color:"primary",variant:"contained",disabled:!S||T,startIcon:T?(0,s.jsx)(A.A,{size:16,color:"inherit"}):void 0,children:T?"Saving...":"Save Changes"})]})]})}}}]);
2
+ //# sourceMappingURL=532.bf600078.chunk.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static/532.bf600078.chunk.js","mappings":"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","sources":["webpack://internal.plugin-kuadrant/./src/components/ConfirmDeleteDialog/ConfirmDeleteDialog.tsx","webpack://internal.plugin-kuadrant/./src/components/MyApiKeysCard/MyApiKeysCard.tsx","webpack://internal.plugin-kuadrant/./src/components/PermissionGate/PermissionGate.tsx","webpack://internal.plugin-kuadrant/./src/components/PlanPolicyDetailsCard/PlanPolicyDetails.tsx","webpack://internal.plugin-kuadrant/./src/utils/validation.ts","webpack://internal.plugin-kuadrant/./src/components/CreateAPIProductDialog/CreateAPIProductDialog.tsx","webpack://internal.plugin-kuadrant/./src/components/EditAPIProductDialog/EditAPIProductDialog.tsx","webpack://internal.plugin-kuadrant/./src/components/KuadrantPage/KuadrantPage.tsx","webpack://internal.plugin-kuadrant/./src/components/EditAPIKeyRequestDialog/EditAPIKeyRequestDialog.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogContentText,\n DialogActions,\n Button,\n TextField,\n Typography,\n Box,\n CircularProgress,\n} from '@material-ui/core';\nimport WarningIcon from '@material-ui/icons/Warning';\n\nexport interface ConfirmDeleteDialogProps {\n open: boolean;\n title: string;\n description: string;\n // for dangerous deletes, require typing this text to confirm\n confirmText?: string;\n // severity affects styling - 'high' shows warning icon and requires text confirmation\n severity?: 'normal' | 'high';\n deleting?: boolean;\n onConfirm: () => void;\n onCancel: () => void;\n}\n\nexport const ConfirmDeleteDialog = ({\n open,\n title,\n description,\n confirmText,\n severity = 'normal',\n deleting = false,\n onConfirm,\n onCancel,\n}: ConfirmDeleteDialogProps) => {\n const [inputValue, setInputValue] = useState('');\n\n // reset input when dialog opens/closes\n useEffect(() => {\n if (!open) {\n setInputValue('');\n }\n }, [open]);\n\n const requiresTextConfirmation = severity === 'high' && confirmText;\n const canConfirm = requiresTextConfirmation ? inputValue === confirmText : true;\n\n const handleConfirm = () => {\n if (canConfirm) {\n onConfirm();\n }\n };\n\n return (\n <Dialog\n open={open}\n onClose={deleting ? undefined : onCancel}\n maxWidth=\"sm\"\n fullWidth\n >\n <DialogTitle>\n {severity === 'high' && (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <WarningIcon color=\"error\" />\n <span>{title}</span>\n </Box>\n )}\n {severity !== 'high' && title}\n </DialogTitle>\n <DialogContent>\n <DialogContentText style={{ whiteSpace: 'pre-line' }}>\n {description}\n </DialogContentText>\n {requiresTextConfirmation && (\n <Box mt={2}>\n <Typography variant=\"body2\" color=\"textSecondary\" gutterBottom>\n Type <strong>{confirmText}</strong> to confirm:\n </Typography>\n <TextField\n fullWidth\n variant=\"outlined\"\n size=\"small\"\n value={inputValue}\n onChange={e => setInputValue(e.target.value)}\n disabled={deleting}\n autoFocus\n placeholder={confirmText}\n />\n </Box>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onCancel} disabled={deleting}>\n Cancel\n </Button>\n <Button\n onClick={handleConfirm}\n color=\"secondary\"\n variant=\"contained\"\n disabled={deleting || !canConfirm}\n startIcon={deleting ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {deleting ? 'Deleting...' : 'Delete'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n","import React, { useState } from 'react';\nimport { InfoCard, Table, TableColumn, Link, Progress } from '@backstage/core-components';\nimport { useApi, configApiRef, fetchApiRef, identityApiRef, alertApiRef } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { Box, Chip, Typography, Tabs, Tab, IconButton, Tooltip, Menu, MenuItem, CircularProgress } from '@material-ui/core';\nimport VisibilityIcon from '@material-ui/icons/Visibility';\nimport VisibilityOffIcon from '@material-ui/icons/VisibilityOff';\nimport MoreVertIcon from '@material-ui/icons/MoreVert';\nimport { EditAPIKeyRequestDialog } from '../EditAPIKeyRequestDialog';\nimport { ConfirmDeleteDialog } from '../ConfirmDeleteDialog';\nimport { APIKey } from '../../types/api-management';\n\nexport const MyApiKeysCard = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const identityApi = useApi(identityApiRef);\n const alertApi = useApi(alertApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [selectedTab, setSelectedTab] = useState(0);\n const [, setUserId] = useState<string>('');\n const [visibleKeys, setVisibleKeys] = useState<Set<string>>(new Set());\n const [menuAnchor, setMenuAnchor] = useState<{ top: number; left: number } | null>(null);\n const [menuRequest, setMenuRequest] = useState<APIKey | null>(null);\n const [editDialogState, setEditDialogState] = useState<{ open: boolean; request: APIKey | null; plans: any[] }>({\n open: false,\n request: null,\n plans: [],\n });\n const [refresh, setRefresh] = useState(0);\n const [deleting, setDeleting] = useState<string | null>(null);\n const [deleteDialogState, setDeleteDialogState] = useState<{\n open: boolean;\n request: APIKey | null;\n }>({ open: false, request: null });\n const [apiKeyValues, setApiKeyValues] = useState<Map<string, string>>(new Map());\n const [apiKeyLoading, setApiKeyLoading] = useState<Set<string>>(new Set());\n\n useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n const extractedUserId = identity.userEntityRef.split('/')[1] || 'guest';\n console.log(`MyApiKeysCard: setting userId from userEntityRef: ${identity.userEntityRef} -> \"${extractedUserId}\"`);\n setUserId(extractedUserId);\n }, [identityApi]);\n\n const [optimisticallyDeleted, setOptimisticallyDeleted] = useState<Set<string>>(new Set());\n\n const { value: requests, loading, error } = useAsync(async () => {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/my`\n );\n if (!response.ok) {\n throw new Error('failed to fetch requests');\n }\n const data = await response.json();\n return data.items || [];\n }, [backendUrl, fetchApi, refresh]);\n\n if (loading) {\n return (\n <InfoCard title=\"My API Keys\">\n <Progress />\n </InfoCard>\n );\n }\n\n if (error) {\n return (\n <InfoCard title=\"My API Keys\">\n <Typography color=\"error\">Error loading API keys: {error.message}</Typography>\n </InfoCard>\n );\n }\n\n const allRequests = (requests || []).filter(\n (r: APIKey) => !optimisticallyDeleted.has(r.metadata.name)\n );\n const approvedRequests = allRequests.filter((r: APIKey) => r.status?.phase === 'Approved');\n const pendingRequests = allRequests.filter((r: APIKey) => !r.status?.phase || r.status.phase === 'Pending');\n const rejectedRequests = allRequests.filter((r: APIKey) => r.status?.phase === 'Rejected');\n\n const toggleKeyVisibility = (keyName: string) => {\n setVisibleKeys(prev => {\n const newSet = new Set(prev);\n if (newSet.has(keyName)) {\n newSet.delete(keyName);\n } else {\n newSet.add(keyName);\n }\n return newSet;\n });\n };\n\n const fetchApiKeyFromSecret = async (requestNamespace: string, requestName: string) => {\n const key = `${requestNamespace}/${requestName}`;\n if (apiKeyLoading.has(key)) {\n return;\n }\n\n setApiKeyLoading(prev => new Set(prev).add(key));\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/${requestNamespace}/${requestName}/secret`\n );\n if (response.ok) {\n const data = await response.json();\n setApiKeyValues(prev => new Map(prev).set(key, data.apiKey));\n }\n } catch (err) {\n console.error('failed to fetch api key:', err);\n } finally {\n setApiKeyLoading(prev => {\n const next = new Set(prev);\n next.delete(key);\n return next;\n });\n }\n };\n\n const clearApiKeyValue = (requestNamespace: string, requestName: string) => {\n const key = `${requestNamespace}/${requestName}`;\n setApiKeyValues(prev => {\n const next = new Map(prev);\n next.delete(key);\n return next;\n });\n };\n\n const handleMenuClose = () => {\n setMenuAnchor(null);\n setMenuRequest(null);\n };\n\n const handleEdit = async () => {\n if (!menuRequest) return;\n\n const request = menuRequest;\n handleMenuClose();\n\n // Fetch available plans for this API\n try {\n const apiProductName = request.spec.apiProductRef?.name;\n const apiProductNamespace = request.metadata.namespace;\n const apiProductResponse = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${apiProductNamespace}/${apiProductName}`\n );\n\n if (apiProductResponse.ok) {\n const apiProduct = await apiProductResponse.json();\n const plans = apiProduct.spec?.plans || [];\n setEditDialogState({ open: true, request, plans });\n } else {\n console.error('Failed to fetch API product');\n setEditDialogState({ open: true, request, plans: [] });\n }\n } catch (err) {\n console.error('Error fetching plans:', err);\n setEditDialogState({ open: true, request, plans: [] });\n }\n };\n\n const handleDeleteClick = () => {\n if (!menuRequest) return;\n const request = menuRequest;\n handleMenuClose();\n setDeleteDialogState({ open: true, request });\n };\n\n const handleDeleteConfirm = async () => {\n if (!deleteDialogState.request) return;\n\n const request = deleteDialogState.request;\n const requestName = request.metadata.name;\n\n // optimistic update - remove from UI immediately\n setOptimisticallyDeleted(prev => new Set(prev).add(requestName));\n setDeleting(requestName);\n\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/${request.metadata.namespace}/${request.metadata.name}`,\n { method: 'DELETE' }\n );\n\n if (!response.ok) {\n throw new Error('Failed to delete request');\n }\n\n setRefresh(r => r + 1);\n alertApi.post({ message: 'Request deleted', severity: 'success', display: 'transient' });\n setDeleteDialogState({ open: false, request: null });\n } catch (err) {\n console.error('Error deleting request:', err);\n // rollback optimistic update on error\n setOptimisticallyDeleted(prev => {\n const next = new Set(prev);\n next.delete(requestName);\n return next;\n });\n alertApi.post({ message: 'Failed to delete request', severity: 'error', display: 'transient' });\n } finally {\n setDeleting(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogState({ open: false, request: null });\n };\n\n const columns: TableColumn<APIKey>[] = [\n {\n title: 'API Product',\n field: 'spec.apiProductRef.name',\n render: (row: APIKey) => {\n const apiProductName = row.spec.apiProductRef?.name || 'unknown';\n return (\n <Link to={`/catalog/default/api/${apiProductName}/api-keys`}>\n <strong>{apiProductName}</strong>\n </Link>\n );\n },\n },\n {\n title: 'Tier',\n field: 'spec.planTier',\n render: (row: APIKey) => {\n const color = row.spec.planTier === 'gold' ? 'primary' :\n row.spec.planTier === 'silver' ? 'default' : 'secondary';\n return <Chip label={row.spec.planTier} color={color} size=\"small\" />;\n },\n },\n {\n title: 'Use Case',\n field: 'spec.useCase',\n render: (row: APIKey) => {\n if (!row.spec.useCase) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n return (\n <Tooltip title={row.spec.useCase} placement=\"top\">\n <Typography\n variant=\"body2\"\n style={{\n maxWidth: '200px',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n }}\n >\n {row.spec.useCase}\n </Typography>\n </Tooltip>\n );\n },\n },\n {\n title: 'Status',\n field: 'status.phase',\n render: (row: APIKey) => {\n const phase = row.status?.phase || 'Pending';\n const color = phase === 'Approved' ? 'primary' :\n phase === 'Rejected' ? 'secondary' : 'default';\n return <Chip label={phase} color={color} size=\"small\" />;\n },\n },\n {\n title: 'Reviewed By',\n field: 'status.reviewedBy',\n render: (row: APIKey) => {\n if ((row.status?.phase === 'Approved' || row.status?.phase === 'Rejected') && row.status.reviewedBy) {\n const reviewedDate = row.status.reviewedAt ? new Date(row.status.reviewedAt).toLocaleDateString() : '';\n return (\n <Box>\n <Typography variant=\"body2\">{row.status.reviewedBy}</Typography>\n {reviewedDate && (\n <Typography variant=\"caption\" color=\"textSecondary\">\n {reviewedDate}\n </Typography>\n )}\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'API Key',\n field: 'status.secretRef',\n filtering: false,\n render: (row: APIKey) => {\n if (row.status?.phase !== 'Approved') {\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n }\n\n const key = `${row.metadata.namespace}/${row.metadata.name}`;\n const hasSecretRef = row.status?.secretRef?.name;\n const isVisible = visibleKeys.has(row.metadata.name);\n const isLoading = apiKeyLoading.has(key);\n const apiKeyValue = apiKeyValues.get(key);\n\n if (!hasSecretRef) {\n return (\n <Typography variant=\"body2\" color=\"textSecondary\">\n Awaiting secret...\n </Typography>\n );\n }\n\n const handleToggle = () => {\n if (isVisible) {\n // hiding - clear the value from memory\n clearApiKeyValue(row.metadata.namespace, row.metadata.name);\n toggleKeyVisibility(row.metadata.name);\n } else {\n // showing - fetch fresh value\n fetchApiKeyFromSecret(row.metadata.namespace, row.metadata.name);\n toggleKeyVisibility(row.metadata.name);\n }\n };\n\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isLoading ? 'Loading...' : isVisible && apiKeyValue ? apiKeyValue : '•'.repeat(20) + '...'}\n </Box>\n <Tooltip title={isVisible ? 'hide key' : 'show key'}>\n <IconButton\n size=\"small\"\n onClick={handleToggle}\n disabled={isLoading}\n >\n {isVisible ? <VisibilityOffIcon fontSize=\"small\" /> : <VisibilityIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n );\n },\n },\n {\n title: 'Requested',\n field: 'metadata.creationTimestamp',\n render: (row: APIKey) => {\n if (!row.metadata.creationTimestamp) {\n return <Typography variant=\"body2\">-</Typography>;\n }\n const date = new Date(row.metadata.creationTimestamp);\n return <Typography variant=\"body2\">{date.toLocaleDateString()}</Typography>;\n },\n },\n {\n title: '',\n filtering: false,\n render: (row: APIKey) => {\n const isDeleting = deleting === row.metadata.name;\n if (isDeleting) {\n return <CircularProgress size={20} />;\n }\n return (\n <IconButton\n size=\"small\"\n onClick={(e) => {\n e.stopPropagation();\n const rect = e.currentTarget.getBoundingClientRect();\n setMenuAnchor({ top: rect.bottom, left: rect.left });\n setMenuRequest(row);\n }}\n aria-controls={menuAnchor ? 'myapikeys-menu' : undefined}\n aria-haspopup=\"true\"\n >\n <MoreVertIcon />\n </IconButton>\n );\n },\n },\n ];\n\n const getTabData = () => {\n switch (selectedTab) {\n case 0:\n return approvedRequests;\n case 1:\n return pendingRequests;\n case 2:\n return rejectedRequests;\n default:\n return allRequests;\n }\n };\n\n const getTabColumns = () => {\n switch (selectedTab) {\n case 0: // Active - no Reason\n return columns.filter(col => col.title !== 'Reason');\n case 1: // Pending - no Reason, Reviewed By, API Key\n return columns.filter(col =>\n col.title !== 'Reason' &&\n col.title !== 'Reviewed By' &&\n col.title !== 'API Key'\n );\n case 2: // Rejected - no API Key\n return columns.filter(col => col.title !== 'API Key');\n default:\n return columns;\n }\n };\n\n const tabData = getTabData();\n const tabColumns = getTabColumns();\n const isPending = (row: APIKey) => !row.status || row.status.phase === 'Pending';\n\n return (\n <>\n <InfoCard\n title=\"My API Keys\"\n subheader={`${approvedRequests.length} active, ${pendingRequests.length} pending`}\n >\n <Box mb={2}>\n <Tabs\n value={selectedTab}\n onChange={(_, newValue) => setSelectedTab(newValue)}\n indicatorColor=\"primary\"\n textColor=\"primary\"\n >\n <Tab label={`Active (${approvedRequests.length})`} />\n <Tab label={`Pending (${pendingRequests.length})`} />\n <Tab label={`Rejected (${rejectedRequests.length})`} />\n </Tabs>\n </Box>\n {tabData.length === 0 ? (\n <Box p={3} textAlign=\"center\">\n <Typography variant=\"body1\" color=\"textSecondary\">\n {selectedTab === 0 && 'No active API keys. Request access to an API to get started.'}\n {selectedTab === 1 && 'No pending requests.'}\n {selectedTab === 2 && 'No rejected requests.'}\n </Typography>\n </Box>\n ) : (\n <Table\n options={{\n paging: tabData.length > 5,\n pageSize: 20,\n search: true,\n filtering: true,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={tabColumns}\n data={tabData.map((item: APIKey) => ({\n ...item,\n id: item.metadata.name,\n }))}\n />\n )}\n </InfoCard>\n\n <Menu\n id=\"myapikeys-menu\"\n open={Boolean(menuAnchor)}\n onClose={handleMenuClose}\n anchorReference=\"anchorPosition\"\n anchorPosition={menuAnchor || { top: 0, left: 0 }}\n >\n {menuRequest && (() => {\n const items = [];\n if (isPending(menuRequest)) {\n items.push(<MenuItem key=\"edit\" onClick={handleEdit}>Edit</MenuItem>);\n }\n items.push(<MenuItem key=\"delete\" onClick={handleDeleteClick}>Delete</MenuItem>);\n return items;\n })()}\n </Menu>\n\n {editDialogState.request && (\n <EditAPIKeyRequestDialog\n open={editDialogState.open}\n request={editDialogState.request}\n availablePlans={editDialogState.plans}\n onClose={() => setEditDialogState({ open: false, request: null, plans: [] })}\n onSuccess={() => {\n setEditDialogState({ open: false, request: null, plans: [] });\n setRefresh(r => r + 1);\n }}\n />\n )}\n\n <ConfirmDeleteDialog\n open={deleteDialogState.open}\n title=\"Delete API Key Request\"\n description={`Are you sure you want to delete the API key request for ${deleteDialogState.request?.spec.apiProductRef?.name || 'this API'}?`}\n deleting={deleting !== null}\n onConfirm={handleDeleteConfirm}\n onCancel={handleDeleteCancel}\n />\n </>\n );\n};\n","import React from 'react';\nimport { Typography, Box } from '@material-ui/core';\nimport { Progress } from '@backstage/core-components';\nimport { Permission } from '@backstage/plugin-permission-common';\nimport { useKuadrantPermission } from '../../utils/permissions';\n\ninterface PermissionGateProps {\n children: React.ReactNode;\n permission: Permission;\n fallback?: React.ReactNode;\n errorMessage?: string;\n}\n\nexport const PermissionGate = ({ children, permission, fallback, errorMessage }: PermissionGateProps) => {\n const { allowed, loading, error } = useKuadrantPermission(permission);\n\n if (loading) {\n return <Progress />;\n }\n\n if (error) {\n return (\n <Box p={4}>\n <Typography color=\"error\">\n Unable to check permissions: {error.message}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n Please try again or contact your administrator\n </Typography>\n </Box>\n );\n }\n\n if (!allowed) {\n if (fallback) {\n return <>{fallback}</>;\n }\n return (\n <Box p={4}>\n <Typography color=\"textSecondary\">\n {errorMessage || 'You don\\'t have permission to view this page'}\n </Typography>\n <Box mt={1}>\n <Typography variant=\"caption\" color=\"textSecondary\">\n Required permission: {permission.name}\n </Typography>\n </Box>\n </Box>\n );\n }\n\n return <>{children}</>;\n};\n","import React from 'react';\nimport { Box, Typography, Chip } from '@material-ui/core';\nimport { Alert } from '@material-ui/lab';\n\ninterface PlanPolicyDetailsProps {\n selectedPolicy: {\n metadata: {\n name: string;\n };\n plans?: Array<{\n tier: string;\n description?: string;\n limits?: {\n daily?: number;\n monthly?: number;\n yearly?: number;\n };\n }>;\n } | null;\n alertSeverity?: 'warning' | 'info';\n alertMessage?: string;\n includeTopMargin?: boolean;\n}\n\nexport const PlanPolicyDetails: React.FC<PlanPolicyDetailsProps> = ({\n selectedPolicy,\n alertSeverity = 'warning',\n alertMessage = 'No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.',\n includeTopMargin = true,\n}) => {\n return (\n <Box\n mt={includeTopMargin ? 1 : 0}\n p={2}\n bgcolor=\"#f5f5f5\"\n borderRadius={1}\n border=\"1px solid #e0e0e0\"\n >\n {selectedPolicy ? (\n <>\n <Typography variant=\"subtitle2\" gutterBottom style={{ fontWeight: 600 }}>\n Associated PlanPolicy: <strong>{selectedPolicy.metadata.name}</strong>\n </Typography>\n\n {selectedPolicy.plans && selectedPolicy.plans.length > 0 ? (\n <>\n <Typography\n variant=\"caption\"\n display=\"block\"\n gutterBottom\n color=\"textSecondary\"\n style={{ marginTop: 8 }}\n >\n Available Plans:\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" mt={1} style={{ gap: 8 }}>\n {selectedPolicy.plans.map((plan: any, idx: number) => {\n const limitText = plan.limits?.daily\n ? `${plan.limits.daily}/day`\n : plan.limits?.monthly\n ? `${plan.limits.monthly}/month`\n : plan.limits?.yearly\n ? `${plan.limits.yearly}/year`\n : 'No limit';\n\n return (\n <Chip\n key={idx}\n label={`${plan.tier}: ${limitText}`}\n size=\"small\"\n variant=\"outlined\"\n color=\"primary\"\n />\n );\n })}\n </Box>\n {selectedPolicy.plans.some((p: any) => p.description) && (\n <Box mt={1}>\n {selectedPolicy.plans.filter((p: any) => p.description).map((plan: any, idx: number) => (\n <Typography key={idx} variant=\"caption\" display=\"block\" color=\"textSecondary\">\n • <strong>{plan.tier}:</strong> {plan.description}\n </Typography>\n ))}\n </Box>\n )}\n </>\n ) : (\n <Typography variant=\"caption\" color=\"textSecondary\">\n No plans defined in this PlanPolicy\n </Typography>\n )}\n </>\n ) : (\n <Alert severity={alertSeverity}>{alertMessage}</Alert>\n )}\n </Box>\n );\n};\n\n","// Kubernetes name validation\nexport const validateKubernetesName = (value: string): string | null => {\n if (!value || !value.trim()) {\n return 'Name is required';\n }\n if (value.length > 253) {\n return 'Must be 253 characters or less';\n }\n\n const dns1123Regex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;\n\n if (!dns1123Regex.test(value)) {\n return 'Must be lowercase alphanumeric with hyphens, start and end with alphanumeric';\n }\n\n return null;\n};\n\n// email validation\nexport const validateEmail = (value: string): string | null => {\n if (!value) {\n return null;\n }\n\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n if (!emailRegex.test(value)) {\n return 'Must be a valid email address';\n }\n\n return null;\n};\n\n// URL validation\nexport const validateURL = (value: string): string | null => {\n if (!value) {\n return null;\n }\n\n try {\n const url = new URL(value);\n if (!['http:', 'https:'].includes(url.protocol)) {\n return 'Must be a valid HTTP or HTTPS URL';\n }\n return null;\n } catch {\n return 'Must be a valid URL';\n }\n};\n","import React, {useEffect, useState} from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Box,\n Typography,\n Chip,\n Grid,\n MenuItem,\n CircularProgress,\n makeStyles,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { Alert } from '@material-ui/lab';\nimport useAsync from 'react-use/lib/useAsync';\nimport { PlanPolicyDetails } from '../PlanPolicyDetailsCard';\nimport { validateKubernetesName, validateEmail, validateURL } from '../../utils/validation';\n\nconst useStyles = makeStyles({\n asterisk: {\n color: '#f44336',\n },\n});\n\ninterface CreateAPIProductDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\nexport const CreateAPIProductDialog = ({ open, onClose, onSuccess }: CreateAPIProductDialogProps) => {\n const classes = useStyles();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const [name, setName] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n const [version, setVersion] = useState('v1');\n const [approvalMode, setApprovalMode] = useState<'automatic' | 'manual'>('manual');\n const [publishStatus, setPublishStatus] = useState<'Draft' | 'Published'>('Published');\n const [tags, setTags] = useState<string[]>([]);\n const [tagInput, setTagInput] = useState('');\n const [selectedHTTPRoute, setSelectedHTTPRoute] = useState('');\n const [contactEmail, setContactEmail] = useState('');\n const [contactTeam, setContactTeam] = useState('');\n const [docsURL, setDocsURL] = useState('');\n const [openAPISpec, setOpenAPISpec] = useState('');\n const [error, setError] = useState('');\n const [creating, setCreating] = useState(false);\n const [httpRoutesRetry, setHttpRoutesRetry] = useState(0);\n const [nameError, setNameError] = useState<string | null>(null);\n const [contactEmailError, setContactEmailError] = useState<string | null>(null);\n const [docsURLError, setDocsURLError] = useState<string | null>(null);\n const [openAPISpecError, setOpenAPISpecError] = useState<string | null>(null);\n const {\n value: httpRoutes,\n loading: httpRoutesLoading,\n error: httpRoutesError\n } = useAsync(async () => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/httproutes`);\n const data = await response.json();\n // filter to only show httproutes annotated for backstage exposure\n return (data.items || []).filter((route: any) =>\n route.metadata.annotations?.['backstage.io/expose'] === 'true'\n );\n }, [backendUrl, fetchApi, open, httpRoutesRetry]);\n\n // load planpolicies with full details to show associated plans\n const {\n value: planPolicies,\n error: planPoliciesError\n } = useAsync(async () => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, open]);\n\n // find planpolicy associated with selected httproute\n const getPlanPolicyForRoute = (routeNamespace: string, routeName: string) => {\n if (!planPolicies?.items) return null;\n\n return planPolicies.items.find((pp: any) => {\n const ref = pp.targetRef;\n return (\n ref?.kind === 'HTTPRoute' &&\n ref?.name === routeName &&\n (!ref?.namespace || ref?.namespace === routeNamespace)\n );\n });\n };\n\n const selectedRouteInfo = selectedHTTPRoute ? selectedHTTPRoute.split('/') : null;\n const selectedPolicy = selectedRouteInfo\n ? getPlanPolicyForRoute(selectedRouteInfo[0], selectedRouteInfo[1])\n : null;\n\n useEffect(() => {\n if (open) {\n setNameError(null);\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n }\n }, [open]);\n\n // validate handlers\n const handleNameChange = (value: string) => {\n setName(value);\n setNameError(validateKubernetesName(value));\n };\n\n const handleContactEmailChange = (value: string) => {\n setContactEmail(value);\n setContactEmailError(validateEmail(value));\n };\n\n const handleDocsURLChange = (value: string) => {\n setDocsURL(value);\n setDocsURLError(validateURL(value));\n };\n\n const handleOpenAPISpecChange = (value: string) => {\n setOpenAPISpec(value);\n setOpenAPISpecError(validateURL(value));\n };\n\n const handleAddTag = () => {\n if (tagInput.trim() && !tags.includes(tagInput.trim())) {\n setTags([...tags, tagInput.trim()]);\n setTagInput('');\n }\n };\n\n const handleDeleteTag = (tagToDelete: string) => {\n setTags(tags.filter(tag => tag !== tagToDelete));\n };\n\n const handleCreate = async () => {\n setError('');\n setCreating(true);\n\n try {\n if (!selectedHTTPRoute) {\n throw new Error('Please select an HTTPRoute');\n }\n\n const [selectedRouteNamespace, selectedRouteName] = selectedHTTPRoute.split('/');\n\n // derive namespace from selected httproute\n const namespace = selectedRouteNamespace;\n\n const apiProduct = {\n apiVersion: 'devportal.kuadrant.io/v1alpha1',\n kind: 'APIProduct',\n metadata: {\n name,\n namespace,\n },\n spec: {\n displayName,\n description,\n version,\n approvalMode,\n publishStatus,\n tags,\n targetRef: {\n group: 'gateway.networking.k8s.io',\n kind: 'HTTPRoute',\n name: selectedRouteName,\n namespace: selectedRouteNamespace,\n },\n ...(contactEmail || contactTeam ? {\n contact: {\n ...(contactEmail && { email: contactEmail }),\n ...(contactTeam && { team: contactTeam }),\n },\n } : {}),\n ...(docsURL || openAPISpec ? {\n documentation: {\n ...(docsURL && { docsURL }),\n ...(openAPISpec && { openAPISpec }),\n },\n } : {}),\n },\n };\n\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(apiProduct),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || 'failed to create apiproduct');\n }\n\n onSuccess();\n handleClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setCreating(false);\n }\n };\n\n const handleClose = () => {\n setName('');\n setDisplayName('');\n setDescription('');\n setVersion('v1');\n setApprovalMode('manual');\n setPublishStatus('Published');\n setTags([]);\n setTagInput('');\n setSelectedHTTPRoute('');\n setContactEmail('');\n setContactTeam('');\n setDocsURL('');\n setOpenAPISpec('');\n setError('');\n setNameError(null);\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n onClose();\n };\n\n const hasValidationErrors = !!nameError || !!contactEmailError || !!docsURLError || !!openAPISpecError;\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>Create API Product</DialogTitle>\n <DialogContent>\n {error && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n {error}\n </Alert>\n )}\n {httpRoutesError && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n <strong>Failed to load HTTPRoutes:</strong> {httpRoutesError.message}\n <Box mt={1}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => setHttpRoutesRetry(prev => prev + 1)}\n >\n Retry\n </Button>\n </Box>\n </Alert>\n )}\n\n {planPoliciesError && (\n <Alert severity=\"warning\" style={{ marginBottom: 16 }}>\n <strong>Failed to load PlanPolicies:</strong> {planPoliciesError.message}\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n You can still create the API Product, but plan information may be incomplete.\n </Typography>\n </Alert>\n )}\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n onChange={e => handleNameChange(e.target.value)}\n placeholder=\"my-api\"\n helperText={nameError || \"Kubernetes resource name (lowercase, hyphens)\"}\n error={!!nameError}\n margin=\"normal\"\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Display Name\"\n value={displayName}\n onChange={e => setDisplayName(e.target.value)}\n placeholder=\"My API\"\n margin=\"normal\"\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Version\"\n value={version}\n onChange={e => setVersion(e.target.value)}\n placeholder=\"v1\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"Approval Mode\"\n value={approvalMode}\n onChange={e => setApprovalMode(e.target.value as 'automatic' | 'manual')}\n margin=\"normal\"\n helperText=\"Automatic: keys are created immediately. Manual: requires approval.\"\n disabled={creating}\n >\n <MenuItem value=\"manual\">Manual</MenuItem>\n <MenuItem value=\"automatic\">Automatic</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"Publish Status\"\n value={publishStatus}\n onChange={e => setPublishStatus(e.target.value as 'Draft' | 'Published')}\n margin=\"normal\"\n helperText=\"Draft: hidden from catalog. Published: visible to consumers.\"\n disabled={creating}\n >\n <MenuItem value=\"Draft\">Draft</MenuItem>\n <MenuItem value=\"Published\">Published</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"Description\"\n value={description}\n onChange={e => setDescription(e.target.value)}\n placeholder=\"API description\"\n margin=\"normal\"\n multiline\n rows={2}\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\" gutterBottom style={{ marginTop: 16 }}>\n Tags\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" marginBottom={1} style={{ gap: 8 }}>\n {tags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n onDelete={creating ? undefined : () => handleDeleteTag(tag)}\n size=\"small\"\n disabled={creating}\n />\n ))}\n </Box>\n <Box display=\"flex\" style={{ gap: 8 }}>\n <TextField\n fullWidth\n size=\"small\"\n value={tagInput}\n onChange={e => setTagInput(e.target.value)}\n onKeyPress={e => e.key === 'Enter' && handleAddTag()}\n placeholder=\"Add tag\"\n disabled={creating}\n />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\" disabled={creating}>\n Add\n </Button>\n </Box>\n </Grid>\n\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"HTTPRoute\"\n value={selectedHTTPRoute}\n onChange={e => setSelectedHTTPRoute(e.target.value)}\n margin=\"normal\"\n required\n helperText={\n httpRoutesError\n ? \"Unable to load HTTPRoutes. Please retry.\"\n : \"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.\"\n }\n error={!!httpRoutesError}\n disabled={httpRoutesLoading || creating || !!httpRoutesError}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n >\n {httpRoutesLoading && (\n <MenuItem value=\"\">Loading...</MenuItem>\n )}\n {httpRoutesError && (\n <MenuItem value=\"\">Error loading routes</MenuItem>\n )}\n {!httpRoutesLoading && !httpRoutesError && httpRoutes && httpRoutes.length === 0 && (\n <MenuItem value=\"\">No HTTPRoutes available</MenuItem>\n )}\n {!httpRoutesLoading && !httpRoutesError && httpRoutes && httpRoutes.map((route: any) => (\n <MenuItem\n key={`${route.metadata.namespace}/${route.metadata.name}`}\n value={`${route.metadata.namespace}/${route.metadata.name}`}\n >\n {route.metadata.name} ({route.metadata.namespace})\n </MenuItem>\n ))}\n </TextField>\n </Grid>\n {selectedHTTPRoute && (\n <Grid item xs={12}>\n <PlanPolicyDetails\n selectedPolicy={selectedPolicy}\n alertSeverity=\"warning\"\n alertMessage=\"No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.\"\n includeTopMargin={true}\n />\n </Grid>\n )}\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => handleContactEmailChange(e.target.value)}\n placeholder=\"api-team@example.com\"\n helperText={contactEmailError || \"Contact email for API support\"}\n error={!!contactEmailError}\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Team\"\n value={contactTeam}\n onChange={e => setContactTeam(e.target.value)}\n placeholder=\"platform-team\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => handleDocsURLChange(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n helperText={docsURLError || \"Link to API documentation\"}\n error={!!docsURLError}\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => handleOpenAPISpecChange(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n helperText={openAPISpecError || \"Link to OpenAPI specification\"}\n error={!!openAPISpecError}\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n </Grid>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating}>Cancel</Button>\n <Button\n onClick={handleCreate}\n color=\"primary\"\n variant=\"contained\"\n disabled={creating || !name || !displayName || !description || !selectedHTTPRoute || hasValidationErrors}\n startIcon={creating ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {creating ? 'Creating...' : 'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Box,\n Typography,\n Chip,\n Grid,\n MenuItem,\n CircularProgress,\n makeStyles,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { Alert } from '@material-ui/lab';\nimport { Progress } from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { PlanPolicyDetails } from '../PlanPolicyDetailsCard';\nimport { validateEmail, validateURL } from '../../utils/validation';\n\nconst useStyles = makeStyles({\n asterisk: {\n color: '#f44336',\n },\n});\n\ninterface EditAPIProductDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n namespace: string;\n name: string;\n}\n\nexport const EditAPIProductDialog = ({open, onClose, onSuccess, namespace, name}: EditAPIProductDialogProps) => {\n const classes = useStyles();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [loading, setLoading] = useState(false);\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n const [version, setVersion] = useState('v1');\n const [publishStatus, setPublishStatus] = useState<'Draft' | 'Published'>('Draft');\n const [approvalMode, setApprovalMode] = useState<'automatic' | 'manual'>('manual');\n const [tags, setTags] = useState<string[]>([]);\n const [targetRef, setTargetRef] = useState<any>(null);\n const [tagInput, setTagInput] = useState('');\n const [contactEmail, setContactEmail] = useState('');\n const [contactTeam, setContactTeam] = useState('');\n const [docsURL, setDocsURL] = useState('');\n const [openAPISpec, setOpenAPISpec] = useState('');\n const [error, setError] = useState('');\n const [saving, setSaving] = useState(false);\n // valid error states\n const [contactEmailError, setContactEmailError] = useState<string | null>(null);\n const [docsURLError, setDocsURLError] = useState<string | null>(null);\n const [openAPISpecError, setOpenAPISpecError] = useState<string | null>(null);\n\n // Load APIProduct data when dialog opens\n useEffect(() => {\n if (open && namespace && name) {\n setLoading(true);\n setError('');\n\n fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`)\n .then(async res => {\n if (!res.ok) {\n const errorData = await res.json();\n throw new Error(errorData.error || `Failed to fetch API product: ${res.status}`);\n }\n return res.json();\n })\n .then(data => {\n setDisplayName(data.spec.displayName || '');\n setDescription(data.spec.description || '');\n setVersion(data.spec.version || 'v1');\n setPublishStatus(data.spec.publishStatus || 'Draft');\n setApprovalMode(data.spec.approvalMode || 'manual');\n setTags(data.spec.tags || []);\n setTargetRef(data.spec.targetRef || null);\n setContactEmail(data.spec.contact?.email || '');\n setContactTeam(data.spec.contact?.team || '');\n setDocsURL(data.spec.documentation?.docsURL || '');\n setOpenAPISpec(data.spec.documentation?.openAPISpec || '');\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n setLoading(false);\n })\n .catch(err => {\n setError(err.message || 'Failed to load API product');\n setLoading(false);\n });\n }\n }, [open, namespace, name, backendUrl, fetchApi]);\n\n // load planpolicies with full details to show associated plans\n const {\n value: planPolicies,\n error: planPoliciesError\n } = useAsync(async () => {\n if (!open) return null;\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, open]);\n\n // find planpolicy associated with targetRef\n const selectedPolicy = React.useMemo(() => {\n if (!planPolicies?.items || !targetRef) return null;\n\n return planPolicies.items.find((pp: any) => {\n const ref = pp.targetRef;\n return (\n ref?.kind === 'HTTPRoute' &&\n ref?.name === targetRef.name &&\n (!ref?.namespace || ref?.namespace === (targetRef.namespace || namespace))\n );\n });\n }, [planPolicies, targetRef, namespace]);\n\n // val handlers\n\n useEffect(() => {\n if (open) {\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n }\n }, [open]);\n\n const handleContactEmailChange = (value: string) => {\n setContactEmail(value);\n setContactEmailError(validateEmail(value));\n };\n\n const handleDocsURLChange = (value: string) => {\n setDocsURL(value);\n setDocsURLError(validateURL(value));\n };\n\n const handleOpenAPISpecChange = (value: string) => {\n setOpenAPISpec(value);\n setOpenAPISpecError(validateURL(value));\n };\n\n const handleAddTag = () => {\n if (tagInput.trim() && !tags.includes(tagInput.trim())) {\n setTags([...tags, tagInput.trim()]);\n setTagInput('');\n }\n };\n\n const handleDeleteTag = (tagToDelete: string) => {\n setTags(tags.filter(tag => tag !== tagToDelete));\n };\n\n const handleSave = async () => {\n setError('');\n setSaving(true);\n\n try {\n const patch = {\n spec: {\n displayName,\n description,\n version,\n publishStatus,\n approvalMode,\n tags,\n targetRef,\n ...(contactEmail || contactTeam ? {\n contact: {\n ...(contactEmail && { email: contactEmail }),\n ...(contactTeam && { team: contactTeam }),\n },\n } : {}),\n ...(docsURL || openAPISpec ? {\n documentation: {\n ...(docsURL && { docsURL }),\n ...(openAPISpec && { openAPISpec }),\n },\n } : {}),\n },\n };\n\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,\n {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(patch),\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || 'failed to update apiproduct');\n }\n\n onSuccess();\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>Edit API Product</DialogTitle>\n <DialogContent>\n {error && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n {error}\n </Alert>\n )}\n {planPoliciesError && (\n <Alert severity=\"warning\" style={{ marginBottom: 16 }}>\n <strong>Failed to load PlanPolicies:</strong> {planPoliciesError.message}\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n Plan information may be incomplete.\n </Typography>\n </Alert>\n )}\n {loading ? (\n <Progress />\n ) : (\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n disabled\n helperText=\"Kubernetes resource name (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Namespace\"\n value={namespace}\n disabled\n helperText=\"Derived from HTTPRoute (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Display Name\"\n value={displayName}\n onChange={e => setDisplayName(e.target.value)}\n placeholder=\"My API\"\n margin=\"normal\"\n required\n disabled={saving}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Version\"\n value={version}\n onChange={e => setVersion(e.target.value)}\n placeholder=\"v1\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n select\n label=\"Publish Status\"\n value={publishStatus}\n onChange={e => setPublishStatus(e.target.value as 'Draft' | 'Published')}\n margin=\"normal\"\n helperText=\"Draft: Hidden from catalog. Published: Visible in catalog.\"\n disabled={saving}\n >\n <MenuItem value=\"Draft\">Draft (Hidden)</MenuItem>\n <MenuItem value=\"Published\">Published (Visible)</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n select\n label=\"Approval Mode\"\n value={approvalMode}\n onChange={e => setApprovalMode(e.target.value as 'automatic' | 'manual')}\n margin=\"normal\"\n helperText=\"Automatic: keys created immediately. Manual: requires approval.\"\n disabled={saving}\n >\n <MenuItem value=\"manual\">Manual</MenuItem>\n <MenuItem value=\"automatic\">Automatic</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"Description\"\n value={description}\n onChange={e => setDescription(e.target.value)}\n placeholder=\"API description\"\n margin=\"normal\"\n multiline\n rows={2}\n required\n disabled={saving}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\" gutterBottom style={{ marginTop: 16 }}>\n Tags\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" marginBottom={1} style={{ gap: 8 }}>\n {tags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n onDelete={saving ? undefined : () => handleDeleteTag(tag)}\n size=\"small\"\n disabled={saving}\n />\n ))}\n </Box>\n <Box display=\"flex\" style={{ gap: 8 }}>\n <TextField\n fullWidth\n size=\"small\"\n value={tagInput}\n onChange={e => setTagInput(e.target.value)}\n onKeyPress={e => e.key === 'Enter' && handleAddTag()}\n placeholder=\"Add tag\"\n disabled={saving}\n />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\" disabled={saving}>\n Add\n </Button>\n </Box>\n </Grid>\n {targetRef && (\n <>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"HTTPRoute\"\n value={`${targetRef.namespace || namespace}/${targetRef.name}`}\n disabled\n helperText=\"Target HTTPRoute (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n\n <Grid item xs={12}>\n <PlanPolicyDetails\n selectedPolicy={selectedPolicy}\n alertSeverity=\"info\"\n alertMessage=\"No PlanPolicy found for this HTTPRoute.\"\n includeTopMargin={false}\n />\n </Grid>\n </>\n )}\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => handleContactEmailChange(e.target.value)}\n placeholder=\"api-team@example.com\"\n helperText={contactEmailError || \"Contact email for API support\"}\n error={!!contactEmailError}\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Team\"\n value={contactTeam}\n onChange={e => setContactTeam(e.target.value)}\n placeholder=\"platform-team\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => handleDocsURLChange(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n helperText={docsURLError || \"Link to API documentation\"}\n error={!!docsURLError}\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => handleOpenAPISpecChange(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n helperText={openAPISpecError || \"Link to OpenAPI specification\"}\n error={!!openAPISpecError}\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n </Grid>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={saving}>Cancel</Button>\n <Button\n onClick={handleSave}\n color=\"primary\"\n variant=\"contained\"\n disabled={saving || loading || !displayName || !description || !!contactEmailError || !!docsURLError || !!openAPISpecError}\n startIcon={saving ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {saving ? 'Saving...' : 'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n","import React, { useState } from 'react';\nimport { Typography, Grid, Box, Chip, Button, IconButton } from '@material-ui/core';\nimport AddIcon from '@material-ui/icons/Add';\nimport DeleteIcon from '@material-ui/icons/Delete';\nimport EditIcon from '@material-ui/icons/Edit';\nimport {\n InfoCard,\n Header,\n Page,\n Content,\n SupportButton,\n Progress,\n ResponseErrorPanel,\n Link,\n Table,\n TableColumn,\n} from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { useApi, configApiRef, fetchApiRef, alertApiRef, identityApiRef } from '@backstage/core-plugin-api';\nimport { ApprovalQueueCard } from '../ApprovalQueueCard';\nimport { MyApiKeysCard } from '../MyApiKeysCard';\nimport { PermissionGate } from '../PermissionGate';\nimport { CreateAPIProductDialog } from '../CreateAPIProductDialog';\nimport {\n kuadrantApiProductCreatePermission,\n kuadrantApiProductDeleteOwnPermission,\n kuadrantApiProductDeleteAllPermission,\n kuadrantApiProductUpdateOwnPermission,\n kuadrantApiProductUpdateAllPermission,\n kuadrantApiProductListPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantApiKeyRequestReadOwnPermission,\n kuadrantPlanPolicyListPermission,\n} from '../../permissions';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { EditAPIProductDialog } from '../EditAPIProductDialog';\nimport { ConfirmDeleteDialog } from '../ConfirmDeleteDialog';\n\ntype KuadrantResource = {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: string;\n annotations?: Record<string, string>;\n };\n spec?: any;\n};\n\ntype KuadrantList = {\n items: KuadrantResource[];\n};\n\nexport const ResourceList = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const alertApi = useApi(alertApiRef);\n const identityApi = useApi(identityApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [userEntityRef, setUserEntityRef] = useState<string>('');\n const [createDialogOpen, setCreateDialogOpen] = useState(false);\n const [editDialogOpen, setEditDialogOpen] = useState(false);\n const [refreshTrigger, setRefreshTrigger] = useState(0);\n const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);\n const [apiProductToDelete, setApiProductToDelete] = useState<{ namespace: string; name: string } | null>(null);\n const [apiProductToEdit, setApiProductToEdit] = useState<{ namespace: string; name: string } | null>(null);\n const [deleting, setDeleting] = useState(false);\n const [deleteStats, setDeleteStats] = useState<{requests: number; secrets: number} | null>(null);\n\n const {\n allowed: canCreateApiProduct,\n loading: createPermissionLoading,\n error: createPermissionError,\n } = useKuadrantPermission(kuadrantApiProductCreatePermission);\n\n const {\n allowed: canViewAllRequests,\n loading: approvalQueueAllPermissionLoading,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadAllPermission);\n\n const {\n allowed: canViewOwnRequests,\n loading: approvalQueueOwnPermissionLoading,\n error: approvalQueuePermissionError,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadOwnPermission);\n\n const canViewApprovalQueue = canViewAllRequests || canViewOwnRequests;\n const approvalQueuePermissionLoading = approvalQueueAllPermissionLoading || approvalQueueOwnPermissionLoading;\n\n const {\n allowed: canDeleteOwnApiProduct,\n loading: deleteOwnPermissionLoading,\n } = useKuadrantPermission(kuadrantApiProductDeleteOwnPermission);\n\n const {\n allowed: canDeleteAllApiProducts,\n loading: deleteAllPermissionLoading,\n error: deletePermissionError,\n } = useKuadrantPermission(kuadrantApiProductDeleteAllPermission);\n\n const {\n allowed: canUpdateOwnApiProduct,\n } = useKuadrantPermission(kuadrantApiProductUpdateOwnPermission);\n\n const {\n allowed: canUpdateAllApiProducts,\n } = useKuadrantPermission(kuadrantApiProductUpdateAllPermission);\n\n const deletePermissionLoading = deleteOwnPermissionLoading || deleteAllPermissionLoading;\n\n const {\n allowed: canListPlanPolicies,\n loading: planPolicyPermissionLoading,\n error: planPolicyPermissionError,\n } = useKuadrantPermission(kuadrantPlanPolicyListPermission);\n\n useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n setUserEntityRef(identity.userEntityRef);\n }, [identityApi]);\n\n const { value: apiProducts, loading: apiProductsLoading, error: apiProductsError } = useAsync(async (): Promise<KuadrantList> => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`);\n return await response.json();\n }, [backendUrl, fetchApi, refreshTrigger]);\n\n const { value: planPolicies, loading: planPoliciesLoading, error: planPoliciesError } = useAsync(async (): Promise<KuadrantList> => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, refreshTrigger]);\n\n const loading = apiProductsLoading || planPoliciesLoading || createPermissionLoading || approvalQueuePermissionLoading || deletePermissionLoading || planPolicyPermissionLoading;\n const error = apiProductsError || planPoliciesError;\n const permissionError = createPermissionError || approvalQueuePermissionError || deletePermissionError || planPolicyPermissionError;\n\n const handleCreateSuccess = () => {\n setRefreshTrigger(prev => prev + 1);\n alertApi.post({ message: 'API Product created', severity: 'success', display: 'transient' });\n };\n\n const handleEditClick = (namespace: string, name: string) => {\n setApiProductToEdit({ namespace, name });\n setEditDialogOpen(true);\n };\n\n const handleEditSuccess = () => {\n setRefreshTrigger(prev => prev + 1);\n alertApi.post({ message: 'API Product updated', severity: 'success', display: 'transient' });\n };\n\n const handleDeleteClick = async (namespace: string, name: string) => {\n setApiProductToDelete({ namespace, name });\n setDeleteStats(null);\n\n try {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/requests?namespace=${namespace}`);\n if (response.ok) {\n const data = await response.json();\n const related = (data.items || []).filter(\n (r: any) => r.spec.apiName === name && r.spec.apiNamespace === namespace\n );\n const approved = related.filter((r: any) => r.status?.phase === 'Approved').length;\n setDeleteStats({ requests: related.length, secrets: approved });\n }\n } catch (err) {\n console.warn('Failed to fetch delete stats:', err);\n }\n\n setDeleteDialogOpen(true);\n };\n\n const handleDeleteConfirm = async () => {\n if (!apiProductToDelete) return;\n\n setDeleting(true);\n try {\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${apiProductToDelete.namespace}/${apiProductToDelete.name}`,\n { method: 'DELETE' }\n );\n\n if (!response.ok) {\n throw new Error('failed to delete apiproduct');\n }\n\n setRefreshTrigger(prev => prev + 1);\n alertApi.post({ message: 'API Product deleted', severity: 'success', display: 'transient' });\n } catch (err) {\n console.error('error deleting apiproduct:', err);\n alertApi.post({ message: 'Failed to delete API Product', severity: 'error', display: 'transient' });\n } finally {\n setDeleting(false);\n setDeleteDialogOpen(false);\n setApiProductToDelete(null);\n }\n };\n\n const handleDeleteCancel = () => {\n setDeleteDialogOpen(false);\n setApiProductToDelete(null);\n };\n\n const formatDate = (dateString: string) => {\n const date = new Date(dateString);\n return date.toLocaleDateString('en-GB', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n };\n\n const columns: TableColumn[] = [\n {\n title: 'Name',\n field: 'spec.displayName',\n render: (row: any) => {\n const publishStatus = row.spec?.publishStatus;\n const isPublished = publishStatus === 'Published';\n const displayName = row.spec?.displayName ?? row.metadata.name;\n\n if (isPublished) {\n return (\n <Link to={`/catalog/default/api/${row.metadata.name}/api-product`}>\n <strong>{displayName}</strong>\n </Link>\n );\n }\n\n return (\n <span className=\"text-muted\">\n <strong>{displayName}</strong>\n </span>\n );\n },\n customFilterAndSearch: (term, row: any) => {\n const displayName = row.spec?.displayName || row.metadata.name || '';\n return displayName.toLowerCase().includes(term.toLowerCase());\n },\n },\n {\n title: 'Resource Name',\n field: 'metadata.name',\n },\n {\n title: 'Version',\n field: 'spec.version',\n render: (row: any) => row.spec?.version || '-',\n },\n {\n title: 'HTTPRoute',\n field: 'spec.targetRef.name',\n render: (row: any) => row.spec?.targetRef?.name || '-',\n },\n {\n title: 'Publish Status',\n field: 'spec.publishStatus',\n render: (row: any) => {\n const status = row.spec?.publishStatus || 'Draft';\n return (\n <Chip\n label={status}\n size=\"small\"\n color={status === 'Published' ? 'primary' : 'default'}\n />\n );\n },\n },\n {\n title: 'Approval Mode',\n field: 'spec.approvalMode',\n render: (row: any) => {\n const mode = row.spec?.approvalMode || 'manual';\n return (\n <Chip\n label={mode}\n size=\"small\"\n color={mode === 'automatic' ? 'secondary' : 'default'}\n />\n );\n },\n },\n {\n title: 'Namespace',\n field: 'metadata.namespace',\n },\n {\n title: 'Created',\n field: 'metadata.creationTimestamp',\n render: (row: any) => formatDate(row.metadata.creationTimestamp),\n },\n {\n title: 'Actions',\n field: 'actions',\n filtering: false,\n render: (row: any) => {\n const owner = row.metadata?.annotations?.['backstage.io/owner'];\n const isOwner = owner === userEntityRef;\n const canEdit = canUpdateAllApiProducts || (canUpdateOwnApiProduct && isOwner);\n const canDelete = canDeleteAllApiProducts || (canDeleteOwnApiProduct && isOwner);\n\n if (!canEdit && !canDelete) return null;\n\n return (\n <Box display=\"flex\" style={{ gap: 4 }}>\n {canEdit && (\n <IconButton\n size=\"small\"\n onClick={() => handleEditClick(row.metadata.namespace, row.metadata.name)}\n title=\"Edit API Product\"\n >\n <EditIcon fontSize=\"small\" />\n </IconButton>\n )}\n\n {canDelete && (\n <IconButton\n size=\"small\"\n onClick={() => handleDeleteClick(row.metadata.namespace, row.metadata.name)}\n title=\"Delete API Product\"\n >\n <DeleteIcon fontSize=\"small\" />\n </IconButton>\n )}\n </Box>\n );\n },\n },\n ];\n\n const planPolicyColumns: TableColumn[] = [\n {\n title: 'Name',\n field: 'metadata.name',\n render: (row: any) => (\n <Link to={`/kuadrant/planpolicy/${row.metadata.namespace}/${row.metadata.name}`}>\n <strong>{row.metadata.name}</strong>\n </Link>\n ),\n },\n {\n title: 'Namespace',\n field: 'metadata.namespace',\n },\n ];\n\n const renderResources = (resources: KuadrantResource[] | undefined) => {\n if (!resources || resources.length === 0) {\n return <Typography variant=\"body2\" color=\"textSecondary\">No API products found</Typography>;\n }\n return (\n <Table\n options={{\n paging: resources.length > 5,\n pageSize: 20,\n search: true,\n filtering: true,\n debounceInterval: 300,\n toolbar: true,\n emptyRowsWhenPaging: false,\n }}\n columns={columns}\n data={resources}\n />\n );\n };\n\n const renderPlanPolicies = (resources: KuadrantResource[] | undefined) => {\n if (!resources || resources.length === 0) {\n return <Typography variant=\"body2\" color=\"textSecondary\">No plan policies found</Typography>;\n }\n return (\n <Table\n options={{ paging: false, search: false, toolbar: false }}\n columns={planPolicyColumns}\n data={resources}\n />\n );\n };\n\n return (\n <Page themeId=\"tool\">\n <Header title=\"Kuadrant\" subtitle=\"API management for Kubernetes\">\n <SupportButton>Manage API products and access requests</SupportButton>\n </Header>\n <Content>\n {loading && <Progress />}\n {error && <ResponseErrorPanel error={error} />}\n {permissionError && (\n <Box p={2}>\n <Typography color=\"error\">\n unable to check permissions: {permissionError.message}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n permission: {createPermissionError ? 'kuadrant.apiproduct.create' :\n deletePermissionError ? 'kuadrant.apiproduct.delete' :\n approvalQueuePermissionError ? 'kuadrant.apikeyrequest.read.all' :\n planPolicyPermissionError ? 'kuadrant.planpolicy.list' : 'unknown'}\n </Typography>\n <Typography variant=\"body2\" color=\"textSecondary\">\n please try again or contact your administrator\n </Typography>\n </Box>\n )}\n {!loading && !error && !permissionError && (\n <Grid container spacing={3} direction=\"column\">\n <Grid item>\n <MyApiKeysCard />\n </Grid>\n\n <Grid item>\n <InfoCard\n title=\"API Products\"\n action={\n canCreateApiProduct ? (\n <Box display=\"flex\" alignItems=\"center\" height=\"100%\" mt={1}>\n <Button\n variant=\"contained\"\n color=\"primary\"\n size=\"small\"\n startIcon={<AddIcon />}\n onClick={() => setCreateDialogOpen(true)}\n >\n Create API Product\n </Button>\n </Box>\n ) : undefined\n }\n >\n {renderResources(apiProducts?.items)}\n </InfoCard>\n </Grid>\n\n {canListPlanPolicies && (\n <Grid item>\n <InfoCard title=\"Plan Policies\">\n {renderPlanPolicies(planPolicies?.items)}\n </InfoCard>\n </Grid>\n )}\n\n {canViewApprovalQueue && (\n <Grid item>\n <ApprovalQueueCard />\n </Grid>\n )}\n </Grid>\n )}\n <CreateAPIProductDialog\n open={createDialogOpen}\n onClose={() => setCreateDialogOpen(false)}\n onSuccess={handleCreateSuccess}\n />\n <EditAPIProductDialog\n open={editDialogOpen}\n onClose={() => setEditDialogOpen(false)}\n onSuccess={handleEditSuccess}\n namespace={apiProductToEdit?.namespace || ''}\n name={apiProductToEdit?.name || ''}\n />\n <ConfirmDeleteDialog\n open={deleteDialogOpen}\n title=\"Delete API Product\"\n description={\n deleteStats\n ? `Deleting \"${apiProductToDelete?.name}\" will also remove:\n\n• ${deleteStats.requests} API Key Request(s)\n• ${deleteStats.secrets} API Key Secret(s)\n\nThis action cannot be undone.`\n : `Deleting \"${apiProductToDelete?.name}\" will also remove all associated API Key Requests and Secrets.\nThis action cannot be undone.`\n }\n confirmText={apiProductToDelete?.name}\n severity=\"high\"\n deleting={deleting}\n onConfirm={handleDeleteConfirm}\n onCancel={handleDeleteCancel}\n />\n </Content>\n </Page>\n );\n};\n\nexport const KuadrantPage = () => {\n return (\n <PermissionGate\n permission={kuadrantApiProductListPermission}\n errorMessage=\"you don't have permission to view the Kuadrant page\"\n >\n <ResourceList />\n </PermissionGate>\n );\n};\n","import React, { useState, useEffect } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Box,\n Typography,\n FormControl,\n InputLabel,\n Select,\n MenuItem,\n CircularProgress,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { APIKey } from '../../types/api-management';\n\ninterface EditAPIKeyDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n request: APIKey;\n availablePlans: Array<{\n tier: string;\n description?: string;\n limits?: any;\n }>;\n}\n\nexport const EditAPIKeyRequestDialog = ({\n open,\n onClose,\n onSuccess,\n request,\n availablePlans,\n}: EditAPIKeyDialogProps) => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const [planTier, setPlanTier] = useState('');\n const [useCase, setUseCase] = useState('');\n const [saving, setSaving] = useState(false);\n const [error, setError] = useState('');\n\n useEffect(() => {\n if (open && request) {\n setPlanTier(request.spec.planTier || '');\n setUseCase(request.spec.useCase || '');\n setError('');\n }\n }, [open, request]);\n\n const handleSave = async () => {\n if (!planTier) {\n setError('Please select a tier');\n return;\n }\n\n setError('');\n setSaving(true);\n\n try {\n const patch = {\n spec: {\n planTier,\n useCase: useCase.trim(),\n },\n };\n\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/requests/${request.metadata.namespace}/${request.metadata.name}`,\n {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(patch),\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json().catch(() => ({}));\n throw new Error(errorData.error || `Failed to update request: ${response.status}`);\n }\n\n onSuccess();\n onClose();\n } catch (err) {\n console.error('Error updating API key request:', err);\n setError(err instanceof Error ? err.message : 'Unknown error occurred');\n } finally {\n setSaving(false);\n }\n };\n\n const handleClose = () => {\n if (!saving) {\n setError('');\n onClose();\n }\n };\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"sm\" fullWidth>\n <DialogTitle>Edit API Access Request</DialogTitle>\n <DialogContent>\n {error && (\n <Box mb={2} p={2} bgcolor=\"error.main\" color=\"error.contrastText\" borderRadius={1}>\n <Typography variant=\"body2\">{error}</Typography>\n </Box>\n )}\n\n <FormControl fullWidth margin=\"normal\">\n <InputLabel>Tier</InputLabel>\n <Select\n value={planTier}\n onChange={(e) => setPlanTier(e.target.value as string)}\n disabled={saving}\n >\n {availablePlans.map((plan) => {\n const limitDesc = Object.entries(plan.limits || {})\n .map(([key, val]) => `${val} per ${key}`)\n .join(', ');\n return (\n <MenuItem key={plan.tier} value={plan.tier}>\n {plan.tier} {limitDesc ? `(${limitDesc})` : ''}\n </MenuItem>\n );\n })}\n </Select>\n </FormControl>\n\n <TextField\n label=\"Use Case\"\n placeholder=\"Describe how you plan to use this API\"\n multiline\n rows={3}\n fullWidth\n margin=\"normal\"\n value={useCase}\n onChange={(e) => setUseCase(e.target.value)}\n disabled={saving}\n helperText=\"Explain your intended use of this API for admin review\"\n />\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={saving}>\n Cancel\n </Button>\n <Button\n onClick={handleSave}\n color=\"primary\"\n variant=\"contained\"\n disabled={!planTier || saving}\n startIcon={saving ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {saving ? 'Saving...' : 'Save Changes'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":["ConfirmDeleteDialog","open","title","description","confirmText","severity","deleting","onConfirm","onCancel","inputValue","setInputValue","useState","useEffect","requiresTextConfirmation","canConfirm","Dialog","onClose","undefined","maxWidth","fullWidth","DialogTitle","Box","display","alignItems","style","gap","WarningIcon","color","span","DialogContent","DialogContentText","whiteSpace","mt","Typography","variant","gutterBottom","strong","TextField","size","value","onChange","e","target","disabled","autoFocus","placeholder","DialogActions","Button","onClick","startIcon","CircularProgress","MyApiKeysCard","deleteDialogState","config","useApi","configApiRef","fetchApi","fetchApiRef","identityApi","identityApiRef","alertApi","alertApiRef","backendUrl","getString","selectedTab","setSelectedTab","setUserId","visibleKeys","setVisibleKeys","Set","menuAnchor","setMenuAnchor","menuRequest","setMenuRequest","editDialogState","setEditDialogState","request","plans","refresh","setRefresh","setDeleting","setDeleteDialogState","apiKeyValues","setApiKeyValues","Map","apiKeyLoading","setApiKeyLoading","useAsync","async","identity","getBackstageIdentity","extractedUserId","userEntityRef","split","console","log","optimisticallyDeleted","setOptimisticallyDeleted","requests","loading","error","response","fetch","ok","Error","json","items","InfoCard","Progress","message","allRequests","filter","r","has","metadata","name","approvedRequests","status","phase","pendingRequests","rejectedRequests","toggleKeyVisibility","keyName","prev","newSet","delete","add","handleMenuClose","handleEdit","apiProductName","spec","apiProductRef","apiProductNamespace","namespace","apiProductResponse","apiProduct","err","handleDeleteClick","columns","field","render","row","Link","to","planTier","Chip","label","useCase","Tooltip","placement","overflow","textOverflow","reviewedBy","reviewedDate","reviewedAt","Date","toLocaleDateString","filtering","key","hasSecretRef","secretRef","isVisible","isLoading","apiKeyValue","get","fontFamily","fontSize","repeat","IconButton","requestNamespace","requestName","next","clearApiKeyValue","data","set","apiKey","fetchApiKeyFromSecret","VisibilityOffIcon","VisibilityIcon","creationTimestamp","date","stopPropagation","rect","currentTarget","getBoundingClientRect","top","bottom","left","aria-controls","aria-haspopup","MoreVertIcon","tabData","getTabData","tabColumns","col","getTabColumns","subheader","length","mb","Tabs","_","newValue","indicatorColor","textColor","Tab","p","textAlign","Table","options","paging","pageSize","search","debounceInterval","toolbar","emptyRowsWhenPaging","map","item","id","Menu","Boolean","anchorReference","anchorPosition","push","MenuItem","EditAPIKeyRequestDialog","availablePlans","onSuccess","method","post","PermissionGate","children","permission","fallback","errorMessage","allowed","useKuadrantPermission","PlanPolicyDetails","selectedPolicy","alertSeverity","alertMessage","includeTopMargin","bgcolor","borderRadius","border","fontWeight","marginTop","flexWrap","plan","idx","limitText","limits","daily","monthly","yearly","tier","some","Alert","validateEmail","test","validateURL","url","URL","includes","protocol","useStyles","makeStyles","asterisk","CreateAPIProductDialog","classes","setName","displayName","setDisplayName","setDescription","version","setVersion","approvalMode","setApprovalMode","publishStatus","setPublishStatus","tags","setTags","tagInput","setTagInput","selectedHTTPRoute","setSelectedHTTPRoute","contactEmail","setContactEmail","contactTeam","setContactTeam","docsURL","setDocsURL","openAPISpec","setOpenAPISpec","setError","creating","setCreating","httpRoutesRetry","setHttpRoutesRetry","nameError","setNameError","contactEmailError","setContactEmailError","docsURLError","setDocsURLError","openAPISpecError","setOpenAPISpecError","httpRoutes","httpRoutesLoading","httpRoutesError","route","annotations","planPolicies","planPoliciesError","selectedRouteInfo","routeNamespace","routeName","find","pp","ref","targetRef","kind","handleAddTag","trim","handleClose","hasValidationErrors","marginBottom","Grid","container","spacing","xs","handleNameChange","validateKubernetesName","helperText","margin","required","InputLabelProps","select","multiline","rows","tag","onDelete","handleDeleteTag","tagToDelete","onKeyPress","handleContactEmailChange","handleDocsURLChange","handleOpenAPISpecChange","selectedRouteNamespace","selectedRouteName","apiVersion","group","contact","email","team","documentation","headers","body","JSON","stringify","errorData","String","EditAPIProductDialog","setLoading","setTargetRef","saving","setSaving","then","res","catch","React","patch","ResourceList","setUserEntityRef","createDialogOpen","setCreateDialogOpen","editDialogOpen","setEditDialogOpen","refreshTrigger","setRefreshTrigger","deleteDialogOpen","setDeleteDialogOpen","apiProductToDelete","setApiProductToDelete","apiProductToEdit","setApiProductToEdit","deleteStats","setDeleteStats","canCreateApiProduct","createPermissionLoading","createPermissionError","kuadrantApiProductCreatePermission","canViewAllRequests","approvalQueueAllPermissionLoading","kuadrantApiKeyRequestReadAllPermission","canViewOwnRequests","approvalQueueOwnPermissionLoading","approvalQueuePermissionError","kuadrantApiKeyRequestReadOwnPermission","canViewApprovalQueue","approvalQueuePermissionLoading","canDeleteOwnApiProduct","deleteOwnPermissionLoading","kuadrantApiProductDeleteOwnPermission","canDeleteAllApiProducts","deleteAllPermissionLoading","deletePermissionError","kuadrantApiProductDeleteAllPermission","canUpdateOwnApiProduct","kuadrantApiProductUpdateOwnPermission","canUpdateAllApiProducts","kuadrantApiProductUpdateAllPermission","deletePermissionLoading","canListPlanPolicies","planPolicyPermissionLoading","planPolicyPermissionError","kuadrantPlanPolicyListPermission","apiProducts","apiProductsLoading","apiProductsError","planPoliciesLoading","permissionError","isPublished","className","customFilterAndSearch","term","toLowerCase","mode","formatDate","dateString","year","month","day","isOwner","canEdit","canDelete","handleEditClick","EditIcon","related","apiName","apiNamespace","approved","secrets","warn","DeleteIcon","planPolicyColumns","Page","themeId","Header","subtitle","SupportButton","Content","ResponseErrorPanel","direction","action","height","AddIcon","resources","renderPlanPolicies","ApprovalQueueCard","KuadrantPage","kuadrantApiProductListPermission","setPlanTier","setUseCase","FormControl","InputLabel","Select","limitDesc","Object","entries","val","join"],"sourceRoot":""}
@@ -0,0 +1,2 @@
1
+ "use strict";(self.webpackChunkinternal_plugin_kuadrant=self.webpackChunkinternal_plugin_kuadrant||[]).push([[879],{72627:(e,n,a)=>{a.r(n),a.d(n,{EntityKuadrantApiAccessCard:()=>p,EntityKuadrantApiKeyManagementTab:()=>u,EntityKuadrantApiKeysContent:()=>l,EntityKuadrantApiProductInfoContent:()=>m,KuadrantApprovalQueueCard:()=>c,KuadrantPage:()=>d,PlanPolicyDetailPage:()=>s,kuadrantPlugin:()=>i});var t=a(22097);const o=(0,t.createRouteRef)({id:"kuadrant"}),r=(0,t.createSubRouteRef)({id:"kuadrant/resource",parent:o,path:"/:kind/:namespace/:name"}),i=(0,t.createPlugin)({id:"kuadrant",routes:{root:o,resource:r}}),d=i.provide((0,t.createRoutableExtension)({name:"KuadrantPage",component:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(2120),a.e(2198),a.e(4556),a.e(3483),a.e(8441),a.e(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(7094),a.e(6281),a.e(532)]).then(a.bind(a,80532)).then(e=>e.KuadrantPage),mountPoint:o})),p=i.provide((0,t.createComponentExtension)({name:"EntityKuadrantApiAccessCard",component:{lazy:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(6659),a.e(441)]).then(a.bind(a,60441)).then(e=>e.ApiAccessCard)}})),u=i.provide((0,t.createComponentExtension)({name:"EntityKuadrantApiKeyManagementTab",component:{lazy:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(2120),a.e(2198),a.e(4556),a.e(5478),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(7094),a.e(6659),a.e(4306)]).then(a.bind(a,54306)).then(e=>e.ApiKeyManagementTab)}})),l=i.provide((0,t.createComponentExtension)({name:"EntityKuadrantApiKeysContent",component:{lazy:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(2120),a.e(2198),a.e(4556),a.e(5478),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(7094),a.e(6659),a.e(4306)]).then(a.bind(a,54306)).then(e=>e.ApiKeyManagementTab)}})),c=i.provide((0,t.createComponentExtension)({name:"KuadrantApprovalQueueCard",component:{lazy:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(2120),a.e(2198),a.e(4556),a.e(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(7094),a.e(6281),a.e(5222)]).then(a.bind(a,95631)).then(e=>e.ApprovalQueueCard)}})),m=i.provide((0,t.createComponentExtension)({name:"EntityKuadrantApiProductInfoContent",component:{lazy:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(2120),a.e(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(7094),a.e(6659),a.e(5453)]).then(a.bind(a,75453)).then(e=>e.ApiProductInfoCard)}})),s=i.provide((0,t.createComponentExtension)({name:"PlanPolicyDetailPage",component:{lazy:()=>Promise.all([a.e(5568),a.e(6352),a.e(9288),a.e(2198),a.e(3483),a.e(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),a.e(8365)]).then(a.bind(a,58365)).then(e=>e.PlanPolicyDetailPage)}}))}}]);
2
+ //# sourceMappingURL=exposed-PluginRoot.7023ce03.chunk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"static/exposed-PluginRoot.0ac7fe4b.chunk.js","mappings":"6ZAEO,MAAMA,GAAeC,EAAAA,EAAAA,gBAAe,CACzCC,GAAI,aAGOC,GAAmBC,EAAAA,EAAAA,mBAAkB,CAChDF,GAAI,oBACJG,OAAQL,EACRM,KAAM,4BCDKC,GAAiBC,EAAAA,EAAAA,cAAa,CACzCN,GAAI,WACJO,OAAQ,CACNC,KAAMV,EACNW,SAAUR,KAIDS,EAAeL,EAAeM,SACzCC,EAAAA,EAAAA,yBAAwB,CACtBC,KAAM,eACNC,UAAW,IACT,8MAAoCC,KAAKC,GAAKA,EAAEN,cAClDO,WAAYnB,KAIHoB,EAA8Bb,EAAeM,SACxDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,8BACNC,UAAW,CACTM,KAAM,IACJ,iJAAqCL,KAAKC,GAAKA,EAAEK,mBAK5CC,EAAoCjB,EAAeM,SAC9DQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,oCACNC,UAAW,CACTM,KAAM,IACJ,gLAA2CL,KAAKC,GAAKA,EAAEO,yBAMlDC,EAA+BnB,EAAeM,SACzDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,+BACNC,UAAW,CACTM,KAAM,IACJ,gLAA2CL,KAAKC,GAAKA,EAAEO,yBAKlDE,EAA4BpB,EAAeM,SACtDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,4BACNC,UAAW,CACTM,KAAM,IACJ,0LAAyCL,KAAKC,GAAKA,EAAEU,uBAKhDC,EAAsCtB,EAAeM,SAChEQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,sCACNC,UAAW,CACTM,KAAM,IACJ,sKAA0CL,KAAKC,GAAKA,EAAEY,wBAKjDC,EAAuBxB,EAAeM,SACjDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,uBACNC,UAAW,CACTM,KAAM,IACJ,4JAA4CL,KAAKC,GAAKA,EAAEa,yB","sources":["webpack://internal.plugin-kuadrant/./src/routes.ts","webpack://internal.plugin-kuadrant/./src/plugin.ts"],"sourcesContent":["import { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'kuadrant',\n});\n\nexport const resourceRouteRef = createSubRouteRef({\n id: 'kuadrant/resource',\n parent: rootRouteRef,\n path: '/:kind/:namespace/:name',\n});\n","import {\n createPlugin,\n createRoutableExtension,\n createComponentExtension,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef, resourceRouteRef } from './routes';\n\nexport const kuadrantPlugin = createPlugin({\n id: 'kuadrant',\n routes: {\n root: rootRouteRef,\n resource: resourceRouteRef,\n },\n});\n\nexport const KuadrantPage = kuadrantPlugin.provide(\n createRoutableExtension({\n name: 'KuadrantPage',\n component: () =>\n import('./components/KuadrantPage').then(m => m.KuadrantPage),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const EntityKuadrantApiAccessCard = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiAccessCard',\n component: {\n lazy: () =>\n import('./components/ApiAccessCard').then(m => m.ApiAccessCard),\n },\n }),\n);\n\nexport const EntityKuadrantApiKeyManagementTab = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiKeyManagementTab',\n component: {\n lazy: () =>\n import('./components/ApiKeyManagementTab').then(m => m.ApiKeyManagementTab),\n },\n }),\n);\n\n// entity content extension for api keys tab\nexport const EntityKuadrantApiKeysContent = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiKeysContent',\n component: {\n lazy: () =>\n import('./components/ApiKeyManagementTab').then(m => m.ApiKeyManagementTab),\n },\n }),\n);\n\nexport const KuadrantApprovalQueueCard = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'KuadrantApprovalQueueCard',\n component: {\n lazy: () =>\n import('./components/ApprovalQueueCard').then(m => m.ApprovalQueueCard),\n },\n }),\n);\n\nexport const EntityKuadrantApiProductInfoContent = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiProductInfoContent',\n component: {\n lazy: () =>\n import('./components/ApiProductInfoCard').then(m => m.ApiProductInfoCard),\n },\n }),\n);\n\nexport const PlanPolicyDetailPage = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'PlanPolicyDetailPage',\n component: {\n lazy: () =>\n import('./components/PlanPolicyDetailPage').then(m => m.PlanPolicyDetailPage),\n },\n }),\n);\n"],"names":["rootRouteRef","createRouteRef","id","resourceRouteRef","createSubRouteRef","parent","path","kuadrantPlugin","createPlugin","routes","root","resource","KuadrantPage","provide","createRoutableExtension","name","component","then","m","mountPoint","EntityKuadrantApiAccessCard","createComponentExtension","lazy","ApiAccessCard","EntityKuadrantApiKeyManagementTab","ApiKeyManagementTab","EntityKuadrantApiKeysContent","KuadrantApprovalQueueCard","ApprovalQueueCard","EntityKuadrantApiProductInfoContent","ApiProductInfoCard","PlanPolicyDetailPage"],"sourceRoot":""}
1
+ {"version":3,"file":"static/exposed-PluginRoot.7023ce03.chunk.js","mappings":"6ZAEO,MAAMA,GAAeC,EAAAA,EAAAA,gBAAe,CACzCC,GAAI,aAGOC,GAAmBC,EAAAA,EAAAA,mBAAkB,CAChDF,GAAI,oBACJG,OAAQL,EACRM,KAAM,4BCDKC,GAAiBC,EAAAA,EAAAA,cAAa,CACzCN,GAAI,WACJO,OAAQ,CACNC,KAAMV,EACNW,SAAUR,KAIDS,EAAeL,EAAeM,SACzCC,EAAAA,EAAAA,yBAAwB,CACtBC,KAAM,eACNC,UAAW,IACT,6MAAoCC,KAAKC,GAAKA,EAAEN,cAClDO,WAAYnB,KAIHoB,EAA8Bb,EAAeM,SACxDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,8BACNC,UAAW,CACTM,KAAM,IACJ,iJAAqCL,KAAKC,GAAKA,EAAEK,mBAK5CC,EAAoCjB,EAAeM,SAC9DQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,oCACNC,UAAW,CACTM,KAAM,IACJ,gLAA2CL,KAAKC,GAAKA,EAAEO,yBAMlDC,EAA+BnB,EAAeM,SACzDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,+BACNC,UAAW,CACTM,KAAM,IACJ,gLAA2CL,KAAKC,GAAKA,EAAEO,yBAKlDE,EAA4BpB,EAAeM,SACtDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,4BACNC,UAAW,CACTM,KAAM,IACJ,0LAAyCL,KAAKC,GAAKA,EAAEU,uBAKhDC,EAAsCtB,EAAeM,SAChEQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,sCACNC,UAAW,CACTM,KAAM,IACJ,sKAA0CL,KAAKC,GAAKA,EAAEY,wBAKjDC,EAAuBxB,EAAeM,SACjDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,uBACNC,UAAW,CACTM,KAAM,IACJ,4JAA4CL,KAAKC,GAAKA,EAAEa,yB","sources":["webpack://internal.plugin-kuadrant/./src/routes.ts","webpack://internal.plugin-kuadrant/./src/plugin.ts"],"sourcesContent":["import { createRouteRef, createSubRouteRef } from '@backstage/core-plugin-api';\n\nexport const rootRouteRef = createRouteRef({\n id: 'kuadrant',\n});\n\nexport const resourceRouteRef = createSubRouteRef({\n id: 'kuadrant/resource',\n parent: rootRouteRef,\n path: '/:kind/:namespace/:name',\n});\n","import {\n createPlugin,\n createRoutableExtension,\n createComponentExtension,\n} from '@backstage/core-plugin-api';\n\nimport { rootRouteRef, resourceRouteRef } from './routes';\n\nexport const kuadrantPlugin = createPlugin({\n id: 'kuadrant',\n routes: {\n root: rootRouteRef,\n resource: resourceRouteRef,\n },\n});\n\nexport const KuadrantPage = kuadrantPlugin.provide(\n createRoutableExtension({\n name: 'KuadrantPage',\n component: () =>\n import('./components/KuadrantPage').then(m => m.KuadrantPage),\n mountPoint: rootRouteRef,\n }),\n);\n\nexport const EntityKuadrantApiAccessCard = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiAccessCard',\n component: {\n lazy: () =>\n import('./components/ApiAccessCard').then(m => m.ApiAccessCard),\n },\n }),\n);\n\nexport const EntityKuadrantApiKeyManagementTab = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiKeyManagementTab',\n component: {\n lazy: () =>\n import('./components/ApiKeyManagementTab').then(m => m.ApiKeyManagementTab),\n },\n }),\n);\n\n// entity content extension for api keys tab\nexport const EntityKuadrantApiKeysContent = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiKeysContent',\n component: {\n lazy: () =>\n import('./components/ApiKeyManagementTab').then(m => m.ApiKeyManagementTab),\n },\n }),\n);\n\nexport const KuadrantApprovalQueueCard = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'KuadrantApprovalQueueCard',\n component: {\n lazy: () =>\n import('./components/ApprovalQueueCard').then(m => m.ApprovalQueueCard),\n },\n }),\n);\n\nexport const EntityKuadrantApiProductInfoContent = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'EntityKuadrantApiProductInfoContent',\n component: {\n lazy: () =>\n import('./components/ApiProductInfoCard').then(m => m.ApiProductInfoCard),\n },\n }),\n);\n\nexport const PlanPolicyDetailPage = kuadrantPlugin.provide(\n createComponentExtension({\n name: 'PlanPolicyDetailPage',\n component: {\n lazy: () =>\n import('./components/PlanPolicyDetailPage').then(m => m.PlanPolicyDetailPage),\n },\n }),\n);\n"],"names":["rootRouteRef","createRouteRef","id","resourceRouteRef","createSubRouteRef","parent","path","kuadrantPlugin","createPlugin","routes","root","resource","KuadrantPage","provide","createRoutableExtension","name","component","then","m","mountPoint","EntityKuadrantApiAccessCard","createComponentExtension","lazy","ApiAccessCard","EntityKuadrantApiKeyManagementTab","ApiKeyManagementTab","EntityKuadrantApiKeysContent","KuadrantApprovalQueueCard","ApprovalQueueCard","EntityKuadrantApiProductInfoContent","ApiProductInfoCard","PlanPolicyDetailPage"],"sourceRoot":""}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kuadrant/kuadrant-backstage-plugin-frontend",
3
- "version": "0.0.2-dev-06b7d4e",
3
+ "version": "0.0.2-dev-b0a6833",
4
4
  "license": "Apache-2.0",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1,2 +0,0 @@
1
- "use strict";(self.webpackChunkinternal_plugin_kuadrant=self.webpackChunkinternal_plugin_kuadrant||[]).push([[7632],{63221:(e,a,t)=>{t.d(a,{K:()=>v});var s=t(31085),n=t(95478),l=t(76891),i=t(61477),r=t(10394),o=t(46805),d=t(59461),c=t(72501),u=t(16249),p=t(93453),m=t(64947),h=t(78467),x=t(77225);const v=({open:e,title:a,description:t,confirmText:v,severity:A="normal",deleting:g=!1,onConfirm:j,onCancel:f})=>{const[y,b]=(0,n.useState)("");(0,n.useEffect)(()=>{e||b("")},[e]);const P="high"===A&&v,S=!P||y===v;return(0,s.jsxs)(l.A,{open:e,onClose:g?void 0:f,maxWidth:"sm",fullWidth:!0,children:[(0,s.jsxs)(i.A,{children:["high"===A&&(0,s.jsxs)(r.A,{display:"flex",alignItems:"center",style:{gap:8},children:[(0,s.jsx)(x.A,{color:"error"}),(0,s.jsx)("span",{children:a})]}),"high"!==A&&a]}),(0,s.jsxs)(o.A,{children:[(0,s.jsx)(d.A,{style:{whiteSpace:"pre-line"},children:t}),P&&(0,s.jsxs)(r.A,{mt:2,children:[(0,s.jsxs)(c.A,{variant:"body2",color:"textSecondary",gutterBottom:!0,children:["Type ",(0,s.jsx)("strong",{children:v})," to confirm:"]}),(0,s.jsx)(u.A,{fullWidth:!0,variant:"outlined",size:"small",value:y,onChange:e=>b(e.target.value),disabled:g,autoFocus:!0,placeholder:v})]})]}),(0,s.jsxs)(p.A,{children:[(0,s.jsx)(m.A,{onClick:f,disabled:g,children:"Cancel"}),(0,s.jsx)(m.A,{onClick:()=>{S&&j()},color:"secondary",variant:"contained",disabled:g||!S,startIcon:g?(0,s.jsx)(h.A,{size:16,color:"inherit"}):void 0,children:g?"Deleting...":"Delete"})]})]})}},84189:(e,a,t)=>{t.d(a,{n:()=>j});var s=t(31085),n=t(95478),l=t(76891),i=t(61477),r=t(46805),o=t(10394),d=t(72501),c=t(95061),u=t(48543),p=t(81215),m=t(26343),h=t(16249),x=t(93453),v=t(64947),A=t(78467),g=t(22097);const j=({open:e,onClose:a,onSuccess:t,request:j,availablePlans:f})=>{const y=(0,g.useApi)(g.configApiRef),b=(0,g.useApi)(g.fetchApiRef),P=y.getString("backend.baseUrl"),[S,w]=(0,n.useState)(""),[k,C]=(0,n.useState)(""),[T,R]=(0,n.useState)(!1),[I,$]=(0,n.useState)("");(0,n.useEffect)(()=>{e&&j&&(w(j.spec.planTier||""),C(j.spec.useCase||""),$(""))},[e,j]);const q=()=>{T||($(""),a())};return(0,s.jsxs)(l.A,{open:e,onClose:q,maxWidth:"sm",fullWidth:!0,children:[(0,s.jsx)(i.A,{children:"Edit API Access Request"}),(0,s.jsxs)(r.A,{children:[I&&(0,s.jsx)(o.A,{mb:2,p:2,bgcolor:"error.main",color:"error.contrastText",borderRadius:1,children:(0,s.jsx)(d.A,{variant:"body2",children:I})}),(0,s.jsxs)(c.A,{fullWidth:!0,margin:"normal",children:[(0,s.jsx)(u.A,{children:"Tier"}),(0,s.jsx)(p.A,{value:S,onChange:e=>w(e.target.value),disabled:T,children:f.map(e=>{const a=Object.entries(e.limits||{}).map(([e,a])=>`${a} per ${e}`).join(", ");return(0,s.jsxs)(m.A,{value:e.tier,children:[e.tier," ",a?`(${a})`:""]},e.tier)})})]}),(0,s.jsx)(h.A,{label:"Use Case",placeholder:"Describe how you plan to use this API",multiline:!0,rows:3,fullWidth:!0,margin:"normal",value:k,onChange:e=>C(e.target.value),disabled:T,helperText:"Explain your intended use of this API for admin review"})]}),(0,s.jsxs)(x.A,{children:[(0,s.jsx)(v.A,{onClick:q,disabled:T,children:"Cancel"}),(0,s.jsx)(v.A,{onClick:async()=>{if(S){$(""),R(!0);try{const e={spec:{planTier:S,useCase:k.trim()}},s=await b.fetch(`${P}/api/kuadrant/requests/${j.metadata.namespace}/${j.metadata.name}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){const e=await s.json().catch(()=>({}));throw new Error(e.error||`Failed to update request: ${s.status}`)}t(),a()}catch(e){console.error("Error updating API key request:",e),$(e instanceof Error?e.message:"Unknown error occurred")}finally{R(!1)}}else $("Please select a tier")},color:"primary",variant:"contained",disabled:!S||T,startIcon:T?(0,s.jsx)(A.A,{size:16,color:"inherit"}):void 0,children:T?"Saving...":"Save Changes"})]})]})}},95251:(e,a,t)=>{t.r(a),t.d(a,{KuadrantPage:()=>ae});var s=t(31085),n=t(95478),l=t.n(n),i=t(67720),r=t(10394),o=t(29365),d=t(72501),c=t(42899),u=t(64947),p=t(18466),m=t(39590),h=t(75625),x=t(37725),v=t(25010),A=t(289),g=t(55639),j=t(45210),f=t(46681),y=t(86687),b=t(42367),P=t(96040),S=t(91638),w=t(22097),k=t(16281),C=t(71677),T=t(78467),R=t(31653),I=t(38605),$=t(37757),q=t(26343),W=t(32269),E=t(61524),N=t(71407),D=t(84189),M=t(63221);const z=()=>{var e,a;const t=(0,w.useApi)(w.configApiRef),l=(0,w.useApi)(w.fetchApiRef),c=(0,w.useApi)(w.identityApiRef),u=(0,w.useApi)(w.alertApiRef),p=t.getString("backend.baseUrl"),[m,h]=(0,n.useState)(0),[,A]=(0,n.useState)(""),[g,j]=(0,n.useState)(new Set),[f,b]=(0,n.useState)(null),[k,z]=(0,n.useState)(null),[K,L]=(0,n.useState)({open:!1,request:null,plans:[]}),[B,U]=(0,n.useState)(0),[F,H]=(0,n.useState)(null),[_,O]=(0,n.useState)({open:!1,request:null}),[V,J]=(0,n.useState)(new Map),[Y,X]=(0,n.useState)(new Set);(0,S.A)(async()=>{const e=await c.getBackstageIdentity(),a=e.userEntityRef.split("/")[1]||"guest";console.log(`MyApiKeysCard: setting userId from userEntityRef: ${e.userEntityRef} -> "${a}"`),A(a)},[c]);const[G,Q]=(0,n.useState)(new Set),{value:Z,loading:ee,error:ae}=(0,S.A)(async()=>{const e=await l.fetch(`${p}/api/kuadrant/requests/my`);if(!e.ok)throw new Error("failed to fetch requests");return(await e.json()).items||[]},[p,l,B]);if(ee)return(0,s.jsx)(P.n,{title:"My API Keys",children:(0,s.jsx)(y.k,{})});if(ae)return(0,s.jsx)(P.n,{title:"My API Keys",children:(0,s.jsxs)(d.A,{color:"error",children:["Error loading API keys: ",ae.message]})});const te=(Z||[]).filter(e=>!G.has(e.metadata.name)),se=te.filter(e=>{var a;return"Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)}),ne=te.filter(e=>{var a;return!(null===(a=e.status)||void 0===a?void 0:a.phase)||"Pending"===e.status.phase}),le=te.filter(e=>{var a;return"Rejected"===(null===(a=e.status)||void 0===a?void 0:a.phase)}),ie=e=>{j(a=>{const t=new Set(a);return t.has(e)?t.delete(e):t.add(e),t})},re=()=>{b(null),z(null)},oe=async()=>{if(!k)return;const e=k;re();try{var a;const s=null===(a=e.spec.apiProductRef)||void 0===a?void 0:a.name,n=e.metadata.namespace,i=await l.fetch(`${p}/api/kuadrant/apiproducts/${n}/${s}`);if(i.ok){var t;const a=(null===(t=(await i.json()).spec)||void 0===t?void 0:t.plans)||[];L({open:!0,request:e,plans:a})}else console.error("Failed to fetch API product"),L({open:!0,request:e,plans:[]})}catch(a){console.error("Error fetching plans:",a),L({open:!0,request:e,plans:[]})}},de=()=>{if(!k)return;const e=k;re(),O({open:!0,request:e})},ce=[{title:"API Product",field:"spec.apiProductRef.name",render:e=>{var a;const t=(null===(a=e.spec.apiProductRef)||void 0===a?void 0:a.name)||"unknown";return(0,s.jsx)(x.N_,{to:`/catalog/default/api/${t}/api-keys`,children:(0,s.jsx)("strong",{children:t})})}},{title:"Tier",field:"spec.planTier",render:e=>{const a="gold"===e.spec.planTier?"primary":"silver"===e.spec.planTier?"default":"secondary";return(0,s.jsx)(i.A,{label:e.spec.planTier,color:a,size:"small"})}},{title:"Use Case",field:"spec.useCase",render:e=>e.spec.useCase?(0,s.jsx)(C.Ay,{title:e.spec.useCase,placement:"top",children:(0,s.jsx)(d.A,{variant:"body2",style:{maxWidth:"200px",overflow:"hidden",textOverflow:"ellipsis",whiteSpace:"nowrap"},children:e.spec.useCase})}):(0,s.jsx)(d.A,{variant:"body2",children:"-"})},{title:"Status",field:"status.phase",render:e=>{var a;const t=(null===(a=e.status)||void 0===a?void 0:a.phase)||"Pending",n="Approved"===t?"primary":"Rejected"===t?"secondary":"default";return(0,s.jsx)(i.A,{label:t,color:n,size:"small"})}},{title:"Reviewed By",field:"status.reviewedBy",render:e=>{var a,t;if(("Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)||"Rejected"===(null===(t=e.status)||void 0===t?void 0:t.phase))&&e.status.reviewedBy){const a=e.status.reviewedAt?new Date(e.status.reviewedAt).toLocaleDateString():"";return(0,s.jsxs)(r.A,{children:[(0,s.jsx)(d.A,{variant:"body2",children:e.status.reviewedBy}),a&&(0,s.jsx)(d.A,{variant:"caption",color:"textSecondary",children:a})]})}return(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"-"})}},{title:"API Key",field:"status.secretRef",filtering:!1,render:e=>{var a,t,n;if("Approved"!==(null===(a=e.status)||void 0===a?void 0:a.phase))return(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"-"});const i=`${e.metadata.namespace}/${e.metadata.name}`,c=null===(n=e.status)||void 0===n||null===(t=n.secretRef)||void 0===t?void 0:t.name,u=g.has(e.metadata.name),m=Y.has(i),h=V.get(i);return c?(0,s.jsxs)(r.A,{display:"flex",alignItems:"center",style:{gap:8},children:[(0,s.jsx)(r.A,{fontFamily:"monospace",fontSize:"0.875rem",children:m?"Loading...":u&&h?h:"•".repeat(20)+"..."}),(0,s.jsx)(C.Ay,{title:u?"hide key":"show key",children:(0,s.jsx)(o.A,{size:"small",onClick:()=>{u?(((e,a)=>{const t=`${e}/${a}`;J(e=>{const a=new Map(e);return a.delete(t),a})})(e.metadata.namespace,e.metadata.name),ie(e.metadata.name)):((async(e,a)=>{const t=`${e}/${a}`;if(!Y.has(t)){X(e=>new Set(e).add(t));try{const s=await l.fetch(`${p}/api/kuadrant/requests/${e}/${a}/secret`);if(s.ok){const e=await s.json();J(a=>new Map(a).set(t,e.apiKey))}}catch(e){console.error("failed to fetch api key:",e)}finally{X(e=>{const a=new Set(e);return a.delete(t),a})}}})(e.metadata.namespace,e.metadata.name),ie(e.metadata.name))},disabled:m,children:u?(0,s.jsx)(E.A,{fontSize:"small"}):(0,s.jsx)(W.A,{fontSize:"small"})})})]}):(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"Awaiting secret..."})}},{title:"Requested",field:"metadata.creationTimestamp",render:e=>{if(!e.metadata.creationTimestamp)return(0,s.jsx)(d.A,{variant:"body2",children:"-"});const a=new Date(e.metadata.creationTimestamp);return(0,s.jsx)(d.A,{variant:"body2",children:a.toLocaleDateString()})}},{title:"",filtering:!1,render:e=>F===e.metadata.name?(0,s.jsx)(T.A,{size:20}):(0,s.jsx)(o.A,{size:"small",onClick:a=>{a.stopPropagation();const t=a.currentTarget.getBoundingClientRect();b({top:t.bottom,left:t.left}),z(e)},"aria-controls":f?"myapikeys-menu":void 0,"aria-haspopup":"true",children:(0,s.jsx)(N.A,{})})}],ue=(()=>{switch(m){case 0:return se;case 1:return ne;case 2:return le;default:return te}})(),pe=(()=>{switch(m){case 0:return ce.filter(e=>"Reason"!==e.title);case 1:return ce.filter(e=>"Reason"!==e.title&&"Reviewed By"!==e.title&&"API Key"!==e.title);case 2:return ce.filter(e=>"API Key"!==e.title);default:return ce}})();return(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(P.n,{title:"My API Keys",subheader:`${se.length} active, ${ne.length} pending`,children:[(0,s.jsx)(r.A,{mb:2,children:(0,s.jsxs)(R.A,{value:m,onChange:(e,a)=>h(a),indicatorColor:"primary",textColor:"primary",children:[(0,s.jsx)(I.A,{label:`Active (${se.length})`}),(0,s.jsx)(I.A,{label:`Pending (${ne.length})`}),(0,s.jsx)(I.A,{label:`Rejected (${le.length})`})]})}),0===ue.length?(0,s.jsx)(r.A,{p:3,textAlign:"center",children:(0,s.jsxs)(d.A,{variant:"body1",color:"textSecondary",children:[0===m&&"No active API keys. Request access to an API to get started.",1===m&&"No pending requests.",2===m&&"No rejected requests."]})}):(0,s.jsx)(v.X,{options:{paging:ue.length>5,pageSize:20,search:!0,filtering:!0,debounceInterval:300,toolbar:!0,emptyRowsWhenPaging:!1},columns:pe,data:ue.map(e=>({...e,id:e.metadata.name}))})]}),(0,s.jsx)($.A,{id:"myapikeys-menu",open:Boolean(f),onClose:re,anchorReference:"anchorPosition",anchorPosition:f||{top:0,left:0},children:k&&(()=>{const e=[];var a;return(a=k).status&&"Pending"!==a.status.phase||e.push((0,s.jsx)(q.A,{onClick:oe,children:"Edit"},"edit")),e.push((0,s.jsx)(q.A,{onClick:de,children:"Delete"},"delete")),e})()}),K.request&&(0,s.jsx)(D.n,{open:K.open,request:K.request,availablePlans:K.plans,onClose:()=>L({open:!1,request:null,plans:[]}),onSuccess:()=>{L({open:!1,request:null,plans:[]}),U(e=>e+1)}}),(0,s.jsx)(M.K,{open:_.open,title:"Delete API Key Request",description:`Are you sure you want to delete the API key request for ${(null===(a=_.request)||void 0===a||null===(e=a.spec.apiProductRef)||void 0===e?void 0:e.name)||"this API"}?`,deleting:null!==F,onConfirm:async()=>{if(!_.request)return;const e=_.request,a=e.metadata.name;Q(e=>new Set(e).add(a)),H(a);try{if(!(await l.fetch(`${p}/api/kuadrant/requests/${e.metadata.namespace}/${e.metadata.name}`,{method:"DELETE"})).ok)throw new Error("Failed to delete request");U(e=>e+1),u.post({message:"Request deleted",severity:"success",display:"transient"}),O({open:!1,request:null})}catch(e){console.error("Error deleting request:",e),Q(e=>{const t=new Set(e);return t.delete(a),t}),u.post({message:"Failed to delete request",severity:"error",display:"transient"})}finally{H(null)}},onCancel:()=>{O({open:!1,request:null})}})]})};var K=t(46205);const L=({children:e,permission:a,fallback:t,errorMessage:n})=>{const{allowed:l,loading:i,error:o}=(0,K.l)(a);return i?(0,s.jsx)(y.k,{}):o?(0,s.jsxs)(r.A,{p:4,children:[(0,s.jsxs)(d.A,{color:"error",children:["Unable to check permissions: ",o.message]}),(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"Please try again or contact your administrator"})]}):l?(0,s.jsx)(s.Fragment,{children:e}):t?(0,s.jsx)(s.Fragment,{children:t}):(0,s.jsxs)(r.A,{p:4,children:[(0,s.jsx)(d.A,{color:"textSecondary",children:n||"You don't have permission to view this page"}),(0,s.jsx)(r.A,{mt:1,children:(0,s.jsxs)(d.A,{variant:"caption",color:"textSecondary",children:["Required permission: ",a.name]})})]})};var B=t(58837),U=t(76891),F=t(61477),H=t(46805),_=t(16249),O=t(93453),V=t(84441);const J=({selectedPolicy:e,alertSeverity:a="warning",alertMessage:t="No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.",includeTopMargin:n=!0})=>(0,s.jsx)(r.A,{mt:n?1:0,p:2,bgcolor:"#f5f5f5",borderRadius:1,border:"1px solid #e0e0e0",children:e?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsxs)(d.A,{variant:"subtitle2",gutterBottom:!0,style:{fontWeight:600},children:["Associated PlanPolicy: ",(0,s.jsx)("strong",{children:e.metadata.name})]}),e.plans&&e.plans.length>0?(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(d.A,{variant:"caption",display:"block",gutterBottom:!0,color:"textSecondary",style:{marginTop:8},children:"Available Plans:"}),(0,s.jsx)(r.A,{display:"flex",flexWrap:"wrap",mt:1,style:{gap:8},children:e.plans.map((e,a)=>{var t,n,l;const r=(null===(t=e.limits)||void 0===t?void 0:t.daily)?`${e.limits.daily}/day`:(null===(n=e.limits)||void 0===n?void 0:n.monthly)?`${e.limits.monthly}/month`:(null===(l=e.limits)||void 0===l?void 0:l.yearly)?`${e.limits.yearly}/year`:"No limit";return(0,s.jsx)(i.A,{label:`${e.tier}: ${r}`,size:"small",variant:"outlined",color:"primary"},a)})}),e.plans.some(e=>e.description)&&(0,s.jsx)(r.A,{mt:1,children:e.plans.filter(e=>e.description).map((e,a)=>(0,s.jsxs)(d.A,{variant:"caption",display:"block",color:"textSecondary",children:["• ",(0,s.jsxs)("strong",{children:[e.tier,":"]})," ",e.description]},a))})]}):(0,s.jsx)(d.A,{variant:"caption",color:"textSecondary",children:"No plans defined in this PlanPolicy"})]}):(0,s.jsx)(V.A,{severity:a,children:t})}),Y=(0,B.A)({asterisk:{color:"#f44336"}}),X=({open:e,onClose:a,onSuccess:t})=>{const l=Y(),o=(0,w.useApi)(w.configApiRef),p=(0,w.useApi)(w.fetchApiRef),m=o.getString("backend.baseUrl"),[h,x]=(0,n.useState)(""),[v,A]=(0,n.useState)(""),[g,j]=(0,n.useState)(""),[f,y]=(0,n.useState)("v1"),[b,P]=(0,n.useState)("manual"),[k,C]=(0,n.useState)("Published"),[R,I]=(0,n.useState)([]),[$,W]=(0,n.useState)(""),[E,N]=(0,n.useState)(""),[D,M]=(0,n.useState)(""),[z,K]=(0,n.useState)(""),[L,B]=(0,n.useState)(""),[X,G]=(0,n.useState)(""),[Q,Z]=(0,n.useState)(""),[ee,ae]=(0,n.useState)(!1),{value:te,loading:se}=(0,S.A)(async()=>{const e=await p.fetch(`${m}/api/kuadrant/httproutes`);return((await e.json()).items||[]).filter(e=>{var a;return"true"===(null===(a=e.metadata.annotations)||void 0===a?void 0:a["backstage.io/expose"])})},[m,p,e]),{value:ne}=(0,S.A)(async()=>{const e=await p.fetch(`${m}/api/kuadrant/planpolicies`);return await e.json()},[m,p,e]),le=E?E.split("/"):null,ie=le?(re=le[0],oe=le[1],(null==ne?void 0:ne.items)?ne.items.find(e=>{const a=e.targetRef;return"HTTPRoute"===(null==a?void 0:a.kind)&&(null==a?void 0:a.name)===oe&&(!(null==a?void 0:a.namespace)||(null==a?void 0:a.namespace)===re)}):null):null;var re,oe;const de=()=>{$.trim()&&!R.includes($.trim())&&(I([...R,$.trim()]),W(""))},ce=()=>{x(""),A(""),j(""),y("v1"),P("manual"),C("Published"),I([]),W(""),N(""),M(""),K(""),B(""),G(""),Z(""),a()};return(0,s.jsxs)(U.A,{open:e,onClose:ce,maxWidth:"md",fullWidth:!0,children:[(0,s.jsx)(F.A,{children:"Create API Product"}),(0,s.jsxs)(H.A,{children:[Q&&(0,s.jsx)(V.A,{severity:"error",style:{marginBottom:16},children:Q}),(0,s.jsxs)(c.A,{container:!0,spacing:2,children:[(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Name",value:h,onChange:e=>x(e.target.value),placeholder:"my-api",helperText:"Kubernetes resource name (lowercase, hyphens)",margin:"normal",required:!0,disabled:ee,InputLabelProps:{classes:{asterisk:l.asterisk}}})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Display Name",value:v,onChange:e=>A(e.target.value),placeholder:"My API",margin:"normal",required:!0,disabled:ee,InputLabelProps:{classes:{asterisk:l.asterisk}}})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Version",value:f,onChange:e=>y(e.target.value),placeholder:"v1",margin:"normal",disabled:ee})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsxs)(_.A,{fullWidth:!0,select:!0,label:"Approval Mode",value:b,onChange:e=>P(e.target.value),margin:"normal",helperText:"Automatic: keys are created immediately. Manual: requires approval.",disabled:ee,children:[(0,s.jsx)(q.A,{value:"manual",children:"Manual"}),(0,s.jsx)(q.A,{value:"automatic",children:"Automatic"})]})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsxs)(_.A,{fullWidth:!0,select:!0,label:"Publish Status",value:k,onChange:e=>C(e.target.value),margin:"normal",helperText:"Draft: hidden from catalog. Published: visible to consumers.",disabled:ee,children:[(0,s.jsx)(q.A,{value:"Draft",children:"Draft"}),(0,s.jsx)(q.A,{value:"Published",children:"Published"})]})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Description",value:g,onChange:e=>j(e.target.value),placeholder:"API description",margin:"normal",multiline:!0,rows:2,required:!0,disabled:ee,InputLabelProps:{classes:{asterisk:l.asterisk}}})}),(0,s.jsxs)(c.A,{item:!0,xs:12,children:[(0,s.jsx)(d.A,{variant:"subtitle2",gutterBottom:!0,style:{marginTop:16},children:"Tags"}),(0,s.jsx)(r.A,{display:"flex",flexWrap:"wrap",marginBottom:1,style:{gap:8},children:R.map(e=>(0,s.jsx)(i.A,{label:e,onDelete:ee?void 0:()=>{return a=e,void I(R.filter(e=>e!==a));var a},size:"small",disabled:ee},e))}),(0,s.jsxs)(r.A,{display:"flex",style:{gap:8},children:[(0,s.jsx)(_.A,{fullWidth:!0,size:"small",value:$,onChange:e=>W(e.target.value),onKeyPress:e=>"Enter"===e.key&&de(),placeholder:"Add tag",disabled:ee}),(0,s.jsx)(u.A,{onClick:de,variant:"outlined",size:"small",disabled:ee,children:"Add"})]})]}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsxs)(_.A,{fullWidth:!0,select:!0,label:"HTTPRoute",value:E,onChange:e=>N(e.target.value),margin:"normal",required:!0,helperText:"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.",disabled:se||ee,InputLabelProps:{classes:{asterisk:l.asterisk}},children:[se&&(0,s.jsx)(q.A,{value:"",children:"Loading..."}),!se&&te&&0===te.length&&(0,s.jsx)(q.A,{value:"",children:"No HTTPRoutes available"}),!se&&te&&te.map(e=>(0,s.jsxs)(q.A,{value:`${e.metadata.namespace}/${e.metadata.name}`,children:[e.metadata.name," (",e.metadata.namespace,")"]},`${e.metadata.namespace}/${e.metadata.name}`))]})}),E&&(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(J,{selectedPolicy:ie,alertSeverity:"warning",alertMessage:"No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.",includeTopMargin:!0})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Contact Email",value:D,onChange:e=>M(e.target.value),placeholder:"api-team@example.com",margin:"normal",disabled:ee})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Contact Team",value:z,onChange:e=>K(e.target.value),placeholder:"platform-team",margin:"normal",disabled:ee})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Docs URL",value:L,onChange:e=>B(e.target.value),placeholder:"https://api.example.com/docs",margin:"normal",disabled:ee})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"OpenAPI Spec URL",value:X,onChange:e=>G(e.target.value),placeholder:"https://api.example.com/openapi.json",margin:"normal",disabled:ee})})]})]}),(0,s.jsxs)(O.A,{children:[(0,s.jsx)(u.A,{onClick:ce,disabled:ee,children:"Cancel"}),(0,s.jsx)(u.A,{onClick:async()=>{Z(""),ae(!0);try{if(!E)throw new Error("Please select an HTTPRoute");const[e,a]=E.split("/"),s={apiVersion:"devportal.kuadrant.io/v1alpha1",kind:"APIProduct",metadata:{name:h,namespace:e},spec:{displayName:v,description:g,version:f,approvalMode:b,publishStatus:k,tags:R,targetRef:{group:"gateway.networking.k8s.io",kind:"HTTPRoute",name:a,namespace:e},...D||z?{contact:{...D&&{email:D},...z&&{team:z}}}:{},...L||X?{documentation:{...L&&{docsURL:L},...X&&{openAPISpec:X}}}:{}}},n=await p.fetch(`${m}/api/kuadrant/apiproducts`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!n.ok){const e=await n.json();throw new Error(e.error||"failed to create apiproduct")}t(),ce()}catch(e){Z(e instanceof Error?e.message:String(e))}finally{ae(!1)}},color:"primary",variant:"contained",disabled:ee||!h||!v||!g||!E,startIcon:ee?(0,s.jsx)(T.A,{size:16,color:"inherit"}):void 0,children:ee?"Creating...":"Create"})]})]})};var G=t(34955);const Q=(0,B.A)({asterisk:{color:"#f44336"}}),Z=({open:e,onClose:a,onSuccess:t,namespace:o,name:p})=>{const m=Q(),h=(0,w.useApi)(w.configApiRef),x=(0,w.useApi)(w.fetchApiRef),v=h.getString("backend.baseUrl"),[A,g]=(0,n.useState)(!1),[j,f]=(0,n.useState)(""),[b,P]=(0,n.useState)(""),[k,C]=(0,n.useState)("v1"),[R,I]=(0,n.useState)("Draft"),[$,W]=(0,n.useState)("manual"),[E,N]=(0,n.useState)([]),[D,M]=(0,n.useState)(null),[z,K]=(0,n.useState)(""),[L,B]=(0,n.useState)(""),[Y,X]=(0,n.useState)(""),[G,Z]=(0,n.useState)(""),[ee,ae]=(0,n.useState)(""),[te,se]=(0,n.useState)(""),[ne,le]=(0,n.useState)(!1);(0,n.useEffect)(()=>{e&&o&&p&&(g(!0),se(""),x.fetch(`${v}/api/kuadrant/apiproducts/${o}/${p}`).then(async e=>{if(!e.ok){const a=await e.json();throw new Error(a.error||`Failed to fetch API product: ${e.status}`)}return e.json()}).then(e=>{var a,t,s,n;f(e.spec.displayName||""),P(e.spec.description||""),C(e.spec.version||"v1"),I(e.spec.publishStatus||"Draft"),W(e.spec.approvalMode||"manual"),N(e.spec.tags||[]),M(e.spec.targetRef||null),B((null===(a=e.spec.contact)||void 0===a?void 0:a.email)||""),X((null===(t=e.spec.contact)||void 0===t?void 0:t.team)||""),Z((null===(s=e.spec.documentation)||void 0===s?void 0:s.docsURL)||""),ae((null===(n=e.spec.documentation)||void 0===n?void 0:n.openAPISpec)||""),g(!1)}).catch(e=>{se(e.message||"Failed to load API product"),g(!1)}))},[e,o,p,v,x]);const{value:ie}=(0,S.A)(async()=>{if(!e)return null;const a=await x.fetch(`${v}/api/kuadrant/planpolicies`);return await a.json()},[v,x,e]),re=l().useMemo(()=>(null==ie?void 0:ie.items)&&D?ie.items.find(e=>{const a=e.targetRef;return"HTTPRoute"===(null==a?void 0:a.kind)&&(null==a?void 0:a.name)===D.name&&(!(null==a?void 0:a.namespace)||(null==a?void 0:a.namespace)===(D.namespace||o))}):null,[ie,D,o]),oe=()=>{z.trim()&&!E.includes(z.trim())&&(N([...E,z.trim()]),K(""))};return(0,s.jsxs)(U.A,{open:e,onClose:a,maxWidth:"md",fullWidth:!0,children:[(0,s.jsx)(F.A,{children:"Edit API Product"}),(0,s.jsxs)(H.A,{children:[te&&(0,s.jsx)(V.A,{severity:"error",style:{marginBottom:16},children:te}),A?(0,s.jsx)(y.k,{}):(0,s.jsxs)(c.A,{container:!0,spacing:2,children:[(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Name",value:p,disabled:!0,helperText:"Kubernetes resource name (immutable)",margin:"normal"})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Namespace",value:o,disabled:!0,helperText:"Derived from HTTPRoute (immutable)",margin:"normal"})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Display Name",value:j,onChange:e=>f(e.target.value),placeholder:"My API",margin:"normal",required:!0,disabled:ne,InputLabelProps:{classes:{asterisk:m.asterisk}}})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Version",value:k,onChange:e=>C(e.target.value),placeholder:"v1",margin:"normal",disabled:ne})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsxs)(_.A,{fullWidth:!0,select:!0,label:"Publish Status",value:R,onChange:e=>I(e.target.value),margin:"normal",helperText:"Draft: Hidden from catalog. Published: Visible in catalog.",disabled:ne,children:[(0,s.jsx)(q.A,{value:"Draft",children:"Draft (Hidden)"}),(0,s.jsx)(q.A,{value:"Published",children:"Published (Visible)"})]})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsxs)(_.A,{fullWidth:!0,select:!0,label:"Approval Mode",value:$,onChange:e=>W(e.target.value),margin:"normal",helperText:"Automatic: keys created immediately. Manual: requires approval.",disabled:ne,children:[(0,s.jsx)(q.A,{value:"manual",children:"Manual"}),(0,s.jsx)(q.A,{value:"automatic",children:"Automatic"})]})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Description",value:b,onChange:e=>P(e.target.value),placeholder:"API description",margin:"normal",multiline:!0,rows:2,required:!0,disabled:ne,InputLabelProps:{classes:{asterisk:m.asterisk}}})}),(0,s.jsxs)(c.A,{item:!0,xs:12,children:[(0,s.jsx)(d.A,{variant:"subtitle2",gutterBottom:!0,style:{marginTop:16},children:"Tags"}),(0,s.jsx)(r.A,{display:"flex",flexWrap:"wrap",marginBottom:1,style:{gap:8},children:E.map(e=>(0,s.jsx)(i.A,{label:e,onDelete:ne?void 0:()=>{return a=e,void N(E.filter(e=>e!==a));var a},size:"small",disabled:ne},e))}),(0,s.jsxs)(r.A,{display:"flex",style:{gap:8},children:[(0,s.jsx)(_.A,{fullWidth:!0,size:"small",value:z,onChange:e=>K(e.target.value),onKeyPress:e=>"Enter"===e.key&&oe(),placeholder:"Add tag",disabled:ne}),(0,s.jsx)(u.A,{onClick:oe,variant:"outlined",size:"small",disabled:ne,children:"Add"})]})]}),D&&(0,s.jsxs)(s.Fragment,{children:[(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"HTTPRoute",value:`${D.namespace||o}/${D.name}`,disabled:!0,helperText:"Target HTTPRoute (immutable)",margin:"normal"})}),(0,s.jsx)(c.A,{item:!0,xs:12,children:(0,s.jsx)(J,{selectedPolicy:re,alertSeverity:"info",alertMessage:"No PlanPolicy found for this HTTPRoute.",includeTopMargin:!1})})]}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Contact Email",value:L,onChange:e=>B(e.target.value),placeholder:"api-team@example.com",margin:"normal",disabled:ne})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Contact Team",value:Y,onChange:e=>X(e.target.value),placeholder:"platform-team",margin:"normal",disabled:ne})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"Docs URL",value:G,onChange:e=>Z(e.target.value),placeholder:"https://api.example.com/docs",margin:"normal",disabled:ne})}),(0,s.jsx)(c.A,{item:!0,xs:6,children:(0,s.jsx)(_.A,{fullWidth:!0,label:"OpenAPI Spec URL",value:ee,onChange:e=>ae(e.target.value),placeholder:"https://api.example.com/openapi.json",margin:"normal",disabled:ne})})]})]}),(0,s.jsxs)(O.A,{children:[(0,s.jsx)(u.A,{onClick:a,disabled:ne,children:"Cancel"}),(0,s.jsx)(u.A,{onClick:async()=>{se(""),le(!0);try{const e={spec:{displayName:j,description:b,version:k,publishStatus:R,approvalMode:$,tags:E,targetRef:D,...L||Y?{contact:{...L&&{email:L},...Y&&{team:Y}}}:{},...G||ee?{documentation:{...G&&{docsURL:G},...ee&&{openAPISpec:ee}}}:{}}},s=await x.fetch(`${v}/api/kuadrant/apiproducts/${o}/${p}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!s.ok){const e=await s.json();throw new Error(e.error||"failed to update apiproduct")}t(),a()}catch(e){se(e instanceof Error?e.message:String(e))}finally{le(!1)}},color:"primary",variant:"contained",disabled:ne||A||!j||!b,startIcon:ne?(0,s.jsx)(T.A,{size:16,color:"inherit"}):void 0,children:ne?"Saving...":"Save"})]})]})},ee=()=>{const e=(0,w.useApi)(w.configApiRef),a=(0,w.useApi)(w.fetchApiRef),t=(0,w.useApi)(w.alertApiRef),l=(0,w.useApi)(w.identityApiRef),C=e.getString("backend.baseUrl"),[T,R]=(0,n.useState)(""),[I,$]=(0,n.useState)(!1),[q,W]=(0,n.useState)(!1),[E,N]=(0,n.useState)(0),[D,L]=(0,n.useState)(!1),[B,U]=(0,n.useState)(null),[F,H]=(0,n.useState)(null),[_,O]=(0,n.useState)(!1),[V,J]=(0,n.useState)(null),{allowed:Y,loading:Q,error:ee}=(0,K.l)(G.FL),{allowed:ae,loading:te}=(0,K.l)(G.TE),{allowed:se,loading:ne,error:le}=(0,K.l)(G.SU),ie=ae||se,re=te||ne,{allowed:oe,loading:de}=(0,K.l)(G.EM),{allowed:ce,loading:ue,error:pe}=(0,K.l)(G.R_),{allowed:me}=(0,K.l)(G.U3),{allowed:he}=(0,K.l)(G.v_),xe=de||ue,{allowed:ve,loading:Ae,error:ge}=(0,K.l)(G.J);(0,S.A)(async()=>{const e=await l.getBackstageIdentity();R(e.userEntityRef)},[l]);const{value:je,loading:fe,error:ye}=(0,S.A)(async()=>{const e=await a.fetch(`${C}/api/kuadrant/apiproducts`);return await e.json()},[C,a,E]),{value:be,loading:Pe,error:Se}=(0,S.A)(async()=>{const e=await a.fetch(`${C}/api/kuadrant/planpolicies`);return await e.json()},[C,a,E]),we=fe||Pe||Q||re||xe||Ae,ke=ye||Se,Ce=ee||le||pe||ge,Te=[{title:"Name",field:"spec.displayName",render:e=>{var a,t;const n="Published"===(null===(a=e.spec)||void 0===a?void 0:a.publishStatus);var l;const i=null!==(l=null===(t=e.spec)||void 0===t?void 0:t.displayName)&&void 0!==l?l:e.metadata.name;return n?(0,s.jsx)(x.N_,{to:`/catalog/default/api/${e.metadata.name}/api-product`,children:(0,s.jsx)("strong",{children:i})}):(0,s.jsx)("span",{className:"text-muted",children:(0,s.jsx)("strong",{children:i})})},customFilterAndSearch:(e,a)=>{var t;return((null===(t=a.spec)||void 0===t?void 0:t.displayName)||a.metadata.name||"").toLowerCase().includes(e.toLowerCase())}},{title:"Resource Name",field:"metadata.name"},{title:"Version",field:"spec.version",render:e=>{var a;return(null===(a=e.spec)||void 0===a?void 0:a.version)||"-"}},{title:"HTTPRoute",field:"spec.targetRef.name",render:e=>{var a,t;return(null===(t=e.spec)||void 0===t||null===(a=t.targetRef)||void 0===a?void 0:a.name)||"-"}},{title:"Publish Status",field:"spec.publishStatus",render:e=>{var a;const t=(null===(a=e.spec)||void 0===a?void 0:a.publishStatus)||"Draft";return(0,s.jsx)(i.A,{label:t,size:"small",color:"Published"===t?"primary":"default"})}},{title:"Approval Mode",field:"spec.approvalMode",render:e=>{var a;const t=(null===(a=e.spec)||void 0===a?void 0:a.approvalMode)||"manual";return(0,s.jsx)(i.A,{label:t,size:"small",color:"automatic"===t?"secondary":"default"})}},{title:"Namespace",field:"metadata.namespace"},{title:"Created",field:"metadata.creationTimestamp",render:e=>{return a=e.metadata.creationTimestamp,new Date(a).toLocaleDateString("en-GB",{year:"numeric",month:"short",day:"numeric"});var a}},{title:"Actions",field:"actions",filtering:!1,render:e=>{var t,n;const l=(null===(n=e.metadata)||void 0===n||null===(t=n.annotations)||void 0===t?void 0:t["backstage.io/owner"])===T,i=he||me&&l,d=ce||oe&&l;return i||d?(0,s.jsxs)(r.A,{display:"flex",style:{gap:4},children:[i&&(0,s.jsx)(o.A,{size:"small",onClick:()=>{return a=e.metadata.namespace,t=e.metadata.name,H({namespace:a,name:t}),void W(!0);var a,t},title:"Edit API Product",children:(0,s.jsx)(h.A,{fontSize:"small"})}),d&&(0,s.jsx)(o.A,{size:"small",onClick:()=>(async(e,t)=>{U({namespace:e,name:t}),J(null);try{const s=await a.fetch(`${C}/api/kuadrant/requests?namespace=${e}`);if(s.ok){const a=((await s.json()).items||[]).filter(a=>a.spec.apiName===t&&a.spec.apiNamespace===e),n=a.filter(e=>{var a;return"Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)}).length;J({requests:a.length,secrets:n})}}catch(e){console.warn("Failed to fetch delete stats:",e)}L(!0)})(e.metadata.namespace,e.metadata.name),title:"Delete API Product",children:(0,s.jsx)(m.A,{fontSize:"small"})})]}):null}}],Re=[{title:"Name",field:"metadata.name",render:e=>(0,s.jsx)(x.N_,{to:`/kuadrant/planpolicy/${e.metadata.namespace}/${e.metadata.name}`,children:(0,s.jsx)("strong",{children:e.metadata.name})})},{title:"Namespace",field:"metadata.namespace"}];return(0,s.jsxs)(A.Y,{themeId:"tool",children:[(0,s.jsx)(g.Y,{title:"Kuadrant",subtitle:"API management for Kubernetes",children:(0,s.jsx)(j.Y,{children:"Manage API products and access requests"})}),(0,s.jsxs)(f.U,{children:[we&&(0,s.jsx)(y.k,{}),ke&&(0,s.jsx)(b._,{error:ke}),Ce&&(0,s.jsxs)(r.A,{p:2,children:[(0,s.jsxs)(d.A,{color:"error",children:["unable to check permissions: ",Ce.message]}),(0,s.jsxs)(d.A,{variant:"body2",color:"textSecondary",children:["permission: ",ee?"kuadrant.apiproduct.create":pe?"kuadrant.apiproduct.delete":le?"kuadrant.apikeyrequest.read.all":ge?"kuadrant.planpolicy.list":"unknown"]}),(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"please try again or contact your administrator"})]}),!we&&!ke&&!Ce&&(0,s.jsxs)(c.A,{container:!0,spacing:3,direction:"column",children:[(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(z,{})}),(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(P.n,{title:"API Products",action:Y?(0,s.jsx)(r.A,{display:"flex",alignItems:"center",height:"100%",mt:1,children:(0,s.jsx)(u.A,{variant:"contained",color:"primary",size:"small",startIcon:(0,s.jsx)(p.A,{}),onClick:()=>$(!0),children:"Create API Product"})}):void 0,children:(Ie=null==je?void 0:je.items,Ie&&0!==Ie.length?(0,s.jsx)(v.X,{options:{paging:Ie.length>5,pageSize:20,search:!0,filtering:!0,debounceInterval:300,toolbar:!0,emptyRowsWhenPaging:!1},columns:Te,data:Ie}):(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"No API products found"}))})}),ve&&(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(P.n,{title:"Plan Policies",children:(e=>e&&0!==e.length?(0,s.jsx)(v.X,{options:{paging:!1,search:!1,toolbar:!1},columns:Re,data:e}):(0,s.jsx)(d.A,{variant:"body2",color:"textSecondary",children:"No plan policies found"}))(null==be?void 0:be.items)})}),ie&&(0,s.jsx)(c.A,{item:!0,children:(0,s.jsx)(k.d,{})})]}),(0,s.jsx)(X,{open:I,onClose:()=>$(!1),onSuccess:()=>{N(e=>e+1),t.post({message:"API Product created",severity:"success",display:"transient"})}}),(0,s.jsx)(Z,{open:q,onClose:()=>W(!1),onSuccess:()=>{N(e=>e+1),t.post({message:"API Product updated",severity:"success",display:"transient"})},namespace:(null==F?void 0:F.namespace)||"",name:(null==F?void 0:F.name)||""}),(0,s.jsx)(M.K,{open:D,title:"Delete API Product",description:V?`Deleting "${null==B?void 0:B.name}" will also remove:\n\n• ${V.requests} API Key Request(s)\n• ${V.secrets} API Key Secret(s)\n\nThis action cannot be undone.`:`Deleting "${null==B?void 0:B.name}" will also remove all associated API Key Requests and Secrets.\nThis action cannot be undone.`,confirmText:null==B?void 0:B.name,severity:"high",deleting:_,onConfirm:async()=>{if(B){O(!0);try{if(!(await a.fetch(`${C}/api/kuadrant/apiproducts/${B.namespace}/${B.name}`,{method:"DELETE"})).ok)throw new Error("failed to delete apiproduct");N(e=>e+1),t.post({message:"API Product deleted",severity:"success",display:"transient"})}catch(e){console.error("error deleting apiproduct:",e),t.post({message:"Failed to delete API Product",severity:"error",display:"transient"})}finally{O(!1),L(!1),U(null)}}},onCancel:()=>{L(!1),U(null)}})]})]});var Ie},ae=()=>(0,s.jsx)(L,{permission:G.OP,errorMessage:"you don't have permission to view the Kuadrant page",children:(0,s.jsx)(ee,{})})}}]);
2
- //# sourceMappingURL=7632.3141cc8f.chunk.js.map