Documentation

Exemple facet list

Construire une facet list backoffice typee avec columns, filters, sorts et Relay.

Une facet list decrit comment une entite backoffice apparait dans les vues liste: query, fragment, rows, columns, filters, sorts et etat par defaut.

import {
  createListFacet,
  type BackofficeColumnSpec,
  type BackofficeFilterSpec,
  type BackofficeListFacetConfig,
  type BackofficeSortSpec,
} from '@plumile/backoffice-core';

import { ProjectListPageQuery } from '../queries/ProjectListPageQuery.js';
import { ProjectListFragment } from '../queries/ProjectListFragment.js';

type ProjectWhere = {
  archived?: boolean;
  owner?: { id?: string };
};

type ProjectSort = 'CREATED_AT_DESC' | 'CREATED_AT_ASC';

type ProjectRowRef = {
  id: string;
  name: string;
  owner: { id: string; name: string } | null;
  createdAt: string;
};

type ProjectRow = {
  id: string;
  name: string;
  ownerName: string | null;
  createdAt: string;
};

const columns: readonly BackofficeColumnSpec<ProjectRow>[] = [
  {
    key: 'name',
    header: (t) => t('project.columns.name'),
    size: 'lg',
    cell: {
      type: 'link',
      value: (row) => row.name,
      to: (row) => `/projects/${row.id}`,
    },
  },
  {
    key: 'owner',
    header: (t) => t('project.columns.owner'),
    size: 'md',
    cell: { type: 'text', value: (row) => row.ownerName },
  },
];

const filters: readonly BackofficeFilterSpec<ProjectWhere>[] = [
  {
    id: 'ownerId',
    kind: 'entityId',
    entity: 'users',
    label: (t) => t('project.filters.owner'),
    toGraphQL: (value) => ({ owner: { id: value } }),
    fromGraphQL: (where) => where.owner?.id ?? null,
  },
];

const sorts: readonly BackofficeSortSpec<ProjectSort>[] = [
  { id: 'CREATED_AT_DESC', label: (t) => t('sort.newest') },
  { id: 'CREATED_AT_ASC', label: (t) => t('sort.oldest') },
];

export const projectListFacet = createListFacet({
  kind: 'list',
  id: 'projects',
  label: (t) => t('project.entity.plural'),
  list: {
    title: (t) => t('project.entity.plural'),
    query: ProjectListPageQuery,
    fragment: ProjectListFragment,
    getConnection: (data) => data.projects,
    toRow: (node: ProjectRowRef): ProjectRow => ({
      id: node.id,
      name: node.name,
      ownerName: node.owner?.name ?? null,
      createdAt: node.createdAt,
    }),
    getRowId: (row) => row.id,
    columns,
    filters,
    sorts,
    defaultState: { sort: 'CREATED_AT_DESC' },
  },
} satisfies BackofficeListFacetConfig<ProjectWhere, ProjectSort>);

Gardez le mapping GraphQL dans le module de facet ou un helper proche. Cela aligne columns, filters, etat URL et query list.

Pour le mapping standalone entre filtres d’URL et GraphQL, voir Where GraphQL.