ronantakizawa/codereview-bench huggingface dataset:
Repository: strapi/strapi
File: packages/core/content-manager/admin/src/pages/EditView/components/FormInputs/Relations/RelationModal.tsx (TypeScript)

Code before:
const getAdminBasePath = () => {
  return (process.env.ADMIN_PATH ?? '').replace(window.location.origin, '');
};

const RelationModalTrigger = ({
  children,
  relation,
}: {
  children: React.ReactNode;
  relation: DocumentMeta;
}) => {
  const dispatch = useRelationModal('ModalTrigger', (state) => state.dispatch);
  const relationOpenMode = useRelationModal(
    'ModalTrigger',
    (state) => state.relationOpenMode
  );
  const navigate = useNavigate();

  const handleClick = () => {
    const fullPageUrl = getFullPageUrl(relation);

    switch (relationOpenMode) {
      case 'page':
        navigate(fullPageUrl);
        break;
      case 'newTab':
        window.open(`${getAdminBasePath()}${fullPageUrl}`, '_blank');
        break;
      case 'modal':
      default:
        dispatch({
          type: 'GO_TO_RELATION',
          payload: { document: relation, shouldBypassConfirmation: false },
        });
        break;
    }
  };

  return <StyledTextButton onClick={handleClick}>{children}</StyledTextButton>;
};

const StyledTextButton = styled(TextButton)`
  max-width: 100%;
  & > span {
    font-size: ${({ theme }) => theme.fontSizes[2]};
    width: inherit;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
`;

Review comment (suggestion):
`window.open` doesn't seem to be a common pattern we use. Perhaps it would be
better to conditionally change the tsx and do something more consistent with the
rest of the repo?

just as an example:
```
         <IconButton
            ...
            target="_blank"
        >

```

Code after:

  if (relationOpenMode === 'newTab') {
    return (
      <StyledRelationLink to={fullPageUrl} target="_blank" rel="noopener noreferrer">
        {children}
      </StyledRelationLink>
    );
  }

  if (relationOpenMode === 'page') {
    return <StyledRelationLink to={fullPageUrl}>{children}</StyledRelationLink>;
  }

  return (
    <StyledTextButton
      onClick={() =>
        dispatch({
          type: 'GO_TO_RELATION',
          payload: { document: relation, shouldBypassConfirmation: false },
        })
      }
    >
      {children}
    </StyledTextButton>
  );
};

const StyledTextButton = styled(TextButton)`
  max-width: 100%;
  & > span {
    font-size: ${({ theme }) => theme.fontSizes[2]};
    width: inherit;
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
`;

const StyledRelationLink = styled(RouterLink)`
  max-width: 100%;
  font-size: ${({ theme }) => theme.fontSizes[2]};
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  display: block;
  color: ${({ theme }) => theme.colors.primary600};
  text-decoration: none;

  &:hover,
  &:focus {
    color: ${({ theme }) => theme.colors.primary700};
Repository: strapi/strapi
File: packages/core/content-manager/shared/contracts/content-types.ts (TypeScript)

Code before:
import type { Struct } from '@strapi/types';
import { errors } from '@strapi/utils';
import { ComponentConfiguration } from './components';

export type RelationOpenMode = 'modal' | 'page' | 'newTab';

export type Settings = {
  bulkable: boolean;
  filterable: boolean;
  searchable: boolean;
  pageSize: number;
  mainField: string;
  defaultSortBy: string;
  defaultSortOrder: string;
  relationOpenMode: RelationOpenMode;
};

export type Metadatas = {
  [key: string]: {
    edit: {
      label?: string;
      description?: string;
      placeholder?: string;
      visible?: boolean;
      editable?: boolean;
    };
    list: {
      label?: string;
      mainField?: string;
      searchable?: boolean;
      sortable?: boolean;
    };
  };
};

export type Layouts = {
  list: string[];
  edit: { name: string; size: number }[][];
};


Review comment (bug):
i18n test are failing with:
 
```
Error: admin/src/contentManagerHooks/tests/listView.test.ts(16,5): error TS2741: Property 'relationOpenMode' is missing in type '{ bulkable: true; defaultSortBy: string; defaultSortOrder: string; filterable: true; searchable: true; pageSize: number; mainField: string; }' but required in type 'LayoutSettings'.
```

relationOpenMode is already correctly defaulting to 'modal' where its used so I think we can fix this by making it optional on the type?


```suggestion
  relationOpenMode?: RelationOpenMode;
