Skip to content

feat: control maintenance banner with a feature flag#1968

Merged
stalniy merged 1 commit intoakash-network:mainfrom
jzsfkzm:feature/1949-maintenance-banner-feature-flag
Sep 26, 2025
Merged

feat: control maintenance banner with a feature flag#1968
stalniy merged 1 commit intoakash-network:mainfrom
jzsfkzm:feature/1949-maintenance-banner-feature-flag

Conversation

@jzsfkzm
Copy link
Contributor

@jzsfkzm jzsfkzm commented Sep 25, 2025

closes #1949

Summary by CodeRabbit

  • New Features

    • Maintenance banner is now driven by a runtime feature flag; message, date, and enabled state are served dynamically without redeploys.
    • Banner visibility and initial open state reflect the current flag and its payload.
  • Chores

    • Removed legacy environment-based maintenance banner variables and updated environment samples and config schema accordingly.

@jzsfkzm jzsfkzm requested a review from a team as a code owner September 25, 2025 11:42
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Sep 25, 2025

Walkthrough

Replaced env-driven maintenance banner with an Unleash variant-based feature flag. Layout and TopBanner now read the "maintenance_banner" variant via a new useVariant hook; related env vars and schema entries were removed and the FeatureFlag type was extended.

Changes

Cohort / File(s) Summary of changes
Layout & banner components
apps/deploy-web/src/components/layout/Layout.tsx, apps/deploy-web/src/components/layout/TopBanner.tsx
Switched maintenance banner control from static env values to a runtime Unleash variant via useVariant("maintenance_banner"); removed imports/usages of browserEnvConfig for banner values and parse variant payload for message/date.
Feature-flag hook
apps/deploy-web/src/hooks/useVariant.tsx
Added useVariant wrapper hook that selects between a local dummy variant and @unleash/nextjs/client's useVariant based on NEXT_PUBLIC_UNLEASH_ENABLE_ALL. Exported hook used by components.
Env schema & browser config
apps/deploy-web/src/config/env-config.schema.ts, apps/deploy-web/src/config/browser-env.config.ts
Removed NEXT_PUBLIC_MAINTENANCE_BANNER_ENABLED, NEXT_PUBLIC_MAINTENANCE_BANNER_MESSAGE, and NEXT_PUBLIC_MAINTENANCE_BANNER_MESSAGE_DATE from browser schema/config and resulting BrowserEnvConfig shape.
Feature flag types
apps/deploy-web/src/types/feature-flags.ts
Added "maintenance_banner" literal to FeatureFlag union type.
Env files
apps/deploy-web/env/.env.production, apps/deploy-web/env/.env.sample, apps/deploy-web/env/.env.staging
Removed the three maintenance banner env declarations from production/sample/staging env files; .env.production also had an unrelated PEM content extension.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  actor User
  participant Layout as Layout.tsx
  participant VariantHook as useVariant
  participant Unleash as Unleash / Variant Store
  participant Banner as MaintenanceBanner

  User->>Layout: Request page
  Layout->>VariantHook: useVariant("maintenance_banner")
  VariantHook->>Unleash: fetch variant (or return dummy if ENABLE_ALL)
  Unleash-->>VariantHook: variant { enabled, payload }
  VariantHook-->>Layout: variant
  alt variant.enabled == true
    Layout->>Banner: render with payload.message / payload.date (open=true)
  else
    Layout->>Banner: do not render (or keep closed)
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • stalniy

Poem

I nibble flags beneath the moon,
A banner hops and hums a tune.
No env to bind, the variant sings—
Dynamic change on nimble wings. 🐇✨

Pre-merge checks and finishing touches

