diff --git a/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx b/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx
index 9dda1c65e3..69bf8885e7 100644
--- a/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx
+++ b/plugins/cost-insights/src/components/EntityCosts/EntityCosts.tsx
@@ -120,7 +120,7 @@ export const EntityCostsCard = () => {
return
{error.message};
}
- if (!dailyCost) {
+ if (!dailyCost || !dailyCost.aggregation.length) {
return
No daily costs;
}
diff --git a/plugins/dynatrace/CHANGELOG.md b/plugins/dynatrace/CHANGELOG.md
index 60be881c47..e403cf500c 100644
--- a/plugins/dynatrace/CHANGELOG.md
+++ b/plugins/dynatrace/CHANGELOG.md
@@ -1,5 +1,16 @@
# @backstage/plugin-dynatrace
+## 2.0.0-next.2
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/catalog-model@1.2.0-next.1
+ - @backstage/core-components@0.12.4-next.1
+ - @backstage/core-plugin-api@1.3.0
+ - @backstage/theme@0.2.16
+ - @backstage/plugin-catalog-react@1.3.0-next.2
+
## 2.0.0-next.1
### Patch Changes
diff --git a/plugins/dynatrace/package.json b/plugins/dynatrace/package.json
index c7656c52de..4cf4a84c33 100644
--- a/plugins/dynatrace/package.json
+++ b/plugins/dynatrace/package.json
@@ -1,6 +1,6 @@
{
"name": "@backstage/plugin-dynatrace",
- "version": "2.0.0-next.1",
+ "version": "2.0.0-next.2",
"main": "src/index.ts",
"types": "src/index.ts",
"license": "Apache-2.0",
diff --git a/plugins/entity-validation/.eslintrc.js b/plugins/entity-validation/.eslintrc.js
new file mode 100644
index 0000000000..e2a53a6ad2
--- /dev/null
+++ b/plugins/entity-validation/.eslintrc.js
@@ -0,0 +1 @@
+module.exports = require('@backstage/cli/config/eslint-factory')(__dirname);
diff --git a/plugins/entity-validation/CHANGELOG.md b/plugins/entity-validation/CHANGELOG.md
new file mode 100644
index 0000000000..aa1e41a299
--- /dev/null
+++ b/plugins/entity-validation/CHANGELOG.md
@@ -0,0 +1,19 @@
+# @backstage/plugin-entity-validation
+
+## 0.1.0-next.0
+
+### Minor Changes
+
+- d34b3267f9: First implementation for the entity validation UI. For more information refer to its `README.md`.
+
+### Patch Changes
+
+- Updated dependencies
+ - @backstage/catalog-model@1.2.0-next.1
+ - @backstage/core-components@0.12.4-next.1
+ - @backstage/catalog-client@1.3.1-next.1
+ - @backstage/core-plugin-api@1.3.0
+ - @backstage/errors@1.1.4
+ - @backstage/theme@0.2.16
+ - @backstage/plugin-catalog-common@1.0.11-next.1
+ - @backstage/plugin-catalog-react@1.3.0-next.2
diff --git a/plugins/entity-validation/README.md b/plugins/entity-validation/README.md
new file mode 100644
index 0000000000..1f864d0857
--- /dev/null
+++ b/plugins/entity-validation/README.md
@@ -0,0 +1,53 @@
+# entity-validation
+
+This plugin creates a new page in Backstage where the user can validate the entities.
+
+
+
+## Getting started
+
+First of all, install the package in the `app` package by running the following command:
+
+```bash
+yarn add --cwd packages/app @backstage/plugin-entity-validation
+```
+
+Add the new route to the app by adding the following line:
+
+```typescript
+// In packages/app/src/App.tsx
+import { EntityValidationPage } from '@backstage/plugin-entity-validation';
+
+const routes = (
+
+ {/* ...other routes */}
+ } />
+
+);
+```
+
+To add the new page to your sidebar, you must include these lines in your `Root.tsx` file:
+
+```typescript
+ // In packages/app/src/components/Root/Root.tsx
+ import BuildIcon from '@material-ui/icons/Build';
+
+ ...
+
+ export const Root = ({ children }: PropsWithChildren<{}>) => (
+
+
+ {/* ...other elements */}
+ }>
+ {/* Global nav, not org-specific */}
+ {/* ...other sidebars */}
+
+ {/* End global nav */}
+
+
+ {/* ...other elements */}
+
+ {children}
+
+ );
+```
diff --git a/plugins/entity-validation/api-report.md b/plugins/entity-validation/api-report.md
new file mode 100644
index 0000000000..2fccbf9471
--- /dev/null
+++ b/plugins/entity-validation/api-report.md
@@ -0,0 +1,27 @@
+## API Report File for "@backstage/plugin-entity-validation"
+
+> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
+
+```ts
+///
+
+import { BackstagePlugin } from '@backstage/core-plugin-api';
+import { RouteRef } from '@backstage/core-plugin-api';
+
+// @public (undocumented)
+export const EntityValidationPage: (props: {
+ defaultYaml?: string | undefined;
+ defaultLocation?: string | undefined;
+}) => JSX.Element;
+
+// @public (undocumented)
+export const entityValidationPlugin: BackstagePlugin<
+ {
+ root: RouteRef
;
+ },
+ {},
+ {}
+>;
+
+// (No @packageDocumentation comment for this package)
+```
diff --git a/plugins/entity-validation/dev/index.tsx b/plugins/entity-validation/dev/index.tsx
new file mode 100644
index 0000000000..1e1dfa760c
--- /dev/null
+++ b/plugins/entity-validation/dev/index.tsx
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import { createDevApp } from '@backstage/dev-utils';
+import { entityValidationPlugin, EntityValidationPage } from '../src/plugin';
+
+createDevApp()
+ .registerPlugin(entityValidationPlugin)
+ .addPage({
+ element: ,
+ title: 'Root Page',
+ path: '/entity-validation',
+ })
+ .render();
diff --git a/plugins/entity-validation/docs/entity-validation.png b/plugins/entity-validation/docs/entity-validation.png
new file mode 100644
index 0000000000..00cb5fafe0
Binary files /dev/null and b/plugins/entity-validation/docs/entity-validation.png differ
diff --git a/plugins/entity-validation/package.json b/plugins/entity-validation/package.json
new file mode 100644
index 0000000000..6a00e4ad16
--- /dev/null
+++ b/plugins/entity-validation/package.json
@@ -0,0 +1,68 @@
+{
+ "name": "@backstage/plugin-entity-validation",
+ "version": "0.1.0-next.0",
+ "main": "src/index.ts",
+ "types": "src/index.ts",
+ "license": "Apache-2.0",
+ "publishConfig": {
+ "access": "public",
+ "main": "dist/index.esm.js",
+ "types": "dist/index.d.ts"
+ },
+ "backstage": {
+ "role": "frontend-plugin"
+ },
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/backstage/backstage",
+ "directory": "plugins/entity-validation"
+ },
+ "scripts": {
+ "start": "backstage-cli package start",
+ "build": "backstage-cli package build",
+ "lint": "backstage-cli package lint",
+ "test": "backstage-cli package test",
+ "clean": "backstage-cli package clean",
+ "prepack": "backstage-cli package prepack",
+ "postpack": "backstage-cli package postpack"
+ },
+ "dependencies": {
+ "@backstage/catalog-client": "workspace:^",
+ "@backstage/catalog-model": "workspace:^",
+ "@backstage/core-components": "workspace:^",
+ "@backstage/core-plugin-api": "workspace:^",
+ "@backstage/errors": "workspace:^",
+ "@backstage/plugin-catalog-common": "workspace:^",
+ "@backstage/plugin-catalog-react": "workspace:^",
+ "@backstage/theme": "workspace:^",
+ "@codemirror/language": "^6.0.0",
+ "@codemirror/legacy-modes": "^6.1.0",
+ "@codemirror/view": "^6.0.0",
+ "@material-ui/core": "^4.12.2",
+ "@material-ui/icons": "^4.9.1",
+ "@material-ui/lab": "^4.0.0-alpha.57",
+ "@react-hookz/web": "^20.0.0",
+ "@uiw/react-codemirror": "^4.9.3",
+ "lodash": "^4.17.21",
+ "react-use": "^17.2.4",
+ "yaml": "^2.0.0"
+ },
+ "peerDependencies": {
+ "react": "^16.13.1 || ^17.0.0"
+ },
+ "devDependencies": {
+ "@backstage/cli": "workspace:^",
+ "@backstage/core-app-api": "workspace:^",
+ "@backstage/dev-utils": "workspace:^",
+ "@backstage/test-utils": "workspace:^",
+ "@testing-library/jest-dom": "^5.10.1",
+ "@testing-library/react": "^12.1.3",
+ "@testing-library/user-event": "^14.0.0",
+ "@types/node": "*",
+ "cross-fetch": "^3.1.5",
+ "msw": "^0.49.0"
+ },
+ "files": [
+ "dist"
+ ]
+}
diff --git a/plugins/entity-validation/src/components/EntityTextArea/EntityTextArea.tsx b/plugins/entity-validation/src/components/EntityTextArea/EntityTextArea.tsx
new file mode 100644
index 0000000000..c39f8d5ed7
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityTextArea/EntityTextArea.tsx
@@ -0,0 +1,97 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useMemo, useState } from 'react';
+import { Box, makeStyles } from '@material-ui/core';
+import CodeMirror from '@uiw/react-codemirror';
+import { showPanel } from '@codemirror/view';
+import { StreamLanguage } from '@codemirror/language';
+import { yaml as yamlSupport } from '@codemirror/legacy-modes/mode/yaml';
+import { useKeyboardEvent } from '@react-hookz/web';
+
+const useStyles = makeStyles(theme => ({
+ container: {
+ position: 'relative',
+ width: '100%',
+ height: '100%',
+ minHeight: '400px',
+ },
+ codeMirror: {
+ position: 'absolute',
+ top: 0,
+ bottom: 0,
+ left: 0,
+ right: 0,
+ },
+ infoPanel: {
+ color: theme.palette.info.main,
+ lineHeight: 2,
+ margin: theme.spacing(0, 1),
+ },
+}));
+
+type TemplateTextAreaProps = {
+ catalogYaml: string;
+ onChange: (value: string) => void;
+ onValidate: () => void;
+};
+
+export const EntityTextArea = ({
+ catalogYaml,
+ onChange,
+ onValidate,
+}: TemplateTextAreaProps) => {
+ const classes = useStyles();
+ const [close, setClose] = useState(false);
+
+ const panelExtension = useMemo(() => {
+ if (close) {
+ return showPanel.of(null);
+ }
+
+ const dom = document.createElement('div');
+ dom.classList.add(classes.infoPanel);
+ dom.textContent =
+ 'To validate your catalog-info.yaml click on the "Validate" button or use "Ctrl + S" or "Ctrl + Enter"';
+ dom.onclick = () => setClose(true);
+ return showPanel.of(() => ({ dom, top: true }));
+ }, [classes, close]);
+
+ // Triggers a validation when Ctrl+S or Ctrl+Enter instead of default behavior
+ useKeyboardEvent(
+ e => (e.key === 's' || e.key === 'Enter') && (e.ctrlKey || e.metaKey),
+ e => {
+ e.preventDefault();
+ onValidate();
+ },
+ );
+
+ return (
+
+ {
+ // Prevent new line if Ctrl + Enter was clicked
+ if (e.key === 'Enter' && (e.ctrlKey || e.metaKey)) e.preventDefault();
+ }}
+ />
+
+ );
+};
diff --git a/plugins/entity-validation/src/components/EntityTextArea/index.ts b/plugins/entity-validation/src/components/EntityTextArea/index.ts
new file mode 100644
index 0000000000..d2a5e41d0f
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityTextArea/index.ts
@@ -0,0 +1,16 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from './EntityTextArea';
diff --git a/plugins/entity-validation/src/components/EntityValidationOutput/EntityResult.tsx b/plugins/entity-validation/src/components/EntityValidationOutput/EntityResult.tsx
new file mode 100644
index 0000000000..85d47fa2c2
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityValidationOutput/EntityResult.tsx
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useState } from 'react';
+import { ValidateEntityResponse } from '@backstage/catalog-client';
+import { useApp } from '@backstage/core-plugin-api';
+import {
+ Collapse,
+ IconButton,
+ ListItem,
+ ListItemIcon,
+ ListItemSecondaryAction,
+ ListItemText,
+ makeStyles,
+ Paper,
+} from '@material-ui/core';
+import { humanizeEntityRef } from '@backstage/plugin-catalog-react';
+import WorkIcon from '@material-ui/icons/Work';
+import ExpandLessIcon from '@material-ui/icons/ExpandLess';
+import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
+import { MarkdownContent } from '@backstage/core-components';
+import { ValidationOutputOk } from '../../types';
+
+const useStyles = makeStyles(theme => ({
+ validationOk: {
+ color: theme.palette.success.main,
+ },
+ validationNotOk: {
+ color: theme.palette.error.main,
+ },
+ errorContainer: {
+ color: theme.palette.error.main,
+ background: theme.palette.background.paper,
+ padding: theme.spacing(2),
+ },
+}));
+
+type EntityResultProps = {
+ isFirstError?: boolean;
+ item: ValidationOutputOk;
+};
+
+export const EntityResult = ({
+ isFirstError = false,
+ item,
+}: EntityResultProps) => {
+ const classes = useStyles();
+ const app = useApp();
+ const [expanded, setExpanded] = useState(isFirstError);
+
+ const Icon =
+ app.getSystemIcon(`kind:${item.entity.kind.toLocaleLowerCase('en-US')}`) ??
+ WorkIcon;
+
+ const fetchErrorMessages = (response: ValidateEntityResponse) => {
+ if (!response.valid) {
+ return response.errors.map(err => err.message).join('\n\n');
+ }
+ return '';
+ };
+
+ return (
+ <>
+
+
+
+
+ setExpanded(!expanded)}
+ />
+ {!item.response.valid && (
+
+ setExpanded(!expanded)}>
+ {expanded ? : }
+
+
+ )}
+
+ {!item.response.valid && (
+
+
+
+
+
+ )}
+ >
+ );
+};
diff --git a/plugins/entity-validation/src/components/EntityValidationOutput/EntityValidationOutput.tsx b/plugins/entity-validation/src/components/EntityValidationOutput/EntityValidationOutput.tsx
new file mode 100644
index 0000000000..bc7e22ef54
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityValidationOutput/EntityValidationOutput.tsx
@@ -0,0 +1,162 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import { identityApiRef, useApi } from '@backstage/core-plugin-api';
+import {
+ catalogApiRef,
+ humanizeEntityRef,
+} from '@backstage/plugin-catalog-react';
+import { List, makeStyles, Typography } from '@material-ui/core';
+import useAsync from 'react-use/lib/useAsync';
+import { InfoCard, Progress } from '@backstage/core-components';
+import Alert from '@material-ui/lab/Alert';
+import {
+ CatalogProcessorResult,
+ ValidationOutput,
+ ValidationOutputError,
+ ValidationOutputOk,
+} from '../../types';
+import { EntityResult } from './EntityResult';
+
+const useStyles = makeStyles(theme => ({
+ validationOk: {
+ color: theme.palette.success.main,
+ },
+ validationNotOk: {
+ color: theme.palette.error.main,
+ },
+}));
+
+function sortResults(items: Array) {
+ return items.sort((a, b) =>
+ humanizeEntityRef(a.entity).localeCompare(humanizeEntityRef(b.entity)),
+ );
+}
+
+type EntityValidationOutputProps = {
+ processorResults?: CatalogProcessorResult[];
+ locationUrl: string;
+};
+
+export const EntityValidationOutput = ({
+ processorResults,
+ locationUrl,
+}: EntityValidationOutputProps) => {
+ const classes = useStyles();
+ const catalogApi = useApi(catalogApiRef);
+ const identityApi = useApi(identityApiRef);
+
+ const { value = [], loading } = useAsync(async (): Promise<
+ ValidationOutput[] | undefined
+ > => {
+ if (!processorResults) {
+ return undefined;
+ }
+
+ const location = locationUrl
+ ? `url:${locationUrl}`
+ : 'url:http://localhost';
+
+ return await Promise.all(
+ processorResults.map(async item => {
+ if (item.type === 'entity') {
+ const { token } = await identityApi.getCredentials();
+
+ const validateResult = await catalogApi.validateEntity(
+ item.entity,
+ location,
+ {
+ token,
+ },
+ );
+ return {
+ type: 'valid',
+ entity: item.entity,
+ response: validateResult,
+ };
+ } else if (item.type === 'error') {
+ return {
+ type: 'error',
+ processingError: `Malformed entity YAML, ${item.error}`,
+ };
+ }
+ return {
+ type: 'error',
+ processingError: `Internal error, failed to parse entity`,
+ };
+ }),
+ );
+ }, [processorResults]);
+
+ if (loading) {
+ return ;
+ }
+
+ const errors = value.filter(
+ v => v.type === 'error',
+ ) as ValidationOutputError[];
+
+ const results = sortResults(
+ value.filter(v => v.type === 'valid') as ValidationOutputOk[],
+ );
+ // If there are any errors, only the first one will be expanded
+ const firstErrorIndex = results.findIndex(r => !r.response.valid);
+
+ if (errors.length !== 0) {
+ return (
+ <>
+ {errors.map(err => (
+ {err.processingError}
+ ))}
+ >
+ );
+ }
+
+ return (
+
+ {results.length === 0 ? (
+
+
+ No entity definitions found or validated yet
+
+
+ ) : (
+ <>
+
+ {results.map((item, key) => (
+
+ ))}
+
+
+ {results.every(r => r.response.valid) ? (
+
+ All the entities are valid!
+
+ ) : (
+
+ One or more entities have validation errors
+
+ )}
+
+ >
+ )}
+
+ );
+};
diff --git a/plugins/entity-validation/src/components/EntityValidationOutput/index.ts b/plugins/entity-validation/src/components/EntityValidationOutput/index.ts
new file mode 100644
index 0000000000..8d327581c6
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityValidationOutput/index.ts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+export * from './EntityValidationOutput';
+export * from './EntityResult';
diff --git a/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx
new file mode 100644
index 0000000000..dc86af8763
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2023 The Backstage Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React, { useState } from 'react';
+import { Button, Content, Header, Page } from '@backstage/core-components';
+import { EntityTextArea } from '../EntityTextArea';
+import { Grid, TextField } from '@material-ui/core';
+import { CatalogProcessorResult } from '../../types';
+import { parseEntityYaml } from '../../utils';
+import { EntityValidationOutput } from '../EntityValidationOutput';
+
+const EXAMPLE_CATALOG_INFO_YAML = `# Put your catalog-info.yaml below and validate it
+apiVersion: backstage.io/v1alpha1
+kind: Component
+metadata:
+ name: test
+ description: Component description
+ links: []
+ tags: []
+ annotations: {}
+spec:
+ type: service
+ lifecycle: experimental
+ owner: owner
+`;
+
+export const EntityValidationPage = (props: {
+ defaultYaml?: string;
+ defaultLocation?: string;
+}) => {
+ const {
+ defaultYaml = EXAMPLE_CATALOG_INFO_YAML,
+ defaultLocation = 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml',
+ } = props;
+
+ const [catalogYaml, setCatalogYaml] = useState(defaultYaml);
+ const [yamlFiles, setYamlFiles] = useState();
+ const [locationUrl, setLocationUrl] = useState('');
+
+ const parseYaml = () => {
+ const parsedFiles = [
+ ...parseEntityYaml(Buffer.from(catalogYaml), {
+ type: 'url',
+ target: locationUrl ? locationUrl : 'http://localhost',
+ }),
+ ];
+ setYamlFiles(parsedFiles);
+ };
+
+ return (
+
+
+
+
+
+