```

Code after:
import type { Struct } from '@strapi/types';
import { errors } from '@strapi/utils';
import { ComponentConfiguration } from './components';

export type RelationOpenMode = 'modal' | 'page' | 'newTab';

export type Settings = {
  bulkable: boolean;
  filterable: boolean;
  searchable: boolean;
  pageSize: number;
  mainField: string;
  defaultSortBy: string;
  defaultSortOrder: string;
  relationOpenMode?: RelationOpenMode;
};

export type Metadatas = {
  [key: string]: {
    edit: {
      label?: string;
      description?: string;
      placeholder?: string;
      visible?: boolean;
      editable?: boolean;
    };
    list: {
      label?: string;
      mainField?: string;
      searchable?: boolean;
      sortable?: boolean;
    };
  };
};

export type Layouts = {
  list: string[];
  edit: { name: string; size: number }[][];
};
Repository: strapi/strapi
File: packages/core/strapi/src/node/core/linked-packages.ts (TypeScript)

Code before:
import path from 'node:path';
import { createRequire } from 'node:module';
import readPkgUp from 'read-pkg-up';

/**
 * Detects if @strapi/design-system is linked (portal:, file:, or yarn link).
 * Returns the package root path when linked, null otherwise.
 */
export const getLinkedDesignSystemPath = (cwd: string): string | null => {
  try {
    const require = createRequire(import.meta.url);
    const resolvedPath = require.resolve('@strapi/design-system');
    const pkg = readPkgUp.sync({ cwd: path.dirname(resolvedPath) });
    if (!pkg) return null;
    const pkgRoot = path.dirname(pkg.path);
    const relativePath = path.relative(cwd, pkgRoot);
    const isLinked = relativePath.startsWith('..') || path.isAbsolute(relativePath);
    return isLinked ? pkgRoot : null;
  } catch {
    return null;
  }
};

export const isDesignSystemLinked = (cwd: string): boolean =>
  getLinkedDesignSystemPath(cwd) !== null;


Review comment (suggestion):
Just an idea but could something like this be safer? A more accurate way to detect a package is locally linked?
```suggestion
const isInNodeModules = pkgRoot.split(path.sep).includes("node_modules");
const isLinked = !isInNodeModules;
```

Code after:
import path from 'node:path';
import { getModulePath } from './resolve-module';

const DESIGN_SYSTEM_MODULE = '@strapi/design-system';

/**
 * Detect if a package is locally linked (portal:, file:, yarn link) rather than installed in node_modules.
 * When linked, the resolved path is outside node_modules.
 *
 * @internal
 */
export const isPackageLinked = (mod: string): boolean => {
  const pkgRoot = getModulePath(mod);
  const pathSegments = pkgRoot.split(path.sep);
  return !pathSegments.includes('node_modules');
};

/**
 * Detects if @strapi/design-system is linked (portal:, file:, or yarn link).
 * Returns the package root path when linked, null otherwise.
 * Uses the heuristic: linked packages resolve outside node_modules.
 */
export const getLinkedDesignSystemPath = (): string | null => {
  try {
    const pkgRoot = getModulePath(DESIGN_SYSTEM_MODULE);
    return isPackageLinked(DESIGN_SYSTEM_MODULE) ? pkgRoot : null;
  } catch {
    return null;
  }
};

export const isDesignSystemLinked = (): boolean => getLinkedDesignSystemPath() !== null;
Repository: streamlit/streamlit
File: frontend/app/src/components/Sidebar/utils.test.ts (TypeScript)

Code before:
/**
 * Copyright (c) Streamlit Inc. (2018-2022) Snowflake Inc. (2022-2025)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import { PageConfig } from "@streamlit/protobuf"

import { shouldCollapse } from "./utils"

describe("shouldCollapse", () => {
  it("should collapse given state is collapsed", () => {
    expect(
      shouldCollapse(PageConfig.SidebarState.COLLAPSED, 50, 100)
    ).toBeTruthy()
  })

  it("should not collapse given state is expanded", () => {
    expect(
      shouldCollapse(PageConfig.SidebarState.EXPANDED, 50, 100)
    ).toBeFalsy()
  })

  it("should collapse given state is auto and width is less than breakpoint", () => {
    const windowInnerWidth = 40
    expect(
      shouldCollapse(PageConfig.SidebarState.AUTO, 50, windowInnerWidth)
    ).toBeTruthy()
  })

  it("should not collapse given state is auto and width greater less than breakpoint", () => {
    const windowInnerWidth = 60
    expect(
      shouldCollapse(PageConfig.SidebarState.AUTO, 50, windowInnerWidth)
    ).toBeFalsy()
  })
})


Review comment (suggestion):
It seems like we aren't really setting `NaN` to some default, I don't think this is an expected path but it seems better to return the default value if we do have `NaN` here to be defensive.  

Code after:
  describe("valid width range", () => {
    it("should return width unchanged when within valid bounds", () => {
      const validWidths = [300, 250.5]

      validWidths.forEach(width => {
        expect(clampSidebarWidth(width)).toBe(width)
      })
    })
  })

  describe("edge cases and error handling", () => {
    it("should handle boundary values correctly", () => {
      // Just below minimum
      expect(clampSidebarWidth(MIN_SIDEBAR_WIDTH - 1)).toBe(MIN_SIDEBAR_WIDTH)

      // Just above maximum
      expect(clampSidebarWidth(MAX_SIDEBAR_WIDTH + 1)).toBe(MAX_SIDEBAR_WIDTH)
    })

    it("should handle special numeric values", () => {
      // These should be handled gracefully by Math.max/Math.min
      expect(clampSidebarWidth(Number.NaN)).toBe(
        Number.parseInt(DEFAULT_WIDTH, 10)
      )
      expect(clampSidebarWidth(Number.MAX_VALUE)).toBe(MAX_SIDEBAR_WIDTH)
      expect(clampSidebarWidth(Number.MIN_VALUE)).toBe(MIN_SIDEBAR_WIDTH)
    })
  })
})
Repository: streamlit/streamlit
File: frontend/lib/src/render-tree/visitors/DebugVisitor.test.ts (TypeScript)

Code before:
describe("DebugVisitor.visitBlockNode", () => {
  it("prints child count and iterates children with proper connectors", () => {
    const tree = block([
      text("one"),
      block([text("two-a"), text("two-b")]),
      text("three"),
    ])

    const out = tree.accept(new DebugVisitor())

    // Root line
    expect(out.split("\n")[0]).toBe("└── BlockNode [3 children]")

    // Check connectors and indentation for children
    expect(out).toContain('├── ElementNode [text] "one"')
    expect(out).toContain("├── BlockNode [2 children]")
    expect(out).toContain('│   ├── ElementNode [text] "two-a"')
    expect(out).toContain('│   └── ElementNode [text] "two-b"')
    expect(out).toContain('└── ElementNode [text] "three"')
  })

  it("includes run hash when scriptRunId is set on block", () => {
    const runId = "1234567890abcdef"
    const b = block([text("c")], runId)
    const out = b.accept(new DebugVisitor())
    expect(out.split("\n")[0]).toContain("(run: 123456)")
  })
})

describe("DebugVisitor.generateDebugString", () => {
  it("delegates to visitor with provided prefix and isLast", () => {
    const root = block([text("a"), text("b")])

    const out = DebugVisitor.generateDebugString(root, "X   ", false)

    // Root should start with provided prefix and non-last connector
    expect(out.startsWith("X   ├── BlockNode")).toBe(true)
  })
})


Review comment (suggestion):
**nit (non-blocking):** You could make this slightly more stable by utilizing the `MAX_HASH_LENGTH` to create the expected value. 

Code after:

describe("DebugVisitor.visitBlockNode", () => {
  it("prints child count and iterates children with proper connectors", () => {
    const tree = block([
      text("one"),
      block([text("two-a"), text("two-b")]),
      text("three"),
    ])

    const out = tree.accept(new DebugVisitor())

    // Root line
    expect(out.split("\n")[0]).toBe("└── BlockNode [3 children]")

    // Check connectors and indentation for children
    expect(out).toContain('├── ElementNode [text] "one"')
    expect(out).toContain("├── BlockNode [2 children]")
    expect(out).toContain('│   ├── ElementNode [text] "two-a"')
    expect(out).toContain('│   └── ElementNode [text] "two-b"')
    expect(out).toContain('└── ElementNode [text] "three"')
  })

  it("includes run hash when scriptRunId is set on block", () => {
    const runId = "1234567890abcdef"
    const b = block([text("c")], runId)
    const out = b.accept(new DebugVisitor())
    expect(out.split("\n")[0]).toContain(
      `(run: ${runId.substring(0, MAX_HASH_LENGTH)})`
    )
  })
})

describe("DebugVisitor.generateDebugString", () => {
  it("delegates to visitor with provided prefix and isLast", () => {
    const root = block([text("a"), text("b")])

    const out = DebugVisitor.generateDebugString(root, "X   ", false)

    // Root should start with provided prefix and non-last connector
    expect(out.startsWith("X   ├── BlockNode")).toBe(true)
  })
})
Repository: streamlit/streamlit
File: frontend/lib/src/components/widgets/Slider/Slider.tsx (TypeScript)

Code before:
  StyledThumb,
  StyledThumbValue,
  StyledThumbWrapper,
} from "./styled-components"

interface SliderTickBarProps {
  minLabel: string
  maxLabel: string
  isHovered: boolean
  isDisabled: boolean
}

function SliderTickBar({
  minLabel,
  maxLabel,
  isHovered,
  isDisabled,
}: SliderTickBarProps): ReactElement {
  return (
    <StyledSliderTickBar
      data-testid="stSliderTickBar"
      isHovered={isHovered}
      isDisabled={isDisabled}
    >
      <StreamlitMarkdown source={minLabel} allowHTML={false} inheritFont />
      <StreamlitMarkdown source={maxLabel} allowHTML={false} inheritFont />
    </StyledSliderTickBar>
  )
}

export interface Props {
  disabled: boolean
  element: SliderProto
  widgetMgr: WidgetStateManager
  width: number
  fragmentId?: string
}

function Slider({
  disabled,
  element,
  widgetMgr,
  fragmentId,
}: Props): ReactElement {
  const [value, setValueWithSource] = useBasicWidgetState<
    number[],
    SliderProto
  >({
    getStateFromWidgetMgr,
    getDefaultStateFromProto,
    getCurrStateFromProto,

Review comment (suggestion):
I think we also want to apply the `isLabel` flag here so that our set of markdown restrictions that we apply to labels also applies here. 

Code after:
  StyledThumb,
  StyledThumbValue,
  StyledThumbWrapper,
} from "./styled-components"

interface SliderTickBarProps {
  minLabel: string
  maxLabel: string
  isHovered: boolean
  isDisabled: boolean
}

function SliderTickBar({
  minLabel,
  maxLabel,
  isHovered,
  isDisabled,
}: SliderTickBarProps): ReactElement {
  return (
    <StyledSliderTickBar
      data-testid="stSliderTickBar"
      isHovered={isHovered}
      isDisabled={isDisabled}
    >
      <StreamlitMarkdown
        source={minLabel}
        allowHTML={false}
        inheritFont
        isLabel
      />
      <StreamlitMarkdown
        source={maxLabel}
        allowHTML={false}
        inheritFont
        isLabel
      />
    </StyledSliderTickBar>
  )
}

export interface Props {
  disabled: boolean
  element: SliderProto
  widgetMgr: WidgetStateManager
  width: number
  fragmentId?: string
}

function Slider({
  disabled,
  element,
Repository: streamlit/streamlit
File: e2e_playwright/st_markdown.py (Python)

Code before:
st.caption(
    """Justified caption text this should be long to
demonstrate justification properly. This is a longer paragraph that demonstrates
text justification properly. The text stretches to fill the available width.""",
    text_alignment="justify",
    help="This is a help tooltip!",
)

# Test for gh-13339: Tooltip with newlines should render correctly
st.header("Tooltip with Newlines (gh-13339)")

st.container(key="markdown_newlines_tooltip").markdown(
    "Markdown with newlines in tooltip",
    help="Line 1\n\nLine 2\n\nLine 3",
)

st.container(key="caption_newlines_tooltip").caption(
    "Caption with newlines in tooltip",
    help="Line 1\n\nLine 2\n\nLine 3",
)

st.container(key="markdown_center_newlines_tooltip").markdown(
    "Center aligned with newlines in tooltip",
    text_alignment="center",
    help="Line 1\n\nLine 2\n\nLine 3",
)


Review comment (bug):
**suggestion:** We should add tests for this case, which seems to be broken:

```py
st.markdown("Test", help="Help before ] help after")
```

<img width="234" height="105" alt="Image" src="https://github.com/user-attachments/assets/3b70792c-0001-4d59-80c4-c7d3db21f9a8" />

Code after:
st.caption(
    """Justified caption text this should be long to
demonstrate justification properly. This is a longer paragraph that demonstrates
text justification properly. The text stretches to fill the available width.""",
    text_alignment="justify",
    help="This is a help tooltip!",
)

# Test for gh-13339: Tooltip with newlines should render correctly
st.header("Tooltip with Newlines (gh-13339)")

st.container(key="markdown_newlines_tooltip").markdown(
    "Markdown with newlines in tooltip",
    help="Line 1\n\nLine 2\n\nLine 3",
)

st.container(key="caption_newlines_tooltip").caption(
    "Caption with newlines in tooltip",
    help="Line 1\n\nLine 2\n\nLine 3",
)

st.container(key="markdown_center_newlines_tooltip").markdown(
    "Center aligned with newlines in tooltip",
    text_alignment="center",
    help="Line 1\n\nLine 2\n\nLine 3",
)

st.container(key="markdown_spaces_around_newlines").markdown(
    "Markdown with spaces around newlines",
    help="Line 1 \n\n Line 2 \n\n Line 3",
)

st.container(key="markdown_bracket_in_tooltip").markdown(
    "Markdown with closing bracket in tooltip",
    help="Line 1 ] Line 2 ] Line 3",
)

# Complex markdown in tooltip - comprehensive test
st.header("Complex Tooltip Case")

st.container(key="markdown_complex_tooltip").markdown(
    "Tooltip with complex markdown",
    help="""**Bold**, *italic*, and `code` with brackets [x]

Links: [Streamlit](https://streamlit.io) Colors: :red[red] :blue[blue]

Emoji: 🎉 Array: array[index] Dict: dict[key]""",
)
Repository: streamlit/streamlit
File: frontend/lib/src/components/elements/ExceptionElement/ExceptionElement.test.tsx (TypeScript)

Code before:

      expect(screen.queryByText("Copy")).not.toBeInTheDocument()
      expect(screen.queryByText("Ask Google")).not.toBeInTheDocument()
      expect(screen.queryByText("Ask ChatGPT")).not.toBeInTheDocument()
    })

    it("should not render exception links when showErrorLinks is false", () => {
      windowSpy.mockReturnValue({ ...originalLocation, hostname: "localhost" })
      renderWithContexts(<ExceptionElement {...getProps()} />, {
        libConfigContext: {
          showErrorLinks: Config.ShowErrorLinks.SHOW_ERROR_LINKS_FALSE,
        },
      })

      expect(screen.queryByText("Copy")).not.toBeInTheDocument()
      expect(screen.queryByText("Ask Google")).not.toBeInTheDocument()
      expect(screen.queryByText("Ask ChatGPT")).not.toBeInTheDocument()
    })

    it("should render exception links when showErrorLinks is true on non-localhost", () => {
      windowSpy.mockReturnValue({ ...originalLocation, hostname: "foo.com" })
      renderWithContexts(<ExceptionElement {...getProps()} />, {
        libConfigContext: {
          showErrorLinks: Config.ShowErrorLinks.SHOW_ERROR_LINKS_TRUE,
        },
      })

      expect(screen.getByText("Copy")).toBeInTheDocument()
      expect(screen.getByText("Ask Google")).toBeInTheDocument()
      expect(screen.getByText("Ask ChatGPT")).toBeInTheDocument()
    })
  })
})


Review comment (suggestion):
I think these tests are fairly cheap to run, so we might as well add the other cases (i.e. config true + localhost, config false + non-localhost). Maybe you could parameterize them to reduce the reading overhead. 

Code after:
        })
      }
      expect(screen.getByText("Copy")).toBeInTheDocument()
      expect(screen.getByText("Ask Google")).toBeInTheDocument()
      expect(screen.getByText("Ask ChatGPT")).toBeInTheDocument()
    })

    it.each([
      ["foo.com", undefined],
      ["foo.com", Config.ShowErrorLinks.SHOW_ERROR_LINKS_AUTO],
      ["localhost", Config.ShowErrorLinks.SHOW_ERROR_LINKS_FALSE],
      ["foo.com", Config.ShowErrorLinks.SHOW_ERROR_LINKS_FALSE],
    ])("hides links: hostname=%s, config=%s", (hostname, showErrorLinks) => {
      windowSpy.mockReturnValue({ ...originalLocation, hostname })
      if (showErrorLinks === undefined) {
        render(<ExceptionElement {...getProps()} />)
      } else {
        renderWithContexts(<ExceptionElement {...getProps()} />, {
          libConfigContext: { showErrorLinks },
        })
      }
      expect(screen.queryByText("Copy")).not.toBeInTheDocument()
      expect(screen.queryByText("Ask Google")).not.toBeInTheDocument()
      expect(screen.queryByText("Ask ChatGPT")).not.toBeInTheDocument()
    })
  })
})
Repository: streamlit/streamlit
File: proto/streamlit/proto/NewSession.proto (Protocol Buffers)

Code before:
  int32 max_cached_message_age = 3;

  // DEPRECATED: the mapbox token was moved to the DeckGlJsonChart message.
  string mapbox_token = 4;

  // See config option "server.allowRunOnSave".
  bool allow_run_on_save = 5;

  // See config option "ui.hideTopBar".
  bool hide_top_bar = 6;

  // See config option "client.showSidebarNavigation".
  bool hide_sidebar_nav = 7;

  // See config option "client.toolbarMode".
  enum ToolbarMode {
    AUTO = 0;
    DEVELOPER = 1;
    VIEWER = 2;
    MINIMAL = 3;
  }
  ToolbarMode toolbar_mode = 8;

  // See config option "client.showErrorLinks".
  enum ShowErrorLinks {
    SHOW_ERROR_LINKS_AUTO = 0;
    SHOW_ERROR_LINKS_TRUE = 1;
    SHOW_ERROR_LINKS_FALSE = 2;
  }
  ShowErrorLinks show_error_links = 9;

  reserved 1;
}

// Custom theme configuration options. Like other config options, these are set
// in .streamlit/config.toml.
//
// IMPORTANT: This message is passed in JSON format in a host-to-guest postMessage. So DO NOT
// rename its proto fields!
message CustomThemeConfig {
  enum BaseTheme {
    LIGHT = 0;
    DARK = 1;
  }

  // DEPRECATED: Use body_font instead:
  enum FontFamily {
    SANS_SERIF = 0;
    SERIF = 1;
    MONOSPACE = 2;
  }

Review comment (suggestion):
We don't do this for all enums, but the [proto best practices](https://protobuf.dev/best-practices/dos-donts/#unspecified-enum) specify using this first value as an unspecified value. So, `SHOW_ERROR_LINKS_UNSPECIFIED = 0;` and then `SHOW_ERROR_LINKS_AUTO = 1;`.

Code after:
  int32 max_cached_message_age = 3;

  // DEPRECATED: the mapbox token was moved to the DeckGlJsonChart message.
  string mapbox_token = 4;

  // See config option "server.allowRunOnSave".
  bool allow_run_on_save = 5;

  // See config option "ui.hideTopBar".
  bool hide_top_bar = 6;

  // See config option "client.showSidebarNavigation".
  bool hide_sidebar_nav = 7;

  // See config option "client.toolbarMode".
  enum ToolbarMode {
    AUTO = 0;
    DEVELOPER = 1;
    VIEWER = 2;
    MINIMAL = 3;
  }
  ToolbarMode toolbar_mode = 8;

  // See config option "client.showErrorLinks".
  enum ShowErrorLinks {
    SHOW_ERROR_LINKS_UNSPECIFIED = 0;
    SHOW_ERROR_LINKS_AUTO = 1;
    SHOW_ERROR_LINKS_TRUE = 2;
    SHOW_ERROR_LINKS_FALSE = 3;
  }
  ShowErrorLinks show_error_links = 9;

  reserved 1;
}

// Custom theme configuration options. Like other config options, these are set
// in .streamlit/config.toml.
//
// IMPORTANT: This message is passed in JSON format in a host-to-guest postMessage. So DO NOT
// rename its proto fields!
message CustomThemeConfig {
  enum BaseTheme {
    LIGHT = 0;
    DARK = 1;
  }

  // DEPRECATED: Use body_font instead:
  enum FontFamily {
    SANS_SERIF = 0;
    SERIF = 1;
    MONOSPACE = 2;