-
Notifications
You must be signed in to change notification settings - Fork 4.2k
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
🪟 🎨 Display free tag on release stage pills for users enrolled in the free connectors program #21892
Conversation
@@ -37,13 +33,10 @@ export const ReleaseStageBadge: React.FC<ReleaseStageBadgeProps> = ({ | |||
<div | |||
className={classNames(styles.pill, { | |||
[styles["pill--small"]]: small, | |||
[styles["pill--contains-tag"]]: showFreeTag, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One downside of putting all code shared with OSS on the other side of a component boundary: we no longer have a good way to conditionally change the padding-right
from 6px
to 2px
based on whether a free tag is displayed. Instead, the FreeTag
component uses a negative margin-right
; that's a hacky solution, though, do let me know if you have a better idea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I don't think the negative margin-right
is that bad, but another idea:
{!fcpEnabled && <div
className={classNames(styles.pill, {
[styles["pill--small"]]: small
})}
>
<FormattedMessage id={`connector.releaseStage.${stage}`} />
</div>}
{fcpEnabled && <FCPReleaseStageBadge stage={stage} />}
Where <FCPReleaseStageBadge>
renders the whole pill + conditionally a free tag. It's duplicate code, but I think it's warranted to have a clean split between "feature enabled" and "feature disabled".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do like that a bit better, but I'm inclined to save that for later, when consolidating the three implementations of stage pills (there's another copy-paste StageLabel
component in cloud/components/experiments/
, used by the sign up page; I left that untouched for now since not-yet-created accounts will never be enrolled). If the overall design of the status pills changes, as things stand, it would be way too easy to overlook one of those.
2f87a61
to
06e1f85
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Left a few ideas for improvements, but nothing blocking 👍
@@ -12,7 +12,7 @@ interface IProps { | |||
const Content = styled.div<{ enabled?: boolean }>` | |||
display: flex; | |||
align-items: center; | |||
color: ${({ theme, enabled }) => (!enabled ? theme.greyColor40 : "inheret")}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😄
@@ -37,13 +33,10 @@ export const ReleaseStageBadge: React.FC<ReleaseStageBadgeProps> = ({ | |||
<div | |||
className={classNames(styles.pill, { | |||
[styles["pill--small"]]: small, | |||
[styles["pill--contains-tag"]]: showFreeTag, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tbh I don't think the negative margin-right
is that bad, but another idea:
{!fcpEnabled && <div
className={classNames(styles.pill, {
[styles["pill--small"]]: small
})}
>
<FormattedMessage id={`connector.releaseStage.${stage}`} />
</div>}
{fcpEnabled && <FCPReleaseStageBadge stage={stage} />}
Where <FCPReleaseStageBadge>
renders the whole pill + conditionally a free tag. It's duplicate code, but I think it's warranted to have a clean split between "feature enabled" and "feature disabled".
const { enrollmentStatusQuery } = useFreeConnectorProgram(); | ||
const { isEnrolled } = enrollmentStatusQuery.data || {}; | ||
const { formatMessage } = useIntl(); | ||
const freeStages: Array<ReleaseStage | undefined> = ["alpha", "beta"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const freeStages: Array<ReleaseStage | undefined> = ["alpha", "beta"]; | |
const freeStages: ReleaseStage[] = ["alpha", "beta"]; |
I can't imagine why we would want undefined
in this array?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The type checker is very uncomfortable relying on the fact that (someArray as Array<T>).includes(undefined) === false
for all types T
, even though it's totally idiomatic js; so the elements of freeStages
have to match the type of isEnrolled
. Absent type errors, I would have just used an inline array literal (["alpha", "beta"].includes(releaseStage)
).
The other reasonable alternative would be to cast isEnrolled
, as freeStages.includes(releaseStage as ReleaseStage)
; I think it's an equivalently good solution for this case, but a general preference for avoiding casts was the tie-breaker (because every time I read one I have to consider the possibility of human error in addition to all the types).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure I quite follow - the change I suggested passes my TS checker just fine (so does ["alpha", "beta"].includes(releaseStage)
, for that matter). What error are you seeing there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...none, now 😳. I certainly remember only adding that | undefined
in response to some Argument of type ReleaseStage | undefined is not assignable to parameter of type ReleaseStage
error, but now it even type-checks if I go back to the inline array of strings I tried initially. I feel like I'm taking crazy pills, but I'll take the cleaner code, I guess.
...ctor/ConnectorForm/components/FrequentlyUsedConnectors/FrequentlyUsedConnectorsCard.test.tsx
Outdated
Show resolved
Hide resolved
This is distinct from the LaunchDarkly-backed experiment we're referencing within `cloud/components/experiments/FreeConnectorProgram`: it's primary use is to prevent triggering cloud-only API calls in the OSS build.
It does seem as though we should consolidate on a single release stage pill implementation! That will have to wait for a follow-up, though.
"...and your little type assertion, too!"
89a6f2c
to
f6dd490
Compare
What
Displays the free badge on release stage pills if:
Closes #21812.
How, and some additional considerations
FeatureItem.FreeConnectorProgram
flag and adds it todefaultCloudFeatures
. As of now, there is no correspondingfeatureService.FREE_CONNECTOR_PROGRAM
flag in LaunchDarkly, since all our dynamic override needs are met by the temporary experiment flag we're using to roll the feature out.FreeTag
component to encapsulate all interaction withuseFreeConnectorProgram
, and by extension the cloud-only endpoint that backs it, behind a component boundary. This means OSS builds always get to short-circuit that API via conditionals like{ useFeature(FeatureItem.FreeConnectorProgram) && <FreeTag releaseStage={releaseStage} /> }
; closes Refactor useFreeConnectorProgram() so it does not fire in OSS #21872showFreeTag
prop, largely as a way to avoid a big, pointless rewrite of some unit test setup code. This pattern dramatically simplified the extra setup needed, making it once again reasonable to centralize the "should the free tag render for this workspace/connector?" logic within the pills.FreeConnectorProgram
directory, rather than as a helper component withinReleaseStageBadge.tsx
in order to deal with the fact that there are two separate, almost-identical implementations of release stage pills. Obvious possible follow-up refactoring there.But how does it look
From the connection page title, embedded in a
ReleaseStageBadge
:From the new source/destination dropdown, embedded in a
StageLabel
(is there any reason not to just use aReleaseStageBadge
here?):