❌ Failed checks (2 warnings)
Check name Status Explanation Resolution
Out of Scope Changes Check ⚠️ Warning The PR unexpectedly alters the NEXT_PUBLIC_UI_CONFIG_PUBLIC_KEY value in .env.production, which is unrelated to the maintenance banner feature flag objectives defined in the linked issue. Please remove the unrelated UI configuration key change or move it to a separate PR so this branch only contains maintenance banner feature flag updates.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title clearly and concisely communicates the primary change of controlling the maintenance banner via a feature flag and aligns exactly with the PR’s implementation focus.
Linked Issues Check ✅ Passed The implementation replaces static environment-based banner control with a runtime feature flag using Unleash variants, enabling both dynamic enable/disable and message/date updates as required by issue #1949.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@stalniy
Copy link
Contributor

stalniy commented Sep 25, 2025

@jzsfkzm we don't want to only enable or disable it, we also want to change the message without redeployment. For example, we will need to change date. Sorry this was not specified anywhere in the task but maintanance related variables should be controlled dynamically.

FFs in unleash has variants, later this variants can be retried on client side. I thought to use variants to store message and date

@jzsfkzm jzsfkzm force-pushed the feature/1949-maintenance-banner-feature-flag branch from f5a8752 to 85df374 Compare September 25, 2025 21:08
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
apps/deploy-web/src/components/layout/Layout.tsx (1)

56-104: Ensure maintenance banner reacts to flag updates

isMaintenanceBannerOpen is initialised once and never re-synchronised with the Unleash flag. If the flag flips from false→true while the user is on the page, the banner stays closed, so we don't satisfy the “toggle dynamically without redeploy” requirement. Please derive the open state from the latest maintenanceBannerFlag.enabled value.

-  const [isMaintenanceBannerOpen, setIsMaintenanceBannerOpen] = useState(!!maintenanceBannerFlag.enabled);
+  const [isMaintenanceBannerOpen, setIsMaintenanceBannerOpen] = useState(!!maintenanceBannerFlag.enabled);
+
+  useEffect(() => {
+    if (!maintenanceBannerFlag.enabled) {
+      setIsMaintenanceBannerOpen(false);
+      return;
+    }
+
+    setIsMaintenanceBannerOpen(true);
+  }, [maintenanceBannerFlag.enabled]);
apps/deploy-web/src/components/layout/TopBanner.tsx (1)

22-36: Guard against invalid maintenance banner payloads

JSON.parse(maintenanceBannerFlag.payload?.value as string) will throw when the payload is absent, not JSON, or when the variant carries a plain string. Any of those cases crashes the entire layout, and FormattedDate will also raise if you pass an empty/invalid date. We need defensive parsing plus a validity check before rendering the date.

