api-platform / admin

A beautiful and fully-featured administration interface builder for hypermedia APIs
https://api-platform.com/docs/admin/
MIT License
480 stars 130 forks source link

Admin interface not rendering dropdown for Enum on HydraAdmin #494

Open mihai-amihailesei opened 1 year ago

mihai-amihailesei commented 1 year ago

API Platform version(s) affected: 3.1.1

Description
HydraAdmin component does not render an Enum type field as a dropdown selection. OpenApiAdmin component renders correctly.

How to reproduce
Create an entity and a backed Enum, set the backed enum as a property on the entity. Configure the property openapi context with enum and values from the backed enum.

API documentation properly shows the property as an enum on both schemas, however, when rendered with the HydraAdmin component it gets rendered as a plain text field.

https://github.com/mihai-amihailesei/api-platform-admin-bug

alanpoulain commented 1 year ago

It's because API Platform doesn't return information about the enum with Hydra.

PawelSuwinski commented 1 year ago

A workaround for now to have OpenAPi3 enums with Hydra is a proxy of Hydra doc parser, ex.

import {
  parseOpenApi3Documentation,
  parseHydraDocumentation,
} from "@api-platform/api-doc-parser";

// parseHydraDocumentation proxy to add enum fields values what for now is
// supported only in openapi parser.
export const parseHydraDocumentationWithEnums = new Proxy(
  parseHydraDocumentation,
  {
    async apply(target, thisArg, args) {
      const result = await target.apply(thisArg, args);
      const enums = (
        await parseOpenApi3Documentation(args[0] + "docs.json")
      ).api.resources.reduce(
        (enums, resource) =>
          Object.assign(enums, {
            [resource.name]: Object.fromEntries(
              resource.fields
                .filter((field) => field.enum)
                .map((field) =>
                  Object.assign(enums[resource.name] ?? {}, [
                    field.name,
                    { enum: field.enum },
                  ])
                )
            ),
          }),
        {}
      );
      result.api.resources = result.api.resources.map((resource) =>
        Object.assign(resource, {
          fields: resource.fields.map((field) =>
            Object.assign(field, enums[resource.name][field.name] ?? {})
          ),
        })
      );

      return result;
    },
  }
);