From da3c46b55711bdfc2a9d218e722565eff3f57945 Mon Sep 17 00:00:00 2001 From: Jeremy Ruppel Date: Fri, 3 Apr 2026 09:52:52 -0400 Subject: [PATCH] feat: add onboarding info fields to first user setup (#23989) Add optional demographic and newsletter preference fields to the setup page: business use (yes/no), industry type, organization size, and two newsletter toggles (marketing, release/security updates). The new data flows through telemetry via a FirstUserOnboarding struct in the snapshot payload, sent once when the first user is created. The telemetry-server and BigQuery schema changes are required separately to persist this data. --------- Co-authored-by: default Co-authored-by: Claude Sonnet 4.6 --- coderd/apidoc/docs.go | 112 +++++++++++++++++++++++++++++++++ coderd/apidoc/swagger.json | 112 +++++++++++++++++++++++++++++++++ coderd/telemetry/telemetry.go | 13 ++++ coderd/users.go | 20 +++++- coderd/users_test.go | 87 +++++++++++++++++++++++++ codersdk/users.go | 62 ++++++++++++++++-- docs/reference/api/schemas.md | 81 +++++++++++++++++++++--- docs/reference/api/users.md | 7 +++ site/src/api/typesGenerated.ts | 70 +++++++++++++++++++++ 9 files changed, 549 insertions(+), 15 deletions(-) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index c47d54d9f0..74ef34d1be 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -14565,6 +14565,59 @@ const docTemplate = `{ } } }, + "codersdk.CreateFirstUserOnboardingInfo": { + "type": "object", + "properties": { + "industry_type": { + "enum": [ + "Technology", + "Financial Services", + "Healthcare", + "Government", + "Education", + "Retail", + "Manufacturing", + "Media", + "Telecom", + "Energy", + "Transportation", + "Consulting", + "Non-Profit", + "Other" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.IndustryType" + } + ] + }, + "is_business": { + "type": "boolean" + }, + "newsletter_marketing": { + "type": "boolean" + }, + "newsletter_releases": { + "type": "boolean" + }, + "org_size": { + "enum": [ + "Just me", + "2-10", + "11-50", + "51-200", + "201-1000", + "1001-5000", + "5000+" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.OrgSizeRange" + } + ] + } + } + }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": [ @@ -14579,6 +14632,9 @@ const docTemplate = `{ "name": { "type": "string" }, + "onboarding_info": { + "$ref": "#/definitions/codersdk.CreateFirstUserOnboardingInfo" + }, "password": { "type": "string" }, @@ -16430,6 +16486,41 @@ const docTemplate = `{ } } }, + "codersdk.IndustryType": { + "type": "string", + "enum": [ + "Technology", + "Financial Services", + "Healthcare", + "Government", + "Education", + "Retail", + "Manufacturing", + "Media", + "Telecom", + "Energy", + "Transportation", + "Consulting", + "Non-Profit", + "Other" + ], + "x-enum-varnames": [ + "IndustryTypeTechnology", + "IndustryTypeFinancial", + "IndustryTypeHealthcare", + "IndustryTypeGovernment", + "IndustryTypeEducation", + "IndustryTypeRetail", + "IndustryTypeManufacturing", + "IndustryTypeMedia", + "IndustryTypeTelecom", + "IndustryTypeEnergy", + "IndustryTypeTransportation", + "IndustryTypeConsulting", + "IndustryTypeNonProfit", + "IndustryTypeOther" + ] + }, "codersdk.InsightsReportInterval": { "type": "string", "enum": [ @@ -17616,6 +17707,27 @@ const docTemplate = `{ "OptionTypeListString" ] }, + "codersdk.OrgSizeRange": { + "type": "string", + "enum": [ + "Just me", + "2-10", + "11-50", + "51-200", + "201-1000", + "1001-5000", + "5000+" + ], + "x-enum-varnames": [ + "OrgSizeRangeJustMe", + "OrgSizeRange2To10", + "OrgSizeRange11To50", + "OrgSizeRange51To200", + "OrgSizeRange201To1K", + "OrgSizeRange1KTo5K", + "OrgSizeRange5KPlus" + ] + }, "codersdk.Organization": { "type": "object", "required": [ diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 3d61d5c5d0..38bbf2bc7a 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -13105,6 +13105,59 @@ } } }, + "codersdk.CreateFirstUserOnboardingInfo": { + "type": "object", + "properties": { + "industry_type": { + "enum": [ + "Technology", + "Financial Services", + "Healthcare", + "Government", + "Education", + "Retail", + "Manufacturing", + "Media", + "Telecom", + "Energy", + "Transportation", + "Consulting", + "Non-Profit", + "Other" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.IndustryType" + } + ] + }, + "is_business": { + "type": "boolean" + }, + "newsletter_marketing": { + "type": "boolean" + }, + "newsletter_releases": { + "type": "boolean" + }, + "org_size": { + "enum": [ + "Just me", + "2-10", + "11-50", + "51-200", + "201-1000", + "1001-5000", + "5000+" + ], + "allOf": [ + { + "$ref": "#/definitions/codersdk.OrgSizeRange" + } + ] + } + } + }, "codersdk.CreateFirstUserRequest": { "type": "object", "required": ["email", "password", "username"], @@ -13115,6 +13168,9 @@ "name": { "type": "string" }, + "onboarding_info": { + "$ref": "#/definitions/codersdk.CreateFirstUserOnboardingInfo" + }, "password": { "type": "string" }, @@ -14914,6 +14970,41 @@ } } }, + "codersdk.IndustryType": { + "type": "string", + "enum": [ + "Technology", + "Financial Services", + "Healthcare", + "Government", + "Education", + "Retail", + "Manufacturing", + "Media", + "Telecom", + "Energy", + "Transportation", + "Consulting", + "Non-Profit", + "Other" + ], + "x-enum-varnames": [ + "IndustryTypeTechnology", + "IndustryTypeFinancial", + "IndustryTypeHealthcare", + "IndustryTypeGovernment", + "IndustryTypeEducation", + "IndustryTypeRetail", + "IndustryTypeManufacturing", + "IndustryTypeMedia", + "IndustryTypeTelecom", + "IndustryTypeEnergy", + "IndustryTypeTransportation", + "IndustryTypeConsulting", + "IndustryTypeNonProfit", + "IndustryTypeOther" + ] + }, "codersdk.InsightsReportInterval": { "type": "string", "enum": ["day", "week"], @@ -16038,6 +16129,27 @@ "OptionTypeListString" ] }, + "codersdk.OrgSizeRange": { + "type": "string", + "enum": [ + "Just me", + "2-10", + "11-50", + "51-200", + "201-1000", + "1001-5000", + "5000+" + ], + "x-enum-varnames": [ + "OrgSizeRangeJustMe", + "OrgSizeRange2To10", + "OrgSizeRange11To50", + "OrgSizeRange51To200", + "OrgSizeRange201To1K", + "OrgSizeRange1KTo5K", + "OrgSizeRange5KPlus" + ] + }, "codersdk.Organization": { "type": "object", "required": ["created_at", "id", "is_default", "updated_at"], diff --git a/coderd/telemetry/telemetry.go b/coderd/telemetry/telemetry.go index b39ad95fc5..056183e5cc 100644 --- a/coderd/telemetry/telemetry.go +++ b/coderd/telemetry/telemetry.go @@ -1502,6 +1502,7 @@ type Snapshot struct { PrebuiltWorkspaces []PrebuiltWorkspace `json:"prebuilt_workspaces"` AIBridgeInterceptionsSummaries []AIBridgeInterceptionsSummary `json:"aibridge_interceptions_summaries"` BoundaryUsageSummary *BoundaryUsageSummary `json:"boundary_usage_summary"` + FirstUserOnboarding *FirstUserOnboarding `json:"first_user_onboarding"` } // Deployment contains information about the host running Coder. @@ -1551,6 +1552,18 @@ type User struct { LoginType string `json:"login_type,omitempty"` } +// FirstUserOnboarding contains optional demographic and newsletter +// preference data collected during first user setup. This is sent +// once when the first user is created. Pointer fields distinguish an +// explicit answer from a skipped question. +type FirstUserOnboarding struct { + IsBusiness *bool `json:"is_business"` + IndustryType string `json:"industry_type"` + OrgSize string `json:"org_size"` + NewsletterMarketing *bool `json:"newsletter_marketing"` + NewsletterReleases *bool `json:"newsletter_releases"` +} + type Group struct { ID uuid.UUID `json:"id"` Name string `json:"name"` diff --git a/coderd/users.go b/coderd/users.go index 29d4002c17..78f5ad65c9 100644 --- a/coderd/users.go +++ b/coderd/users.go @@ -281,8 +281,26 @@ func (api *API) postFirstUser(rw http.ResponseWriter, r *http.Request) { telemetryUser := telemetry.ConvertUser(user) // Send the initial users email address! telemetryUser.Email = &user.Email + // Only populate onboarding data when the client actually sent it. A nil + // OnboardingInfo means the request came from an older client, the CLI, or + // the OIDC flow — not from a user who answered "no" to every question. + // + // Note: newsletter consent (NewsletterMarketing) is bundled here alongside + // product-analytics fields. These may have different legal bases under GDPR + // and should be separated in a follow-up once the legal posture is clarified. + var onboarding *telemetry.FirstUserOnboarding + if createUser.OnboardingInfo != nil { + onboarding = &telemetry.FirstUserOnboarding{ + IsBusiness: createUser.OnboardingInfo.IsBusiness, + IndustryType: string(createUser.OnboardingInfo.IndustryType), + OrgSize: string(createUser.OnboardingInfo.OrgSize), + NewsletterMarketing: createUser.OnboardingInfo.NewsletterMarketing, + NewsletterReleases: createUser.OnboardingInfo.NewsletterReleases, + } + } api.Telemetry.Report(&telemetry.Snapshot{ - Users: []telemetry.User{telemetryUser}, + Users: []telemetry.User{telemetryUser}, + FirstUserOnboarding: onboarding, }) httpapi.Write(ctx, rw, http.StatusCreated, codersdk.CreateFirstUserResponse{ diff --git a/coderd/users_test.go b/coderd/users_test.go index 4d1463d148..2b9f60422e 100644 --- a/coderd/users_test.go +++ b/coderd/users_test.go @@ -116,6 +116,93 @@ func TestFirstUser(t *testing.T) { }) } +func TestFirstUser_OnboardingTelemetry(t *testing.T) { + t.Parallel() + + t.Run("OnboardingInfoFlowsToSnapshot", func(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitMedium) + fTelemetry := newFakeTelemetryReporter(ctx, t, 10) + client := coderdtest.New(t, &coderdtest.Options{ + TelemetryReporter: fTelemetry, + }) + + isBusiness := true + wantMarketing := false + wantReleases := true + _, err := client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{ + Email: "admin@coder.com", + Username: "admin", + Password: "SomeSecurePassword!", + OnboardingInfo: &codersdk.CreateFirstUserOnboardingInfo{ + IsBusiness: &isBusiness, + IndustryType: codersdk.IndustryTypeTechnology, + OrgSize: codersdk.OrgSizeRange51To200, + NewsletterMarketing: &wantMarketing, + NewsletterReleases: &wantReleases, + }, + }) + require.NoError(t, err) + + snapshot := testutil.TryReceive(ctx, t, fTelemetry.snapshots) + require.NotNil(t, snapshot.FirstUserOnboarding) + require.NotNil(t, snapshot.FirstUserOnboarding.IsBusiness) + require.True(t, *snapshot.FirstUserOnboarding.IsBusiness) + require.Equal(t, string(codersdk.IndustryTypeTechnology), snapshot.FirstUserOnboarding.IndustryType) + require.Equal(t, string(codersdk.OrgSizeRange51To200), snapshot.FirstUserOnboarding.OrgSize) + require.NotNil(t, snapshot.FirstUserOnboarding.NewsletterMarketing) + require.False(t, *snapshot.FirstUserOnboarding.NewsletterMarketing) + require.NotNil(t, snapshot.FirstUserOnboarding.NewsletterReleases) + require.True(t, *snapshot.FirstUserOnboarding.NewsletterReleases) + }) + + t.Run("NilWhenOnboardingInfoOmitted", func(t *testing.T) { + t.Parallel() + + ctx := testutil.Context(t, testutil.WaitMedium) + fTelemetry := newFakeTelemetryReporter(ctx, t, 10) + client := coderdtest.New(t, &coderdtest.Options{ + TelemetryReporter: fTelemetry, + }) + + _, err := client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{ + Email: "admin@coder.com", + Username: "admin", + Password: "SomeSecurePassword!", + // No OnboardingInfo — simulates old CLI or OIDC flow. + }) + require.NoError(t, err) + + snapshot := testutil.TryReceive(ctx, t, fTelemetry.snapshots) + require.Nil(t, snapshot.FirstUserOnboarding) + }) + + t.Run("EmptyOnboardingInfoIsNonNilWithZeroFields", func(t *testing.T) { + t.Parallel() + ctx := testutil.Context(t, testutil.WaitMedium) + fTelemetry := newFakeTelemetryReporter(ctx, t, 10) + client := coderdtest.New(t, &coderdtest.Options{ + TelemetryReporter: fTelemetry, + }) + _, err := client.CreateFirstUser(ctx, codersdk.CreateFirstUserRequest{ + Email: "admin@coder.com", Username: "admin", + Password: "SomeSecurePassword!", + OnboardingInfo: &codersdk.CreateFirstUserOnboardingInfo{}, + }) + require.NoError(t, err) + snapshot := testutil.TryReceive(ctx, t, fTelemetry.snapshots) + require.NotNil(t, snapshot.FirstUserOnboarding, + "non-nil OnboardingInfo must produce non-nil telemetry") + require.Nil(t, snapshot.FirstUserOnboarding.IsBusiness, + "nil *bool must stay nil, not become false") + require.Nil(t, snapshot.FirstUserOnboarding.NewsletterMarketing) + require.Nil(t, snapshot.FirstUserOnboarding.NewsletterReleases) + require.Empty(t, snapshot.FirstUserOnboarding.IndustryType) + require.Empty(t, snapshot.FirstUserOnboarding.OrgSize) + }) +} + func TestPostLogin(t *testing.T) { t.Parallel() t.Run("InvalidUser", func(t *testing.T) { diff --git a/codersdk/users.go b/codersdk/users.go index d7a113b0f6..9935f9ec18 100644 --- a/codersdk/users.go +++ b/codersdk/users.go @@ -125,12 +125,13 @@ type LicensorTrialRequest struct { } type CreateFirstUserRequest struct { - Email string `json:"email" validate:"required,email"` - Username string `json:"username" validate:"required,username"` - Name string `json:"name" validate:"user_real_name"` - Password string `json:"password" validate:"required"` - Trial bool `json:"trial"` - TrialInfo CreateFirstUserTrialInfo `json:"trial_info"` + Email string `json:"email" validate:"required,email"` + Username string `json:"username" validate:"required,username"` + Name string `json:"name" validate:"user_real_name"` + Password string `json:"password" validate:"required"` + Trial bool `json:"trial"` + TrialInfo CreateFirstUserTrialInfo `json:"trial_info"` + OnboardingInfo *CreateFirstUserOnboardingInfo `json:"onboarding_info,omitempty"` } type CreateFirstUserTrialInfo struct { @@ -143,6 +144,55 @@ type CreateFirstUserTrialInfo struct { Developers string `json:"developers"` } +// OrgSizeRange represents a bucketed headcount range for an organization. +// These values are fixed by agreement with the frontend and the telemetry +// schema — do not change them without coordinating both sides. +type OrgSizeRange string + +const ( + OrgSizeRangeJustMe OrgSizeRange = "Just me" + OrgSizeRange2To10 OrgSizeRange = "2-10" + OrgSizeRange11To50 OrgSizeRange = "11-50" + OrgSizeRange51To200 OrgSizeRange = "51-200" + OrgSizeRange201To1K OrgSizeRange = "201-1000" + OrgSizeRange1KTo5K OrgSizeRange = "1001-5000" + OrgSizeRange5KPlus OrgSizeRange = "5000+" +) + +// IndustryType represents the industry vertical an organization operates in. +// These values are fixed by agreement with the frontend and the telemetry +// schema — do not change them without coordinating both sides. +type IndustryType string + +const ( + IndustryTypeTechnology IndustryType = "Technology" + IndustryTypeFinancial IndustryType = "Financial Services" + IndustryTypeHealthcare IndustryType = "Healthcare" + IndustryTypeGovernment IndustryType = "Government" + IndustryTypeEducation IndustryType = "Education" + IndustryTypeRetail IndustryType = "Retail" + IndustryTypeManufacturing IndustryType = "Manufacturing" + IndustryTypeMedia IndustryType = "Media" + IndustryTypeTelecom IndustryType = "Telecom" + IndustryTypeEnergy IndustryType = "Energy" + IndustryTypeTransportation IndustryType = "Transportation" + IndustryTypeConsulting IndustryType = "Consulting" + IndustryTypeNonProfit IndustryType = "Non-Profit" + IndustryTypeOther IndustryType = "Other" +) + +// CreateFirstUserOnboardingInfo contains optional demographic and +// newsletter preference data collected during first user setup. +// Pointer fields allow an explicit "no" answer to be distinguished +// from a skipped question, which matters for the telemetry schema. +type CreateFirstUserOnboardingInfo struct { + IsBusiness *bool `json:"is_business"` + IndustryType IndustryType `json:"industry_type" validate:"omitempty,oneof=Technology 'Financial Services' Healthcare Government Education Retail Manufacturing Media Telecom Energy Transportation Consulting Non-Profit Other"` + OrgSize OrgSizeRange `json:"org_size" validate:"omitempty,oneof='Just me' 2-10 11-50 51-200 201-1000 1001-5000 5000+"` + NewsletterMarketing *bool `json:"newsletter_marketing"` + NewsletterReleases *bool `json:"newsletter_releases"` +} + // CreateFirstUserResponse contains IDs for newly created user info. type CreateFirstUserResponse struct { UserID uuid.UUID `json:"user_id" format:"uuid"` diff --git a/docs/reference/api/schemas.md b/docs/reference/api/schemas.md index 7f96b4619a..276360250d 100644 --- a/docs/reference/api/schemas.md +++ b/docs/reference/api/schemas.md @@ -2246,12 +2246,48 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in | `password` | string | true | | | | `to_type` | [codersdk.LoginType](#codersdklogintype) | true | | To type is the login type to convert to. | +## codersdk.CreateFirstUserOnboardingInfo + +```json +{ + "industry_type": "Technology", + "is_business": true, + "newsletter_marketing": true, + "newsletter_releases": true, + "org_size": "Just me" +} +``` + +### Properties + +| Name | Type | Required | Restrictions | Description | +|------------------------|------------------------------------------------|----------|--------------|-------------| +| `industry_type` | [codersdk.IndustryType](#codersdkindustrytype) | false | | | +| `is_business` | boolean | false | | | +| `newsletter_marketing` | boolean | false | | | +| `newsletter_releases` | boolean | false | | | +| `org_size` | [codersdk.OrgSizeRange](#codersdkorgsizerange) | false | | | + +#### Enumerated Values + +| Property | Value(s) | +|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `industry_type` | `Consulting`, `Education`, `Energy`, `Financial Services`, `Government`, `Healthcare`, `Manufacturing`, `Media`, `Non-Profit`, `Other`, `Retail`, `Technology`, `Telecom`, `Transportation` | +| `org_size` | `1001-5000`, `11-50`, `2-10`, `201-1000`, `5000+`, `51-200`, `Just me` | + ## codersdk.CreateFirstUserRequest ```json { "email": "string", "name": "string", + "onboarding_info": { + "industry_type": "Technology", + "is_business": true, + "newsletter_marketing": true, + "newsletter_releases": true, + "org_size": "Just me" + }, "password": "string", "trial": true, "trial_info": { @@ -2269,14 +2305,15 @@ AuthorizationObject can represent a "set" of objects, such as: all workspaces in ### Properties -| Name | Type | Required | Restrictions | Description | -|--------------|------------------------------------------------------------------------|----------|--------------|-------------| -| `email` | string | true | | | -| `name` | string | false | | | -| `password` | string | true | | | -| `trial` | boolean | false | | | -| `trial_info` | [codersdk.CreateFirstUserTrialInfo](#codersdkcreatefirstusertrialinfo) | false | | | -| `username` | string | true | | | +| Name | Type | Required | Restrictions | Description | +|-------------------|----------------------------------------------------------------------------------|----------|--------------|-------------| +| `email` | string | true | | | +| `name` | string | false | | | +| `onboarding_info` | [codersdk.CreateFirstUserOnboardingInfo](#codersdkcreatefirstuseronboardinginfo) | false | | | +| `password` | string | true | | | +| `trial` | boolean | false | | | +| `trial_info` | [codersdk.CreateFirstUserTrialInfo](#codersdkcreatefirstusertrialinfo) | false | | | +| `username` | string | true | | | ## codersdk.CreateFirstUserResponse @@ -5128,6 +5165,20 @@ Only certain features set these fields: - FeatureManagedAgentLimit| | `label` | string | false | | | | `url` | string | false | | | +## codersdk.IndustryType + +```json +"Technology" +``` + +### Properties + +#### Enumerated Values + +| Value(s) | +|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| `Consulting`, `Education`, `Energy`, `Financial Services`, `Government`, `Healthcare`, `Manufacturing`, `Media`, `Non-Profit`, `Other`, `Retail`, `Technology`, `Telecom`, `Transportation` | + ## codersdk.InsightsReportInterval ```json @@ -6359,6 +6410,20 @@ Only certain features set these fields: - FeatureManagedAgentLimit| |--------------------------------------------| | `bool`, `list(string)`, `number`, `string` | +## codersdk.OrgSizeRange + +```json +"Just me" +``` + +### Properties + +#### Enumerated Values + +| Value(s) | +|------------------------------------------------------------------------| +| `1001-5000`, `11-50`, `2-10`, `201-1000`, `5000+`, `51-200`, `Just me` | + ## codersdk.Organization ```json diff --git a/docs/reference/api/users.md b/docs/reference/api/users.md index 51303309a3..9fdd458348 100644 --- a/docs/reference/api/users.md +++ b/docs/reference/api/users.md @@ -245,6 +245,13 @@ curl -X POST http://coder-server:8080/api/v2/users/first \ { "email": "string", "name": "string", + "onboarding_info": { + "industry_type": "Technology", + "is_business": true, + "newsletter_marketing": true, + "newsletter_releases": true, + "org_size": "Just me" + }, "password": "string", "trial": true, "trial_info": { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index cc8c56d182..9e8b8c3a77 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -2383,6 +2383,21 @@ export interface CreateChatRequest { readonly labels?: Record; } +// From codersdk/users.go +/** + * CreateFirstUserOnboardingInfo contains optional demographic and + * newsletter preference data collected during first user setup. + * Pointer fields allow an explicit "no" answer to be distinguished + * from a skipped question, which matters for the telemetry schema. + */ +export interface CreateFirstUserOnboardingInfo { + readonly is_business: boolean | null; + readonly industry_type: IndustryType; + readonly org_size: OrgSizeRange; + readonly newsletter_marketing: boolean | null; + readonly newsletter_releases: boolean | null; +} + // From codersdk/users.go export interface CreateFirstUserRequest { readonly email: string; @@ -2391,6 +2406,7 @@ export interface CreateFirstUserRequest { readonly password: string; readonly trial: boolean; readonly trial_info: CreateFirstUserTrialInfo; + readonly onboarding_info?: CreateFirstUserOnboardingInfo; } // From codersdk/users.go @@ -3844,6 +3860,40 @@ export const InboxNotificationFallbackIconTemplate = "DEFAULT_ICON_TEMPLATE"; // From codersdk/inboxnotification.go export const InboxNotificationFallbackIconWorkspace = "DEFAULT_ICON_WORKSPACE"; +// From codersdk/users.go +export type IndustryType = + | "Consulting" + | "Education" + | "Energy" + | "Financial Services" + | "Government" + | "Healthcare" + | "Manufacturing" + | "Media" + | "Non-Profit" + | "Other" + | "Retail" + | "Technology" + | "Telecom" + | "Transportation"; + +export const IndustryTypes: IndustryType[] = [ + "Consulting", + "Education", + "Energy", + "Financial Services", + "Government", + "Healthcare", + "Manufacturing", + "Media", + "Non-Profit", + "Other", + "Retail", + "Technology", + "Telecom", + "Transportation", +]; + // From codersdk/insights.go export type InsightsReportInterval = "day" | "week"; @@ -4786,6 +4836,26 @@ export const OptionTypes: OptionType[] = [ "string", ]; +// From codersdk/users.go +export type OrgSizeRange = + | "11-50" + | "1001-5000" + | "201-1000" + | "2-10" + | "51-200" + | "5000+" + | "Just me"; + +export const OrgSizeRanges: OrgSizeRange[] = [ + "11-50", + "1001-5000", + "201-1000", + "2-10", + "51-200", + "5000+", + "Just me", +]; + // From codersdk/organizations.go /** * Organization is the JSON representation of a Coder organization.