diff --git a/cli/exp_taskcreate.go b/cli/exp_taskcreate.go index 40f45a903c85b..9125b86329746 100644 --- a/cli/exp_taskcreate.go +++ b/cli/exp_taskcreate.go @@ -23,7 +23,7 @@ func (r *RootCmd) taskCreate() *serpent.Command { taskInput string ) - return &serpent.Command{ + cmd := &serpent.Command{ Use: "create [template]", Short: "Create an experimental task", Middleware: serpent.Chain( @@ -123,4 +123,6 @@ func (r *RootCmd) taskCreate() *serpent.Command { return nil }, } + orgContext.AttachOptions(cmd) + return cmd } diff --git a/cli/exp_taskcreate_test.go b/cli/exp_taskcreate_test.go index 520838c53acca..121f22eb525f6 100644 --- a/cli/exp_taskcreate_test.go +++ b/cli/exp_taskcreate_test.go @@ -29,12 +29,13 @@ func TestTaskCreate(t *testing.T) { taskCreatedAt = time.Now() organizationID = uuid.New() + anotherOrganizationID = uuid.New() templateID = uuid.New() templateVersionID = uuid.New() templateVersionPresetID = uuid.New() ) - templateAndVersionFoundHandler := func(t *testing.T, ctx context.Context, templateName, templateVersionName, presetName, prompt string) http.HandlerFunc { + templateAndVersionFoundHandler := func(t *testing.T, ctx context.Context, orgID uuid.UUID, templateName, templateVersionName, presetName, prompt string) http.HandlerFunc { t.Helper() return func(w http.ResponseWriter, r *http.Request) { @@ -42,14 +43,14 @@ func TestTaskCreate(t *testing.T) { case "/api/v2/users/me/organizations": httpapi.Write(ctx, w, http.StatusOK, []codersdk.Organization{ {MinimalOrganization: codersdk.MinimalOrganization{ - ID: organizationID, + ID: orgID, }}, }) - case fmt.Sprintf("/api/v2/organizations/%s/templates/my-template/versions/my-template-version", organizationID): + case fmt.Sprintf("/api/v2/organizations/%s/templates/my-template/versions/my-template-version", orgID): httpapi.Write(ctx, w, http.StatusOK, codersdk.TemplateVersion{ ID: templateVersionID, }) - case fmt.Sprintf("/api/v2/organizations/%s/templates/my-template", organizationID): + case fmt.Sprintf("/api/v2/organizations/%s/templates/my-template", orgID): httpapi.Write(ctx, w, http.StatusOK, codersdk.Template{ ID: templateID, ActiveVersionID: templateVersionID, @@ -94,47 +95,47 @@ func TestTaskCreate(t *testing.T) { handler func(t *testing.T, ctx context.Context) http.HandlerFunc }{ { - args: []string{"my-template@my-template-version", "--input", "my custom prompt"}, + args: []string{"my-template@my-template-version", "--input", "my custom prompt", "--org", organizationID.String()}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "my-template-version", "", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "my-template-version", "", "my custom prompt") }, }, { - args: []string{"my-template", "--input", "my custom prompt"}, + args: []string{"my-template", "--input", "my custom prompt", "--org", organizationID.String()}, env: []string{"CODER_TASK_TEMPLATE_VERSION=my-template-version"}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "my-template-version", "", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "my-template-version", "", "my custom prompt") }, }, { - args: []string{"--input", "my custom prompt"}, + args: []string{"--input", "my custom prompt", "--org", organizationID.String()}, env: []string{"CODER_TASK_TEMPLATE_NAME=my-template", "CODER_TASK_TEMPLATE_VERSION=my-template-version"}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "my-template-version", "", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "my-template-version", "", "my custom prompt") }, }, { - env: []string{"CODER_TASK_TEMPLATE_NAME=my-template", "CODER_TASK_TEMPLATE_VERSION=my-template-version", "CODER_TASK_INPUT=my custom prompt"}, + env: []string{"CODER_TASK_TEMPLATE_NAME=my-template", "CODER_TASK_TEMPLATE_VERSION=my-template-version", "CODER_TASK_INPUT=my custom prompt", "CODER_ORGANIZATION=" + organizationID.String()}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "my-template-version", "", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "my-template-version", "", "my custom prompt") }, }, { - args: []string{"my-template", "--input", "my custom prompt"}, + args: []string{"my-template", "--input", "my custom prompt", "--org", organizationID.String()}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "", "", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "", "", "my custom prompt") }, }, { - args: []string{"my-template", "--input", "my custom prompt", "--preset", "my-preset"}, + args: []string{"my-template", "--input", "my custom prompt", "--preset", "my-preset", "--org", organizationID.String()}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "", "my-preset", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "", "my-preset", "my custom prompt") }, }, { @@ -142,14 +143,14 @@ func TestTaskCreate(t *testing.T) { env: []string{"CODER_TASK_PRESET_NAME=my-preset"}, expectOutput: fmt.Sprintf("The task %s has been created at %s!", cliui.Keyword("task-wild-goldfish-27"), cliui.Timestamp(taskCreatedAt)), handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "", "my-preset", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "", "my-preset", "my custom prompt") }, }, { args: []string{"my-template", "--input", "my custom prompt", "--preset", "not-real-preset"}, expectError: `preset "not-real-preset" not found`, handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { - return templateAndVersionFoundHandler(t, ctx, "my-template", "", "my-preset", "my custom prompt") + return templateAndVersionFoundHandler(t, ctx, organizationID, "my-template", "", "my-preset", "my custom prompt") }, }, { @@ -173,7 +174,7 @@ func TestTaskCreate(t *testing.T) { }, }, { - args: []string{"not-real-template", "--input", "my custom prompt"}, + args: []string{"not-real-template", "--input", "my custom prompt", "--org", organizationID.String()}, expectError: httpapi.ResourceNotFoundResponse.Message, handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { @@ -192,6 +193,40 @@ func TestTaskCreate(t *testing.T) { } }, }, + { + args: []string{"template-in-different-org", "--input", "my-custom-prompt", "--org", anotherOrganizationID.String()}, + expectError: httpapi.ResourceNotFoundResponse.Message, + handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/api/v2/users/me/organizations": + httpapi.Write(ctx, w, http.StatusOK, []codersdk.Organization{ + {MinimalOrganization: codersdk.MinimalOrganization{ + ID: anotherOrganizationID, + }}, + }) + case fmt.Sprintf("/api/v2/organizations/%s/templates/template-in-different-org", anotherOrganizationID): + httpapi.ResourceNotFound(w) + default: + t.Errorf("unexpected path: %s", r.URL.Path) + } + } + }, + }, + { + args: []string{"no-org", "--input", "my-custom-prompt"}, + expectError: "Must select an organization with --org=", + handler: func(t *testing.T, ctx context.Context) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + switch r.URL.Path { + case "/api/v2/users/me/organizations": + httpapi.Write(ctx, w, http.StatusOK, []codersdk.Organization{}) + default: + t.Errorf("unexpected path: %s", r.URL.Path) + } + } + }, + }, } for _, tt := range tests { diff --git a/coderd/httpmw/loggermw/logger.go b/coderd/httpmw/loggermw/logger.go index 8f21f9aa32123..37e15b3bfcf81 100644 --- a/coderd/httpmw/loggermw/logger.go +++ b/coderd/httpmw/loggermw/logger.go @@ -4,6 +4,9 @@ import ( "context" "fmt" "net/http" + "net/url" + "strconv" + "strings" "sync" "time" @@ -15,6 +18,59 @@ import ( "github.com/coder/coder/v2/coderd/tracing" ) +var ( + safeParams = []string{"page", "limit", "offset"} + countParams = []string{"ids", "template_ids"} +) + +func safeQueryParams(params url.Values) []slog.Field { + if len(params) == 0 { + return nil + } + + fields := make([]slog.Field, 0, len(params)) + for key, values := range params { + // Check if this parameter should be included + for _, pattern := range safeParams { + if strings.EqualFold(key, pattern) { + // Prepend query parameters in the log line to ensure we don't have issues with collisions + // in case any other internal logging fields already log fields with similar names + fieldName := "query_" + key + + // Log the actual values for non-sensitive parameters + if len(values) == 1 { + fields = append(fields, slog.F(fieldName, values[0])) + continue + } + fields = append(fields, slog.F(fieldName, values)) + } + } + // Some query params we just want to log the count of the params length + for _, pattern := range countParams { + if !strings.EqualFold(key, pattern) { + continue + } + count := 0 + + // Prepend query parameters in the log line to ensure we don't have issues with collisions + // in case any other internal logging fields already log fields with similar names + fieldName := "query_" + key + + // Count comma-separated values for CSV format + for _, v := range values { + if strings.Contains(v, ",") { + count += len(strings.Split(v, ",")) + continue + } + count++ + } + // For logging we always want strings + fields = append(fields, slog.F(fieldName+"_count", strconv.Itoa(count))) + } + } + return fields +} + func Logger(log slog.Logger) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { @@ -39,6 +95,11 @@ func Logger(log slog.Logger) func(next http.Handler) http.Handler { slog.F("start", start), ) + // Add safe query parameters to the log + if queryFields := safeQueryParams(r.URL.Query()); len(queryFields) > 0 { + httplog = httplog.With(queryFields...) + } + logContext := NewRequestLogger(httplog, r.Method, start) ctx := WithRequestLogger(r.Context(), logContext) diff --git a/coderd/httpmw/loggermw/logger_internal_test.go b/coderd/httpmw/loggermw/logger_internal_test.go index f372c665fda14..bf090464241a0 100644 --- a/coderd/httpmw/loggermw/logger_internal_test.go +++ b/coderd/httpmw/loggermw/logger_internal_test.go @@ -4,6 +4,7 @@ import ( "context" "net/http" "net/http/httptest" + "net/url" "slices" "strings" "sync" @@ -292,6 +293,76 @@ func TestRequestLogger_RouteParamsLogging(t *testing.T) { } } +func TestSafeQueryParams(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + params url.Values + expected map[string]interface{} + }{ + { + name: "safe parameters", + params: url.Values{ + "page": []string{"1"}, + "limit": []string{"10"}, + "filter": []string{"active"}, + "sort": []string{"name"}, + "offset": []string{"2"}, + "ids": []string{"some-id,another-id", "second-param"}, + "template_ids": []string{"some-id,another-id", "second-param"}, + }, + expected: map[string]interface{}{ + "query_page": "1", + "query_limit": "10", + "query_offset": "2", + "query_ids_count": "3", + "query_template_ids_count": "3", + }, + }, + { + name: "unknown/sensitive parameters", + params: url.Values{ + "token": []string{"secret-token"}, + "api_key": []string{"secret-key"}, + "coder_signed_app_token": []string{"jwt-token"}, + "coder_application_connect_api_key": []string{"encrypted-key"}, + "client_secret": []string{"oauth-secret"}, + "code": []string{"auth-code"}, + }, + expected: map[string]interface{}{}, + }, + { + name: "mixed parameters", + params: url.Values{ + "page": []string{"1"}, + "token": []string{"secret"}, + "filter": []string{"active"}, + }, + expected: map[string]interface{}{ + "query_page": "1", + }, + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + + fields := safeQueryParams(tt.params) + + // Convert fields to map for easier comparison + result := make(map[string]interface{}) + for _, field := range fields { + result[field.Name] = field.Value + } + + require.Equal(t, tt.expected, result) + }) + } +} + type fakeSink struct { entries []slog.SinkEntry newEntries chan slog.SinkEntry diff --git a/site/src/components/Sidebar/Sidebar.tsx b/site/src/components/Sidebar/Sidebar.tsx index ab289a7d7e0e8..4f626b8802354 100644 --- a/site/src/components/Sidebar/Sidebar.tsx +++ b/site/src/components/Sidebar/Sidebar.tsx @@ -5,10 +5,11 @@ import { cn } from "utils/cn"; interface SidebarProps { children?: ReactNode; + className?: string; } -export const Sidebar: FC = ({ children }) => { - return ; +export const Sidebar: FC = ({ className, children }) => { + return ; }; interface SidebarHeaderProps { diff --git a/site/src/modules/dashboard/DashboardLayout.tsx b/site/src/modules/dashboard/DashboardLayout.tsx index 1bbf5347e085e..1b3c5945b4c0d 100644 --- a/site/src/modules/dashboard/DashboardLayout.tsx +++ b/site/src/modules/dashboard/DashboardLayout.tsx @@ -23,10 +23,10 @@ export const DashboardLayout: FC = () => { {canViewDeployment && } -
+
-
+
}> diff --git a/site/src/modules/management/OrganizationSettingsLayout.tsx b/site/src/modules/management/OrganizationSettingsLayout.tsx index edbe759e0d5fb..46947c750bca6 100644 --- a/site/src/modules/management/OrganizationSettingsLayout.tsx +++ b/site/src/modules/management/OrganizationSettingsLayout.tsx @@ -91,7 +91,7 @@ const OrganizationSettingsLayout: FC = () => { organizationPermissions, }} > -
+
@@ -121,8 +121,8 @@ const OrganizationSettingsLayout: FC = () => { )} -
-
+
+
}> diff --git a/site/src/modules/management/OrganizationSidebar.tsx b/site/src/modules/management/OrganizationSidebar.tsx index 4f77348eefa93..ebcc5e13ce5bf 100644 --- a/site/src/modules/management/OrganizationSidebar.tsx +++ b/site/src/modules/management/OrganizationSidebar.tsx @@ -13,7 +13,7 @@ export const OrganizationSidebar: FC = () => { useOrganizationSettings(); return ( - + { return ( -
+
-
+
}> diff --git a/site/src/pages/AuditPage/AuditPageView.tsx b/site/src/pages/AuditPage/AuditPageView.tsx index f69e62581d202..ed19092c0a640 100644 --- a/site/src/pages/AuditPage/AuditPageView.tsx +++ b/site/src/pages/AuditPage/AuditPageView.tsx @@ -57,7 +57,7 @@ export const AuditPageView: FC = ({ const isEmpty = !isLoading && auditLogs?.length === 0; return ( - + diff --git a/site/src/pages/ConnectionLogPage/ConnectionLogPageView.tsx b/site/src/pages/ConnectionLogPage/ConnectionLogPageView.tsx index fe3840d098aaa..0fcadf085f7ff 100644 --- a/site/src/pages/ConnectionLogPage/ConnectionLogPageView.tsx +++ b/site/src/pages/ConnectionLogPage/ConnectionLogPageView.tsx @@ -56,7 +56,7 @@ export const ConnectionLogPageView: FC = ({ const isEmpty = !isLoading && connectionLogs?.length === 0; return ( - + diff --git a/site/src/pages/CreateTemplateGalleryPage/CreateTemplateGalleryPageView.tsx b/site/src/pages/CreateTemplateGalleryPage/CreateTemplateGalleryPageView.tsx index 0ac220d4bcf67..0dfdb4a219504 100644 --- a/site/src/pages/CreateTemplateGalleryPage/CreateTemplateGalleryPageView.tsx +++ b/site/src/pages/CreateTemplateGalleryPage/CreateTemplateGalleryPageView.tsx @@ -24,7 +24,7 @@ export const CreateTemplateGalleryPageView: FC< CreateTemplateGalleryPageViewProps > = ({ starterTemplatesByTag, error }) => { return ( - + diff --git a/site/src/pages/GroupsPage/GroupsPage.tsx b/site/src/pages/GroupsPage/GroupsPage.tsx index c5089cbad1e6b..64459955c91ec 100644 --- a/site/src/pages/GroupsPage/GroupsPage.tsx +++ b/site/src/pages/GroupsPage/GroupsPage.tsx @@ -76,7 +76,7 @@ const GroupsPage: FC = () => { } return ( - <> +
{helmet} { canCreateGroup={permissions.createGroup} groupsEnabled={groupsEnabled} /> - +
); }; diff --git a/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx b/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx index ff197cc52aad6..92cfa5b404efa 100644 --- a/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/CustomRolesPage/CustomRolesPage.tsx @@ -58,7 +58,7 @@ const CustomRolesPage: FC = () => { } return ( - <> +
{pageTitle( @@ -116,7 +116,7 @@ const CustomRolesPage: FC = () => { }} /> </RequirePermission> - </> + </div> ); }; diff --git a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx index 59a086a024b9a..ea9604a385621 100644 --- a/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/IdpSyncPage/IdpSyncPage.tsx @@ -117,7 +117,7 @@ const IdpSyncPage: FC = () => { } return ( - <> + <div className="w-full max-w-screen-2xl pb-10"> {helmet} <div className="flex flex-col gap-12"> @@ -182,7 +182,7 @@ const IdpSyncPage: FC = () => { </Cond> </ChooseOne> </div> - </> + </div> ); }; diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx index f2c270cd929af..2e226f79f8066 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPage.tsx @@ -1,4 +1,3 @@ -import type { Interpolation, Theme } from "@emotion/react"; import { getErrorMessage } from "api/errors"; import { groupsByUserIdInOrganization } from "api/queries/groups"; import { @@ -156,9 +155,7 @@ const OrganizationMembersPage: FC = () => { </ul> </p> - <p css={styles.test}> - Are you sure you want to remove this member? - </p> + <p className="pb-5">Are you sure you want to remove this member?</p> </Stack> } /> @@ -166,10 +163,4 @@ const OrganizationMembersPage: FC = () => { ); }; -const styles = { - test: { - paddingBottom: 20, - }, -} satisfies Record<string, Interpolation<Theme>>; - export default OrganizationMembersPage; diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx index 7f8ed8e92ea17..f720ba692d0ca 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationMembersPageView.tsx @@ -81,7 +81,7 @@ export const OrganizationMembersPageView: FC< updateMemberRoles, }) => { return ( - <div> + <div className="w-full max-w-screen-2xl pb-10"> <SettingsHeader> <SettingsHeaderTitle>Members</SettingsHeaderTitle> </SettingsHeader> diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerJobsPage/OrganizationProvisionerJobsPageView.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerJobsPage/OrganizationProvisionerJobsPageView.tsx index 8b6a2a839b8af..f54cb163e3eea 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerJobsPage/OrganizationProvisionerJobsPageView.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerJobsPage/OrganizationProvisionerJobsPageView.tsx @@ -99,7 +99,7 @@ const OrganizationProvisionerJobsPageView: FC< } return ( - <> + <div className="w-full max-w-screen-2xl pb-10"> <Helmet> <title> {pageTitle( @@ -227,7 +227,7 @@ const OrganizationProvisionerJobsPageView: FC< </TableBody> </Table> </section> - </> + </div> ); }; diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerKeysPage/OrganizationProvisionerKeysPageView.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerKeysPage/OrganizationProvisionerKeysPageView.tsx index 6d5b1be3552ea..a8812cb603051 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerKeysPage/OrganizationProvisionerKeysPageView.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationProvisionerKeysPage/OrganizationProvisionerKeysPageView.tsx @@ -45,7 +45,7 @@ export const OrganizationProvisionerKeysPageView: FC< OrganizationProvisionerKeysPageViewProps > = ({ showPaywall, provisionerKeyDaemons, error, onRetry }) => { return ( - <section> + <section className="w-full max-w-screen-2xl pb-10"> <SettingsHeader> <SettingsHeaderTitle>Provisioner Keys</SettingsHeaderTitle> <SettingsHeaderDescription> diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationProvisionersPage/OrganizationProvisionersPageView.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationProvisionersPage/OrganizationProvisionersPageView.tsx index ac6e45aed24cf..386d87d8c1324 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationProvisionersPage/OrganizationProvisionersPageView.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationProvisionersPage/OrganizationProvisionersPageView.tsx @@ -58,7 +58,7 @@ export const OrganizationProvisionersPageView: FC< onRetry, }) => { return ( - <section> + <section className="w-full max-w-screen-2xl pb-10"> <SettingsHeader> <SettingsHeaderTitle>Provisioners</SettingsHeaderTitle> <SettingsHeaderDescription> diff --git a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPageView.tsx b/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPageView.tsx index 16bc561efcc7d..a5891df618471 100644 --- a/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPageView.tsx +++ b/site/src/pages/OrganizationSettingsPage/OrganizationSettingsPageView.tsx @@ -68,7 +68,7 @@ export const OrganizationSettingsPageView: FC< const [isDeleting, setIsDeleting] = useState(false); return ( - <div> + <div className="w-full max-w-screen-2xl pb-10"> <SettingsHeader> <SettingsHeaderTitle>Settings</SettingsHeaderTitle> </SettingsHeader> diff --git a/site/src/pages/TemplatePage/TemplateLayout.tsx b/site/src/pages/TemplatePage/TemplateLayout.tsx index c6b9f81945f30..57fad23dc975f 100644 --- a/site/src/pages/TemplatePage/TemplateLayout.tsx +++ b/site/src/pages/TemplatePage/TemplateLayout.tsx @@ -108,7 +108,7 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ if (error || workspacePermissionsQuery.error) { return ( - <div css={{ margin: 16 }}> + <div className="p-4"> <ErrorAlert error={error} /> </div> ); @@ -119,7 +119,7 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ } return ( - <> + <div className="pb-12"> <TemplatePageHeader template={data.template} activeVersion={data.activeVersion} @@ -166,6 +166,6 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ <Suspense fallback={<Loader />}>{children}</Suspense> </TemplateLayoutContext.Provider> </Margins> - </> + </div> ); }; diff --git a/site/src/pages/TemplatesPage/TemplatesPageView.tsx b/site/src/pages/TemplatesPage/TemplatesPageView.tsx index c8e391a7ebc2b..a37cb31232816 100644 --- a/site/src/pages/TemplatesPage/TemplatesPageView.tsx +++ b/site/src/pages/TemplatesPage/TemplatesPageView.tsx @@ -205,7 +205,7 @@ export const TemplatesPageView: FC<TemplatesPageViewProps> = ({ const isEmpty = templates && templates.length === 0; return ( - <Margins> + <Margins className="pb-12"> <PageHeader actions={ canCreateTemplates && ( diff --git a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx index 43db670850a49..aa10f315b6f2d 100644 --- a/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx +++ b/site/src/pages/UserSettingsPage/AppearancePage/AppearanceForm.tsx @@ -21,6 +21,7 @@ import { terminalFontLabels, terminalFonts, } from "theme/constants"; +import { cn } from "utils/cn"; import { Section } from "../Section"; interface AppearanceFormProps { @@ -164,7 +165,7 @@ const AutoThemePreviewButton: FC<AutoThemePreviewButtonProps> = ({ onChange={onSelect} css={{ ...visuallyHidden }} /> - <label htmlFor={displayName} className={className}> + <label htmlFor={displayName} className={cn("relative", className)}> <ThemePreview css={{ // This half is absolute to not advance the layout (which would offset the second half)