-export function MaintenanceBanner({ onClose }: { onClose: () => void }) {
-  const maintenanceBannerFlag = useVariant("maintenance_banner");
-
-  const { message, date } = maintenanceBannerFlag.enabled
-    ? (JSON.parse(maintenanceBannerFlag.payload?.value as string) as unknown as { message: string; date: string })
-    : { message: "", date: "" };
+export function MaintenanceBanner({ onClose }: { onClose: () => void }) {
+  const maintenanceBannerFlag = useVariant("maintenance_banner");
+
+  const payloadValue = maintenanceBannerFlag.payload?.value;
+  let message = "";
+  let upgradeDate: Date | undefined;
+
+  if (maintenanceBannerFlag.enabled && typeof payloadValue === "string") {
+    try {
+      const parsedPayload = JSON.parse(payloadValue) as { message?: unknown; date?: unknown };
+
+      if (typeof parsedPayload.message === "string") {
+        message = parsedPayload.message;
+      }
+
+      if (typeof parsedPayload.date === "string") {
+        const parsedDate = new Date(parsedPayload.date);
+        if (!Number.isNaN(parsedDate.getTime())) {
+          upgradeDate = parsedDate;
+        }
+      }
+    } catch (error) {
+      console.error("Invalid maintenance_banner payload", error);
+    }
+  }
 
   return (
     <div className="fixed top-0 z-10 flex h-[40px] w-full items-center justify-center bg-primary px-3 py-2 md:space-x-4">
       <span className="text-xs font-semibold text-white md:text-sm">
-        {message} Upgrade time: <FormattedDate value={date} year="numeric" month="2-digit" day="2-digit" hour="2-digit" minute="2-digit" />
+        {message}
+        {upgradeDate ? (
+          <>
+            {" "}
+            Upgrade time: <FormattedDate value={upgradeDate} year="numeric" month="2-digit" day="2-digit" hour="2-digit" minute="2-digit" />
+          </>
+        ) : null}
       </span>
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f5a8752 and 85df374.

📒 Files selected for processing (9)
  • apps/deploy-web/env/.env.production (0 hunks)
  • apps/deploy-web/env/.env.sample (0 hunks)
  • apps/deploy-web/env/.env.staging (0 hunks)
  • apps/deploy-web/src/components/layout/Layout.tsx (3 hunks)
  • apps/deploy-web/src/components/layout/TopBanner.tsx (2 hunks)
  • apps/deploy-web/src/config/browser-env.config.ts (0 hunks)
  • apps/deploy-web/src/config/env-config.schema.ts (0 hunks)
  • apps/deploy-web/src/hooks/useVariant.tsx (1 hunks)
  • apps/deploy-web/src/types/feature-flags.ts (1 hunks)
💤 Files with no reviewable changes (5)
  • apps/deploy-web/src/config/browser-env.config.ts
  • apps/deploy-web/env/.env.sample
  • apps/deploy-web/env/.env.staging
  • apps/deploy-web/src/config/env-config.schema.ts
  • apps/deploy-web/env/.env.production
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/deploy-web/src/types/feature-flags.ts
🧰 Additional context used
📓 Path-based instructions (2)
**/*.{ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

Never use type any or cast to type any. Always define the proper TypeScript types.

Files:

  • apps/deploy-web/src/components/layout/TopBanner.tsx
  • apps/deploy-web/src/components/layout/Layout.tsx
  • apps/deploy-web/src/hooks/useVariant.tsx
**/*.{js,ts,tsx}

📄 CodeRabbit inference engine (.cursor/rules/general.mdc)

**/*.{js,ts,tsx}: Never use deprecated methods from libraries.
Don't add unnecessary comments to the code

Files:

  • apps/deploy-web/src/components/layout/TopBanner.tsx
  • apps/deploy-web/src/components/layout/Layout.tsx
  • apps/deploy-web/src/hooks/useVariant.tsx
🧠 Learnings (1)
📓 Common learnings
Learnt from: stalniy
PR: akash-network/console#1480
File: apps/deploy-web/src/hooks/useFlag.tsx:0-0
Timestamp: 2025-07-28T10:40:13.595Z
Learning: In the Akash Network Console project, backend-specific feature flags are intentional and acceptable. The frontend FeatureFlag union type should only include flags that are actually used by the frontend, not all flags defined in the backend. Backend can have internal feature flags for backend-only functionality without requiring frontend synchronization.
🧬 Code graph analysis (3)
apps/deploy-web/src/components/layout/TopBanner.tsx (1)
apps/deploy-web/src/hooks/useVariant.tsx (1)
  • useVariant (12-12)
apps/deploy-web/src/components/layout/Layout.tsx (1)
apps/deploy-web/src/hooks/useVariant.tsx (1)
  • useVariant (12-12)
apps/deploy-web/src/hooks/useVariant.tsx (2)
apps/deploy-web/src/config/browser-env.config.ts (1)
  • browserEnvConfig (4-41)
apps/deploy-web/src/types/feature-flags.ts (1)
  • FeatureFlag (1-9)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: validate / validate-app
  • GitHub Check: test-build

@stalniy
Copy link
Contributor

stalniy commented Sep 26, 2025

Awesome!

@stalniy stalniy merged commit 22654c9 into akash-network:main Sep 26, 2025
62 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Nov 17, 2025
stalniy pushed a commit that referenced this pull request Nov 20, 2025
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.

Feature flag to turn on/off warning about future blockchain upgrade

2 participants

Comments