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

feat(flags): Add C# language examples for feature flags #28702

Merged
merged 9 commits into from
Feb 14, 2025
Binary file modified frontend/__snapshots__/lemon-ui-icons--shelf-c--dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified frontend/__snapshots__/lemon-ui-icons--shelf-c--light.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions frontend/src/lib/components/CodeSnippet/CodeSnippet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { copyToClipboard } from 'lib/utils/copyToClipboard'
import { useEffect, useState } from 'react'
import { PrismAsyncLight as SyntaxHighlighter } from 'react-syntax-highlighter'
import bash from 'react-syntax-highlighter/dist/esm/languages/prism/bash'
import csharp from 'react-syntax-highlighter/dist/esm/languages/prism/csharp'
import dart from 'react-syntax-highlighter/dist/esm/languages/prism/dart'
import elixir from 'react-syntax-highlighter/dist/esm/languages/prism/elixir'
import go from 'react-syntax-highlighter/dist/esm/languages/prism/go'
Expand Down Expand Up @@ -52,12 +53,15 @@ export enum Language {
Markup = 'markup',
SQL = 'sql',
Kotlin = 'kotlin',
CSharp = 'csharp',
}

export const getLanguage = (lang: string): Language => {
switch (lang) {
case 'bash':
return Language.Bash
case 'csharp':
return Language.CSharp
case 'jsx':
return Language.JSX
case 'javascript':
Expand Down Expand Up @@ -113,6 +117,7 @@ SyntaxHighlighter.registerLanguage(Language.PHP, php)
SyntaxHighlighter.registerLanguage(Language.Python, python)
SyntaxHighlighter.registerLanguage(Language.Dart, dart)
SyntaxHighlighter.registerLanguage(Language.Go, go)
SyntaxHighlighter.registerLanguage(Language.CSharp, csharp)
SyntaxHighlighter.registerLanguage(Language.JSON, json)
SyntaxHighlighter.registerLanguage(Language.YAML, yaml)
SyntaxHighlighter.registerLanguage(Language.HTML, markup)
Expand Down
20 changes: 20 additions & 0 deletions frontend/src/lib/lemon-ui/icons/icons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,26 @@ export function IconPython(props: LemonIconProps): JSX.Element {
)
}

export function IconCSharp(props: LemonIconProps): JSX.Element {
return (
<LemonIconBase viewBox="0 0 128 128" {...props}>
<path
fill="currentColor"
fillOpacity="0.7"
d="M115.4 30.7L67.1 2.9c-.8-.5-1.9-.7-3.1-.7-1.2 0-2.3.3-3.1.7l-48 27.9c-1.7 1-2.9 3.5-2.9 5.4v55.7c0 1.1.2 2.4 1 3.5l106.8-62c-.6-1.2-1.5-2.1-2.4-2.7z"
/>
<path
fill="currentColor"
d="M10.7 95.3c.5.8 1.2 1.5 1.9 1.9l48.2 27.9c.8.5 1.9.7 3.1.7 1.2 0 2.3-.3 3.1-.7l48-27.9c1.7-1 2.9-3.5 2.9-5.4V36.1c0-.9-.1-1.9-.6-2.8l-106.6 62z"
/>
<path
fill="#fff"
d="M85.3 76.1C81.1 83.5 73.1 88.5 64 88.5c-13.5 0-24.5-11-24.5-24.5s11-24.5 24.5-24.5c9.1 0 17.1 5 21.3 12.5l13-7.5c-6.8-11.9-19.6-20-34.3-20-21.8 0-39.5 17.7-39.5 39.5s17.7 39.5 39.5 39.5c14.6 0 27.4-8 34.2-19.8l-12.9-7.6zM97 66.2l.9-4.3h-4.2v-4.7h5.1L100 51h4.9l-1.2 6.1h3.8l1.2-6.1h4.8l-1.2 6.1h2.4v4.7h-3.3l-.9 4.3h4.2v4.7h-5.1l-1.2 6h-4.9l1.2-6h-3.8l-1.2 6h-4.8l1.2-6h-2.4v-4.7H97zm4.8 0h3.8l.9-4.3h-3.8l-.9 4.3z"
/>
</LemonIconBase>
)
}

export function IconHandClick(props: LemonIconProps): JSX.Element {
return (
<LemonIconBase viewBox="0 0 18 18" {...props}>
Expand Down
21 changes: 20 additions & 1 deletion frontend/src/scenes/feature-flags/FeatureFlagCodeOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { IconServer } from '@posthog/icons'
import {
IconAndroidOS,
IconAppleIOS,
IconCSharp,
IconFlutter,
IconGolang,
IconJavascript,
Expand All @@ -17,6 +18,7 @@ import { SDKKey } from '~/types'
import {
AndroidSnippet,
APISnippet,
CSharpSnippet,
FeatureFlagSnippet,
FlutterSnippet,
GolangSnippet,
Expand Down Expand Up @@ -149,9 +151,24 @@ export const OPTIONS: InstructionOption[] = [
key: SDKKey.RUBY,
Icon: IconRuby,
},
{
value: 'C#/.NET',
documentationLink: `${DOC_BASE_URL}libraries/dotnet${UTM_TAGS}`,
Snippet: CSharpSnippet,
type: LibraryType.Server,
key: SDKKey.DOTNET,
Icon: IconCSharp,
},
]

export const LOCAL_EVALUATION_LIBRARIES: string[] = [SDKKey.NODE_JS, SDKKey.PYTHON, SDKKey.RUBY, SDKKey.PHP, SDKKey.GO]
export const LOCAL_EVALUATION_LIBRARIES: string[] = [
SDKKey.NODE_JS,
SDKKey.PYTHON,
SDKKey.RUBY,
SDKKey.PHP,
SDKKey.GO,
SDKKey.DOTNET,
]

export const PAYLOAD_LIBRARIES: string[] = [
SDKKey.API,
Expand All @@ -164,6 +181,7 @@ export const PAYLOAD_LIBRARIES: string[] = [
SDKKey.REACT_NATIVE,
SDKKey.IOS,
SDKKey.FLUTTER,
SDKKey.DOTNET,
SDKKey.GO,
]

Expand All @@ -173,6 +191,7 @@ export const REMOTE_CONFIGURATION_LIBRARIES: string[] = [
SDKKey.PYTHON,
SDKKey.GO,
SDKKey.RUBY,
SDKKey.DOTNET,
]

export const BOOTSTRAPPING_OPTIONS: InstructionOption[] = [
Expand Down
95 changes: 95 additions & 0 deletions frontend/src/scenes/feature-flags/FeatureFlagSnippets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,101 @@ if ${conditional}:
)
}

export function CSharpSnippet({
flagKey,
groupType,
multivariant,
localEvaluation,
payload,
remoteConfiguration,
encryptedPayload,
samplePropertyName,
}: FeatureFlagSnippet): JSX.Element {
const clientSuffix = 'posthog.'
const flagFunction = payload
? 'GetFeatureFlagAsync'
: multivariant
? 'GetFeatureFlagAsync'
: 'IsFeatureEnabledAsync'

const propertyName = samplePropertyName || 'isAuthorized'

if (remoteConfiguration) {
const reminder = `// ` + REMOTE_CONFIG_REMINDER + (encryptedPayload ? `\n// ${ENCRYPTED_PAYLOAD_REMINDER}` : '')

return (
<>
<CodeSnippet language={Language.CSharp} wrap>
{`${reminder}
var remoteConfigPayload = await posthog.GetRemoteConfigPayloadAsync("${flagKey}");`}
</CodeSnippet>
</>
)
}

const localEvalCommentAddition = localEvaluation
? groupType
? `// add group properties used in the flag to ensure the flag
// is evaluated locally, vs. going to our servers
`
: `// add person properties used in the flag to ensure the flag
// is evaluated locally, vs. going to our servers
`
: ''

const localEvalCodeAddition = localEvaluation
? groupType
? `{ ["${propertyName}"] = "value", ["name"] = "xyz" }`
: `
personProperties: new() { ["${propertyName}"] = "value" }`
: ''

const flagSnippet = groupType
? `await ${clientSuffix}${flagFunction}(
"${flagKey}",
"user distinct id",
new FeatureFlagOptions
{
${localEvalCommentAddition}Groups = [new Group("${groupType.group_type}", "<${
groupType.name_singular || 'group'
} ID>")${localEvalCodeAddition}]
}
);`
: localEvalCodeAddition
? `await ${clientSuffix}${flagFunction}(
"${flagKey}",
"user distinct id",${localEvalCodeAddition}
);`
: `await ${clientSuffix}${flagFunction}("${flagKey}", "user distinct id");`
const variableName = payload ? 'matchedFlagPayload' : multivariant ? 'enabledVariant' : 'isMyFlagEnabled'

const conditional = multivariant ? `${variableName} == 'example-variant'` : `${variableName}`

const followUpCode = payload
? `
if (matchedFlagPayload is { Payload: {} payload })
{
// The payload is a JsonDocument.
Console.WriteLine(payload.RootElement.GetRawText());
}`
: `

if (${conditional}) {
// Do something differently for this ${groupType ? groupType.name_singular || 'group' : 'user'}
}
`

return (
<>
<CodeSnippet language={Language.CSharp} wrap>
{`${
localEvaluation ? '// ' + LOCAL_EVAL_REMINDER : ''
}var ${variableName} = ${flagSnippet}${followUpCode}`}
</CodeSnippet>
</>
)
}

export function AndroidSnippet({ flagKey, multivariant, payload }: FeatureFlagSnippet): JSX.Element {
const clientSuffix = 'PostHog.'

Expand Down
1 change: 1 addition & 0 deletions frontend/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4482,6 +4482,7 @@ export enum SDKKey {
BUBBLE = 'bubble',
DJANGO = 'django',
DOCUSAURUS = 'docusaurus',
DOTNET = 'dotnet',
ELIXIR = 'elixir',
FRAMER = 'framer',
FLUTTER = 'flutter',
Expand Down
Loading