Skip to content

Conversation

@tylix
Copy link
Collaborator

@tylix tylix commented Jun 1, 2025

✅ PR Checklist

Please ensure the following before submitting your PR:

  • My commit message follows Conventional Commits
  • I’ve tested the changes and confirmed they work as expected
  • I’ve updated any relevant documentation
  • I’ve added tests (if applicable)

🔗 Linked Issue

No issue created

📖 Description

  • You can now create feature flags with multiple variants (for A/B/n testing).
  • Each user/session will get randomly (but persistently) assigned a variant, according to your configured distribution.
  • You can target UI/behavior to specific variants using both code (isEnabled('flag:variant')) and templates (v-feature="'flag:variant'").
  • The validation logic is improved and split for clarity: one validator checks flag naming and config, another checks for undeclared flags used in code.
  • Playground and docs updated to show off these features.

🚨 Breaking Changes

  • Yes
  • No

🧪 Type of Change

  • 🐛 Bug fix
  • ✨ New feature
  • 🧹 Code style / formatting
  • 🔨 Refactoring (no functional changes)
  • 🧰 Tooling / CI
  • 📝 Docs update
  • 🧪 Tests
  • 💡 Other (please describe):

🧩 Additional Context

No additional context.

@tylix tylix requested a review from nicokempe as a code owner June 1, 2025 17:21
@nicokempe nicokempe requested a review from Copilot June 1, 2025 17:21
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for feature variants by extending the feature flag mechanism. The key changes include:

  • Adding a new composable (useFeatureVariant) to retrieve and select feature flag variants.
  • Updating the vFeature directive to handle variant strings and control element visibility based on the selected variant.
  • Modifying scheduled flags filtering and integrating variant examples in the playground.

Reviewed Changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
src/runtime/directives/v-feature.ts Refactored the directive to support an optional variant string in the flag value.
src/runtime/composables/useFeatureVariant.ts Introduced a new composable to determine the appropriate variant based on distribution.
src/runtime/composables/useFeatureFlag.ts Updated the isEnabled logic to account for scheduled flags with optional active dates.
playground/pages/scheduled.vue Adjusted filtering logic for scheduled flags to include timing properties.
playground/pages/index.vue Added UI examples for displaying and resetting feature variants.
playground/nuxt.config.ts Added configuration for the new feature variant (checkoutUI) with distribution.
Comments suppressed due to low confidence (2)

src/runtime/composables/useFeatureFlag.ts:30

  • The conditional check bypasses time-based activation when either 'activeFrom' or 'activeUntil' is missing. Ensure this behavior is intended, and consider adding inline documentation to clarify the design rationale.
if (typeof flag === 'object' && flag.name === flagName && ((!flag?.activeFrom || !flag?.activeUntil) ? true : isFlagActiveNow(flag))) return true

src/runtime/composables/useFeatureVariant.ts:57

  • Ensure that the 'distribution' array provided in the configuration sums to 1; otherwise, the random variant selection may yield unexpected results. Consider normalizing the distribution values or adding a validation check.
for (let i = 0; i < variants.length; i++) {

Copy link
Owner

@nicokempe nicokempe left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

unrelated commit will be removed

}

let selectedVariantIndex: number | null = null
const storedValue = localStorage.getItem(flagName)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tylix localStorage works for client-side only, but it lacks SSR support and can’t be pre-evaluated on the server.

For more flexibility we could use:

Might be worth making this configurable via a persistence: 'state' | 'cookie' | 'local' setting in the Nuxt config.

This way, integrators can choose the storage strategy depending on their use case (e.g. temporary testing, logged-in users, or full A/B testing persistence).

@nicokempe
Copy link
Owner

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Codex Review: Here are some suggestions.

Reply with @codex fix comments to fix any unresolved comments.

About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you open a pull request for review, mark a draft as ready, or comment "@codex review". If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex fix this CI failure" or "@codex address that feedback".

Comment on lines +25 to +31
// 2. Retrieve flag configuration
const config: FeatureFlagsConfig = useRuntimeConfig().public.featureFlags
const env = config.environment
const flags: FeatureFlagInput[] = config.environments?.[env] || []

// Find the specific flag configuration
const flag = flags.find(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Variants never read from configured flag sets

The new useFeatureVariant composable is pulling declared flags from config.environments, but the rest of the codebase (and the updated type) now exposes them under flagSets. Because config.environments is undefined, the flags array is always empty and the subsequent search fails, so every call to isEnabled('feature:variant') will return false even when the flag is correctly configured. The code should reference config.flagSets[env] so that variants can be discovered.

Useful? React with 👍 / 👎.

@nicokempe
Copy link
Owner

Goal

@codex make code changes to this PR (based on an old codebase) so it works on the latest main and can be cleanly merged.

Steps

  1. Rebase/Merge main into this branch.
  2. Resolve conflicts:
    • Use current main as baseline.
    • Re-apply the PR’s changes on top.
    • Adapt to renamed files, APIs, or types.
    • Drop obsolete code.
  3. Conform to standards:
    • Lint & format.
    • Pass tsc --noEmit with strict (no any).
    • Centralize validation in ~/utils/validators.ts.
  4. Fix/update tests
  5. Update docs/PR description with notes on conflicts, API changes, and migration if needed.

Acceptance Criteria

  • ✅ No merge conflicts.
  • ✅ CI green (build, lint, tests, typing).
  • ✅ No removed features without notes.
  • ✅ Commits follow Conventional Commits.

Don’ts

  • ❌ No @ts-ignore
  • ❌ Never use the type "any"
  • ❌ No unrelated refactors.

@chatgpt-codex-connector
Copy link

Goal

@codex make code changes to this PR (based on an old codebase) so it works on the latest main and can be cleanly merged.

Steps

  1. Rebase/Merge main into this branch.
  2. Resolve conflicts:
    • Use current main as baseline.
    • Re-apply the PR’s changes on top.
    • Adapt to renamed files, APIs, or types.
    • Drop obsolete code.
  3. Conform to standards:
    • Lint & format.
    • Pass tsc --noEmit with strict (no any).
    • Centralize validation in ~/utils/validators.ts.
  4. Fix/update tests
  5. Update docs/PR description with notes on conflicts, API changes, and migration if needed.

Acceptance Criteria

  • ✅ No merge conflicts.
  • ✅ CI green (build, lint, tests, typing).
  • ✅ No removed features without notes.
  • ✅ Commits follow Conventional Commits.

Don’ts

  • ❌ No @ts-ignore
  • ❌ Never use the type "any"
  • ❌ No unrelated refactors.

For now, I can only help with PRs you've created.

Repository owner deleted a comment from chatgpt-codex-connector bot Aug 28, 2025
@nicokempe
Copy link
Owner

@codex review

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +25 to +29
// 2. Retrieve flag configuration
const config: FeatureFlagsConfig = useRuntimeConfig().public.featureFlags
const env = config.environment
const flags: FeatureFlagInput[] = config.environments?.[env] || []

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Resolve variants from flagSets instead of environments

The new useFeatureVariant composable tries to load flags from config.environments, but the configuration object exposed at runtime uses the renamed flagSets key. As a result flags is always an empty array, flag becomes undefined, and every call to isEnabled('flag:variant') immediately warns that the flag has no variants and returns false, so variants never work. This should read from config.flagSets like the existing useFeatureFlag composable.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants