Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

User Groups Paywall #10033

Closed
wants to merge 11 commits into from
Closed

User Groups Paywall #10033

wants to merge 11 commits into from

Conversation

MrFlashAccount
Copy link
Contributor

@MrFlashAccount MrFlashAccount commented May 22, 2024

Pull Request Description

Tl;dr 

Closes: enso-org/cloud-v2#1200

This PR adds Initial paywall functionality inside enso and adds paywalls for the Users Group page in settings.

Demo Presentation

CleanShot.2024-05-22.at.15.14.53.mp4


Context:

This Change:

What this change does in the larger context. Specific details to highlight for review:

  1. Adds a new set of components for Paywall functionality
  2. Closes the UsersGroup functionaly behind 2 paywalls - first is for personal/free acc, and the second is for team acc

Test Plan:

The only catch with testing is how to switch UI between different states, and I don't have an answer except switching between accounts or modifying the code to invert the logic.


Important Notes

Checklist

Please ensure that the following checklist has been satisfied before submitting the PR:

  • The documentation has been updated, if necessary.
  • Screenshots/screencasts have been attached, if there are any visual changes. For interactive or animated visual changes, a screencast is preferred.
  • All code follows the
    Scala,
    Java,
    TypeScript,
    and
    Rust
    style guides. In case you are using a language not listed above, follow the Rust style guide.
  • Unit tests have been written where possible.

@MrFlashAccount MrFlashAccount self-assigned this May 22, 2024
@MrFlashAccount MrFlashAccount added g-dashboard CI: No changelog needed Do not require a changelog entry for this PR. x-new-feature Type: new feature request labels May 22, 2024
@MrFlashAccount MrFlashAccount marked this pull request as ready for review May 22, 2024 13:06
@somebody1234
Copy link
Contributor

mostly unrelated, but: i don't think we should let users on the Team plan manage user groups.
iirc the idea is, everyone is in the same user group, unconditionally. so the user group can't be deleted, and users can't be excluded from the group

@MrFlashAccount
Copy link
Contributor Author

@somebody1234 We might want to move this discussion outside of the PR. Maybe move it to the related Issue? I guess we need opinions from @PabloBuchu and/or from @jdunkerley

@@ -137,14 +133,6 @@ const RESTRICTED_SYNTAXES = [
selector: `TSAsExpression:not(:has(TSTypeReference > Identifier[name=const]))`,
message: 'Avoid `as T`. Consider using a type annotation instead.',
},
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This rule makes no sense with 'exactOptionalPropertyTypes`.

Copy link
Contributor

Choose a reason for hiding this comment

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

exactOptionalPropertyTypes is not related to this rule. if anything, exactOptionalPropertyTypes removes undefined from the types of optional properties (unless explicitly declared as | undefined), meaning that this rule shouldn't cause any problem at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In case I want to allow passing smth: undefined, I need to specify it explicitly, but by specifying it explicitly, I'm making eslint angry.

Copy link
Contributor

Choose a reason for hiding this comment

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

@MrFlashAccount but the point of undefined is that you don't need to pass it explicitly. if you need to omit something, simply don't specify the property at all

Copy link
Contributor Author

@MrFlashAccount MrFlashAccount May 22, 2024

Choose a reason for hiding this comment

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

Often we use the object destruction pattern and checking if a property is not undefined before passing it is tedious.

See: https://github.com/enso-org/enso/blob/develop/app/ide-desktop/lib/dashboard/src/components/AriaComponents/Form/Form.tsx#L55

@@ -461,11 +449,6 @@ export default [
selector: ':not(TSModuleDeclaration)[declare=true]',
message: 'No ambient declarations',
},
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This rule makes no sense in case if we re-import default statements from barrel files

@@ -87,10 +87,6 @@ const RESTRICTED_SYNTAXES = [
selector: `:matches(ImportDefaultSpecifier[local.name=/^${NAME}/i], ImportNamespaceSpecifier > Identifier[name=/^${NAME}/i])`,
message: `Don't prefix modules with \`${NAME}\``,
},
{
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed it because creating an interface sometimes it too annoying

Copy link
Contributor

Choose a reason for hiding this comment

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

see review comments

/**
* Build a Subscription URL for contacting sales.
*/
export function getContactSalesURL(): string {
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a reason this should be a function?

Copy link
Contributor

Choose a reason for hiding this comment

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

also i don't think this is the right place to put these functions, as they are not being used in App.tsx, nor are they related to App.tsx.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

They're here because they're related to Paths(and all paths are specified here). Eventually, we'll move the URLs closer to their pages and the function will follow.

Copy link
Contributor

Choose a reason for hiding this comment

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

all paths are specified here

correction: all paths used in App.tsx are specified here. the paths are (or at least, should be) used nowhere outside of App.tsx

Copy link
Contributor Author

Choose a reason for hiding this comment

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

correction: all paths used in App.tsx are specified here. the paths are (or at least, should be) used nowhere outside of App.tsx

Since we don't specify paths outside of the App.tsx this correction makes no change

Copy link
Contributor

Choose a reason for hiding this comment

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

getContactSalesURL is used only in getComponentForPlan.tsx and UpgradeButton.tsx, neither of which are App.tsx - unless i'm misunderstanding something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We keep this function with the URL just because we don't want to forget it when we refactor the Router-related stuff and put to it's own place under /pages

Copy link
Contributor Author

Choose a reason for hiding this comment

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

But if you have a better option - I'll comply

| (3 & { readonly name: PaywallLevelName; readonly label: text.TextId })

export const PAYWALL_LEVELS: Record<PaywallLevelName, PaywallLevelValue> = {
free: Object.assign(0, { name: 'free', label: 'freePlanName' } as const),
Copy link
Contributor

Choose a reason for hiding this comment

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

is there a good reason to use Number objects here? why are the numbers not simply a property of the object?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because plans are Inclusive - all features from a level below are included in the levels above.
So if we want to check that the feature is available, we can simply compare 2 numbers - the user's level and the feature level.

Copy link
Contributor

Choose a reason for hiding this comment

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

we can do that with a property as well. user.plan.level < plan.level

Copy link
Contributor Author

@MrFlashAccount MrFlashAccount May 22, 2024

Choose a reason for hiding this comment

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

I see no arguments why user.plan.level < plan.level is better than level < userLevel

Copy link
Contributor

Choose a reason for hiding this comment

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

it's not! but i'm really, really unsure about passing around a Number object, just so the code looks a tiny bit cleaner in one specific situation.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I my experience checking things like 'level === PaywallLevels.enterprise' or 'level > PaywallLevels.enterpriseEntry' is more than just a one specific case.
Also, since level is a primitive type, we don't care if references don't match.
CleanShot 2024-05-22 at 19 23 12

Copy link
Contributor Author

@MrFlashAccount MrFlashAccount May 22, 2024

Choose a reason for hiding this comment

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

I agree this looks strange and unusual, but it has advantages and doesn't violate the agreement we have in javascript, like do not mutate prototypes

app/ide-desktop/lib/dashboard/src/text/index.ts Outdated Show resolved Hide resolved
@MrFlashAccount MrFlashAccount force-pushed the wip/sergeigarin/paywalls branch 2 times, most recently from 81f2638 to 86008ae Compare May 23, 2024 08:05
Copy link
Contributor

@somebody1234 somebody1234 left a comment

Choose a reason for hiding this comment

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

buttons in settings sidebar no longer have lowered opacity when inactive (they are supposed to).

/>
))}

<ariaComponents.ButtonGroup gap="xxsmall" direction="column" align="start">
Copy link
Contributor

Choose a reason for hiding this comment

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

please try to avoid changing layout from the figma design. (the figma design does not have a gap)

Copy link
Contributor Author

@MrFlashAccount MrFlashAccount May 23, 2024

Choose a reason for hiding this comment

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

Gaps are intended because, even though it's not described in the design if we remove the gaps, menu items will look like they stuck together(see screenshot). Alternatively, we can use a different hover for elements.

CleanShot 2024-05-23 at 13 58 45

Copy link
Contributor

Choose a reason for hiding this comment

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

fair. in that case, we should probably reduce the size of the menu entries and add vertical padding so that the overall height in pixels is still the same? (32 * entries.length)

Copy link
Contributor

Choose a reason for hiding this comment

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

alternatively reduce by just 1px or 0.5px to make the gaps consistent with those ofnthe assets table rows

@MrFlashAccount
Copy link
Contributor Author

buttons in the settings sidebar no longer have lowered opacity when inactive (they are supposed to).

It's intended, we decided to make the buttons look like that with @PabloBuchu because currently, the inactive items look disabled.

Copy link
Contributor

@somebody1234 somebody1234 left a comment

Choose a reason for hiding this comment

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

requested changes have been resolved

@MrFlashAccount
Copy link
Contributor Author

requested changes have been resolved

Can I ask to approve the PR then?

Copy link
Contributor

@somebody1234 somebody1234 left a comment

Choose a reason for hiding this comment

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

github moment

@somebody1234
Copy link
Contributor

(remember that QA is not yet done though)

@MrFlashAccount MrFlashAccount mentioned this pull request May 27, 2024
4 tasks
@MrFlashAccount
Copy link
Contributor Author

Closing this PR in favor of #10087

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
CI: No changelog needed Do not require a changelog entry for this PR. g-dashboard x-new-feature Type: new feature request
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants