Portal Community

FormGroupOverride Type

// packages/types-js/src/TenantOverride.ts

interface FormGroupOverride {
  /** The FormCategoryID of the group being overridden */
  baseCategoryId: number;

  /** The tenant receiving these customisations */
  tenantId: number;

  /** Modifications to existing base forms */
  overrides: FormOverrideEntry[];

  /** Net-new forms visible only to this tenant */
  additions: FormAdditionEntry[];
}

interface FormOverrideEntry {
  /** FormID of the base form being modified */
  formId: number;

  /** Disable the form for this tenant (IsActive = 0 in the tenant row) */
  disable?: boolean;

  /** JSONPath-style key/value patches applied to the base schema */
  overrideSchema?: Record<string, any>;
}

interface FormAdditionEntry {
  /** FormID from the tenant's private range (tenantId × 100000 + groupStart) */
  formId:         number;
  formCode:       string;
  formTypeId:     number;
  primaryUsage:   string;
  nodeUsage?:     string;
  schema:         object;   // Full form schema JSON
}

Complete Example

// Tenant 9 (Acme Corp) customisations to the GuardRails group

const acmeGuardRailsOverride: FormGroupOverride = {
  baseCategoryId: 130,      // GuardRails
  tenantId:       9,

  overrides: [
    // Modify GuardRail_Edit (13001): rename 'Policy Name' to 'Rule Name', change player
    {
      formId: 13001,
      overrideSchema: {
        "metadata.playerOverride":               "gov-accessible",
        "controls[id=policy-name].label":        "Rule Name",
        "controls[id=policy-name].placeholder":  "Enter rule name",
      }
    },
    // Disable GuardRail_Audit dashboard for this tenant (they have their own)
    {
      formId:  13007,
      disable: true,
    }
  ],

  additions: [
    // Add a tenant-specific IP allowlist form (see Guide on Tenant FormID Ranges)
    {
      formId:       913008,
      formCode:     'Acme_GuardRail_IpAllowlist_Edit',
      formTypeId:   2,
      primaryUsage: 'guardrails',
      nodeUsage:    'acme-guardrail-ip-allowlist',
      schema: {
        "metadata": { "formId": 913008, "title": "Edit IP Allowlist (Acme)" },
        "controls": [ /* ... */ ],
        "actions":  [ /* ... */ ]
      }
    }
  ]
};

overrideSchema — JSONPath Targeting

Keys in overrideSchema are JSONPath-style expressions that target a specific location in the base schema JSON. The value replaces the current value at that path:

Key PatternTargetsExample
metadata.{field}Top-level metadata fieldmetadata.playerOverride
controls[id={controlId}].{field}Named control's fieldcontrols[id=policy-name].label
sections[id={sectionId}].{field}Named section's fieldsections[id=details].title
controls[id={controlId}].validation.{rule}Specific validation rulecontrols[id=email].validation.required
controls[id={controlId}].optionsFull options array (replaced)controls[id=currency].options
overrideSchema Is Applied After parseSchema The base schema is first normalised by parseSchema(), then the overrideSchema patches are applied. This means you can use the stable, normalised field names rather than worrying about raw JSON quirks in the base schema.