@kuadrant/kuadrant-backstage-plugin-frontend 0.0.1-test.1-464d7760 → 0.0.1-test.1-48246e3

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 @@
1
+ {"version":3,"file":"static/7632.26afde62.chunk.js","mappings":"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","sources":["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/components/CreateAPIProductDialog/CreateAPIProductDialog.tsx","webpack://internal.plugin-kuadrant/./src/components/EditAPIProductDialog/EditAPIProductDialog.tsx","webpack://internal.plugin-kuadrant/./src/components/KuadrantPage/KuadrantPage.tsx"],"sourcesContent":["import React, { useState } from 'react';\nimport { InfoCard, Table, TableColumn, Link } from '@backstage/core-components';\nimport { useApi, configApiRef, fetchApiRef, identityApiRef } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { Box, Chip, Typography, Tabs, Tab, IconButton, Tooltip } from '@material-ui/core';\nimport VisibilityIcon from '@material-ui/icons/Visibility';\nimport VisibilityOffIcon from '@material-ui/icons/VisibilityOff';\n\ninterface APIKeyRequest {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: string;\n };\n spec: {\n apiName: string;\n apiNamespace: string;\n planTier: string;\n useCase?: string;\n requestedBy: {\n userId: string;\n email?: string;\n };\n };\n status?: {\n phase: 'Pending' | 'Approved' | 'Rejected';\n apiKey?: string;\n apiHostname?: string;\n reason?: string;\n reviewedBy?: string;\n reviewedAt?: string;\n };\n}\n\nexport const MyApiKeysCard = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const identityApi = useApi(identityApiRef);\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\n useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n setUserId(identity.userEntityRef.split('/')[1] || 'guest');\n }, [identityApi]);\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]);\n\n if (loading) {\n return (\n <InfoCard title=\"My API Keys\">\n <Typography>Loading...</Typography>\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 || [];\n const approvedRequests = allRequests.filter((r: APIKeyRequest) => r.status?.phase === 'Approved');\n const pendingRequests = allRequests.filter((r: APIKeyRequest) => !r.status?.phase || r.status.phase === 'Pending');\n const rejectedRequests = allRequests.filter((r: APIKeyRequest) => 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 columns: TableColumn<APIKeyRequest>[] = [\n {\n title: 'API Product',\n field: 'spec.apiName',\n render: (row: APIKeyRequest) => (\n <Link to={`/catalog/default/api/${row.spec.apiName}/api-keys`}>\n <strong>{row.spec.apiName}</strong>\n </Link>\n ),\n },\n {\n title: 'Plan',\n field: 'spec.planTier',\n render: (row: APIKeyRequest) => {\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: APIKeyRequest) => {\n return (\n <Typography variant=\"body2\">\n {row.spec.useCase || '-'}\n </Typography>\n );\n },\n },\n {\n title: 'Status',\n field: 'status.phase',\n render: (row: APIKeyRequest) => {\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: 'Reason',\n render: (row: APIKeyRequest) => {\n if (row.status?.phase === 'Rejected' && row.status.reason) {\n return (\n <Typography variant=\"body2\" color=\"error\">\n {row.status.reason}\n </Typography>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Reviewed By',\n render: (row: APIKeyRequest) => {\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 render: (row: APIKeyRequest) => {\n if (row.status?.phase === 'Approved' && row.status.apiKey) {\n const isVisible = visibleKeys.has(row.metadata.name);\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isVisible ? row.status.apiKey : '•'.repeat(20) + '...'}\n </Box>\n <Tooltip title={isVisible ? 'hide key' : 'show key'}>\n <IconButton\n size=\"small\"\n onClick={() => toggleKeyVisibility(row.metadata.name)}\n >\n {isVisible ? <VisibilityOffIcon fontSize=\"small\" /> : <VisibilityIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Requested',\n field: 'metadata.creationTimestamp',\n render: (row: APIKeyRequest) => {\n const date = new Date(row.metadata.creationTimestamp);\n return date.toLocaleDateString();\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 tabData = getTabData();\n\n return (\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 > 10,\n pageSize: 10,\n search: false,\n toolbar: false,\n }}\n columns={columns}\n data={tabData}\n />\n )}\n </InfoCard>\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","import React, { 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 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';\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\n const { value: httpRoutes, loading: httpRoutesLoading } = 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]);\n\n // load planpolicies with full details to show associated plans\n const { value: planPolicies } = 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 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: 'extensions.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 onClose();\n };\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\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n onChange={e => setName(e.target.value)}\n placeholder=\"my-api\"\n helperText=\"Kubernetes resource name (lowercase, hyphens)\"\n margin=\"normal\"\n required\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 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 />\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 >\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 >\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 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={() => handleDeleteTag(tag)}\n size=\"small\"\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 />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\">\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=\"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.\"\n disabled={httpRoutesLoading}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n >\n {httpRoutesLoading && (\n <MenuItem value=\"\">Loading...</MenuItem>\n )}\n {!httpRoutesLoading && httpRoutes && httpRoutes.length === 0 && (\n <MenuItem value=\"\">No HTTPRoutes available</MenuItem>\n )}\n {!httpRoutesLoading && 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 => setContactEmail(e.target.value)}\n placeholder=\"api-team@example.com\"\n margin=\"normal\"\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 />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => setDocsURL(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => setOpenAPISpec(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n margin=\"normal\"\n />\n </Grid>\n </Grid>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose}>Cancel</Button>\n <Button\n onClick={handleCreate}\n color=\"primary\"\n variant=\"contained\"\n disabled={creating || !name || !displayName || !description || !selectedHTTPRoute}\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 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';\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\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(res => res.json())\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 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 { value: planPolicies } = 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 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\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 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 />\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 >\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 >\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 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={() => handleDeleteTag(tag)}\n size=\"small\"\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 />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\">\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 => setContactEmail(e.target.value)}\n placeholder=\"api-team@example.com\"\n margin=\"normal\"\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 />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => setDocsURL(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => setOpenAPISpec(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n margin=\"normal\"\n />\n </Grid>\n </Grid>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>Cancel</Button>\n <Button\n onClick={handleSave}\n color=\"primary\"\n variant=\"contained\"\n disabled={saving || loading || !displayName || !description}\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, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } 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 } 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 kuadrantApiProductDeletePermission,\n kuadrantApiProductUpdatePermission,\n kuadrantApiProductListPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantPlanPolicyListPermission,\n} from '../../permissions';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { EditAPIProductDialog } from '../EditAPIProductDialog';\n\ntype KuadrantResource = {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: 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 backendUrl = config.getString('backend.baseUrl');\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\n const {\n allowed: canCreateApiProduct,\n loading: createPermissionLoading,\n error: createPermissionError,\n } = useKuadrantPermission(kuadrantApiProductCreatePermission);\n\n const {\n allowed: canViewApprovalQueue,\n loading: approvalQueuePermissionLoading,\n error: approvalQueuePermissionError,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadAllPermission);\n\n const {\n allowed: canDeleteApiProduct,\n loading: deletePermissionLoading,\n error: deletePermissionError,\n } = useKuadrantPermission(kuadrantApiProductDeletePermission);\n\n const {\n allowed: canUpdateApiProduct,\n } = useKuadrantPermission(kuadrantApiProductUpdatePermission);\n\n const {\n allowed: canListPlanPolicies,\n loading: planPolicyPermissionLoading,\n error: planPolicyPermissionError,\n } = useKuadrantPermission(kuadrantPlanPolicyListPermission);\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 };\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 };\n\n const handleDeleteClick = (namespace: string, name: string) => {\n setApiProductToDelete({ namespace, name });\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 } catch (err) {\n console.error('error deleting apiproduct:', err);\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: 'name',\n render: (row: any) => (\n <Link to={`/catalog/default/api/${row.metadata.name}/api-product`}>\n <strong>{row.spec?.displayName || row.metadata.name}</strong>\n </Link>\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: '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 render: (row: any) => (\n <Box display=\"flex\" style={{ gap: 4 }}>\n {canUpdateApiProduct && (\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 {canDeleteApiProduct && (\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 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={{ paging: false, search: false, toolbar: false }}\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 <Dialog open={deleteDialogOpen} onClose={handleDeleteCancel}>\n <DialogTitle>Delete API Product</DialogTitle>\n <DialogContent>\n <DialogContentText>\n Are you sure you want to delete {apiProductToDelete?.name} from namespace {apiProductToDelete?.namespace}?\n This will permanently remove the API Product from Kubernetes.\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleDeleteCancel} color=\"primary\">\n Cancel\n </Button>\n <Button onClick={handleDeleteConfirm} color=\"secondary\" disabled={deleting}>\n {deleting ? 'Deleting...' : 'Delete'}\n </Button>\n </DialogActions>\n </Dialog>\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"],"names":["MyApiKeysCard","config","useApi","configApiRef","fetchApi","fetchApiRef","identityApi","identityApiRef","backendUrl","getString","selectedTab","setSelectedTab","useState","setUserId","visibleKeys","setVisibleKeys","Set","useAsync","async","identity","getBackstageIdentity","userEntityRef","split","value","requests","loading","error","response","fetch","ok","Error","json","items","InfoCard","title","Typography","color","message","allRequests","approvedRequests","filter","r","status","phase","pendingRequests","rejectedRequests","columns","field","render","row","Link","to","spec","apiName","strong","planTier","Chip","label","size","variant","useCase","reason","reviewedBy","reviewedDate","reviewedAt","Date","toLocaleDateString","Box","apiKey","isVisible","has","metadata","name","display","alignItems","style","gap","fontFamily","fontSize","repeat","Tooltip","IconButton","onClick","toggleKeyVisibility","keyName","prev","newSet","delete","add","VisibilityOffIcon","VisibilityIcon","creationTimestamp","tabData","getTabData","subheader","length","mb","Tabs","onChange","_","newValue","indicatorColor","textColor","Tab","p","textAlign","Table","options","paging","pageSize","search","toolbar","data","PermissionGate","children","permission","fallback","errorMessage","allowed","useKuadrantPermission","Progress","mt","PlanPolicyDetails","selectedPolicy","alertSeverity","alertMessage","includeTopMargin","bgcolor","borderRadius","border","gutterBottom","fontWeight","plans","marginTop","flexWrap","map","plan","idx","limitText","limits","daily","monthly","yearly","tier","some","description","Alert","severity","useStyles","makeStyles","asterisk","CreateAPIProductDialog","open","onClose","onSuccess","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","httpRoutes","httpRoutesLoading","route","annotations","planPolicies","selectedRouteInfo","routeNamespace","routeName","find","pp","ref","targetRef","kind","namespace","handleAddTag","trim","includes","handleClose","Dialog","maxWidth","fullWidth","DialogTitle","DialogContent","marginBottom","Grid","container","spacing","item","xs","TextField","e","target","placeholder","helperText","margin","required","InputLabelProps","select","MenuItem","multiline","rows","tag","onDelete","handleDeleteTag","tagToDelete","onKeyPress","key","Button","disabled","DialogActions","selectedRouteNamespace","selectedRouteName","apiProduct","apiVersion","group","contact","email","team","documentation","method","headers","body","JSON","stringify","errorData","err","String","EditAPIProductDialog","setLoading","setTargetRef","saving","setSaving","useEffect","then","res","catch","React","patch","ResourceList","createDialogOpen","setCreateDialogOpen","editDialogOpen","setEditDialogOpen","refreshTrigger","setRefreshTrigger","deleteDialogOpen","setDeleteDialogOpen","apiProductToDelete","setApiProductToDelete","apiProductToEdit","setApiProductToEdit","deleting","setDeleting","canCreateApiProduct","createPermissionLoading","createPermissionError","kuadrantApiProductCreatePermission","canViewApprovalQueue","approvalQueuePermissionLoading","approvalQueuePermissionError","kuadrantApiKeyRequestReadAllPermission","canDeleteApiProduct","deletePermissionLoading","deletePermissionError","kuadrantApiProductDeletePermission","canUpdateApiProduct","kuadrantApiProductUpdatePermission","canListPlanPolicies","planPolicyPermissionLoading","planPolicyPermissionError","kuadrantPlanPolicyListPermission","apiProducts","apiProductsLoading","apiProductsError","planPoliciesLoading","planPoliciesError","permissionError","handleDeleteCancel","formatDate","dateString","year","month","day","handleEditClick","EditIcon","handleDeleteClick","DeleteIcon","planPolicyColumns","Page","themeId","Header","subtitle","SupportButton","Content","ResponseErrorPanel","direction","action","height","startIcon","AddIcon","undefined","resources","renderPlanPolicies","ApprovalQueueCard","DialogContentText","console","KuadrantPage","kuadrantApiProductListPermission"],"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(2198),a.e(4161),a.e(3483),a.e(8617),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(7632)]).then(a.bind(a,95251)).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(2198),a.e(4161),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(2198),a.e(4161),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(2198),a.e(4161),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(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),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.50e173c2.chunk.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"static/exposed-PluginRoot.8bc4d676.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,mMAAoCC,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,sKAA2CL,KAAKC,GAAKA,EAAEO,yBAMlDC,EAA+BnB,EAAeM,SACzDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,+BACNC,UAAW,CACTM,KAAM,IACJ,sKAA2CL,KAAKC,GAAKA,EAAEO,yBAKlDE,EAA4BpB,EAAeM,SACtDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,4BACNC,UAAW,CACTM,KAAM,IACJ,gLAAyCL,KAAKC,GAAKA,EAAEU,uBAKhDC,EAAsCtB,EAAeM,SAChEQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,sCACNC,UAAW,CACTM,KAAM,IACJ,kJAA0CL,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.50e173c2.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,oMAAoCC,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,sKAA2CL,KAAKC,GAAKA,EAAEO,yBAMlDC,EAA+BnB,EAAeM,SACzDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,+BACNC,UAAW,CACTM,KAAM,IACJ,sKAA2CL,KAAKC,GAAKA,EAAEO,yBAKlDE,EAA4BpB,EAAeM,SACtDQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,4BACNC,UAAW,CACTM,KAAM,IACJ,gLAAyCL,KAAKC,GAAKA,EAAEU,uBAKhDC,EAAsCtB,EAAeM,SAChEQ,EAAAA,EAAAA,0BAAyB,CACvBN,KAAM,sCACNC,UAAW,CACTM,KAAM,IACJ,kJAA0CL,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.1-test.1-464d7760",
3
+ "version": "0.0.1-test.1-48246e3",
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([[5811],{5811:(e,a,t)=>{t.r(a),t.d(a,{KuadrantPage:()=>J});var l=t(31085),r=t(95478),s=t(67720),n=t(10394),i=t(29365),o=t(72501),d=t(42899),c=t(64947),u=t(76891),p=t(61477),m=t(46805),h=t(59461),x=t(93453),A=t(18466),v=t(39590),g=t(75625),j=t(37725),f=t(25010),y=t(289),b=t(55639),S=t(45210),P=t(46681),k=t(86687),C=t(42367),w=t(96040),T=t(91638),I=t(22097),R=t(16281),W=t(71677),D=t(31653),N=t(38605),$=t(32269),E=t(61524);const L=()=>{const e=(0,I.useApi)(I.configApiRef),a=(0,I.useApi)(I.fetchApiRef),t=(0,I.useApi)(I.identityApiRef),d=e.getString("backend.baseUrl"),[c,u]=(0,r.useState)(0),[,p]=(0,r.useState)(""),[m,h]=(0,r.useState)(new Set);(0,T.A)(async()=>{const e=await t.getBackstageIdentity();p(e.userEntityRef.split("/")[1]||"guest")},[t]);const{value:x,loading:A,error:v}=(0,T.A)(async()=>{const e=await a.fetch(`${d}/api/kuadrant/requests/my`);if(!e.ok)throw new Error("failed to fetch requests");return(await e.json()).items||[]},[d,a]);if(A)return(0,l.jsx)(w.n,{title:"My API Keys",children:(0,l.jsx)(o.A,{children:"Loading..."})});if(v)return(0,l.jsx)(w.n,{title:"My API Keys",children:(0,l.jsxs)(o.A,{color:"error",children:["Error loading API keys: ",v.message]})});const g=x||[],y=g.filter(e=>{var a;return"Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)}),b=g.filter(e=>{var a;return!(null===(a=e.status)||void 0===a?void 0:a.phase)||"Pending"===e.status.phase}),S=g.filter(e=>{var a;return"Rejected"===(null===(a=e.status)||void 0===a?void 0:a.phase)}),P=[{title:"API Product",field:"spec.apiName",render:e=>(0,l.jsx)(j.N_,{to:`/catalog/default/api/${e.spec.apiName}/api-keys`,children:(0,l.jsx)("strong",{children:e.spec.apiName})})},{title:"Plan",field:"spec.planTier",render:e=>{const a="gold"===e.spec.planTier?"primary":"silver"===e.spec.planTier?"default":"secondary";return(0,l.jsx)(s.A,{label:e.spec.planTier,color:a,size:"small"})}},{title:"Use Case",field:"spec.useCase",render:e=>(0,l.jsx)(o.A,{variant:"body2",children:e.spec.useCase||"-"})},{title:"Status",field:"status.phase",render:e=>{var a;const t=(null===(a=e.status)||void 0===a?void 0:a.phase)||"Pending",r="Approved"===t?"primary":"Rejected"===t?"secondary":"default";return(0,l.jsx)(s.A,{label:t,color:r,size:"small"})}},{title:"Reason",render:e=>{var a;return"Rejected"===(null===(a=e.status)||void 0===a?void 0:a.phase)&&e.status.reason?(0,l.jsx)(o.A,{variant:"body2",color:"error",children:e.status.reason}):(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"-"})}},{title:"Reviewed By",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,l.jsxs)(n.A,{children:[(0,l.jsx)(o.A,{variant:"body2",children:e.status.reviewedBy}),a&&(0,l.jsx)(o.A,{variant:"caption",color:"textSecondary",children:a})]})}return(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"-"})}},{title:"API Key",render:e=>{var a;if("Approved"===(null===(a=e.status)||void 0===a?void 0:a.phase)&&e.status.apiKey){const a=m.has(e.metadata.name);return(0,l.jsxs)(n.A,{display:"flex",alignItems:"center",style:{gap:8},children:[(0,l.jsx)(n.A,{fontFamily:"monospace",fontSize:"0.875rem",children:a?e.status.apiKey:"•".repeat(20)+"..."}),(0,l.jsx)(W.Ay,{title:a?"hide key":"show key",children:(0,l.jsx)(i.A,{size:"small",onClick:()=>{return a=e.metadata.name,void h(e=>{const t=new Set(e);return t.has(a)?t.delete(a):t.add(a),t});var a},children:a?(0,l.jsx)(E.A,{fontSize:"small"}):(0,l.jsx)($.A,{fontSize:"small"})})})]})}return(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"-"})}},{title:"Requested",field:"metadata.creationTimestamp",render:e=>new Date(e.metadata.creationTimestamp).toLocaleDateString()}],k=(()=>{switch(c){case 0:return y;case 1:return b;case 2:return S;default:return g}})();return(0,l.jsxs)(w.n,{title:"My API Keys",subheader:`${y.length} active, ${b.length} pending`,children:[(0,l.jsx)(n.A,{mb:2,children:(0,l.jsxs)(D.A,{value:c,onChange:(e,a)=>u(a),indicatorColor:"primary",textColor:"primary",children:[(0,l.jsx)(N.A,{label:`Active (${y.length})`}),(0,l.jsx)(N.A,{label:`Pending (${b.length})`}),(0,l.jsx)(N.A,{label:`Rejected (${S.length})`})]})}),0===k.length?(0,l.jsx)(n.A,{p:3,textAlign:"center",children:(0,l.jsxs)(o.A,{variant:"body1",color:"textSecondary",children:[0===c&&"No active API keys. Request access to an API to get started.",1===c&&"No pending requests.",2===c&&"No rejected requests."]})}):(0,l.jsx)(f.X,{options:{paging:k.length>10,pageSize:10,search:!1,toolbar:!1},columns:P,data:k})]})};var z=t(46205);const q=({children:e,permission:a,fallback:t,errorMessage:r})=>{const{allowed:s,loading:i,error:d}=(0,z.l)(a);return i?(0,l.jsx)(k.k,{}):d?(0,l.jsxs)(n.A,{p:4,children:[(0,l.jsxs)(o.A,{color:"error",children:["Unable to check permissions: ",d.message]}),(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"Please try again or contact your administrator"})]}):s?(0,l.jsx)(l.Fragment,{children:e}):t?(0,l.jsx)(l.Fragment,{children:t}):(0,l.jsxs)(n.A,{p:4,children:[(0,l.jsx)(o.A,{color:"textSecondary",children:r||"You don't have permission to view this page"}),(0,l.jsx)(n.A,{mt:1,children:(0,l.jsxs)(o.A,{variant:"caption",color:"textSecondary",children:["Required permission: ",a.name]})})]})};var M=t(58837),K=t(16249),U=t(26343),B=t(84441);const H=(0,M.A)({asterisk:{color:"#f44336"}}),_=({open:e,onClose:a,onSuccess:t})=>{const i=H(),h=(0,I.useApi)(I.configApiRef),A=(0,I.useApi)(I.fetchApiRef),v=h.getString("backend.baseUrl"),[g,j]=(0,r.useState)(""),[f,y]=(0,r.useState)(""),[b,S]=(0,r.useState)(""),[P,k]=(0,r.useState)("v1"),[C,w]=(0,r.useState)("manual"),[R,W]=(0,r.useState)("Published"),[D,N]=(0,r.useState)([]),[$,E]=(0,r.useState)(""),[L,z]=(0,r.useState)(""),[q,M]=(0,r.useState)(""),[_,V]=(0,r.useState)(""),[F,O]=(0,r.useState)(""),[Y,J]=(0,r.useState)(""),[X,G]=(0,r.useState)(""),[Q,Z]=(0,r.useState)(!1),{value:ee,loading:ae}=(0,T.A)(async()=>{const e=await A.fetch(`${v}/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"])})},[v,A,e]),te=()=>{$.trim()&&!D.includes($.trim())&&(N([...D,$.trim()]),E(""))},le=()=>{j(""),y(""),S(""),k("v1"),w("manual"),W("Published"),N([]),E(""),z(""),M(""),V(""),O(""),J(""),G(""),a()};return(0,l.jsxs)(u.A,{open:e,onClose:le,maxWidth:"md",fullWidth:!0,children:[(0,l.jsx)(p.A,{children:"Create API Product"}),(0,l.jsxs)(m.A,{children:[X&&(0,l.jsx)(B.A,{severity:"error",style:{marginBottom:16},children:X}),(0,l.jsxs)(d.A,{container:!0,spacing:2,children:[(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Name",value:g,onChange:e=>j(e.target.value),placeholder:"my-api",helperText:"Kubernetes resource name (lowercase, hyphens)",margin:"normal",required:!0,InputLabelProps:{classes:{asterisk:i.asterisk}}})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Display Name",value:f,onChange:e=>y(e.target.value),placeholder:"My API",margin:"normal",required:!0,InputLabelProps:{classes:{asterisk:i.asterisk}}})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Version",value:P,onChange:e=>k(e.target.value),placeholder:"v1",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:12,children:(0,l.jsxs)(K.A,{fullWidth:!0,select:!0,label:"Approval Mode",value:C,onChange:e=>w(e.target.value),margin:"normal",helperText:"Automatic: keys are created immediately. Manual: requires approval.",children:[(0,l.jsx)(U.A,{value:"manual",children:"Manual"}),(0,l.jsx)(U.A,{value:"automatic",children:"Automatic"})]})}),(0,l.jsx)(d.A,{item:!0,xs:12,children:(0,l.jsxs)(K.A,{fullWidth:!0,select:!0,label:"Publish Status",value:R,onChange:e=>W(e.target.value),margin:"normal",helperText:"Draft: hidden from catalog. Published: visible to consumers.",children:[(0,l.jsx)(U.A,{value:"Draft",children:"Draft"}),(0,l.jsx)(U.A,{value:"Published",children:"Published"})]})}),(0,l.jsx)(d.A,{item:!0,xs:12,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Description",value:b,onChange:e=>S(e.target.value),placeholder:"API description",margin:"normal",multiline:!0,rows:2,required:!0,InputLabelProps:{classes:{asterisk:i.asterisk}}})}),(0,l.jsxs)(d.A,{item:!0,xs:12,children:[(0,l.jsx)(o.A,{variant:"subtitle2",gutterBottom:!0,style:{marginTop:16},children:"Tags"}),(0,l.jsx)(n.A,{display:"flex",flexWrap:"wrap",marginBottom:1,style:{gap:8},children:D.map(e=>(0,l.jsx)(s.A,{label:e,onDelete:()=>{return a=e,void N(D.filter(e=>e!==a));var a},size:"small"},e))}),(0,l.jsxs)(n.A,{display:"flex",style:{gap:8},children:[(0,l.jsx)(K.A,{fullWidth:!0,size:"small",value:$,onChange:e=>E(e.target.value),onKeyPress:e=>"Enter"===e.key&&te(),placeholder:"Add tag"}),(0,l.jsx)(c.A,{onClick:te,variant:"outlined",size:"small",children:"Add"})]})]}),(0,l.jsx)(d.A,{item:!0,xs:12,children:(0,l.jsxs)(K.A,{fullWidth:!0,select:!0,label:"HTTPRoute",value:L,onChange:e=>z(e.target.value),margin:"normal",required:!0,helperText:"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.",disabled:ae,InputLabelProps:{classes:{asterisk:i.asterisk}},children:[ae&&(0,l.jsx)(U.A,{value:"",children:"Loading..."}),!ae&&ee&&0===ee.length&&(0,l.jsx)(U.A,{value:"",children:"No HTTPRoutes available"}),!ae&&ee&&ee.map(e=>(0,l.jsxs)(U.A,{value:`${e.metadata.namespace}/${e.metadata.name}`,children:[e.metadata.name," (",e.metadata.namespace,")"]},`${e.metadata.namespace}/${e.metadata.name}`))]})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Contact Email",value:q,onChange:e=>M(e.target.value),placeholder:"api-team@example.com",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Contact Team",value:_,onChange:e=>V(e.target.value),placeholder:"platform-team",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Docs URL",value:F,onChange:e=>O(e.target.value),placeholder:"https://api.example.com/docs",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"OpenAPI Spec URL",value:Y,onChange:e=>J(e.target.value),placeholder:"https://api.example.com/openapi.json",margin:"normal"})})]})]}),(0,l.jsxs)(x.A,{children:[(0,l.jsx)(c.A,{onClick:le,children:"Cancel"}),(0,l.jsx)(c.A,{onClick:async()=>{G(""),Z(!0);try{if(!L)throw new Error("Please select an HTTPRoute");const[e,a]=L.split("/"),l={apiVersion:"extensions.kuadrant.io/v1alpha1",kind:"APIProduct",metadata:{name:g,namespace:e},spec:{displayName:f,description:b,version:P,approvalMode:C,publishStatus:R,tags:D,targetRef:{group:"gateway.networking.k8s.io",kind:"HTTPRoute",name:a,namespace:e},...q||_?{contact:{...q&&{email:q},..._&&{team:_}}}:{},...F||Y?{documentation:{...F&&{docsURL:F},...Y&&{openAPISpec:Y}}}:{}}},r=await A.fetch(`${v}/api/kuadrant/apiproducts`,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(l)});if(!r.ok){const e=await r.json();throw new Error(e.error||"failed to create apiproduct")}t(),le()}catch(e){G(e instanceof Error?e.message:String(e))}finally{Z(!1)}},color:"primary",variant:"contained",disabled:Q||!g||!f||!b||!L,children:Q?"Creating...":"Create"})]})]})};var V=t(34955);const F=(0,M.A)({asterisk:{color:"#f44336"}}),O=({open:e,onClose:a,onSuccess:t,namespace:i,name:h})=>{const A=F(),v=(0,I.useApi)(I.configApiRef),g=(0,I.useApi)(I.fetchApiRef),j=v.getString("backend.baseUrl"),[f,y]=(0,r.useState)(!1),[b,S]=(0,r.useState)(""),[P,C]=(0,r.useState)(""),[w,T]=(0,r.useState)("v1"),[R,W]=(0,r.useState)("Draft"),[D,N]=(0,r.useState)("manual"),[$,E]=(0,r.useState)([]),[L,z]=(0,r.useState)(null),[q,M]=(0,r.useState)(""),[H,_]=(0,r.useState)(""),[V,O]=(0,r.useState)(""),[Y,J]=(0,r.useState)(""),[X,G]=(0,r.useState)(""),[Q,Z]=(0,r.useState)(""),[ee,ae]=(0,r.useState)(!1);(0,r.useEffect)(()=>{e&&i&&h&&(y(!0),Z(""),g.fetch(`${j}/api/kuadrant/apiproducts/${i}/${h}`).then(e=>e.json()).then(e=>{var a,t,l,r;S(e.spec.displayName||""),C(e.spec.description||""),T(e.spec.version||"v1"),W(e.spec.publishStatus||"Draft"),N(e.spec.approvalMode||"manual"),E(e.spec.tags||[]),z(e.spec.targetRef||null),_((null===(a=e.spec.contact)||void 0===a?void 0:a.email)||""),O((null===(t=e.spec.contact)||void 0===t?void 0:t.team)||""),J((null===(l=e.spec.documentation)||void 0===l?void 0:l.docsURL)||""),G((null===(r=e.spec.documentation)||void 0===r?void 0:r.openAPISpec)||""),y(!1)}).catch(e=>{Z(e.message||"Failed to load API Product"),y(!1)}))},[e,i,h,j,g]);const te=()=>{q.trim()&&!$.includes(q.trim())&&(E([...$,q.trim()]),M(""))};return(0,l.jsxs)(u.A,{open:e,onClose:a,maxWidth:"md",fullWidth:!0,children:[(0,l.jsx)(p.A,{children:"Edit API Product"}),(0,l.jsxs)(m.A,{children:[Q&&(0,l.jsx)(B.A,{severity:"error",style:{marginBottom:16},children:Q}),f?(0,l.jsx)(k.k,{}):(0,l.jsxs)(d.A,{container:!0,spacing:2,children:[(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Name",value:h,disabled:!0,helperText:"Kubernetes resource name (immutable)",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Namespace",value:i,disabled:!0,helperText:"Derived from HTTPRoute (immutable)",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Display Name",value:b,onChange:e=>S(e.target.value),placeholder:"My API",margin:"normal",required:!0,InputLabelProps:{classes:{asterisk:A.asterisk}}})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Version",value:w,onChange:e=>T(e.target.value),placeholder:"v1",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsxs)(K.A,{fullWidth:!0,select:!0,label:"Publish Status",value:R,onChange:e=>W(e.target.value),margin:"normal",helperText:"Draft: Hidden from catalog. Published: Visible in catalog.",children:[(0,l.jsx)(U.A,{value:"Draft",children:"Draft (Hidden)"}),(0,l.jsx)(U.A,{value:"Published",children:"Published (Visible)"})]})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsxs)(K.A,{fullWidth:!0,select:!0,label:"Approval Mode",value:D,onChange:e=>N(e.target.value),margin:"normal",helperText:"Automatic: keys created immediately. Manual: requires approval.",children:[(0,l.jsx)(U.A,{value:"manual",children:"Manual"}),(0,l.jsx)(U.A,{value:"automatic",children:"Automatic"})]})}),(0,l.jsx)(d.A,{item:!0,xs:12,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Description",value:P,onChange:e=>C(e.target.value),placeholder:"API description",margin:"normal",multiline:!0,rows:2,required:!0,InputLabelProps:{classes:{asterisk:A.asterisk}}})}),(0,l.jsxs)(d.A,{item:!0,xs:12,children:[(0,l.jsx)(o.A,{variant:"subtitle2",gutterBottom:!0,style:{marginTop:16},children:"Tags"}),(0,l.jsx)(n.A,{display:"flex",flexWrap:"wrap",marginBottom:1,style:{gap:8},children:$.map(e=>(0,l.jsx)(s.A,{label:e,onDelete:()=>{return a=e,void E($.filter(e=>e!==a));var a},size:"small"},e))}),(0,l.jsxs)(n.A,{display:"flex",style:{gap:8},children:[(0,l.jsx)(K.A,{fullWidth:!0,size:"small",value:q,onChange:e=>M(e.target.value),onKeyPress:e=>"Enter"===e.key&&te(),placeholder:"Add tag"}),(0,l.jsx)(c.A,{onClick:te,variant:"outlined",size:"small",children:"Add"})]})]}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Contact Email",value:H,onChange:e=>_(e.target.value),placeholder:"api-team@example.com",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Contact Team",value:V,onChange:e=>O(e.target.value),placeholder:"platform-team",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"Docs URL",value:Y,onChange:e=>J(e.target.value),placeholder:"https://api.example.com/docs",margin:"normal"})}),(0,l.jsx)(d.A,{item:!0,xs:6,children:(0,l.jsx)(K.A,{fullWidth:!0,label:"OpenAPI Spec URL",value:X,onChange:e=>G(e.target.value),placeholder:"https://api.example.com/openapi.json",margin:"normal"})})]})]}),(0,l.jsxs)(x.A,{children:[(0,l.jsx)(c.A,{onClick:a,children:"Cancel"}),(0,l.jsx)(c.A,{onClick:async()=>{Z(""),ae(!0);try{const e={spec:{displayName:b,description:P,version:w,publishStatus:R,approvalMode:D,tags:$,targetRef:L,...H||V?{contact:{...H&&{email:H},...V&&{team:V}}}:{},...Y||X?{documentation:{...Y&&{docsURL:Y},...X&&{openAPISpec:X}}}:{}}},l=await g.fetch(`${j}/api/kuadrant/apiproducts/${i}/${h}`,{method:"PATCH",headers:{"Content-Type":"application/json"},body:JSON.stringify(e)});if(!l.ok){const e=await l.json();throw new Error(e.error||"failed to update apiproduct")}t(),a()}catch(e){Z(e instanceof Error?e.message:String(e))}finally{ae(!1)}},color:"primary",variant:"contained",disabled:ee||f||!b||!P,children:ee?"Saving...":"Save"})]})]})},Y=()=>{const e=(0,I.useApi)(I.configApiRef),a=(0,I.useApi)(I.fetchApiRef),t=e.getString("backend.baseUrl"),[W,D]=(0,r.useState)(!1),[N,$]=(0,r.useState)(!1),[E,q]=(0,r.useState)(0),[M,K]=(0,r.useState)(!1),[U,B]=(0,r.useState)(null),[H,F]=(0,r.useState)(null),[Y,J]=(0,r.useState)(!1),{allowed:X,loading:G,error:Q}=(0,z.l)(V.FL),{allowed:Z,loading:ee,error:ae}=(0,z.l)(V.TE),{allowed:te,loading:le,error:re}=(0,z.l)(V.qC),{allowed:se}=(0,z.l)(V.ib),{allowed:ne,loading:ie,error:oe}=(0,z.l)(V.J),{value:de,loading:ce,error:ue}=(0,T.A)(async()=>{const e=await a.fetch(`${t}/api/kuadrant/apiproducts`);return await e.json()},[t,a,E]),{value:pe,loading:me,error:he}=(0,T.A)(async()=>{const e=await a.fetch(`${t}/api/kuadrant/planpolicies`);return await e.json()},[t,a,E]),xe=ce||me||G||ee||le||ie,Ae=ue||he,ve=Q||ae||re||oe,ge=()=>{K(!1),B(null)},je=[{title:"Name",field:"name",render:e=>{var a;return(0,l.jsx)(j.N_,{to:`/catalog/default/api/${e.metadata.name}/api-product`,children:(0,l.jsx)("strong",{children:(null===(a=e.spec)||void 0===a?void 0:a.displayName)||e.metadata.name})})}},{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,l.jsx)(s.A,{label:t,size:"small",color:"Published"===t?"primary":"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",render:e=>(0,l.jsxs)(n.A,{display:"flex",style:{gap:4},children:[se&&(0,l.jsx)(i.A,{size:"small",onClick:()=>{return a=e.metadata.namespace,t=e.metadata.name,F({namespace:a,name:t}),void $(!0);var a,t},title:"Edit API Product",children:(0,l.jsx)(g.A,{fontSize:"small"})}),te&&(0,l.jsx)(i.A,{size:"small",onClick:()=>{return a=e.metadata.namespace,t=e.metadata.name,B({namespace:a,name:t}),void K(!0);var a,t},title:"Delete API Product",children:(0,l.jsx)(v.A,{fontSize:"small"})})]})}],fe=[{title:"Name",field:"metadata.name",render:e=>(0,l.jsx)(j.N_,{to:`/kuadrant/planpolicy/${e.metadata.namespace}/${e.metadata.name}`,children:(0,l.jsx)("strong",{children:e.metadata.name})})},{title:"Namespace",field:"metadata.namespace"}];return(0,l.jsxs)(y.Y,{themeId:"tool",children:[(0,l.jsx)(b.Y,{title:"Kuadrant",subtitle:"API management for Kubernetes",children:(0,l.jsx)(S.Y,{children:"Manage API products and access requests"})}),(0,l.jsxs)(P.U,{children:[xe&&(0,l.jsx)(k.k,{}),Ae&&(0,l.jsx)(C._,{error:Ae}),ve&&(0,l.jsxs)(n.A,{p:2,children:[(0,l.jsxs)(o.A,{color:"error",children:["unable to check permissions: ",ve.message]}),(0,l.jsxs)(o.A,{variant:"body2",color:"textSecondary",children:["permission: ",Q?"kuadrant.apiproduct.create":re?"kuadrant.apiproduct.delete":ae?"kuadrant.apikeyrequest.read.all":oe?"kuadrant.planpolicy.list":"unknown"]}),(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"please try again or contact your administrator"})]}),!xe&&!Ae&&!ve&&(0,l.jsxs)(d.A,{container:!0,spacing:3,direction:"column",children:[(0,l.jsx)(d.A,{item:!0,children:(0,l.jsx)(L,{})}),(0,l.jsx)(d.A,{item:!0,children:(0,l.jsx)(w.n,{title:"API Products",action:X?(0,l.jsx)(n.A,{display:"flex",alignItems:"center",height:"100%",mt:1,children:(0,l.jsx)(c.A,{variant:"contained",color:"primary",size:"small",startIcon:(0,l.jsx)(A.A,{}),onClick:()=>D(!0),children:"Create API Product"})}):void 0,children:(ye=null==de?void 0:de.items,ye&&0!==ye.length?(0,l.jsx)(f.X,{options:{paging:!1,search:!1,toolbar:!1},columns:je,data:ye}):(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"No API products found"}))})}),ne&&(0,l.jsx)(d.A,{item:!0,children:(0,l.jsx)(w.n,{title:"Plan Policies",children:(e=>e&&0!==e.length?(0,l.jsx)(f.X,{options:{paging:!1,search:!1,toolbar:!1},columns:fe,data:e}):(0,l.jsx)(o.A,{variant:"body2",color:"textSecondary",children:"No plan policies found"}))(null==pe?void 0:pe.items)})}),Z&&(0,l.jsx)(d.A,{item:!0,children:(0,l.jsx)(R.d,{})})]}),(0,l.jsx)(_,{open:W,onClose:()=>D(!1),onSuccess:()=>{q(e=>e+1)}}),(0,l.jsx)(O,{open:N,onClose:()=>$(!1),onSuccess:()=>{q(e=>e+1)},namespace:(null==H?void 0:H.namespace)||"",name:(null==H?void 0:H.name)||""}),(0,l.jsxs)(u.A,{open:M,onClose:ge,children:[(0,l.jsx)(p.A,{children:"Delete API Product"}),(0,l.jsx)(m.A,{children:(0,l.jsxs)(h.A,{children:["Are you sure you want to delete ",null==U?void 0:U.name," from namespace ",null==U?void 0:U.namespace,"? This will permanently remove the API Product from Kubernetes."]})}),(0,l.jsxs)(x.A,{children:[(0,l.jsx)(c.A,{onClick:ge,color:"primary",children:"Cancel"}),(0,l.jsx)(c.A,{onClick:async()=>{if(U){J(!0);try{if(!(await a.fetch(`${t}/api/kuadrant/apiproducts/${U.namespace}/${U.name}`,{method:"DELETE"})).ok)throw new Error("failed to delete apiproduct");q(e=>e+1)}catch(e){console.error("error deleting apiproduct:",e)}finally{J(!1),K(!1),B(null)}}},color:"secondary",disabled:Y,children:Y?"Deleting...":"Delete"})]})]})]})]});var ye},J=()=>(0,l.jsx)(q,{permission:V.vs,errorMessage:"you don't have permission to view the Kuadrant page",children:(0,l.jsx)(Y,{})})}}]);
2
- //# sourceMappingURL=5811.5c192eeb.chunk.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"static/5811.5c192eeb.chunk.js","mappings":"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","sources":["webpack://internal.plugin-kuadrant/./src/components/MyApiKeysCard/MyApiKeysCard.tsx","webpack://internal.plugin-kuadrant/./src/components/PermissionGate/PermissionGate.tsx","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"],"sourcesContent":["import React, { useState } from 'react';\nimport { InfoCard, Table, TableColumn, Link } from '@backstage/core-components';\nimport { useApi, configApiRef, fetchApiRef, identityApiRef } from '@backstage/core-plugin-api';\nimport useAsync from 'react-use/lib/useAsync';\nimport { Box, Chip, Typography, Tabs, Tab, IconButton, Tooltip } from '@material-ui/core';\nimport VisibilityIcon from '@material-ui/icons/Visibility';\nimport VisibilityOffIcon from '@material-ui/icons/VisibilityOff';\n\ninterface APIKeyRequest {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: string;\n };\n spec: {\n apiName: string;\n apiNamespace: string;\n planTier: string;\n useCase?: string;\n requestedBy: {\n userId: string;\n email?: string;\n };\n };\n status?: {\n phase: 'Pending' | 'Approved' | 'Rejected';\n apiKey?: string;\n apiHostname?: string;\n reason?: string;\n reviewedBy?: string;\n reviewedAt?: string;\n };\n}\n\nexport const MyApiKeysCard = () => {\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const identityApi = useApi(identityApiRef);\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\n useAsync(async () => {\n const identity = await identityApi.getBackstageIdentity();\n setUserId(identity.userEntityRef.split('/')[1] || 'guest');\n }, [identityApi]);\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]);\n\n if (loading) {\n return (\n <InfoCard title=\"My API Keys\">\n <Typography>Loading...</Typography>\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 || [];\n const approvedRequests = allRequests.filter((r: APIKeyRequest) => r.status?.phase === 'Approved');\n const pendingRequests = allRequests.filter((r: APIKeyRequest) => !r.status?.phase || r.status.phase === 'Pending');\n const rejectedRequests = allRequests.filter((r: APIKeyRequest) => 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 columns: TableColumn<APIKeyRequest>[] = [\n {\n title: 'API Product',\n field: 'spec.apiName',\n render: (row: APIKeyRequest) => (\n <Link to={`/catalog/default/api/${row.spec.apiName}/api-keys`}>\n <strong>{row.spec.apiName}</strong>\n </Link>\n ),\n },\n {\n title: 'Plan',\n field: 'spec.planTier',\n render: (row: APIKeyRequest) => {\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: APIKeyRequest) => {\n return (\n <Typography variant=\"body2\">\n {row.spec.useCase || '-'}\n </Typography>\n );\n },\n },\n {\n title: 'Status',\n field: 'status.phase',\n render: (row: APIKeyRequest) => {\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: 'Reason',\n render: (row: APIKeyRequest) => {\n if (row.status?.phase === 'Rejected' && row.status.reason) {\n return (\n <Typography variant=\"body2\" color=\"error\">\n {row.status.reason}\n </Typography>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Reviewed By',\n render: (row: APIKeyRequest) => {\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 render: (row: APIKeyRequest) => {\n if (row.status?.phase === 'Approved' && row.status.apiKey) {\n const isVisible = visibleKeys.has(row.metadata.name);\n return (\n <Box display=\"flex\" alignItems=\"center\" style={{ gap: 8 }}>\n <Box fontFamily=\"monospace\" fontSize=\"0.875rem\">\n {isVisible ? row.status.apiKey : '•'.repeat(20) + '...'}\n </Box>\n <Tooltip title={isVisible ? 'hide key' : 'show key'}>\n <IconButton\n size=\"small\"\n onClick={() => toggleKeyVisibility(row.metadata.name)}\n >\n {isVisible ? <VisibilityOffIcon fontSize=\"small\" /> : <VisibilityIcon fontSize=\"small\" />}\n </IconButton>\n </Tooltip>\n </Box>\n );\n }\n return <Typography variant=\"body2\" color=\"textSecondary\">-</Typography>;\n },\n },\n {\n title: 'Requested',\n field: 'metadata.creationTimestamp',\n render: (row: APIKeyRequest) => {\n const date = new Date(row.metadata.creationTimestamp);\n return date.toLocaleDateString();\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 tabData = getTabData();\n\n return (\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 > 10,\n pageSize: 10,\n search: false,\n toolbar: false,\n }}\n columns={columns}\n data={tabData}\n />\n )}\n </InfoCard>\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, { 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 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';\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\n const { value: httpRoutes, loading: httpRoutesLoading } = 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]);\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: 'extensions.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 onClose();\n };\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\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n onChange={e => setName(e.target.value)}\n placeholder=\"my-api\"\n helperText=\"Kubernetes resource name (lowercase, hyphens)\"\n margin=\"normal\"\n required\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 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 />\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 >\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 >\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 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={() => handleDeleteTag(tag)}\n size=\"small\"\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 />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\">\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=\"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.\"\n disabled={httpRoutesLoading}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n >\n {httpRoutesLoading && (\n <MenuItem value=\"\">Loading...</MenuItem>\n )}\n {!httpRoutesLoading && httpRoutes && httpRoutes.length === 0 && (\n <MenuItem value=\"\">No HTTPRoutes available</MenuItem>\n )}\n {!httpRoutesLoading && 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\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => setContactEmail(e.target.value)}\n placeholder=\"api-team@example.com\"\n margin=\"normal\"\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 />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => setDocsURL(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => setOpenAPISpec(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n margin=\"normal\"\n />\n </Grid>\n </Grid>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose}>Cancel</Button>\n <Button\n onClick={handleCreate}\n color=\"primary\"\n variant=\"contained\"\n disabled={creating || !name || !displayName || !description || !selectedHTTPRoute}\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 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';\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\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(res => res.json())\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 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 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\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 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 />\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 >\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 >\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 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={() => handleDeleteTag(tag)}\n size=\"small\"\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 />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\">\n Add\n </Button>\n </Box>\n </Grid>\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => setContactEmail(e.target.value)}\n placeholder=\"api-team@example.com\"\n margin=\"normal\"\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 />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => setDocsURL(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => setOpenAPISpec(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n margin=\"normal\"\n />\n </Grid>\n </Grid>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose}>Cancel</Button>\n <Button\n onClick={handleSave}\n color=\"primary\"\n variant=\"contained\"\n disabled={saving || loading || !displayName || !description}\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, Dialog, DialogTitle, DialogContent, DialogContentText, DialogActions } 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 } 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 kuadrantApiProductDeletePermission,\n kuadrantApiProductUpdatePermission,\n kuadrantApiProductListPermission,\n kuadrantApiKeyRequestReadAllPermission,\n kuadrantPlanPolicyListPermission,\n} from '../../permissions';\nimport { useKuadrantPermission } from '../../utils/permissions';\nimport { EditAPIProductDialog } from '../EditAPIProductDialog';\n\ntype KuadrantResource = {\n metadata: {\n name: string;\n namespace: string;\n creationTimestamp: 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 backendUrl = config.getString('backend.baseUrl');\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\n const {\n allowed: canCreateApiProduct,\n loading: createPermissionLoading,\n error: createPermissionError,\n } = useKuadrantPermission(kuadrantApiProductCreatePermission);\n\n const {\n allowed: canViewApprovalQueue,\n loading: approvalQueuePermissionLoading,\n error: approvalQueuePermissionError,\n } = useKuadrantPermission(kuadrantApiKeyRequestReadAllPermission);\n\n const {\n allowed: canDeleteApiProduct,\n loading: deletePermissionLoading,\n error: deletePermissionError,\n } = useKuadrantPermission(kuadrantApiProductDeletePermission);\n\n const {\n allowed: canUpdateApiProduct,\n } = useKuadrantPermission(kuadrantApiProductUpdatePermission);\n\n const {\n allowed: canListPlanPolicies,\n loading: planPolicyPermissionLoading,\n error: planPolicyPermissionError,\n } = useKuadrantPermission(kuadrantPlanPolicyListPermission);\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 };\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 };\n\n const handleDeleteClick = (namespace: string, name: string) => {\n setApiProductToDelete({ namespace, name });\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 } catch (err) {\n console.error('error deleting apiproduct:', err);\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: 'name',\n render: (row: any) => (\n <Link to={`/catalog/default/api/${row.metadata.name}/api-product`}>\n <strong>{row.spec?.displayName || row.metadata.name}</strong>\n </Link>\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: '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 render: (row: any) => (\n <Box display=\"flex\" style={{ gap: 4 }}>\n {canUpdateApiProduct && (\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 {canDeleteApiProduct && (\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 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={{ paging: false, search: false, toolbar: false }}\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 <Dialog open={deleteDialogOpen} onClose={handleDeleteCancel}>\n <DialogTitle>Delete API Product</DialogTitle>\n <DialogContent>\n <DialogContentText>\n Are you sure you want to delete {apiProductToDelete?.name} from namespace {apiProductToDelete?.namespace}?\n This will permanently remove the API Product from Kubernetes.\n </DialogContentText>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleDeleteCancel} color=\"primary\">\n Cancel\n </Button>\n <Button onClick={handleDeleteConfirm} color=\"secondary\" disabled={deleting}>\n {deleting ? 'Deleting...' : 'Delete'}\n </Button>\n </DialogActions>\n </Dialog>\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"],"names":["MyApiKeysCard","config","useApi","configApiRef","fetchApi","fetchApiRef","identityApi","identityApiRef","backendUrl","getString","selectedTab","setSelectedTab","useState","setUserId","visibleKeys","setVisibleKeys","Set","useAsync","async","identity","getBackstageIdentity","userEntityRef","split","value","requests","loading","error","response","fetch","ok","Error","json","items","InfoCard","title","Typography","color","message","allRequests","approvedRequests","filter","r","status","phase","pendingRequests","rejectedRequests","columns","field","render","row","Link","to","spec","apiName","strong","planTier","Chip","label","size","variant","useCase","reason","reviewedBy","reviewedDate","reviewedAt","Date","toLocaleDateString","Box","apiKey","isVisible","has","metadata","name","display","alignItems","style","gap","fontFamily","fontSize","repeat","Tooltip","IconButton","onClick","toggleKeyVisibility","keyName","prev","newSet","delete","add","VisibilityOffIcon","VisibilityIcon","creationTimestamp","tabData","getTabData","subheader","length","mb","Tabs","onChange","_","newValue","indicatorColor","textColor","Tab","p","textAlign","Table","options","paging","pageSize","search","toolbar","data","PermissionGate","children","permission","fallback","errorMessage","allowed","useKuadrantPermission","Progress","mt","useStyles","makeStyles","asterisk","CreateAPIProductDialog","open","onClose","onSuccess","classes","setName","displayName","setDisplayName","description","setDescription","version","setVersion","approvalMode","setApprovalMode","publishStatus","setPublishStatus","tags","setTags","tagInput","setTagInput","selectedHTTPRoute","setSelectedHTTPRoute","contactEmail","setContactEmail","contactTeam","setContactTeam","docsURL","setDocsURL","openAPISpec","setOpenAPISpec","setError","creating","setCreating","httpRoutes","httpRoutesLoading","route","annotations","handleAddTag","trim","includes","handleClose","Dialog","maxWidth","fullWidth","DialogTitle","DialogContent","Alert","severity","marginBottom","Grid","container","spacing","item","xs","TextField","e","target","placeholder","helperText","margin","required","InputLabelProps","select","MenuItem","multiline","rows","gutterBottom","marginTop","flexWrap","map","tag","onDelete","handleDeleteTag","tagToDelete","onKeyPress","key","Button","disabled","namespace","DialogActions","selectedRouteNamespace","selectedRouteName","apiProduct","apiVersion","kind","targetRef","group","contact","email","team","documentation","method","headers","body","JSON","stringify","errorData","err","String","EditAPIProductDialog","setLoading","setTargetRef","saving","setSaving","useEffect","then","res","catch","patch","ResourceList","createDialogOpen","setCreateDialogOpen","editDialogOpen","setEditDialogOpen","refreshTrigger","setRefreshTrigger","deleteDialogOpen","setDeleteDialogOpen","apiProductToDelete","setApiProductToDelete","apiProductToEdit","setApiProductToEdit","deleting","setDeleting","canCreateApiProduct","createPermissionLoading","createPermissionError","kuadrantApiProductCreatePermission","canViewApprovalQueue","approvalQueuePermissionLoading","approvalQueuePermissionError","kuadrantApiKeyRequestReadAllPermission","canDeleteApiProduct","deletePermissionLoading","deletePermissionError","kuadrantApiProductDeletePermission","canUpdateApiProduct","kuadrantApiProductUpdatePermission","canListPlanPolicies","planPolicyPermissionLoading","planPolicyPermissionError","kuadrantPlanPolicyListPermission","apiProducts","apiProductsLoading","apiProductsError","planPolicies","planPoliciesLoading","planPoliciesError","permissionError","handleDeleteCancel","formatDate","dateString","year","month","day","handleEditClick","EditIcon","handleDeleteClick","DeleteIcon","planPolicyColumns","Page","themeId","Header","subtitle","SupportButton","Content","ResponseErrorPanel","direction","action","height","startIcon","AddIcon","undefined","resources","renderPlanPolicies","ApprovalQueueCard","DialogContentText","console","KuadrantPage","kuadrantApiProductListPermission"],"sourceRoot":""}
@@ -1,2 +0,0 @@
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(2198),a.e(4161),a.e(3483),a.e(8617),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(5811)]).then(a.bind(a,5811)).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(2198),a.e(4161),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(2198),a.e(4161),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(2198),a.e(4161),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(5478),a.e(2469),a.e(4218),a.e(484),a.e(1942),a.e(7976),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.8bc4d676.chunk.js.map