+ {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..d39b234342
--- /dev/null
+++ b/plugins/entity-validation/src/components/EntityValidationPage/EntityValidationPage.tsx
@@ -0,0 +1,117 @@
+/*
+ * 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 '@backstage/plugin-catalog-node';
+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 = ({
+ defaultPreviewCatalog = EXAMPLE_CATALOG_INFO_YAML,
+ locationPlaceholder = 'https://github.com/backstage/backstage/blob/master/catalog-info.yaml',
+}: {
+ defaultPreviewCatalog?: string;
+ locationPlaceholder?: string;
+}) => {
+ const [catalogYaml, setCatalogYaml] = useState(defaultPreviewCatalog);
+ const [yamlFiles, setYamlFiles] = useState