Nasaq

FeatureFlagDetail

One feature flag in full: on/off and percentage rollout per environment, targeting rules built with the rule builder, weighted variants, a kill switch and the audit history.

PreviewOpen ↗

Code

import { FeatureFlagDetail } from "@fadymondy/nasaq/web";<FeatureFlagDetail  flag={flag}  environments={environments}  fields={[{ id: "plan", label: "Plan", kind: "select", options: [{ value: "pro", label: "Pro" }] }]}  audit={audit}  onToggle={async (env, enabled) => { await api.toggle(flag.key, env, enabled); }}  onRolloutChange={async (env, pct) => { await api.rollout(flag.key, env, pct); }}  onKill={async (reason) => { await api.kill(flag.key, reason); }}/>;

Developer Tools · beta

Live examples and controls: FeatureFlagDetail in the lab.

Install

npx shadcn@latest add https://docs.nasaqui.com/r/feature-flag-detail.json

FeatureFlagDetail is the page body for a single flag. Four tabs: Environments (a switch and a rollout slider per environment), Targeting (rules built with RuleBuilder, each serving a variant, first match wins), Variants (keys and weights that always add up to 100) and History (the audit trail). A Kill switch button forces the flag off everywhere, needs a reason, and turns into a Restore button in a danger banner once used.

Every change goes through a callback that returns a promise, so the host decides what saving means; a returned { error } is shown and the control returns to its old value.

When to use

  • The detail screen of a flag in an admin or developer area.

When not to use

Import

import { FeatureFlagDetail } from "@fadymondy/nasaq/web";

Quick start

import { FeatureFlagDetail } from "@fadymondy/nasaq/web";

<FeatureFlagDetail
  flag={flag}
  environments={environments}
  fields={[{ id: "plan", label: "Plan", kind: "select", options: [{ value: "pro", label: "Pro" }] }]}
  audit={audit}
  onToggle={async (env, enabled) => { await api.toggle(flag.key, env, enabled); }}
  onRolloutChange={async (env, pct) => { await api.rollout(flag.key, env, pct); }}
  onKill={async (reason) => { await api.kill(flag.key, reason); }}
/>;

Anatomy

FeatureFlagDetail       data-slot="feature-flag-detail"
  header                name, key, state, Kill switch
  killed banner         Alert with Restore
  Tabs                  Environments | Targeting | Variants | History
    Environments        Switch + Slider per environment
    Targeting           RuleBuilder per rule, serve variant, move, remove, Save
    Variants            key, label, weight, share
    History             FlagAuditHistory (Timeline)

API

FeatureFlagDetail

PropTypeDefaultDescription
flagFeatureFlagrequiredThe flag.
environmentsFlagEnvironmentDef[]required{ id, label }.
fieldsRuleField[]requiredWhat targeting rules can test: plan, country and so on.
auditFlagAuditEntry[]noneHistory tab. Newest first.
onToggle(environmentId, enabled) => Promise<void | { error?: string }>noneWithout it switches are read only.
onRolloutChange(environmentId, percent) => Promise<...>noneCalled when the slider is released (onValueCommitted), not on every drag step.
onRulesChange(rules: RuleDefinition[]) => Promise<...>noneSave on the Targeting tab.
onVariantsChange(variants: FlagVariant[]) => Promise<...>noneSave on the Variants tab.
onKill(reason: string) => Promise<...>noneShows the Kill switch.
onRestore() => Promise<...>noneShows Restore on a killed flag.
className / labelsnoneClasses; Partial<FeatureFlagDetailLabels> strings.

Keep flag, flag.rules, flag.variants and flag.environments referentially stable between renders: the component syncs its drafts from them when they change.

FlagAuditHistory

entries: FlagAuditEntry[], className?, labels?. An entry is { id, action: "created" | "toggled" | "rollout" | "rules" | "variants" | "killed" | "restored", actor, at, environment?, from?, to?, reason? }.

Examples

History on its own, for an activity page:

import { FlagAuditHistory } from "@fadymondy/nasaq/web";

<FlagAuditHistory entries={audit} />;

Read only viewer:

import { FeatureFlagDetail } from "@fadymondy/nasaq/web";

<FeatureFlagDetail flag={flag} environments={envs} fields={fields} audit={audit} />;

Accessibility

KeyAction
Arrow keysSwitch tabs; adjust a focused slider (Shift for bigger steps).
SpaceFlip a switch.
EscapeClose the kill switch dialog.

The kill switch asks for a reason in an alert dialog with focus on the input. The killed state is a banner with text and an icon.

RTL & i18n

Sliders and tabs mirror in RTL. Flag keys and variant keys are left-to-right. Percentages use Latin digits. Built-in English and Arabic strings; override with labels.

Styling & tokens

State and the killed banner use the danger, success, warning and neutral tokens. Logical spacing only.

Do / Don't

  • Do require a reason for the kill switch so the audit trail explains it.
  • Do save the rollout on release, not on each drag step.
  • Don't rely on rule order without saying so: the first match wins.

Lab

https://docs.nasaqui.com/?path=/docs/components-developer-tools-feature-flag-detail--docs

On this page