Skip to content

Extension points

The contract for extending Conjure without forking. Each extension point is a public registry or hook; you add capabilities by registering, never by patching the core.

The extension points

Extension point What you add How Status
Field type renderer Custom field / GFK / GIS display & input @register_field("MyField") โ€” backend schema + frontend renderer pair ๐ŸŸก
Widget Dashboard card / chart @register_widget("name") + frontend widget component โœ…
Action Export, issue, send, refund ADMIN_ACTIONS declaration + sync_admin_actions (permission) + handler ๐Ÿ“‹
AdminConfig attribute Per-model behaviour Declare on the registered config class โœ…
Page eject Fully custom screen Runtime โ†’ codegen .tsx, then own it โœ…

Each extension point is documented with an example here and in the relevant guide, so the "how to add a feature" path stays current with the code.

Field type renderer

Register both halves โ€” the backend describes the field in the schema; the frontend renders it. Without the pair, the field shows as raw text.

from conjure import register_field

@register_field("ColorField")
def color_field_schema(field):
    return {
        "type": "color",          # frontend renderer key
        "control": "color-picker",
        "nullable": field.null,
    }
import { registerFieldRenderer } from "@terracelab/conjure-web";

registerFieldRenderer("color", {
  cell: ({ value }) => <span style={{ background: value }} className="swatch" />,
  control: ColorPickerControl,
});

Widget

backend โ€” conjure/widgets.py or your app
from conjure import register_widget

@register_widget("revenue-trend")
def revenue_trend(request):
    qs = Order.objects.filter(status="paid")
    return {"series": monthly_totals(qs)}
frontend โ€” pages/dashboard/index.tsx
const data = useQuery(queryKeys.widget("revenue-trend"),
                      () => adminApi.widget("revenue-trend"));
// render with Recharts

Served at GET /conjure/widgets/revenue-trend/. See the REST API reference.

Action

๐Ÿ“‹ Three pieces โ€” declaration, permission sync, handler:

conjure/actions.py
ADMIN_ACTIONS = [
    {"model": "order.Order", "codename": "refund", "name": "Refund",
     "kind": "server", "scope": "bulk", "variant": "danger", "confirm": "Refund selected orders?"},
]
python manage.py sync_admin_actions   # creates order.refund permission (no migration)

The handler (dispatched by codename on POST /conjure/r/order.Order/action/refund/) performs the refund, returns a partial-failure report, and writes an audit entry. Full design: Actions & permissions.

AdminConfig attributes

The everyday extension point โ€” already available. Curate list/form/inline behaviour per model. See Registering models for the full attribute set.

Page eject

Pull a runtime-rendered page into codegen you own:

graph LR
  A["GenericModelPage ๐Ÿ“‹"] -->|eject| B["pages/{model}/*.tsx"]
  B --> C["edit ยท // @custom preserved on regen"]

See Custom pages.

Contributing a new extension point

If you're adding a new kind of hook to Conjure itself (not just using one), see Extension development for the registry conventions, the backend/frontend pairing rule, and the docs-with-example requirement.