diff --git a/plugins/catalog-graphql/src/graphql/module.ts b/plugins/catalog-graphql/src/graphql/module.ts index 2f9df09408..6deb2a3aad 100644 --- a/plugins/catalog-graphql/src/graphql/module.ts +++ b/plugins/catalog-graphql/src/graphql/module.ts @@ -48,7 +48,15 @@ export async function createModule( }, CatalogQuery: { list: async () => { - return await catalogClient.list(); + const catalogEntries = await catalogClient.list(); + return catalogEntries.map(entity => ({ + ...entity, + metadata: { + ...entity.metadata, + annotations: entity.metadata.annotations ?? {}, + labels: entity.metadata.labels ?? {}, + }, + })); }, }, EntityMetadata: { diff --git a/plugins/catalog-graphql/src/graphql/types.ts b/plugins/catalog-graphql/src/graphql/types.ts index 567e19c8bb..7294f749ad 100644 --- a/plugins/catalog-graphql/src/graphql/types.ts +++ b/plugins/catalog-graphql/src/graphql/types.ts @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { GraphQLResolveInfo } from 'graphql'; +import { GraphQLResolveInfo, GraphQLScalarType, GraphQLScalarTypeConfig } from 'graphql'; import { ModuleContext } from '@graphql-modules/core'; export type Maybe = T | null; @@ -26,32 +26,40 @@ export type Scalars = { Boolean: boolean; Int: number; Float: number; + JSON: any; + JSONObject: any; }; -export type EntityMetadataAnnotation = { - __typename?: 'EntityMetadataAnnotation'; - key: Scalars['String']; - value: Scalars['String']; -}; + export type EntityMetadata = { __typename?: 'EntityMetadata'; name: Scalars['String']; - namespace?: Maybe; - annotation?: Maybe; - annotations?: Maybe>; + namespace: Scalars['String']; + annotations: Scalars['JSONObject']; + annotation?: Maybe; + labels: Scalars['JSONObject']; + label?: Maybe; + uid: Scalars['String']; + etag: Scalars['String']; + generation: Scalars['Int']; }; export type EntityMetadataAnnotationArgs = { - name?: Maybe; + name: Scalars['String']; +}; + + +export type EntityMetadataLabelArgs = { + name: Scalars['String']; }; export type CatalogEntity = { __typename?: 'CatalogEntity'; - apiVersion?: Maybe; + apiVersion: Scalars['String']; kind: Scalars['String']; - metadata?: Maybe; + metadata: EntityMetadata; }; export type CatalogQuery = { @@ -143,9 +151,11 @@ export type DirectiveResolverFn>; - String: ResolverTypeWrapper>; + JSON: ResolverTypeWrapper>; + JSONObject: ResolverTypeWrapper>; EntityMetadata: ResolverTypeWrapper>; + String: ResolverTypeWrapper>; + Int: ResolverTypeWrapper>; CatalogEntity: ResolverTypeWrapper>; CatalogQuery: ResolverTypeWrapper>; Query: ResolverTypeWrapper<{}>; @@ -154,33 +164,42 @@ export type ResolversTypes = ResolversObject<{ /** Mapping between all available schema types and the resolvers parents */ export type ResolversParentTypes = ResolversObject<{ - EntityMetadataAnnotation: Partial; - String: Partial; + JSON: Partial; + JSONObject: Partial; EntityMetadata: Partial; + String: Partial; + Int: Partial; CatalogEntity: Partial; CatalogQuery: Partial; Query: {}; Boolean: Partial; }>; -export type EntityMetadataAnnotationResolvers = ResolversObject<{ - key?: Resolver; - value?: Resolver; - __isTypeOf?: IsTypeOfResolverFn; -}>; +export interface JsonScalarConfig extends GraphQLScalarTypeConfig { + name: 'JSON'; +} + +export interface JsonObjectScalarConfig extends GraphQLScalarTypeConfig { + name: 'JSONObject'; +} export type EntityMetadataResolvers = ResolversObject<{ name?: Resolver; - namespace?: Resolver, ParentType, ContextType>; - annotation?: Resolver, ParentType, ContextType, RequireFields>; - annotations?: Resolver>, ParentType, ContextType>; + namespace?: Resolver; + annotations?: Resolver; + annotation?: Resolver, ParentType, ContextType, RequireFields>; + labels?: Resolver; + label?: Resolver, ParentType, ContextType, RequireFields>; + uid?: Resolver; + etag?: Resolver; + generation?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; export type CatalogEntityResolvers = ResolversObject<{ - apiVersion?: Resolver, ParentType, ContextType>; + apiVersion?: Resolver; kind?: Resolver; - metadata?: Resolver, ParentType, ContextType>; + metadata?: Resolver; __isTypeOf?: IsTypeOfResolverFn; }>; @@ -194,7 +213,8 @@ export type QueryResolvers; export type Resolvers = ResolversObject<{ - EntityMetadataAnnotation?: EntityMetadataAnnotationResolvers; + JSON?: GraphQLScalarType; + JSONObject?: GraphQLScalarType; EntityMetadata?: EntityMetadataResolvers; CatalogEntity?: CatalogEntityResolvers; CatalogQuery?: CatalogQueryResolvers; diff --git a/plugins/catalog-graphql/src/schema.gql b/plugins/catalog-graphql/src/schema.gql index 02abffa09e..bb8e5bcc87 100644 --- a/plugins/catalog-graphql/src/schema.gql +++ b/plugins/catalog-graphql/src/schema.gql @@ -1,17 +1,13 @@ scalar JSON scalar JSONObject -type EntityMetadataAnnotation { - key: String! - value: String! -} - type EntityMetadata { name: String! namespace: String! - annotations: JSONObject - annotation(name: String): JSON - labels: JSONObject + annotations: JSONObject! + annotation(name: String!): JSON + labels: JSONObject! + label(name: String!): JSON uid: String! etag: String! generation: Int! diff --git a/plugins/catalog-graphql/src/service/client.ts b/plugins/catalog-graphql/src/service/client.ts index f7bc5ccffe..05e73b88b8 100644 --- a/plugins/catalog-graphql/src/service/client.ts +++ b/plugins/catalog-graphql/src/service/client.ts @@ -14,20 +14,30 @@ * limitations under the License. */ -import { Entity } from '@backstage/catalog-model'; +import { Entity, EntityMeta } from '@backstage/catalog-model'; import fetch from 'node-fetch'; +import { JsonObject } from '@backstage/config'; +export interface ReaderEntityMeta extends EntityMeta { + uid: string; + etag: string; + generation: number; + namespace: string; +} +export interface ReaderEntity extends Entity { + metadata: JsonObject & ReaderEntityMeta; +} export class CatalogClient { constructor(private baseUrl: string) {} - async list(): Promise { + async list(): Promise { const res = await fetch(`${this.baseUrl}/catalog/entities`); if (!res.ok) { // todo(blam): need some better way to handle errors here // experiment with throwing the input errors etc and having graphql versions of that - throw new Error(`NOPE, ${await res.text()}`); + throw new Error(await res.text()); } - const entities: Entity[] = await res.json(); + const entities: ReaderEntity[] = await res.json(); return entities; } }