From 5cc1e739a8534b4f94b058ae189e637833165453 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 30 Sep 2024 09:36:06 +0200 Subject: [PATCH 1/8] chore: remove notifications experiment Signed-off-by: Danny Kopping --- cli/notifications_test.go | 1 - cli/server.go | 82 ++++++++++------------ coderd/coderd.go | 10 ++- coderd/notifications/notifications_test.go | 1 - coderd/notifications_test.go | 1 - codersdk/deployment.go | 2 +- enterprise/coderd/coderd.go | 1 - enterprise/coderd/notifications_test.go | 1 - 8 files changed, 41 insertions(+), 58 deletions(-) diff --git a/cli/notifications_test.go b/cli/notifications_test.go index 9d7ff8a37abc3..9d775c6f5842b 100644 --- a/cli/notifications_test.go +++ b/cli/notifications_test.go @@ -20,7 +20,6 @@ func createOpts(t *testing.T) *coderdtest.Options { t.Helper() dt := coderdtest.DeploymentValues(t) - dt.Experiments = []string{string(codersdk.ExperimentNotifications)} return &coderdtest.Options{ DeploymentValues: dt, } diff --git a/cli/server.go b/cli/server.go index 561c1bac16375..52af5e0a74cad 100644 --- a/cli/server.go +++ b/cli/server.go @@ -56,15 +56,16 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/sloghuman" - "github.com/coder/coder/v2/coderd/entitlements" - "github.com/coder/coder/v2/coderd/notifications/reports" - "github.com/coder/coder/v2/coderd/runtimeconfig" "github.com/coder/pretty" "github.com/coder/quartz" "github.com/coder/retry" "github.com/coder/serpent" "github.com/coder/wgtunnel/tunnelsdk" + "github.com/coder/coder/v2/coderd/entitlements" + "github.com/coder/coder/v2/coderd/notifications/reports" + "github.com/coder/coder/v2/coderd/runtimeconfig" + "github.com/coder/coder/v2/buildinfo" "github.com/coder/coder/v2/cli/clilog" "github.com/coder/coder/v2/cli/cliui" @@ -679,10 +680,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. options.OIDCConfig = oc } - experiments := coderd.ReadExperiments( - options.Logger, options.DeploymentValues.Experiments.Value(), - ) - // We'll read from this channel in the select below that tracks shutdown. If it remains // nil, that case of the select will just never fire, but it's important not to have a // "bare" read on this channel. @@ -1003,36 +1000,31 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. defer tracker.Close() // Manage notifications. - var ( - notificationsManager *notifications.Manager - ) - if experiments.Enabled(codersdk.ExperimentNotifications) { - cfg := options.DeploymentValues.Notifications - metrics := notifications.NewMetrics(options.PrometheusRegistry) - helpers := templateHelpers(options) + cfg := options.DeploymentValues.Notifications + metrics := notifications.NewMetrics(options.PrometheusRegistry) + helpers := templateHelpers(options) - // The enqueuer is responsible for enqueueing notifications to the given store. - enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal()) - if err != nil { - return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) - } - options.NotificationsEnqueuer = enqueuer + // The enqueuer is responsible for enqueueing notifications to the given store. + enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal()) + if err != nil { + return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) + } + options.NotificationsEnqueuer = enqueuer - // The notification manager is responsible for: - // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) - // - keeping the store updated with status updates - notificationsManager, err = notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) - if err != nil { - return xerrors.Errorf("failed to instantiate notification manager: %w", err) - } + // The notification manager is responsible for: + // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) + // - keeping the store updated with status updates + notificationsManager, err := notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) + if err != nil { + return xerrors.Errorf("failed to instantiate notification manager: %w", err) + } - // nolint:gocritic // TODO: create own role. - notificationsManager.Run(dbauthz.AsSystemRestricted(ctx)) + // nolint:gocritic // TODO: create own role. + notificationsManager.Run(dbauthz.AsSystemRestricted(ctx)) - // Run report generator to distribute periodic reports. - notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal()) - defer notificationReportGenerator.Close() - } + // Run report generator to distribute periodic reports. + notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal()) + defer notificationReportGenerator.Close() // Wrap the server in middleware that redirects to the access URL if // the request is not to a local IP. @@ -1153,19 +1145,17 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. // Cancel any remaining in-flight requests. shutdownConns() - if notificationsManager != nil { - // Stop the notification manager, which will cause any buffered updates to the store to be flushed. - // If the Stop() call times out, messages that were sent but not reflected as such in the store will have - // their leases expire after a period of time and will be re-queued for sending. - // See CODER_NOTIFICATIONS_LEASE_PERIOD. - cliui.Info(inv.Stdout, "Shutting down notifications manager..."+"\n") - err = shutdownWithTimeout(notificationsManager.Stop, 5*time.Second) - if err != nil { - cliui.Warnf(inv.Stderr, "Notifications manager shutdown took longer than 5s, "+ - "this may result in duplicate notifications being sent: %s\n", err) - } else { - cliui.Info(inv.Stdout, "Gracefully shut down notifications manager\n") - } + // Stop the notification manager, which will cause any buffered updates to the store to be flushed. + // If the Stop() call times out, messages that were sent but not reflected as such in the store will have + // their leases expire after a period of time and will be re-queued for sending. + // See CODER_NOTIFICATIONS_LEASE_PERIOD. + cliui.Info(inv.Stdout, "Shutting down notifications manager..."+"\n") + err = shutdownWithTimeout(notificationsManager.Stop, 5*time.Second) + if err != nil { + cliui.Warnf(inv.Stderr, "Notifications manager shutdown took longer than 5s, "+ + "this may result in duplicate notifications being sent: %s\n", err) + } else { + cliui.Info(inv.Stdout, "Gracefully shut down notifications manager\n") } // Shut down provisioners before waiting for WebSockets diff --git a/coderd/coderd.go b/coderd/coderd.go index 83a780474825b..cbe008a726636 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -37,11 +37,12 @@ import ( "tailscale.com/util/singleflight" "cdr.dev/slog" + "github.com/coder/quartz" + "github.com/coder/serpent" + "github.com/coder/coder/v2/coderd/entitlements" "github.com/coder/coder/v2/coderd/idpsync" "github.com/coder/coder/v2/coderd/runtimeconfig" - "github.com/coder/quartz" - "github.com/coder/serpent" agentproto "github.com/coder/coder/v2/agent/proto" "github.com/coder/coder/v2/buildinfo" @@ -1257,10 +1258,7 @@ func New(options *Options) *API { }) }) r.Route("/notifications", func(r chi.Router) { - r.Use( - apiKeyMiddleware, - httpmw.RequireExperiment(api.Experiments, codersdk.ExperimentNotifications), - ) + r.Use(apiKeyMiddleware) r.Get("/settings", api.notificationsSettings) r.Put("/settings", api.putNotificationsSettings) r.Route("/templates", func(r chi.Router) { diff --git a/coderd/notifications/notifications_test.go b/coderd/notifications/notifications_test.go index 6cc9c9467e9fd..ca1f4f78aad72 100644 --- a/coderd/notifications/notifications_test.go +++ b/coderd/notifications/notifications_test.go @@ -1187,7 +1187,6 @@ func createOpts(t *testing.T) *coderdtest.Options { t.Helper() dt := coderdtest.DeploymentValues(t) - dt.Experiments = []string{string(codersdk.ExperimentNotifications)} return &coderdtest.Options{ DeploymentValues: dt, } diff --git a/coderd/notifications_test.go b/coderd/notifications_test.go index 17598cd812f7f..c4f0a551d4914 100644 --- a/coderd/notifications_test.go +++ b/coderd/notifications_test.go @@ -20,7 +20,6 @@ func createOpts(t *testing.T) *coderdtest.Options { t.Helper() dt := coderdtest.DeploymentValues(t) - dt.Experiments = []string{string(codersdk.ExperimentNotifications)} return &coderdtest.Options{ DeploymentValues: dt, } diff --git a/codersdk/deployment.go b/codersdk/deployment.go index da4f3daabea06..ed4d66001d8d6 100644 --- a/codersdk/deployment.go +++ b/codersdk/deployment.go @@ -2901,7 +2901,7 @@ const ( // users to opt-in to via --experimental='*'. // Experiments that are not ready for consumption by all users should // not be included here and will be essentially hidden. -var ExperimentsAll = Experiments{ExperimentNotifications} +var ExperimentsAll = Experiments{} // Experiments is a list of experiments. // Multiple experiments may be enabled at the same time. diff --git a/enterprise/coderd/coderd.go b/enterprise/coderd/coderd.go index 5127e6ec0887f..e0b8170c6ec2a 100644 --- a/enterprise/coderd/coderd.go +++ b/enterprise/coderd/coderd.go @@ -448,7 +448,6 @@ func New(ctx context.Context, options *Options) (_ *API, err error) { // with the below route, we need to register this route without any mounts or groups to make both work. r.With( apiKeyMiddleware, - httpmw.RequireExperiment(api.AGPL.Experiments, codersdk.ExperimentNotifications), httpmw.ExtractNotificationTemplateParam(options.Database), ).Put("/notifications/templates/{notification_template}/method", api.updateNotificationTemplateMethod) }) diff --git a/enterprise/coderd/notifications_test.go b/enterprise/coderd/notifications_test.go index 5546bec1dcb79..b71bde86a5736 100644 --- a/enterprise/coderd/notifications_test.go +++ b/enterprise/coderd/notifications_test.go @@ -23,7 +23,6 @@ func createOpts(t *testing.T) *coderdenttest.Options { t.Helper() dt := coderdtest.DeploymentValues(t) - dt.Experiments = []string{string(codersdk.ExperimentNotifications)} return &coderdenttest.Options{ Options: &coderdtest.Options{ DeploymentValues: dt, From cb0be34713e0068692265acfaa51d27cabd9e42d Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 30 Sep 2024 14:19:58 +0200 Subject: [PATCH 2/8] Pass transaction into report generator to avoid deadlock Signed-off-by: Danny Kopping --- coderd/notifications/reports/generator.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coderd/notifications/reports/generator.go b/coderd/notifications/reports/generator.go index 0e5372aa8a894..2424498146c60 100644 --- a/coderd/notifications/reports/generator.go +++ b/coderd/notifications/reports/generator.go @@ -49,7 +49,7 @@ func NewReportGenerator(ctx context.Context, logger slog.Logger, db database.Sto return nil } - err = reportFailedWorkspaceBuilds(ctx, logger, db, enqueuer, clk) + err = reportFailedWorkspaceBuilds(ctx, logger, tx, enqueuer, clk) if err != nil { return xerrors.Errorf("unable to generate reports with failed workspace builds: %w", err) } From 6e7c919c79826687f7fbcda3c8497b263726c17c Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 30 Sep 2024 14:44:43 +0200 Subject: [PATCH 3/8] Only close done channel when notifier is present Signed-off-by: Danny Kopping --- coderd/notifications/manager.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/coderd/notifications/manager.go b/coderd/notifications/manager.go index 3c983b2b3ee3d..e7075ab61046e 100644 --- a/coderd/notifications/manager.go +++ b/coderd/notifications/manager.go @@ -153,7 +153,9 @@ func (m *Manager) Run(ctx context.Context) { // events, creating a notifier, and publishing bulk dispatch result updates to the store. func (m *Manager) loop(ctx context.Context) error { defer func() { - close(m.done) + if m.notifier != nil { + close(m.done) + } m.log.Info(context.Background(), "notification manager stopped") }() From 7c571aebe994de79c258f4aea32a238afb9b8f5c Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Mon, 30 Sep 2024 15:24:41 +0200 Subject: [PATCH 4/8] Reorder notification manager to avoid race with CreateInMemoryTaggedProvisionerDaemon Signed-off-by: Danny Kopping --- cli/server.go | 54 +++++++++++++++++++++++++-------------------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/cli/server.go b/cli/server.go index 52af5e0a74cad..612548372c00a 100644 --- a/cli/server.go +++ b/cli/server.go @@ -943,6 +943,33 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. return xerrors.Errorf("write config url: %w", err) } + // Manage notifications. + cfg := options.DeploymentValues.Notifications + metrics := notifications.NewMetrics(options.PrometheusRegistry) + helpers := templateHelpers(options) + + // The enqueuer is responsible for enqueueing notifications to the given store. + enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal()) + if err != nil { + return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) + } + options.NotificationsEnqueuer = enqueuer + + // The notification manager is responsible for: + // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) + // - keeping the store updated with status updates + notificationsManager, err := notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) + if err != nil { + return xerrors.Errorf("failed to instantiate notification manager: %w", err) + } + + // nolint:gocritic // TODO: create own role. + notificationsManager.Run(dbauthz.AsSystemRestricted(ctx)) + + // Run report generator to distribute periodic reports. + notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal()) + defer notificationReportGenerator.Close() + // Since errCh only has one buffered slot, all routines // sending on it must be wrapped in a select/default to // avoid leaving dangling goroutines waiting for the @@ -999,33 +1026,6 @@ func (r *RootCmd) Server(newAPI func(context.Context, *coderd.Options) (*coderd. options.WorkspaceUsageTracker = tracker defer tracker.Close() - // Manage notifications. - cfg := options.DeploymentValues.Notifications - metrics := notifications.NewMetrics(options.PrometheusRegistry) - helpers := templateHelpers(options) - - // The enqueuer is responsible for enqueueing notifications to the given store. - enqueuer, err := notifications.NewStoreEnqueuer(cfg, options.Database, helpers, logger.Named("notifications.enqueuer"), quartz.NewReal()) - if err != nil { - return xerrors.Errorf("failed to instantiate notification store enqueuer: %w", err) - } - options.NotificationsEnqueuer = enqueuer - - // The notification manager is responsible for: - // - creating notifiers and managing their lifecycles (notifiers are responsible for dequeueing/sending notifications) - // - keeping the store updated with status updates - notificationsManager, err := notifications.NewManager(cfg, options.Database, helpers, metrics, logger.Named("notifications.manager")) - if err != nil { - return xerrors.Errorf("failed to instantiate notification manager: %w", err) - } - - // nolint:gocritic // TODO: create own role. - notificationsManager.Run(dbauthz.AsSystemRestricted(ctx)) - - // Run report generator to distribute periodic reports. - notificationReportGenerator := reports.NewReportGenerator(ctx, logger.Named("notifications.report_generator"), options.Database, options.NotificationsEnqueuer, quartz.NewReal()) - defer notificationReportGenerator.Close() - // Wrap the server in middleware that redirects to the access URL if // the request is not to a local IP. var handler http.Handler = coderAPI.RootHandler From 0107ad16dc7c6501e186f2f427fe427a5ef587aa Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 1 Oct 2024 12:04:20 +0200 Subject: [PATCH 5/8] Remove experiment reference & show beta badge in frontend Signed-off-by: Danny Kopping --- .../FeatureStageBadge/FeatureStageBadge.tsx | 2 +- .../NotificationsPage/NotificationsPage.tsx | 1 + site/src/pages/DeploySettingsPage/Sidebar.tsx | 9 +++-- .../ManagementSettingsPage/SidebarView.tsx | 5 +-- site/src/pages/UserSettingsPage/Section.tsx | 36 +++++++++++++------ site/src/pages/UserSettingsPage/Sidebar.tsx | 8 ++--- 6 files changed, 38 insertions(+), 23 deletions(-) diff --git a/site/src/components/FeatureStageBadge/FeatureStageBadge.tsx b/site/src/components/FeatureStageBadge/FeatureStageBadge.tsx index 52cdfaeb01a11..763b180d03bbe 100644 --- a/site/src/components/FeatureStageBadge/FeatureStageBadge.tsx +++ b/site/src/components/FeatureStageBadge/FeatureStageBadge.tsx @@ -10,7 +10,7 @@ import { docs } from "utils/docs"; * All types of feature that we are currently supporting. Defined as record to * ensure that we can't accidentally make typos when writing the badge text. */ -const featureStageBadgeTypes = { +export const featureStageBadgeTypes = { beta: "beta", experimental: "experimental", } as const satisfies Record; diff --git a/site/src/pages/DeploySettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/DeploySettingsPage/NotificationsPage/NotificationsPage.tsx index c073792248072..511959d3ec55f 100644 --- a/site/src/pages/DeploySettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/DeploySettingsPage/NotificationsPage/NotificationsPage.tsx @@ -43,6 +43,7 @@ export const NotificationsPage: FC = () => { title="Notifications" description="Control delivery methods for notifications on this deployment." layout="fluid" + featureStage={"beta"} > diff --git a/site/src/pages/DeploySettingsPage/Sidebar.tsx b/site/src/pages/DeploySettingsPage/Sidebar.tsx index 607920d65ee2f..88e6ecd0d8e61 100644 --- a/site/src/pages/DeploySettingsPage/Sidebar.tsx +++ b/site/src/pages/DeploySettingsPage/Sidebar.tsx @@ -14,6 +14,7 @@ import { } from "components/Sidebar/Sidebar"; import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; +import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge"; export const Sidebar: FC = () => { const { experiments } = useDashboard(); @@ -51,11 +52,9 @@ export const Sidebar: FC = () => { Observability - {experiments.includes("notifications") && ( - - Notifications - - )} + + Notifications + ); }; diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx index f76b4da5b339f..817c59ac3b00f 100644 --- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx +++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx @@ -148,11 +148,12 @@ const DeploymentSettingsNavigation: FC = ({ Users )} - {experiments.includes("notifications") && ( + Notifications - )} + + )} diff --git a/site/src/pages/UserSettingsPage/Section.tsx b/site/src/pages/UserSettingsPage/Section.tsx index edc2740537fbc..8c52aca1eb9cb 100644 --- a/site/src/pages/UserSettingsPage/Section.tsx +++ b/site/src/pages/UserSettingsPage/Section.tsx @@ -1,4 +1,9 @@ import type { Interpolation, Theme } from "@emotion/react"; +import { + FeatureStageBadge, + type featureStageBadgeTypes, +} from "components/FeatureStageBadge/FeatureStageBadge"; +import { Stack } from "components/Stack/Stack"; import type { FC, ReactNode } from "react"; type SectionLayout = "fixed" | "fluid"; @@ -13,6 +18,7 @@ export interface SectionProps { layout?: SectionLayout; className?: string; children?: ReactNode; + featureStage?: keyof typeof featureStageBadgeTypes; } export const Section: FC = ({ @@ -24,6 +30,7 @@ export const Section: FC = ({ className = "", children, layout = "fixed", + featureStage, }) => { return (
@@ -32,16 +39,25 @@ export const Section: FC = ({
{title && ( -

- {title} -

+ +

+ {title} +

+ {featureStage && ( + + )} +
)} {description && typeof description === "string" && (

{description}

diff --git a/site/src/pages/UserSettingsPage/Sidebar.tsx b/site/src/pages/UserSettingsPage/Sidebar.tsx index 2580e00f02e07..8f6e54230e8a5 100644 --- a/site/src/pages/UserSettingsPage/Sidebar.tsx +++ b/site/src/pages/UserSettingsPage/Sidebar.tsx @@ -57,11 +57,9 @@ export const Sidebar: FC = ({ user }) => { Tokens - {experiments.includes("notifications") && ( - - Notifications - - )} + + Notifications + ); }; From 0aa6d7becd3bccedef2d4e9074e59c4c2db7a34d Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 1 Oct 2024 12:22:37 +0200 Subject: [PATCH 6/8] Ensuring done channel cannot be closed twice Signed-off-by: Danny Kopping --- coderd/notifications/manager.go | 9 ++++++--- site/src/pages/DeploySettingsPage/Sidebar.tsx | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/coderd/notifications/manager.go b/coderd/notifications/manager.go index e7075ab61046e..8b765bbe88c33 100644 --- a/coderd/notifications/manager.go +++ b/coderd/notifications/manager.go @@ -54,6 +54,7 @@ type Manager struct { runOnce sync.Once stopOnce sync.Once + doneOnce sync.Once stop chan any done chan any @@ -153,9 +154,9 @@ func (m *Manager) Run(ctx context.Context) { // events, creating a notifier, and publishing bulk dispatch result updates to the store. func (m *Manager) loop(ctx context.Context) error { defer func() { - if m.notifier != nil { + m.doneOnce.Do(func() { close(m.done) - } + }) m.log.Info(context.Background(), "notification manager stopped") }() @@ -366,7 +367,9 @@ func (m *Manager) Stop(ctx context.Context) error { // If the notifier hasn't been started, we don't need to wait for anything. // This is only really during testing when we want to enqueue messages only but not deliver them. if m.notifier == nil { - close(m.done) + m.doneOnce.Do(func() { + close(m.done) + }) } else { m.notifier.stop() } diff --git a/site/src/pages/DeploySettingsPage/Sidebar.tsx b/site/src/pages/DeploySettingsPage/Sidebar.tsx index 88e6ecd0d8e61..1f1172834a5fa 100644 --- a/site/src/pages/DeploySettingsPage/Sidebar.tsx +++ b/site/src/pages/DeploySettingsPage/Sidebar.tsx @@ -7,6 +7,7 @@ import NotificationsIcon from "@mui/icons-material/NotificationsNoneOutlined"; import Globe from "@mui/icons-material/PublicOutlined"; import ApprovalIcon from "@mui/icons-material/VerifiedUserOutlined"; import VpnKeyOutlined from "@mui/icons-material/VpnKeyOutlined"; +import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge"; import { GitIcon } from "components/Icons/GitIcon"; import { Sidebar as BaseSidebar, @@ -14,7 +15,6 @@ import { } from "components/Sidebar/Sidebar"; import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; -import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge"; export const Sidebar: FC = () => { const { experiments } = useDashboard(); From bf1a148f3e50e7ba164fdd051e38a16dd9c498c3 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 1 Oct 2024 15:25:34 +0200 Subject: [PATCH 7/8] Beta tag on account notification settings pages Signed-off-by: Danny Kopping --- site/src/pages/ManagementSettingsPage/SidebarView.tsx | 2 +- .../UserSettingsPage/NotificationsPage/NotificationsPage.tsx | 1 + site/src/pages/UserSettingsPage/Sidebar.tsx | 3 ++- 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/site/src/pages/ManagementSettingsPage/SidebarView.tsx b/site/src/pages/ManagementSettingsPage/SidebarView.tsx index 817c59ac3b00f..37db583f23ba0 100644 --- a/site/src/pages/ManagementSettingsPage/SidebarView.tsx +++ b/site/src/pages/ManagementSettingsPage/SidebarView.tsx @@ -148,7 +148,7 @@ const DeploymentSettingsNavigation: FC = ({ Users )} - + Notifications diff --git a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx index 49f01f1f00936..c67737fc00530 100644 --- a/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx +++ b/site/src/pages/UserSettingsPage/NotificationsPage/NotificationsPage.tsx @@ -99,6 +99,7 @@ export const NotificationsPage: FC = () => { title="Notifications" description="Configure your notification preferences. Icons on the right of each notification indicate delivery method, either SMTP or Webhook." layout="fluid" + featureStage="beta" > {ready ? ( diff --git a/site/src/pages/UserSettingsPage/Sidebar.tsx b/site/src/pages/UserSettingsPage/Sidebar.tsx index 8f6e54230e8a5..ee1c63062e033 100644 --- a/site/src/pages/UserSettingsPage/Sidebar.tsx +++ b/site/src/pages/UserSettingsPage/Sidebar.tsx @@ -15,6 +15,7 @@ import { import { UserAvatar } from "components/UserAvatar/UserAvatar"; import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; +import {FeatureStageBadge} from "components/FeatureStageBadge/FeatureStageBadge"; interface SidebarProps { user: User; @@ -58,7 +59,7 @@ export const Sidebar: FC = ({ user }) => { Tokens - Notifications + Notifications ); From 27d28b358b07a61f4fbca8c78474442393dd7569 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Tue, 1 Oct 2024 15:29:51 +0200 Subject: [PATCH 8/8] make fmt Signed-off-by: Danny Kopping --- site/src/pages/UserSettingsPage/Sidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/site/src/pages/UserSettingsPage/Sidebar.tsx b/site/src/pages/UserSettingsPage/Sidebar.tsx index ee1c63062e033..196f34d5ce0e1 100644 --- a/site/src/pages/UserSettingsPage/Sidebar.tsx +++ b/site/src/pages/UserSettingsPage/Sidebar.tsx @@ -6,6 +6,7 @@ import NotificationsIcon from "@mui/icons-material/NotificationsNoneOutlined"; import AccountIcon from "@mui/icons-material/Person"; import VpnKeyOutlined from "@mui/icons-material/VpnKeyOutlined"; import type { User } from "api/typesGenerated"; +import { FeatureStageBadge } from "components/FeatureStageBadge/FeatureStageBadge"; import { GitIcon } from "components/Icons/GitIcon"; import { Sidebar as BaseSidebar, @@ -15,7 +16,6 @@ import { import { UserAvatar } from "components/UserAvatar/UserAvatar"; import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; -import {FeatureStageBadge} from "components/FeatureStageBadge/FeatureStageBadge"; interface SidebarProps { user: User;