Skip to content

Conversation

@appflowy
Copy link
Contributor

@appflowy appflowy commented Nov 25, 2025

Description


Checklist

General

  • I've included relevant documentation or comments for the changes introduced.
  • I've tested the changes in multiple environments (e.g., different browsers, operating systems).

Testing

  • I've added or updated tests to validate the changes introduced for AppFlowy Web.

Feature-Specific

  • For feature additions, I've added a preview (video, screenshot, or demo) in the "Feature Preview" section.
  • I've verified that this feature integrates seamlessly with existing functionality.

Summary by Sourcery

Adjust subscription handling and visibility of upgrade prompts based on whether the app is running on an official host.

Bug Fixes:

  • Ensure self-hosted or non-official hosts are treated as having Pro-level access in sharing, publishing, and workspace invitation flows.

Enhancements:

  • Hide the upgrade banner and avoid remote subscription checks when running on non-official hosts.
  • Update the list of official hostnames to treat localhost (without port) as official for subscription logic.

@sourcery-ai
Copy link

sourcery-ai bot commented Nov 25, 2025

Reviewer's Guide

This PR changes how subscription plans and upgrade prompts are handled based on whether the app is running on an official host, defaulting users to Pro and hiding upgrade prompts on non-official hosts, and adjusts the list of official hostnames.

Sequence diagram for subscription handling in SharePanel

sequenceDiagram
  actor User
  participant SharePanel
  participant SubscriptionUtils as SubscriptionUtils_isOfficialHost
  participant AppHandlers as AppHandlers_getSubscriptions

  User->>SharePanel: Open_share_panel(viewId)
  activate SharePanel
  SharePanel->>SubscriptionUtils: isOfficialHost()
  alt Not_official_host
    SubscriptionUtils-->>SharePanel: false
    SharePanel->>SharePanel: setActiveSubscriptionPlan(SubscriptionPlan.Pro)
  else Official_host
    SubscriptionUtils-->>SharePanel: true
    SharePanel->>AppHandlers: getSubscriptions()
    AppHandlers-->>SharePanel: Subscription_list
    SharePanel->>SharePanel: derive_activeSubscriptionPlan_from_subscriptions
  end
  deactivate SharePanel

  Note over User,SharePanel: UpgradeBanner is rendered only when isOfficialHost() is true
Loading

Sequence diagram for subscription handling in PublishManage and InviteMember

sequenceDiagram
  actor User
  participant PublishManage
  participant InviteMember
  participant SubscriptionUtils as SubscriptionUtils_isOfficialHost
  participant AppHandlers as AppHandlers_getSubscriptions

  User->>PublishManage: Open_publish_manage_modal()
  activate PublishManage
  PublishManage->>SubscriptionUtils: isOfficialHost()
  alt Not_official_host
    SubscriptionUtils-->>PublishManage: false
    PublishManage->>PublishManage: setActiveSubscription(SubscriptionPlan.Pro)
  else Official_host
    SubscriptionUtils-->>PublishManage: true
    PublishManage->>AppHandlers: getSubscriptions()
    AppHandlers-->>PublishManage: Subscription_list
    PublishManage->>PublishManage: derive_activeSubscription_from_subscriptions
  end
  deactivate PublishManage

  User->>InviteMember: Open_invite_member_modal()
  activate InviteMember
  InviteMember->>SubscriptionUtils: isOfficialHost()
  alt Not_official_host
    SubscriptionUtils-->>InviteMember: false
    InviteMember->>InviteMember: setActiveSubscriptionPlan(SubscriptionPlan.Pro)
  else Official_host
    SubscriptionUtils-->>InviteMember: true
    InviteMember->>AppHandlers: getSubscriptions()
    AppHandlers-->>InviteMember: Subscription_list
    InviteMember->>InviteMember: derive_activeSubscriptionPlan_from_subscriptions
  end
  deactivate InviteMember
Loading

Updated class diagram for subscription-related components and utilities

classDiagram
  class SubscriptionPlan {
    <<enumeration>>
    Free
    Pro
  }

  class SubscriptionUtils {
    +OFFICIAL_HOSTNAMES Set~string~
    +isOfficialHost() bool
    +getBaseUrlHostname() string
  }

  class SharePanel {
    +viewId string
    +activeSubscriptionPlan SubscriptionPlan
    +loadSubscription() void
  }

  class PublishManage {
    +onClose() void
    +activeSubscription SubscriptionPlan
    +loadSubscription() void
  }

  class InviteMember {
    +workspace any
    +activeSubscriptionPlan SubscriptionPlan
    +loadSubscription() void
  }

  class AppHandlers {
    +getSubscriptions() SubscriptionPlan[]
  }

  SharePanel --> SubscriptionPlan
  PublishManage --> SubscriptionPlan
  InviteMember --> SubscriptionPlan

  SharePanel ..> SubscriptionUtils : uses
  PublishManage ..> SubscriptionUtils : uses
  InviteMember ..> SubscriptionUtils : uses

  SharePanel ..> AppHandlers : uses
  PublishManage ..> AppHandlers : uses
  InviteMember ..> AppHandlers : uses

  SubscriptionUtils o-- SubscriptionPlan : OFFICIAL_HOSTNAMES_drives_isOfficialHost
