@kuadrant/kuadrant-backstage-plugin-frontend 0.0.2-dev-e57ae53 → 0.0.2-dev-25e5ccb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js +48 -7
- package/dist/components/CreateAPIProductDialog/CreateAPIProductDialog.esm.js.map +1 -1
- package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js +36 -4
- package/dist/components/EditAPIProductDialog/EditAPIProductDialog.esm.js.map +1 -1
- package/dist/utils/validation.esm.js +40 -0
- package/dist/utils/validation.esm.js.map +1 -0
- package/dist-scalprum/{internal.plugin-kuadrant.d57df6840acced29678f.js → internal.plugin-kuadrant.4475e90c8a94cfeda29d.js} +2 -2
- package/dist-scalprum/{internal.plugin-kuadrant.d57df6840acced29678f.js.map → internal.plugin-kuadrant.4475e90c8a94cfeda29d.js.map} +1 -1
- package/dist-scalprum/plugin-manifest.json +2 -2
- package/dist-scalprum/static/532.bf600078.chunk.js +2 -0
- package/dist-scalprum/static/532.bf600078.chunk.js.map +1 -0
- package/dist-scalprum/static/exposed-PluginRoot.7023ce03.chunk.js +2 -0
- package/dist-scalprum/static/{exposed-PluginRoot.0ac7fe4b.chunk.js.map → exposed-PluginRoot.7023ce03.chunk.js.map} +1 -1
- package/package.json +1 -1
- package/dist-scalprum/static/7632.a43cc47c.chunk.js +0 -2
- package/dist-scalprum/static/7632.a43cc47c.chunk.js.map +0 -1
- package/dist-scalprum/static/exposed-PluginRoot.0ac7fe4b.chunk.js +0 -2
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import React, { useState } from 'react';
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
2
|
import { makeStyles, Dialog, DialogTitle, DialogContent, Box, Button, Typography, Grid, TextField, MenuItem, Chip, DialogActions, CircularProgress } from '@material-ui/core';
|
|
3
3
|
import { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';
|
|
4
4
|
import { Alert } from '@material-ui/lab';
|
|
5
5
|
import useAsync from 'react-use/lib/useAsync';
|
|
6
6
|
import { PlanPolicyDetails } from '../PlanPolicyDetailsCard/PlanPolicyDetails.esm.js';
|
|
7
|
+
import { validateKubernetesName, validateEmail, validateURL } from '../../utils/validation.esm.js';
|
|
7
8
|
|
|
8
9
|
const useStyles = makeStyles({
|
|
9
10
|
asterisk: {
|
|
@@ -31,6 +32,10 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
31
32
|
const [error, setError] = useState("");
|
|
32
33
|
const [creating, setCreating] = useState(false);
|
|
33
34
|
const [httpRoutesRetry, setHttpRoutesRetry] = useState(0);
|
|
35
|
+
const [nameError, setNameError] = useState(null);
|
|
36
|
+
const [contactEmailError, setContactEmailError] = useState(null);
|
|
37
|
+
const [docsURLError, setDocsURLError] = useState(null);
|
|
38
|
+
const [openAPISpecError, setOpenAPISpecError] = useState(null);
|
|
34
39
|
const {
|
|
35
40
|
value: httpRoutes,
|
|
36
41
|
loading: httpRoutesLoading,
|
|
@@ -58,6 +63,30 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
58
63
|
};
|
|
59
64
|
const selectedRouteInfo = selectedHTTPRoute ? selectedHTTPRoute.split("/") : null;
|
|
60
65
|
const selectedPolicy = selectedRouteInfo ? getPlanPolicyForRoute(selectedRouteInfo[0], selectedRouteInfo[1]) : null;
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
if (open) {
|
|
68
|
+
setNameError(null);
|
|
69
|
+
setContactEmailError(null);
|
|
70
|
+
setDocsURLError(null);
|
|
71
|
+
setOpenAPISpecError(null);
|
|
72
|
+
}
|
|
73
|
+
}, [open]);
|
|
74
|
+
const handleNameChange = (value) => {
|
|
75
|
+
setName(value);
|
|
76
|
+
setNameError(validateKubernetesName(value));
|
|
77
|
+
};
|
|
78
|
+
const handleContactEmailChange = (value) => {
|
|
79
|
+
setContactEmail(value);
|
|
80
|
+
setContactEmailError(validateEmail(value));
|
|
81
|
+
};
|
|
82
|
+
const handleDocsURLChange = (value) => {
|
|
83
|
+
setDocsURL(value);
|
|
84
|
+
setDocsURLError(validateURL(value));
|
|
85
|
+
};
|
|
86
|
+
const handleOpenAPISpecChange = (value) => {
|
|
87
|
+
setOpenAPISpec(value);
|
|
88
|
+
setOpenAPISpecError(validateURL(value));
|
|
89
|
+
};
|
|
61
90
|
const handleAddTag = () => {
|
|
62
91
|
if (tagInput.trim() && !tags.includes(tagInput.trim())) {
|
|
63
92
|
setTags([...tags, tagInput.trim()]);
|
|
@@ -144,8 +173,13 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
144
173
|
setDocsURL("");
|
|
145
174
|
setOpenAPISpec("");
|
|
146
175
|
setError("");
|
|
176
|
+
setNameError(null);
|
|
177
|
+
setContactEmailError(null);
|
|
178
|
+
setDocsURLError(null);
|
|
179
|
+
setOpenAPISpecError(null);
|
|
147
180
|
onClose();
|
|
148
181
|
};
|
|
182
|
+
const hasValidationErrors = !!nameError || !!contactEmailError || !!docsURLError || !!openAPISpecError;
|
|
149
183
|
return /* @__PURE__ */ React.createElement(Dialog, { open, onClose: handleClose, maxWidth: "md", fullWidth: true }, /* @__PURE__ */ React.createElement(DialogTitle, null, "Create API Product"), /* @__PURE__ */ React.createElement(DialogContent, null, error && /* @__PURE__ */ React.createElement(Alert, { severity: "error", style: { marginBottom: 16 } }, error), httpRoutesError && /* @__PURE__ */ React.createElement(Alert, { severity: "error", style: { marginBottom: 16 } }, /* @__PURE__ */ React.createElement("strong", null, "Failed to load HTTPRoutes:"), " ", httpRoutesError.message, /* @__PURE__ */ React.createElement(Box, { mt: 1 }, /* @__PURE__ */ React.createElement(
|
|
150
184
|
Button,
|
|
151
185
|
{
|
|
@@ -160,9 +194,10 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
160
194
|
fullWidth: true,
|
|
161
195
|
label: "Name",
|
|
162
196
|
value: name,
|
|
163
|
-
onChange: (e) =>
|
|
197
|
+
onChange: (e) => handleNameChange(e.target.value),
|
|
164
198
|
placeholder: "my-api",
|
|
165
|
-
helperText: "Kubernetes resource name (lowercase, hyphens)",
|
|
199
|
+
helperText: nameError || "Kubernetes resource name (lowercase, hyphens)",
|
|
200
|
+
error: !!nameError,
|
|
166
201
|
margin: "normal",
|
|
167
202
|
required: true,
|
|
168
203
|
disabled: creating,
|
|
@@ -314,8 +349,10 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
314
349
|
fullWidth: true,
|
|
315
350
|
label: "Contact Email",
|
|
316
351
|
value: contactEmail,
|
|
317
|
-
onChange: (e) =>
|
|
352
|
+
onChange: (e) => handleContactEmailChange(e.target.value),
|
|
318
353
|
placeholder: "api-team@example.com",
|
|
354
|
+
helperText: contactEmailError || "Contact email for API support",
|
|
355
|
+
error: !!contactEmailError,
|
|
319
356
|
margin: "normal",
|
|
320
357
|
disabled: creating
|
|
321
358
|
}
|
|
@@ -336,8 +373,10 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
336
373
|
fullWidth: true,
|
|
337
374
|
label: "Docs URL",
|
|
338
375
|
value: docsURL,
|
|
339
|
-
onChange: (e) =>
|
|
376
|
+
onChange: (e) => handleDocsURLChange(e.target.value),
|
|
340
377
|
placeholder: "https://api.example.com/docs",
|
|
378
|
+
helperText: docsURLError || "Link to API documentation",
|
|
379
|
+
error: !!docsURLError,
|
|
341
380
|
margin: "normal",
|
|
342
381
|
disabled: creating
|
|
343
382
|
}
|
|
@@ -347,8 +386,10 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
347
386
|
fullWidth: true,
|
|
348
387
|
label: "OpenAPI Spec URL",
|
|
349
388
|
value: openAPISpec,
|
|
350
|
-
onChange: (e) =>
|
|
389
|
+
onChange: (e) => handleOpenAPISpecChange(e.target.value),
|
|
351
390
|
placeholder: "https://api.example.com/openapi.json",
|
|
391
|
+
helperText: openAPISpecError || "Link to OpenAPI specification",
|
|
392
|
+
error: !!openAPISpecError,
|
|
352
393
|
margin: "normal",
|
|
353
394
|
disabled: creating
|
|
354
395
|
}
|
|
@@ -358,7 +399,7 @@ const CreateAPIProductDialog = ({ open, onClose, onSuccess }) => {
|
|
|
358
399
|
onClick: handleCreate,
|
|
359
400
|
color: "primary",
|
|
360
401
|
variant: "contained",
|
|
361
|
-
disabled: creating || !name || !displayName || !description || !selectedHTTPRoute,
|
|
402
|
+
disabled: creating || !name || !displayName || !description || !selectedHTTPRoute || hasValidationErrors,
|
|
362
403
|
startIcon: creating ? /* @__PURE__ */ React.createElement(CircularProgress, { size: 16, color: "inherit" }) : undefined
|
|
363
404
|
},
|
|
364
405
|
creating ? "Creating..." : "Create"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CreateAPIProductDialog.esm.js","sources":["../../../src/components/CreateAPIProductDialog/CreateAPIProductDialog.tsx"],"sourcesContent":["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 CircularProgress,\n makeStyles,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { Alert } from '@material-ui/lab';\nimport useAsync from 'react-use/lib/useAsync';\nimport { PlanPolicyDetails } from '../PlanPolicyDetailsCard';\n\nconst useStyles = makeStyles({\n asterisk: {\n color: '#f44336',\n },\n});\n\ninterface CreateAPIProductDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\nexport const CreateAPIProductDialog = ({ open, onClose, onSuccess }: CreateAPIProductDialogProps) => {\n const classes = useStyles();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const [name, setName] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n const [version, setVersion] = useState('v1');\n const [approvalMode, setApprovalMode] = useState<'automatic' | 'manual'>('manual');\n const [publishStatus, setPublishStatus] = useState<'Draft' | 'Published'>('Published');\n const [tags, setTags] = useState<string[]>([]);\n const [tagInput, setTagInput] = useState('');\n const [selectedHTTPRoute, setSelectedHTTPRoute] = useState('');\n const [contactEmail, setContactEmail] = useState('');\n const [contactTeam, setContactTeam] = useState('');\n const [docsURL, setDocsURL] = useState('');\n const [openAPISpec, setOpenAPISpec] = useState('');\n const [error, setError] = useState('');\n const [creating, setCreating] = useState(false);\n const [httpRoutesRetry, setHttpRoutesRetry] = useState(0);\n\n const {\n value: httpRoutes,\n loading: httpRoutesLoading,\n error: httpRoutesError\n } = useAsync(async () => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/httproutes`);\n const data = await response.json();\n // filter to only show httproutes annotated for backstage exposure\n return (data.items || []).filter((route: any) =>\n route.metadata.annotations?.['backstage.io/expose'] === 'true'\n );\n }, [backendUrl, fetchApi, open, httpRoutesRetry]);\n\n // load planpolicies with full details to show associated plans\n const {\n value: planPolicies,\n error: planPoliciesError\n } = useAsync(async () => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, open]);\n\n // find planpolicy associated with selected httproute\n const getPlanPolicyForRoute = (routeNamespace: string, routeName: string) => {\n if (!planPolicies?.items) return null;\n\n return planPolicies.items.find((pp: any) => {\n const ref = pp.targetRef;\n return (\n ref?.kind === 'HTTPRoute' &&\n ref?.name === routeName &&\n (!ref?.namespace || ref?.namespace === routeNamespace)\n );\n });\n };\n\n const selectedRouteInfo = selectedHTTPRoute ? selectedHTTPRoute.split('/') : null;\n const selectedPolicy = selectedRouteInfo\n ? getPlanPolicyForRoute(selectedRouteInfo[0], selectedRouteInfo[1])\n : null;\n\n const handleAddTag = () => {\n if (tagInput.trim() && !tags.includes(tagInput.trim())) {\n setTags([...tags, tagInput.trim()]);\n setTagInput('');\n }\n };\n\n const handleDeleteTag = (tagToDelete: string) => {\n setTags(tags.filter(tag => tag !== tagToDelete));\n };\n\n const handleCreate = async () => {\n setError('');\n setCreating(true);\n\n try {\n if (!selectedHTTPRoute) {\n throw new Error('Please select an HTTPRoute');\n }\n\n const [selectedRouteNamespace, selectedRouteName] = selectedHTTPRoute.split('/');\n\n // derive namespace from selected httproute\n const namespace = selectedRouteNamespace;\n\n const apiProduct = {\n apiVersion: 'devportal.kuadrant.io/v1alpha1',\n kind: 'APIProduct',\n metadata: {\n name,\n namespace,\n },\n spec: {\n displayName,\n description,\n version,\n approvalMode,\n publishStatus,\n tags,\n targetRef: {\n group: 'gateway.networking.k8s.io',\n kind: 'HTTPRoute',\n name: selectedRouteName,\n namespace: selectedRouteNamespace,\n },\n ...(contactEmail || contactTeam ? {\n contact: {\n ...(contactEmail && { email: contactEmail }),\n ...(contactTeam && { team: contactTeam }),\n },\n } : {}),\n ...(docsURL || openAPISpec ? {\n documentation: {\n ...(docsURL && { docsURL }),\n ...(openAPISpec && { openAPISpec }),\n },\n } : {}),\n },\n };\n\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(apiProduct),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || 'failed to create apiproduct');\n }\n\n onSuccess();\n handleClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setCreating(false);\n }\n };\n\n const handleClose = () => {\n setName('');\n setDisplayName('');\n setDescription('');\n setVersion('v1');\n setApprovalMode('manual');\n setPublishStatus('Published');\n setTags([]);\n setTagInput('');\n setSelectedHTTPRoute('');\n setContactEmail('');\n setContactTeam('');\n setDocsURL('');\n setOpenAPISpec('');\n setError('');\n 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 {httpRoutesError && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n <strong>Failed to load HTTPRoutes:</strong> {httpRoutesError.message}\n <Box mt={1}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => setHttpRoutesRetry(prev => prev + 1)}\n >\n Retry\n </Button>\n </Box>\n </Alert>\n )}\n\n {planPoliciesError && (\n <Alert severity=\"warning\" style={{ marginBottom: 16 }}>\n <strong>Failed to load PlanPolicies:</strong> {planPoliciesError.message}\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n You can still create the API Product, but plan information may be incomplete.\n </Typography>\n </Alert>\n )}\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n onChange={e => setName(e.target.value)}\n placeholder=\"my-api\"\n helperText=\"Kubernetes resource name (lowercase, hyphens)\"\n margin=\"normal\"\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Display Name\"\n value={displayName}\n onChange={e => setDisplayName(e.target.value)}\n placeholder=\"My API\"\n margin=\"normal\"\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Version\"\n value={version}\n onChange={e => setVersion(e.target.value)}\n placeholder=\"v1\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"Approval Mode\"\n value={approvalMode}\n onChange={e => setApprovalMode(e.target.value as 'automatic' | 'manual')}\n margin=\"normal\"\n helperText=\"Automatic: keys are created immediately. Manual: requires approval.\"\n disabled={creating}\n >\n <MenuItem value=\"manual\">Manual</MenuItem>\n <MenuItem value=\"automatic\">Automatic</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"Publish Status\"\n value={publishStatus}\n onChange={e => setPublishStatus(e.target.value as 'Draft' | 'Published')}\n margin=\"normal\"\n helperText=\"Draft: hidden from catalog. Published: visible to consumers.\"\n disabled={creating}\n >\n <MenuItem value=\"Draft\">Draft</MenuItem>\n <MenuItem value=\"Published\">Published</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"Description\"\n value={description}\n onChange={e => setDescription(e.target.value)}\n placeholder=\"API description\"\n margin=\"normal\"\n multiline\n rows={2}\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\" gutterBottom style={{ marginTop: 16 }}>\n Tags\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" marginBottom={1} style={{ gap: 8 }}>\n {tags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n onDelete={creating ? undefined : () => handleDeleteTag(tag)}\n size=\"small\"\n disabled={creating}\n />\n ))}\n </Box>\n <Box display=\"flex\" style={{ gap: 8 }}>\n <TextField\n fullWidth\n size=\"small\"\n value={tagInput}\n onChange={e => setTagInput(e.target.value)}\n onKeyPress={e => e.key === 'Enter' && handleAddTag()}\n placeholder=\"Add tag\"\n disabled={creating}\n />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\" disabled={creating}>\n Add\n </Button>\n </Box>\n </Grid>\n\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"HTTPRoute\"\n value={selectedHTTPRoute}\n onChange={e => setSelectedHTTPRoute(e.target.value)}\n margin=\"normal\"\n required\n helperText={\n httpRoutesError\n ? \"Unable to load HTTPRoutes. Please retry.\"\n : \"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.\"\n }\n error={!!httpRoutesError}\n disabled={httpRoutesLoading || creating || !!httpRoutesError}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n >\n {httpRoutesLoading && (\n <MenuItem value=\"\">Loading...</MenuItem>\n )}\n {httpRoutesError && (\n <MenuItem value=\"\">Error loading routes</MenuItem>\n )}\n {!httpRoutesLoading && !httpRoutesError && httpRoutes && httpRoutes.length === 0 && (\n <MenuItem value=\"\">No HTTPRoutes available</MenuItem>\n )}\n {!httpRoutesLoading && !httpRoutesError && httpRoutes && httpRoutes.map((route: any) => (\n <MenuItem\n key={`${route.metadata.namespace}/${route.metadata.name}`}\n value={`${route.metadata.namespace}/${route.metadata.name}`}\n >\n {route.metadata.name} ({route.metadata.namespace})\n </MenuItem>\n ))}\n </TextField>\n </Grid>\n {selectedHTTPRoute && (\n <Grid item xs={12}>\n <PlanPolicyDetails\n selectedPolicy={selectedPolicy}\n alertSeverity=\"warning\"\n alertMessage=\"No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.\"\n includeTopMargin={true}\n />\n </Grid>\n )}\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => setContactEmail(e.target.value)}\n placeholder=\"api-team@example.com\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Team\"\n value={contactTeam}\n onChange={e => setContactTeam(e.target.value)}\n placeholder=\"platform-team\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => setDocsURL(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => setOpenAPISpec(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n </Grid>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating}>Cancel</Button>\n <Button\n onClick={handleCreate}\n color=\"primary\"\n variant=\"contained\"\n disabled={creating || !name || !displayName || !description || !selectedHTTPRoute}\n startIcon={creating ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {creating ? 'Creating...' : 'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CreateAPIProductDialog.esm.js","sources":["../../../src/components/CreateAPIProductDialog/CreateAPIProductDialog.tsx"],"sourcesContent":["import React, {useEffect, useState} from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Box,\n Typography,\n Chip,\n Grid,\n MenuItem,\n CircularProgress,\n makeStyles,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { Alert } from '@material-ui/lab';\nimport useAsync from 'react-use/lib/useAsync';\nimport { PlanPolicyDetails } from '../PlanPolicyDetailsCard';\nimport { validateKubernetesName, validateEmail, validateURL } from '../../utils/validation';\n\nconst useStyles = makeStyles({\n asterisk: {\n color: '#f44336',\n },\n});\n\ninterface CreateAPIProductDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n}\n\nexport const CreateAPIProductDialog = ({ open, onClose, onSuccess }: CreateAPIProductDialogProps) => {\n const classes = useStyles();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n\n const [name, setName] = useState('');\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n const [version, setVersion] = useState('v1');\n const [approvalMode, setApprovalMode] = useState<'automatic' | 'manual'>('manual');\n const [publishStatus, setPublishStatus] = useState<'Draft' | 'Published'>('Published');\n const [tags, setTags] = useState<string[]>([]);\n const [tagInput, setTagInput] = useState('');\n const [selectedHTTPRoute, setSelectedHTTPRoute] = useState('');\n const [contactEmail, setContactEmail] = useState('');\n const [contactTeam, setContactTeam] = useState('');\n const [docsURL, setDocsURL] = useState('');\n const [openAPISpec, setOpenAPISpec] = useState('');\n const [error, setError] = useState('');\n const [creating, setCreating] = useState(false);\n const [httpRoutesRetry, setHttpRoutesRetry] = useState(0);\n const [nameError, setNameError] = useState<string | null>(null);\n const [contactEmailError, setContactEmailError] = useState<string | null>(null);\n const [docsURLError, setDocsURLError] = useState<string | null>(null);\n const [openAPISpecError, setOpenAPISpecError] = useState<string | null>(null);\n const {\n value: httpRoutes,\n loading: httpRoutesLoading,\n error: httpRoutesError\n } = useAsync(async () => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/httproutes`);\n const data = await response.json();\n // filter to only show httproutes annotated for backstage exposure\n return (data.items || []).filter((route: any) =>\n route.metadata.annotations?.['backstage.io/expose'] === 'true'\n );\n }, [backendUrl, fetchApi, open, httpRoutesRetry]);\n\n // load planpolicies with full details to show associated plans\n const {\n value: planPolicies,\n error: planPoliciesError\n } = useAsync(async () => {\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, open]);\n\n // find planpolicy associated with selected httproute\n const getPlanPolicyForRoute = (routeNamespace: string, routeName: string) => {\n if (!planPolicies?.items) return null;\n\n return planPolicies.items.find((pp: any) => {\n const ref = pp.targetRef;\n return (\n ref?.kind === 'HTTPRoute' &&\n ref?.name === routeName &&\n (!ref?.namespace || ref?.namespace === routeNamespace)\n );\n });\n };\n\n const selectedRouteInfo = selectedHTTPRoute ? selectedHTTPRoute.split('/') : null;\n const selectedPolicy = selectedRouteInfo\n ? getPlanPolicyForRoute(selectedRouteInfo[0], selectedRouteInfo[1])\n : null;\n\n useEffect(() => {\n if (open) {\n setNameError(null);\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n }\n }, [open]);\n\n // validate handlers\n const handleNameChange = (value: string) => {\n setName(value);\n setNameError(validateKubernetesName(value));\n };\n\n const handleContactEmailChange = (value: string) => {\n setContactEmail(value);\n setContactEmailError(validateEmail(value));\n };\n\n const handleDocsURLChange = (value: string) => {\n setDocsURL(value);\n setDocsURLError(validateURL(value));\n };\n\n const handleOpenAPISpecChange = (value: string) => {\n setOpenAPISpec(value);\n setOpenAPISpecError(validateURL(value));\n };\n\n const handleAddTag = () => {\n if (tagInput.trim() && !tags.includes(tagInput.trim())) {\n setTags([...tags, tagInput.trim()]);\n setTagInput('');\n }\n };\n\n const handleDeleteTag = (tagToDelete: string) => {\n setTags(tags.filter(tag => tag !== tagToDelete));\n };\n\n const handleCreate = async () => {\n setError('');\n setCreating(true);\n\n try {\n if (!selectedHTTPRoute) {\n throw new Error('Please select an HTTPRoute');\n }\n\n const [selectedRouteNamespace, selectedRouteName] = selectedHTTPRoute.split('/');\n\n // derive namespace from selected httproute\n const namespace = selectedRouteNamespace;\n\n const apiProduct = {\n apiVersion: 'devportal.kuadrant.io/v1alpha1',\n kind: 'APIProduct',\n metadata: {\n name,\n namespace,\n },\n spec: {\n displayName,\n description,\n version,\n approvalMode,\n publishStatus,\n tags,\n targetRef: {\n group: 'gateway.networking.k8s.io',\n kind: 'HTTPRoute',\n name: selectedRouteName,\n namespace: selectedRouteNamespace,\n },\n ...(contactEmail || contactTeam ? {\n contact: {\n ...(contactEmail && { email: contactEmail }),\n ...(contactTeam && { team: contactTeam }),\n },\n } : {}),\n ...(docsURL || openAPISpec ? {\n documentation: {\n ...(docsURL && { docsURL }),\n ...(openAPISpec && { openAPISpec }),\n },\n } : {}),\n },\n };\n\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(apiProduct),\n });\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || 'failed to create apiproduct');\n }\n\n onSuccess();\n handleClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setCreating(false);\n }\n };\n\n const handleClose = () => {\n setName('');\n setDisplayName('');\n setDescription('');\n setVersion('v1');\n setApprovalMode('manual');\n setPublishStatus('Published');\n setTags([]);\n setTagInput('');\n setSelectedHTTPRoute('');\n setContactEmail('');\n setContactTeam('');\n setDocsURL('');\n setOpenAPISpec('');\n setError('');\n setNameError(null);\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n onClose();\n };\n\n const hasValidationErrors = !!nameError || !!contactEmailError || !!docsURLError || !!openAPISpecError;\n\n return (\n <Dialog open={open} onClose={handleClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>Create API Product</DialogTitle>\n <DialogContent>\n {error && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n {error}\n </Alert>\n )}\n {httpRoutesError && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n <strong>Failed to load HTTPRoutes:</strong> {httpRoutesError.message}\n <Box mt={1}>\n <Button\n size=\"small\"\n variant=\"outlined\"\n onClick={() => setHttpRoutesRetry(prev => prev + 1)}\n >\n Retry\n </Button>\n </Box>\n </Alert>\n )}\n\n {planPoliciesError && (\n <Alert severity=\"warning\" style={{ marginBottom: 16 }}>\n <strong>Failed to load PlanPolicies:</strong> {planPoliciesError.message}\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n You can still create the API Product, but plan information may be incomplete.\n </Typography>\n </Alert>\n )}\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n onChange={e => handleNameChange(e.target.value)}\n placeholder=\"my-api\"\n helperText={nameError || \"Kubernetes resource name (lowercase, hyphens)\"}\n error={!!nameError}\n margin=\"normal\"\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Display Name\"\n value={displayName}\n onChange={e => setDisplayName(e.target.value)}\n placeholder=\"My API\"\n margin=\"normal\"\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Version\"\n value={version}\n onChange={e => setVersion(e.target.value)}\n placeholder=\"v1\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"Approval Mode\"\n value={approvalMode}\n onChange={e => setApprovalMode(e.target.value as 'automatic' | 'manual')}\n margin=\"normal\"\n helperText=\"Automatic: keys are created immediately. Manual: requires approval.\"\n disabled={creating}\n >\n <MenuItem value=\"manual\">Manual</MenuItem>\n <MenuItem value=\"automatic\">Automatic</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"Publish Status\"\n value={publishStatus}\n onChange={e => setPublishStatus(e.target.value as 'Draft' | 'Published')}\n margin=\"normal\"\n helperText=\"Draft: hidden from catalog. Published: visible to consumers.\"\n disabled={creating}\n >\n <MenuItem value=\"Draft\">Draft</MenuItem>\n <MenuItem value=\"Published\">Published</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"Description\"\n value={description}\n onChange={e => setDescription(e.target.value)}\n placeholder=\"API description\"\n margin=\"normal\"\n multiline\n rows={2}\n required\n disabled={creating}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\" gutterBottom style={{ marginTop: 16 }}>\n Tags\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" marginBottom={1} style={{ gap: 8 }}>\n {tags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n onDelete={creating ? undefined : () => handleDeleteTag(tag)}\n size=\"small\"\n disabled={creating}\n />\n ))}\n </Box>\n <Box display=\"flex\" style={{ gap: 8 }}>\n <TextField\n fullWidth\n size=\"small\"\n value={tagInput}\n onChange={e => setTagInput(e.target.value)}\n onKeyPress={e => e.key === 'Enter' && handleAddTag()}\n placeholder=\"Add tag\"\n disabled={creating}\n />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\" disabled={creating}>\n Add\n </Button>\n </Box>\n </Grid>\n\n <Grid item xs={12}>\n <TextField\n fullWidth\n select\n label=\"HTTPRoute\"\n value={selectedHTTPRoute}\n onChange={e => setSelectedHTTPRoute(e.target.value)}\n margin=\"normal\"\n required\n helperText={\n httpRoutesError\n ? \"Unable to load HTTPRoutes. Please retry.\"\n : \"Select an HTTPRoute (backstage.io/expose: true). APIProduct will be created in the same namespace.\"\n }\n error={!!httpRoutesError}\n disabled={httpRoutesLoading || creating || !!httpRoutesError}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n >\n {httpRoutesLoading && (\n <MenuItem value=\"\">Loading...</MenuItem>\n )}\n {httpRoutesError && (\n <MenuItem value=\"\">Error loading routes</MenuItem>\n )}\n {!httpRoutesLoading && !httpRoutesError && httpRoutes && httpRoutes.length === 0 && (\n <MenuItem value=\"\">No HTTPRoutes available</MenuItem>\n )}\n {!httpRoutesLoading && !httpRoutesError && httpRoutes && httpRoutes.map((route: any) => (\n <MenuItem\n key={`${route.metadata.namespace}/${route.metadata.name}`}\n value={`${route.metadata.namespace}/${route.metadata.name}`}\n >\n {route.metadata.name} ({route.metadata.namespace})\n </MenuItem>\n ))}\n </TextField>\n </Grid>\n {selectedHTTPRoute && (\n <Grid item xs={12}>\n <PlanPolicyDetails\n selectedPolicy={selectedPolicy}\n alertSeverity=\"warning\"\n alertMessage=\"No PlanPolicy found for this HTTPRoute. API keys and rate limiting may not be available.\"\n includeTopMargin={true}\n />\n </Grid>\n )}\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => handleContactEmailChange(e.target.value)}\n placeholder=\"api-team@example.com\"\n helperText={contactEmailError || \"Contact email for API support\"}\n error={!!contactEmailError}\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Team\"\n value={contactTeam}\n onChange={e => setContactTeam(e.target.value)}\n placeholder=\"platform-team\"\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => handleDocsURLChange(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n helperText={docsURLError || \"Link to API documentation\"}\n error={!!docsURLError}\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => handleOpenAPISpecChange(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n helperText={openAPISpecError || \"Link to OpenAPI specification\"}\n error={!!openAPISpecError}\n margin=\"normal\"\n disabled={creating}\n />\n </Grid>\n </Grid>\n </DialogContent>\n <DialogActions>\n <Button onClick={handleClose} disabled={creating}>Cancel</Button>\n <Button\n onClick={handleCreate}\n color=\"primary\"\n variant=\"contained\"\n disabled={creating || !name || !displayName || !description || !selectedHTTPRoute || hasValidationErrors}\n startIcon={creating ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {creating ? 'Creating...' : 'Create'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -5,6 +5,7 @@ import { Alert } from '@material-ui/lab';
|
|
|
5
5
|
import { Progress } from '@backstage/core-components';
|
|
6
6
|
import useAsync from 'react-use/lib/useAsync';
|
|
7
7
|
import { PlanPolicyDetails } from '../PlanPolicyDetailsCard/PlanPolicyDetails.esm.js';
|
|
8
|
+
import { validateEmail, validateURL } from '../../utils/validation.esm.js';
|
|
8
9
|
|
|
9
10
|
const useStyles = makeStyles({
|
|
10
11
|
asterisk: {
|
|
@@ -31,6 +32,9 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
31
32
|
const [openAPISpec, setOpenAPISpec] = useState("");
|
|
32
33
|
const [error, setError] = useState("");
|
|
33
34
|
const [saving, setSaving] = useState(false);
|
|
35
|
+
const [contactEmailError, setContactEmailError] = useState(null);
|
|
36
|
+
const [docsURLError, setDocsURLError] = useState(null);
|
|
37
|
+
const [openAPISpecError, setOpenAPISpecError] = useState(null);
|
|
34
38
|
useEffect(() => {
|
|
35
39
|
if (open && namespace && name) {
|
|
36
40
|
setLoading(true);
|
|
@@ -53,6 +57,9 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
53
57
|
setContactTeam(data.spec.contact?.team || "");
|
|
54
58
|
setDocsURL(data.spec.documentation?.docsURL || "");
|
|
55
59
|
setOpenAPISpec(data.spec.documentation?.openAPISpec || "");
|
|
60
|
+
setContactEmailError(null);
|
|
61
|
+
setDocsURLError(null);
|
|
62
|
+
setOpenAPISpecError(null);
|
|
56
63
|
setLoading(false);
|
|
57
64
|
}).catch((err) => {
|
|
58
65
|
setError(err.message || "Failed to load API product");
|
|
@@ -75,6 +82,25 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
75
82
|
return ref?.kind === "HTTPRoute" && ref?.name === targetRef.name && (!ref?.namespace || ref?.namespace === (targetRef.namespace || namespace));
|
|
76
83
|
});
|
|
77
84
|
}, [planPolicies, targetRef, namespace]);
|
|
85
|
+
useEffect(() => {
|
|
86
|
+
if (open) {
|
|
87
|
+
setContactEmailError(null);
|
|
88
|
+
setDocsURLError(null);
|
|
89
|
+
setOpenAPISpecError(null);
|
|
90
|
+
}
|
|
91
|
+
}, [open]);
|
|
92
|
+
const handleContactEmailChange = (value) => {
|
|
93
|
+
setContactEmail(value);
|
|
94
|
+
setContactEmailError(validateEmail(value));
|
|
95
|
+
};
|
|
96
|
+
const handleDocsURLChange = (value) => {
|
|
97
|
+
setDocsURL(value);
|
|
98
|
+
setDocsURLError(validateURL(value));
|
|
99
|
+
};
|
|
100
|
+
const handleOpenAPISpecChange = (value) => {
|
|
101
|
+
setOpenAPISpec(value);
|
|
102
|
+
setOpenAPISpecError(validateURL(value));
|
|
103
|
+
};
|
|
78
104
|
const handleAddTag = () => {
|
|
79
105
|
if (tagInput.trim() && !tags.includes(tagInput.trim())) {
|
|
80
106
|
setTags([...tags, tagInput.trim()]);
|
|
@@ -272,8 +298,10 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
272
298
|
fullWidth: true,
|
|
273
299
|
label: "Contact Email",
|
|
274
300
|
value: contactEmail,
|
|
275
|
-
onChange: (e) =>
|
|
301
|
+
onChange: (e) => handleContactEmailChange(e.target.value),
|
|
276
302
|
placeholder: "api-team@example.com",
|
|
303
|
+
helperText: contactEmailError || "Contact email for API support",
|
|
304
|
+
error: !!contactEmailError,
|
|
277
305
|
margin: "normal",
|
|
278
306
|
disabled: saving
|
|
279
307
|
}
|
|
@@ -294,8 +322,10 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
294
322
|
fullWidth: true,
|
|
295
323
|
label: "Docs URL",
|
|
296
324
|
value: docsURL,
|
|
297
|
-
onChange: (e) =>
|
|
325
|
+
onChange: (e) => handleDocsURLChange(e.target.value),
|
|
298
326
|
placeholder: "https://api.example.com/docs",
|
|
327
|
+
helperText: docsURLError || "Link to API documentation",
|
|
328
|
+
error: !!docsURLError,
|
|
299
329
|
margin: "normal",
|
|
300
330
|
disabled: saving
|
|
301
331
|
}
|
|
@@ -305,8 +335,10 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
305
335
|
fullWidth: true,
|
|
306
336
|
label: "OpenAPI Spec URL",
|
|
307
337
|
value: openAPISpec,
|
|
308
|
-
onChange: (e) =>
|
|
338
|
+
onChange: (e) => handleOpenAPISpecChange(e.target.value),
|
|
309
339
|
placeholder: "https://api.example.com/openapi.json",
|
|
340
|
+
helperText: openAPISpecError || "Link to OpenAPI specification",
|
|
341
|
+
error: !!openAPISpecError,
|
|
310
342
|
margin: "normal",
|
|
311
343
|
disabled: saving
|
|
312
344
|
}
|
|
@@ -316,7 +348,7 @@ const EditAPIProductDialog = ({ open, onClose, onSuccess, namespace, name }) =>
|
|
|
316
348
|
onClick: handleSave,
|
|
317
349
|
color: "primary",
|
|
318
350
|
variant: "contained",
|
|
319
|
-
disabled: saving || loading || !displayName || !description,
|
|
351
|
+
disabled: saving || loading || !displayName || !description || !!contactEmailError || !!docsURLError || !!openAPISpecError,
|
|
320
352
|
startIcon: saving ? /* @__PURE__ */ React.createElement(CircularProgress, { size: 16, color: "inherit" }) : undefined
|
|
321
353
|
},
|
|
322
354
|
saving ? "Saving..." : "Save"
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"EditAPIProductDialog.esm.js","sources":["../../../src/components/EditAPIProductDialog/EditAPIProductDialog.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Box,\n Typography,\n Chip,\n Grid,\n MenuItem,\n CircularProgress,\n makeStyles,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { Alert } from '@material-ui/lab';\nimport { Progress } from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { PlanPolicyDetails } from '../PlanPolicyDetailsCard';\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(async res => {\n if (!res.ok) {\n const errorData = await res.json();\n throw new Error(errorData.error || `Failed to fetch API product: ${res.status}`);\n }\n return res.json();\n })\n .then(data => {\n setDisplayName(data.spec.displayName || '');\n setDescription(data.spec.description || '');\n setVersion(data.spec.version || 'v1');\n setPublishStatus(data.spec.publishStatus || 'Draft');\n setApprovalMode(data.spec.approvalMode || 'manual');\n setTags(data.spec.tags || []);\n setTargetRef(data.spec.targetRef || null);\n setContactEmail(data.spec.contact?.email || '');\n setContactTeam(data.spec.contact?.team || '');\n setDocsURL(data.spec.documentation?.docsURL || '');\n setOpenAPISpec(data.spec.documentation?.openAPISpec || '');\n setLoading(false);\n })\n .catch(err => {\n setError(err.message || 'Failed to load API product');\n setLoading(false);\n });\n }\n }, [open, namespace, name, backendUrl, fetchApi]);\n\n // load planpolicies with full details to show associated plans\n const {\n value: planPolicies,\n error: planPoliciesError\n } = useAsync(async () => {\n if (!open) return null;\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, open]);\n\n // find planpolicy associated with targetRef\n const selectedPolicy = React.useMemo(() => {\n if (!planPolicies?.items || !targetRef) return null;\n\n return planPolicies.items.find((pp: any) => {\n const ref = pp.targetRef;\n return (\n ref?.kind === 'HTTPRoute' &&\n ref?.name === targetRef.name &&\n (!ref?.namespace || ref?.namespace === (targetRef.namespace || namespace))\n );\n });\n }, [planPolicies, targetRef, namespace]);\n\n const handleAddTag = () => {\n if (tagInput.trim() && !tags.includes(tagInput.trim())) {\n setTags([...tags, tagInput.trim()]);\n setTagInput('');\n }\n };\n\n const handleDeleteTag = (tagToDelete: string) => {\n setTags(tags.filter(tag => tag !== tagToDelete));\n };\n\n const handleSave = async () => {\n setError('');\n setSaving(true);\n\n try {\n const patch = {\n spec: {\n displayName,\n description,\n version,\n publishStatus,\n approvalMode,\n tags,\n targetRef,\n ...(contactEmail || contactTeam ? {\n contact: {\n ...(contactEmail && { email: contactEmail }),\n ...(contactTeam && { team: contactTeam }),\n },\n } : {}),\n ...(docsURL || openAPISpec ? {\n documentation: {\n ...(docsURL && { docsURL }),\n ...(openAPISpec && { openAPISpec }),\n },\n } : {}),\n },\n };\n\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,\n {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(patch),\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || 'failed to update apiproduct');\n }\n\n onSuccess();\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>Edit API Product</DialogTitle>\n <DialogContent>\n {error && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n {error}\n </Alert>\n )}\n {planPoliciesError && (\n <Alert severity=\"warning\" style={{ marginBottom: 16 }}>\n <strong>Failed to load PlanPolicies:</strong> {planPoliciesError.message}\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n Plan information may be incomplete.\n </Typography>\n </Alert>\n )}\n {loading ? (\n <Progress />\n ) : (\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n disabled\n helperText=\"Kubernetes resource name (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Namespace\"\n value={namespace}\n disabled\n helperText=\"Derived from HTTPRoute (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Display Name\"\n value={displayName}\n onChange={e => setDisplayName(e.target.value)}\n placeholder=\"My API\"\n margin=\"normal\"\n required\n disabled={saving}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Version\"\n value={version}\n onChange={e => setVersion(e.target.value)}\n placeholder=\"v1\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n select\n label=\"Publish Status\"\n value={publishStatus}\n onChange={e => setPublishStatus(e.target.value as 'Draft' | 'Published')}\n margin=\"normal\"\n helperText=\"Draft: Hidden from catalog. Published: Visible in catalog.\"\n disabled={saving}\n >\n <MenuItem value=\"Draft\">Draft (Hidden)</MenuItem>\n <MenuItem value=\"Published\">Published (Visible)</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n select\n label=\"Approval Mode\"\n value={approvalMode}\n onChange={e => setApprovalMode(e.target.value as 'automatic' | 'manual')}\n margin=\"normal\"\n helperText=\"Automatic: keys created immediately. Manual: requires approval.\"\n disabled={saving}\n >\n <MenuItem value=\"manual\">Manual</MenuItem>\n <MenuItem value=\"automatic\">Automatic</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"Description\"\n value={description}\n onChange={e => setDescription(e.target.value)}\n placeholder=\"API description\"\n margin=\"normal\"\n multiline\n rows={2}\n required\n disabled={saving}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\" gutterBottom style={{ marginTop: 16 }}>\n Tags\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" marginBottom={1} style={{ gap: 8 }}>\n {tags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n onDelete={saving ? undefined : () => handleDeleteTag(tag)}\n size=\"small\"\n disabled={saving}\n />\n ))}\n </Box>\n <Box display=\"flex\" style={{ gap: 8 }}>\n <TextField\n fullWidth\n size=\"small\"\n value={tagInput}\n onChange={e => setTagInput(e.target.value)}\n onKeyPress={e => e.key === 'Enter' && handleAddTag()}\n placeholder=\"Add tag\"\n disabled={saving}\n />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\" disabled={saving}>\n Add\n </Button>\n </Box>\n </Grid>\n {targetRef && (\n <>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"HTTPRoute\"\n value={`${targetRef.namespace || namespace}/${targetRef.name}`}\n disabled\n helperText=\"Target HTTPRoute (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n\n <Grid item xs={12}>\n <PlanPolicyDetails\n selectedPolicy={selectedPolicy}\n alertSeverity=\"info\"\n alertMessage=\"No PlanPolicy found for this HTTPRoute.\"\n includeTopMargin={false}\n />\n </Grid>\n </>\n )}\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => setContactEmail(e.target.value)}\n placeholder=\"api-team@example.com\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Team\"\n value={contactTeam}\n onChange={e => setContactTeam(e.target.value)}\n placeholder=\"platform-team\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => setDocsURL(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => setOpenAPISpec(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n </Grid>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={saving}>Cancel</Button>\n <Button\n onClick={handleSave}\n color=\"primary\"\n variant=\"contained\"\n disabled={saving || loading || !displayName || !description}\n startIcon={saving ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {saving ? 'Saving...' : 'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"EditAPIProductDialog.esm.js","sources":["../../../src/components/EditAPIProductDialog/EditAPIProductDialog.tsx"],"sourcesContent":["import React, { useState, useEffect } from 'react';\nimport {\n Dialog,\n DialogTitle,\n DialogContent,\n DialogActions,\n Button,\n TextField,\n Box,\n Typography,\n Chip,\n Grid,\n MenuItem,\n CircularProgress,\n makeStyles,\n} from '@material-ui/core';\nimport { useApi, configApiRef, fetchApiRef } from '@backstage/core-plugin-api';\nimport { Alert } from '@material-ui/lab';\nimport { Progress } from '@backstage/core-components';\nimport useAsync from 'react-use/lib/useAsync';\nimport { PlanPolicyDetails } from '../PlanPolicyDetailsCard';\nimport { validateEmail, validateURL } from '../../utils/validation';\n\nconst useStyles = makeStyles({\n asterisk: {\n color: '#f44336',\n },\n});\n\ninterface EditAPIProductDialogProps {\n open: boolean;\n onClose: () => void;\n onSuccess: () => void;\n namespace: string;\n name: string;\n}\n\nexport const EditAPIProductDialog = ({open, onClose, onSuccess, namespace, name}: EditAPIProductDialogProps) => {\n const classes = useStyles();\n const config = useApi(configApiRef);\n const fetchApi = useApi(fetchApiRef);\n const backendUrl = config.getString('backend.baseUrl');\n const [loading, setLoading] = useState(false);\n const [displayName, setDisplayName] = useState('');\n const [description, setDescription] = useState('');\n const [version, setVersion] = useState('v1');\n const [publishStatus, setPublishStatus] = useState<'Draft' | 'Published'>('Draft');\n const [approvalMode, setApprovalMode] = useState<'automatic' | 'manual'>('manual');\n const [tags, setTags] = useState<string[]>([]);\n const [targetRef, setTargetRef] = useState<any>(null);\n const [tagInput, setTagInput] = useState('');\n const [contactEmail, setContactEmail] = useState('');\n const [contactTeam, setContactTeam] = useState('');\n const [docsURL, setDocsURL] = useState('');\n const [openAPISpec, setOpenAPISpec] = useState('');\n const [error, setError] = useState('');\n const [saving, setSaving] = useState(false);\n // valid error states\n const [contactEmailError, setContactEmailError] = useState<string | null>(null);\n const [docsURLError, setDocsURLError] = useState<string | null>(null);\n const [openAPISpecError, setOpenAPISpecError] = useState<string | null>(null);\n\n // Load APIProduct data when dialog opens\n useEffect(() => {\n if (open && namespace && name) {\n setLoading(true);\n setError('');\n\n fetchApi.fetch(`${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`)\n .then(async res => {\n if (!res.ok) {\n const errorData = await res.json();\n throw new Error(errorData.error || `Failed to fetch API product: ${res.status}`);\n }\n return res.json();\n })\n .then(data => {\n setDisplayName(data.spec.displayName || '');\n setDescription(data.spec.description || '');\n setVersion(data.spec.version || 'v1');\n setPublishStatus(data.spec.publishStatus || 'Draft');\n setApprovalMode(data.spec.approvalMode || 'manual');\n setTags(data.spec.tags || []);\n setTargetRef(data.spec.targetRef || null);\n setContactEmail(data.spec.contact?.email || '');\n setContactTeam(data.spec.contact?.team || '');\n setDocsURL(data.spec.documentation?.docsURL || '');\n setOpenAPISpec(data.spec.documentation?.openAPISpec || '');\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n setLoading(false);\n })\n .catch(err => {\n setError(err.message || 'Failed to load API product');\n setLoading(false);\n });\n }\n }, [open, namespace, name, backendUrl, fetchApi]);\n\n // load planpolicies with full details to show associated plans\n const {\n value: planPolicies,\n error: planPoliciesError\n } = useAsync(async () => {\n if (!open) return null;\n const response = await fetchApi.fetch(`${backendUrl}/api/kuadrant/planpolicies`);\n return await response.json();\n }, [backendUrl, fetchApi, open]);\n\n // find planpolicy associated with targetRef\n const selectedPolicy = React.useMemo(() => {\n if (!planPolicies?.items || !targetRef) return null;\n\n return planPolicies.items.find((pp: any) => {\n const ref = pp.targetRef;\n return (\n ref?.kind === 'HTTPRoute' &&\n ref?.name === targetRef.name &&\n (!ref?.namespace || ref?.namespace === (targetRef.namespace || namespace))\n );\n });\n }, [planPolicies, targetRef, namespace]);\n\n // val handlers\n\n useEffect(() => {\n if (open) {\n setContactEmailError(null);\n setDocsURLError(null);\n setOpenAPISpecError(null);\n }\n }, [open]);\n\n const handleContactEmailChange = (value: string) => {\n setContactEmail(value);\n setContactEmailError(validateEmail(value));\n };\n\n const handleDocsURLChange = (value: string) => {\n setDocsURL(value);\n setDocsURLError(validateURL(value));\n };\n\n const handleOpenAPISpecChange = (value: string) => {\n setOpenAPISpec(value);\n setOpenAPISpecError(validateURL(value));\n };\n\n const handleAddTag = () => {\n if (tagInput.trim() && !tags.includes(tagInput.trim())) {\n setTags([...tags, tagInput.trim()]);\n setTagInput('');\n }\n };\n\n const handleDeleteTag = (tagToDelete: string) => {\n setTags(tags.filter(tag => tag !== tagToDelete));\n };\n\n const handleSave = async () => {\n setError('');\n setSaving(true);\n\n try {\n const patch = {\n spec: {\n displayName,\n description,\n version,\n publishStatus,\n approvalMode,\n tags,\n targetRef,\n ...(contactEmail || contactTeam ? {\n contact: {\n ...(contactEmail && { email: contactEmail }),\n ...(contactTeam && { team: contactTeam }),\n },\n } : {}),\n ...(docsURL || openAPISpec ? {\n documentation: {\n ...(docsURL && { docsURL }),\n ...(openAPISpec && { openAPISpec }),\n },\n } : {}),\n },\n };\n\n const response = await fetchApi.fetch(\n `${backendUrl}/api/kuadrant/apiproducts/${namespace}/${name}`,\n {\n method: 'PATCH',\n headers: {\n 'Content-Type': 'application/json',\n },\n body: JSON.stringify(patch),\n }\n );\n\n if (!response.ok) {\n const errorData = await response.json();\n throw new Error(errorData.error || 'failed to update apiproduct');\n }\n\n onSuccess();\n onClose();\n } catch (err) {\n setError(err instanceof Error ? err.message : String(err));\n } finally {\n setSaving(false);\n }\n };\n\n return (\n <Dialog open={open} onClose={onClose} maxWidth=\"md\" fullWidth>\n <DialogTitle>Edit API Product</DialogTitle>\n <DialogContent>\n {error && (\n <Alert severity=\"error\" style={{ marginBottom: 16 }}>\n {error}\n </Alert>\n )}\n {planPoliciesError && (\n <Alert severity=\"warning\" style={{ marginBottom: 16 }}>\n <strong>Failed to load PlanPolicies:</strong> {planPoliciesError.message}\n <Typography variant=\"body2\" style={{ marginTop: 8 }}>\n Plan information may be incomplete.\n </Typography>\n </Alert>\n )}\n {loading ? (\n <Progress />\n ) : (\n <Grid container spacing={2}>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Name\"\n value={name}\n disabled\n helperText=\"Kubernetes resource name (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Namespace\"\n value={namespace}\n disabled\n helperText=\"Derived from HTTPRoute (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Display Name\"\n value={displayName}\n onChange={e => setDisplayName(e.target.value)}\n placeholder=\"My API\"\n margin=\"normal\"\n required\n disabled={saving}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Version\"\n value={version}\n onChange={e => setVersion(e.target.value)}\n placeholder=\"v1\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n select\n label=\"Publish Status\"\n value={publishStatus}\n onChange={e => setPublishStatus(e.target.value as 'Draft' | 'Published')}\n margin=\"normal\"\n helperText=\"Draft: Hidden from catalog. Published: Visible in catalog.\"\n disabled={saving}\n >\n <MenuItem value=\"Draft\">Draft (Hidden)</MenuItem>\n <MenuItem value=\"Published\">Published (Visible)</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n select\n label=\"Approval Mode\"\n value={approvalMode}\n onChange={e => setApprovalMode(e.target.value as 'automatic' | 'manual')}\n margin=\"normal\"\n helperText=\"Automatic: keys created immediately. Manual: requires approval.\"\n disabled={saving}\n >\n <MenuItem value=\"manual\">Manual</MenuItem>\n <MenuItem value=\"automatic\">Automatic</MenuItem>\n </TextField>\n </Grid>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"Description\"\n value={description}\n onChange={e => setDescription(e.target.value)}\n placeholder=\"API description\"\n margin=\"normal\"\n multiline\n rows={2}\n required\n disabled={saving}\n InputLabelProps={{\n classes: {\n asterisk: classes.asterisk,\n },\n }}\n />\n </Grid>\n\n <Grid item xs={12}>\n <Typography variant=\"subtitle2\" gutterBottom style={{ marginTop: 16 }}>\n Tags\n </Typography>\n <Box display=\"flex\" flexWrap=\"wrap\" marginBottom={1} style={{ gap: 8 }}>\n {tags.map(tag => (\n <Chip\n key={tag}\n label={tag}\n onDelete={saving ? undefined : () => handleDeleteTag(tag)}\n size=\"small\"\n disabled={saving}\n />\n ))}\n </Box>\n <Box display=\"flex\" style={{ gap: 8 }}>\n <TextField\n fullWidth\n size=\"small\"\n value={tagInput}\n onChange={e => setTagInput(e.target.value)}\n onKeyPress={e => e.key === 'Enter' && handleAddTag()}\n placeholder=\"Add tag\"\n disabled={saving}\n />\n <Button onClick={handleAddTag} variant=\"outlined\" size=\"small\" disabled={saving}>\n Add\n </Button>\n </Box>\n </Grid>\n {targetRef && (\n <>\n <Grid item xs={12}>\n <TextField\n fullWidth\n label=\"HTTPRoute\"\n value={`${targetRef.namespace || namespace}/${targetRef.name}`}\n disabled\n helperText=\"Target HTTPRoute (immutable)\"\n margin=\"normal\"\n />\n </Grid>\n\n <Grid item xs={12}>\n <PlanPolicyDetails\n selectedPolicy={selectedPolicy}\n alertSeverity=\"info\"\n alertMessage=\"No PlanPolicy found for this HTTPRoute.\"\n includeTopMargin={false}\n />\n </Grid>\n </>\n )}\n\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Email\"\n value={contactEmail}\n onChange={e => handleContactEmailChange(e.target.value)}\n placeholder=\"api-team@example.com\"\n helperText={contactEmailError || \"Contact email for API support\"}\n error={!!contactEmailError}\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Contact Team\"\n value={contactTeam}\n onChange={e => setContactTeam(e.target.value)}\n placeholder=\"platform-team\"\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"Docs URL\"\n value={docsURL}\n onChange={e => handleDocsURLChange(e.target.value)}\n placeholder=\"https://api.example.com/docs\"\n helperText={docsURLError || \"Link to API documentation\"}\n error={!!docsURLError}\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n <Grid item xs={6}>\n <TextField\n fullWidth\n label=\"OpenAPI Spec URL\"\n value={openAPISpec}\n onChange={e => handleOpenAPISpecChange(e.target.value)}\n placeholder=\"https://api.example.com/openapi.json\"\n helperText={openAPISpecError || \"Link to OpenAPI specification\"}\n error={!!openAPISpecError}\n margin=\"normal\"\n disabled={saving}\n />\n </Grid>\n </Grid>\n )}\n </DialogContent>\n <DialogActions>\n <Button onClick={onClose} disabled={saving}>Cancel</Button>\n <Button\n onClick={handleSave}\n color=\"primary\"\n variant=\"contained\"\n disabled={saving || loading || !displayName || !description || !!contactEmailError || !!docsURLError || !!openAPISpecError}\n startIcon={saving ? <CircularProgress size={16} color=\"inherit\" /> : undefined}\n >\n {saving ? 'Saving...' : 'Save'}\n </Button>\n </DialogActions>\n </Dialog>\n );\n};\n"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const validateKubernetesName = (value) => {
|
|
2
|
+
if (!value || !value.trim()) {
|
|
3
|
+
return "Name is required";
|
|
4
|
+
}
|
|
5
|
+
if (value.length > 253) {
|
|
6
|
+
return "Must be 253 characters or less";
|
|
7
|
+
}
|
|
8
|
+
const dns1123Regex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;
|
|
9
|
+
if (!dns1123Regex.test(value)) {
|
|
10
|
+
return "Must be lowercase alphanumeric with hyphens, start and end with alphanumeric";
|
|
11
|
+
}
|
|
12
|
+
return null;
|
|
13
|
+
};
|
|
14
|
+
const validateEmail = (value) => {
|
|
15
|
+
if (!value) {
|
|
16
|
+
return null;
|
|
17
|
+
}
|
|
18
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
19
|
+
if (!emailRegex.test(value)) {
|
|
20
|
+
return "Must be a valid email address";
|
|
21
|
+
}
|
|
22
|
+
return null;
|
|
23
|
+
};
|
|
24
|
+
const validateURL = (value) => {
|
|
25
|
+
if (!value) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
const url = new URL(value);
|
|
30
|
+
if (!["http:", "https:"].includes(url.protocol)) {
|
|
31
|
+
return "Must be a valid HTTP or HTTPS URL";
|
|
32
|
+
}
|
|
33
|
+
return null;
|
|
34
|
+
} catch {
|
|
35
|
+
return "Must be a valid URL";
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export { validateEmail, validateKubernetesName, validateURL };
|
|
40
|
+
//# sourceMappingURL=validation.esm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"validation.esm.js","sources":["../../src/utils/validation.ts"],"sourcesContent":["// Kubernetes name validation\nexport const validateKubernetesName = (value: string): string | null => {\n if (!value || !value.trim()) {\n return 'Name is required';\n }\n if (value.length > 253) {\n return 'Must be 253 characters or less';\n }\n\n const dns1123Regex = /^[a-z0-9]([-a-z0-9]*[a-z0-9])?$/;\n\n if (!dns1123Regex.test(value)) {\n return 'Must be lowercase alphanumeric with hyphens, start and end with alphanumeric';\n }\n\n return null;\n};\n\n// email validation\nexport const validateEmail = (value: string): string | null => {\n if (!value) {\n return null;\n }\n\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n\n if (!emailRegex.test(value)) {\n return 'Must be a valid email address';\n }\n\n return null;\n};\n\n// URL validation\nexport const validateURL = (value: string): string | null => {\n if (!value) {\n return null;\n }\n\n try {\n const url = new URL(value);\n if (!['http:', 'https:'].includes(url.protocol)) {\n return 'Must be a valid HTTP or HTTPS URL';\n }\n return null;\n } catch {\n return 'Must be a valid URL';\n }\n};\n"],"names":[],"mappings":"AACa,MAAA,sBAAA,GAAyB,CAAC,KAAiC,KAAA;AACtE,EAAA,IAAI,CAAC,KAAA,IAAS,CAAC,KAAA,CAAM,MAAQ,EAAA;AAC3B,IAAO,OAAA,kBAAA;AAAA;AAET,EAAI,IAAA,KAAA,CAAM,SAAS,GAAK,EAAA;AACtB,IAAO,OAAA,gCAAA;AAAA;AAGT,EAAA,MAAM,YAAe,GAAA,iCAAA;AAErB,EAAA,IAAI,CAAC,YAAA,CAAa,IAAK,CAAA,KAAK,CAAG,EAAA;AAC7B,IAAO,OAAA,8EAAA;AAAA;AAGT,EAAO,OAAA,IAAA;AACT;AAGa,MAAA,aAAA,GAAgB,CAAC,KAAiC,KAAA;AAC7D,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAO,OAAA,IAAA;AAAA;AAGT,EAAA,MAAM,UAAa,GAAA,4BAAA;AAEnB,EAAA,IAAI,CAAC,UAAA,CAAW,IAAK,CAAA,KAAK,CAAG,EAAA;AAC3B,IAAO,OAAA,+BAAA;AAAA;AAGT,EAAO,OAAA,IAAA;AACT;AAGa,MAAA,WAAA,GAAc,CAAC,KAAiC,KAAA;AAC3D,EAAA,IAAI,CAAC,KAAO,EAAA;AACV,IAAO,OAAA,IAAA;AAAA;AAGT,EAAI,IAAA;AACF,IAAM,MAAA,GAAA,GAAM,IAAI,GAAA,CAAI,KAAK,CAAA;AACzB,IAAI,IAAA,CAAC,CAAC,OAAS,EAAA,QAAQ,EAAE,QAAS,CAAA,GAAA,CAAI,QAAQ,CAAG,EAAA;AAC/C,MAAO,OAAA,mCAAA;AAAA;AAET,IAAO,OAAA,IAAA;AAAA,GACD,CAAA,MAAA;AACN,IAAO,OAAA,qBAAA;AAAA;AAEX;;;;"}
|