Migrate catalog-react and app blueprints to configSchema
Move EntityCardBlueprint and EntityContentBlueprint to the new `configSchema` option using zod v3, and AppLanguageApi to zod v4. Fix config schema merge in `makeWithOverrides` when mixing `configSchema` and deprecated `config.schema` sources. Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com> Made-with: Cursor
This commit is contained in:
@@ -738,19 +738,15 @@ export function createExtensionBlueprint(options: any): any {
|
||||
if: args.if ?? options.if,
|
||||
inputs: { ...args.inputs, ...options.inputs },
|
||||
output: (args.output ?? options.output) as ExtensionDataRef[],
|
||||
config:
|
||||
options.config || args.config
|
||||
? {
|
||||
schema: {
|
||||
...options.config?.schema,
|
||||
...args.config?.schema,
|
||||
},
|
||||
}
|
||||
: undefined,
|
||||
configSchema:
|
||||
options.configSchema || args.configSchema
|
||||
options.configSchema ||
|
||||
args.configSchema ||
|
||||
options.config?.schema ||
|
||||
args.config?.schema
|
||||
? {
|
||||
...options.config?.schema,
|
||||
...options.configSchema,
|
||||
...args.config?.schema,
|
||||
...args.configSchema,
|
||||
}
|
||||
: (undefined as any),
|
||||
|
||||
@@ -18,14 +18,13 @@
|
||||
import { AppLanguageSelector } from '../../../../packages/core-app-api/src/apis/implementations/AppLanguageApi';
|
||||
import { appLanguageApiRef } from '@backstage/frontend-plugin-api';
|
||||
import { ApiBlueprint } from '@backstage/frontend-plugin-api';
|
||||
import { z } from 'zod';
|
||||
|
||||
export const AppLanguageApi = ApiBlueprint.makeWithOverrides({
|
||||
name: 'app-language',
|
||||
config: {
|
||||
schema: {
|
||||
defaultLanguage: z => z.string().optional(),
|
||||
availableLanguages: z => z.array(z.string()).optional(),
|
||||
},
|
||||
configSchema: {
|
||||
defaultLanguage: z.string().optional(),
|
||||
availableLanguages: z.array(z.string()).optional(),
|
||||
},
|
||||
factory(originalFactory, { config }) {
|
||||
return originalFactory(defineParams =>
|
||||
|
||||
@@ -86,7 +86,8 @@
|
||||
"qs": "^6.9.4",
|
||||
"react-use": "^17.2.4",
|
||||
"yaml": "^2.0.0",
|
||||
"zen-observable": "^0.10.0"
|
||||
"zen-observable": "^0.10.0",
|
||||
"zod": "^3.25.76 || ^4.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@backstage/cli": "workspace:^",
|
||||
@@ -104,8 +105,7 @@
|
||||
"react": "^18.0.2",
|
||||
"react-dom": "^18.0.2",
|
||||
"react-router-dom": "^6.30.2",
|
||||
"react-test-renderer": "^16.13.1",
|
||||
"zod": "^3.25.76 || ^4.0.0"
|
||||
"react-test-renderer": "^16.13.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@backstage/frontend-test-utils": "workspace:^",
|
||||
|
||||
@@ -45,158 +45,20 @@ describe('EntityCardBlueprint', () => {
|
||||
"input": "cards",
|
||||
},
|
||||
"configSchema": {
|
||||
"parse": [Function],
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"filter": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
],
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$exists": {
|
||||
"type": "boolean",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$exists",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$in": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$in",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$contains": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$contains",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$hasPrefix": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$hasPrefix",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
"propertyNames": {
|
||||
"pattern": "^(?!\\$).*$",
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": {
|
||||
"not": {},
|
||||
},
|
||||
"propertyNames": {
|
||||
"pattern": "^\\$",
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$all": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$all",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$any": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$any",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$not": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$not",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"type": {
|
||||
"enum": [
|
||||
"info",
|
||||
"content",
|
||||
],
|
||||
"type": "string",
|
||||
},
|
||||
"_fields": {
|
||||
"filter": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"type": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
"parse": [Function],
|
||||
"schema": [Function],
|
||||
},
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
|
||||
@@ -32,6 +32,7 @@ import {
|
||||
} from '@backstage/filter-predicates';
|
||||
import { resolveEntityFilterData } from './resolveEntityFilterData';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { z } from 'zod/v3';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
@@ -51,12 +52,11 @@ export const EntityCardBlueprint = createExtensionBlueprint({
|
||||
filterExpression: entityFilterExpressionDataRef,
|
||||
type: entityCardTypeDataRef,
|
||||
},
|
||||
config: {
|
||||
schema: {
|
||||
filter: z =>
|
||||
z.union([z.string(), createZodV3FilterPredicateSchema(z)]).optional(),
|
||||
type: z => z.enum(entityCardTypes).optional(),
|
||||
},
|
||||
configSchema: {
|
||||
filter: z
|
||||
.union([z.string(), createZodV3FilterPredicateSchema(z)])
|
||||
.optional(),
|
||||
type: z.enum(entityCardTypes).optional(),
|
||||
},
|
||||
*factory(
|
||||
{
|
||||
|
||||
@@ -47,171 +47,35 @@ describe('EntityContentBlueprint', () => {
|
||||
"input": "contents",
|
||||
},
|
||||
"configSchema": {
|
||||
"parse": [Function],
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"filter": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
],
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$exists": {
|
||||
"type": "boolean",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$exists",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$in": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$in",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$contains": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$contains",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$hasPrefix": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$hasPrefix",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
"propertyNames": {
|
||||
"pattern": "^(?!\\$).*$",
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": {
|
||||
"not": {},
|
||||
},
|
||||
"propertyNames": {
|
||||
"pattern": "^\\$",
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"$ref": "#/properties/filter/anyOf/1/anyOf/0/anyOf/0/additionalProperties/anyOf/0",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$all": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$all",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$any": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$any",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$not": {
|
||||
"$ref": "#/properties/filter/anyOf/1",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$not",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
"group": {
|
||||
"anyOf": [
|
||||
{
|
||||
"const": false,
|
||||
"type": "boolean",
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
},
|
||||
],
|
||||
},
|
||||
"icon": {
|
||||
"type": "string",
|
||||
},
|
||||
"path": {
|
||||
"type": "string",
|
||||
},
|
||||
"title": {
|
||||
"type": "string",
|
||||
},
|
||||
"_fields": {
|
||||
"filter": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"group": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"icon": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"path": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"title": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
"parse": [Function],
|
||||
"schema": [Function],
|
||||
},
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
|
||||
@@ -35,6 +35,7 @@ import {
|
||||
import { resolveEntityFilterData } from './resolveEntityFilterData';
|
||||
import { Entity } from '@backstage/catalog-model';
|
||||
import { ReactElement } from 'react';
|
||||
import { z } from 'zod/v3';
|
||||
|
||||
/**
|
||||
* @alpha
|
||||
@@ -60,15 +61,14 @@ export const EntityContentBlueprint = createExtensionBlueprint({
|
||||
group: entityContentGroupDataRef,
|
||||
icon: entityContentIconDataRef,
|
||||
},
|
||||
config: {
|
||||
schema: {
|
||||
path: z => z.string().optional(),
|
||||
title: z => z.string().optional(),
|
||||
filter: z =>
|
||||
z.union([z.string(), createZodV3FilterPredicateSchema(z)]).optional(),
|
||||
group: z => z.literal(false).or(z.string()).optional(),
|
||||
icon: z => z.string().optional(),
|
||||
},
|
||||
configSchema: {
|
||||
path: z.string().optional(),
|
||||
title: z.string().optional(),
|
||||
filter: z
|
||||
.union([z.string(), createZodV3FilterPredicateSchema(z)])
|
||||
.optional(),
|
||||
group: z.literal(false).or(z.string()).optional(),
|
||||
icon: z.string().optional(),
|
||||
},
|
||||
*factory(
|
||||
params: {
|
||||
|
||||
+7
-136
@@ -63,144 +63,15 @@ describe('EntityContextMenuItemBlueprint', () => {
|
||||
"input": "contextMenuItems",
|
||||
},
|
||||
"configSchema": {
|
||||
"parse": [Function],
|
||||
"schema": {
|
||||
"$schema": "http://json-schema.org/draft-07/schema#",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"filter": {
|
||||
"anyOf": [
|
||||
{
|
||||
"anyOf": [
|
||||
{
|
||||
"additionalProperties": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": [
|
||||
"string",
|
||||
"number",
|
||||
"boolean",
|
||||
],
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$exists": {
|
||||
"type": "boolean",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$exists",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$in": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter/anyOf/0/anyOf/0/additionalProperties/anyOf/0",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$in",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$contains": {
|
||||
"$ref": "#/properties/filter",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$contains",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$hasPrefix": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$hasPrefix",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
"propertyNames": {
|
||||
"pattern": "^(?!\\$).*$",
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": {
|
||||
"not": {},
|
||||
},
|
||||
"propertyNames": {
|
||||
"pattern": "^\\$",
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
"$ref": "#/properties/filter/anyOf/0/anyOf/0/additionalProperties/anyOf/0",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$all": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$all",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$any": {
|
||||
"items": {
|
||||
"$ref": "#/properties/filter",
|
||||
},
|
||||
"type": "array",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$any",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
{
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"$not": {
|
||||
"$ref": "#/properties/filter",
|
||||
},
|
||||
},
|
||||
"required": [
|
||||
"$not",
|
||||
],
|
||||
"type": "object",
|
||||
},
|
||||
],
|
||||
},
|
||||
"_fields": {
|
||||
"filter": {
|
||||
"required": false,
|
||||
"toJsonSchema": [Function],
|
||||
"validate": [Function],
|
||||
},
|
||||
"type": "object",
|
||||
},
|
||||
"parse": [Function],
|
||||
"schema": [Function],
|
||||
},
|
||||
"disabled": false,
|
||||
"factory": [Function],
|
||||
|
||||
Reference in New Issue
Block a user