Loading

Flow diagram for isOfficialHost and subscription behavior

flowchart TD
  A[Start] --> B[Get_base_url_hostname_from_APPFLOWY_BASE_URL]
  B --> C{Hostname_in_OFFICIAL_HOSTNAMES?}
  C -->|Yes| D[isOfficialHost returns true]
  C -->|No| E[isOfficialHost returns false]

  D --> F{Component: SharePanel_or_PublishManage_or_InviteMember}
  E --> F

  F --> G{isOfficialHost_result}

  G -->|true| H[Call_getSubscriptions_and_compute_active_subscription]
  G -->|false| I[Set_active_subscription_to_SubscriptionPlan.Pro]

  H --> J[On_official_hosts_show_UpgradeBanner_in_SharePanel]
  I --> K[On_non_official_hosts_hide_UpgradeBanner_and_treat_as_Pro]

  J --> L[End]
  K --> L[End]
Loading

File-Level Changes

Change Details Files
Gate subscription loading and upgrade UI by official hosting, defaulting to Pro on non-official hosts.
  • Import the official-host detection helper into share, publish management, and workspace invite flows
  • Short-circuit subscription loading on non-official hosts by directly setting the active subscription to Pro
  • Hide the upgrade banner in the share panel when not on an official host
src/components/app/share/SharePanel.tsx
src/components/app/publish-manage/PublishManage.tsx
src/components/app/workspaces/InviteMember.tsx
Adjust official host detection to treat localhost (any port) as official.
  • Update the OFFICIAL_HOSTNAMES set to use bare 'localhost' instead of 'localhost:8000' for base URL hostname checks
src/utils/subscription.ts

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey there - I've reviewed your changes - here's some feedback:

  • In the components where you branch on isOfficialHost (SharePanel, PublishManage, InviteMember), consider computing this once (e.g., const isOfficial = isOfficialHost()) and reusing it in both effects and JSX to avoid repeated calls and ensure consistent behavior if the hosting logic ever changes.
  • Changing OFFICIAL_HOSTNAMES from 'localhost:8000' to 'localhost' may no longer match configurations where APPFLOWY_BASE_URL includes an explicit port (e.g., http://localhost:8000); if you intend to treat any localhost with any port as official, consider normalizing the hostname or matching on hostname only instead of the full host:port string.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the components where you branch on isOfficialHost (SharePanel, PublishManage, InviteMember), consider computing this once (e.g., const isOfficial = isOfficialHost()) and reusing it in both effects and JSX to avoid repeated calls and ensure consistent behavior if the hosting logic ever changes.
- Changing OFFICIAL_HOSTNAMES from 'localhost:8000' to 'localhost' may no longer match configurations where APPFLOWY_BASE_URL includes an explicit port (e.g., http://localhost:8000); if you intend to treat any localhost with any port as official, consider normalizing the hostname or matching on hostname only instead of the full host:port string.

## Individual Comments

### Comment 1
<location> `src/utils/subscription.ts:9` </location>
<code_context>
 import { getConfigValue } from '@/utils/runtime-config';

-const OFFICIAL_HOSTNAMES = new Set(['beta.appflowy.cloud', 'test.appflowy.cloud', 'localhost:8000']);
+const OFFICIAL_HOSTNAMES = new Set(['beta.appflowy.cloud', 'test.appflowy.cloud', 'localhost']);

 function getBaseUrlHostname(): string | null {
</code_context>

<issue_to_address>
**question:** Revisit official-host detection to account for additional local addresses or ports if needed.

Since `URL.hostname` excludes the port, this change now matches purely on hostnames. Please confirm whether other local hosts (e.g. `127.0.0.1` or custom dev hostnames) should also be treated as official; if so, they’ll need to be added to `OFFICIAL_HOSTNAMES` or handled elsewhere.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

import { getConfigValue } from '@/utils/runtime-config';

const OFFICIAL_HOSTNAMES = new Set(['beta.appflowy.cloud', 'test.appflowy.cloud', 'localhost:8000']);
const OFFICIAL_HOSTNAMES = new Set(['beta.appflowy.cloud', 'test.appflowy.cloud', 'localhost']);
Copy link

Choose a reason for hiding this comment

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

question: Revisit official-host detection to account for additional local addresses or ports if needed.

Since URL.hostname excludes the port, this change now matches purely on hostnames. Please confirm whether other local hosts (e.g. 127.0.0.1 or custom dev hostnames) should also be treated as official; if so, they’ll need to be added to OFFICIAL_HOSTNAMES or handled elsewhere.

@appflowy appflowy merged commit ed24f05 into main Nov 25, 2025
12 checks passed
@appflowy appflowy deleted the hide_pro_plan branch November 25, 2025 14:54
josue693 pushed a commit to josue693/AppFlowy-Web that referenced this pull request Dec 21, 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.

2 participants