mirror of
https://github.com/outline/outline.git
synced 2026-06-13 03:14:59 +03:00
chore: Address AI code quality findings (#12163)
- Modal: translate default title and bind Dialog.Title to visible text - Document Header: regroup imports and rename isNew -> wasNew - Redis adapter: surface error.message and guard pingTimeout cleanup - urls: fix typo and correct JSDoc @param names Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -15,7 +15,6 @@ import usePrevious from "~/hooks/usePrevious";
|
||||
import { fadeAndScaleIn, fadeIn } from "~/styles/animations";
|
||||
import Desktop from "~/utils/Desktop";
|
||||
import ErrorBoundary from "./ErrorBoundary";
|
||||
import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
|
||||
import Tooltip from "./Tooltip";
|
||||
import { useDialogContext } from "~/components/DialogContext";
|
||||
|
||||
@@ -32,7 +31,7 @@ type Props = {
|
||||
const Modal: React.FC<Props> = ({
|
||||
children,
|
||||
isOpen,
|
||||
title = "Untitled",
|
||||
title,
|
||||
style,
|
||||
width,
|
||||
height,
|
||||
@@ -41,6 +40,7 @@ const Modal: React.FC<Props> = ({
|
||||
const wasOpen = usePrevious(isOpen);
|
||||
const isMobile = useMobile();
|
||||
const { t } = useTranslation();
|
||||
const resolvedTitle = title ?? t("Untitled");
|
||||
const dialog = useDialogContext();
|
||||
|
||||
const onClose = React.useCallback(() => {
|
||||
@@ -56,9 +56,6 @@ const Modal: React.FC<Props> = ({
|
||||
<Dialog.Root open={isOpen} onOpenChange={(open) => !open && onClose()}>
|
||||
<Dialog.Portal>
|
||||
<StyledOverlay />
|
||||
<Dialog.Title asChild>
|
||||
<VisuallyHidden.Root>{title}</VisuallyHidden.Root>
|
||||
</Dialog.Title>
|
||||
<StyledContent
|
||||
onEscapeKeyDown={onClose}
|
||||
onPointerDownOutside={onClose}
|
||||
@@ -68,11 +65,11 @@ const Modal: React.FC<Props> = ({
|
||||
<Mobile>
|
||||
<MobileContent>
|
||||
<Centered onClick={(ev) => ev.stopPropagation()} column>
|
||||
{title && (
|
||||
<Dialog.Title asChild>
|
||||
<Text size="xlarge" weight="bold">
|
||||
{title}
|
||||
{resolvedTitle}
|
||||
</Text>
|
||||
)}
|
||||
</Dialog.Title>
|
||||
<ErrorBoundary>{children}</ErrorBoundary>
|
||||
</Centered>
|
||||
</MobileContent>
|
||||
@@ -102,7 +99,9 @@ const Modal: React.FC<Props> = ({
|
||||
<ErrorBoundary component="div">{children}</ErrorBoundary>
|
||||
</DesktopContent>
|
||||
<Header>
|
||||
{title && <Text size="large">{title}</Text>}
|
||||
<Dialog.Title asChild>
|
||||
<Text size="large">{resolvedTitle}</Text>
|
||||
</Dialog.Title>
|
||||
<Tooltip content={t("Close")} shortcut="Esc">
|
||||
<NudeButton onClick={onClose}>
|
||||
<CloseIcon />
|
||||
|
||||
@@ -3,13 +3,13 @@ import { TableOfContentsIcon, EditIcon } from "outline-icons";
|
||||
import { useState, useCallback, useEffect } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Link } from "react-router-dom";
|
||||
import useMeasure from "react-use-measure";
|
||||
import styled, { useTheme } from "styled-components";
|
||||
import Icon from "@shared/components/Icon";
|
||||
import useMeasure from "react-use-measure";
|
||||
import useShare from "@shared/hooks/useShare";
|
||||
import { altDisplay, metaDisplay } from "@shared/utils/keyboard";
|
||||
import type Document from "~/models/Document";
|
||||
import type Revision from "~/models/Revision";
|
||||
import type Template from "~/models/Template";
|
||||
import { publishDocument } from "~/actions/definitions/documents";
|
||||
import { restoreRevision } from "~/actions/definitions/revisions";
|
||||
import { Action, Separator } from "~/components/Actions";
|
||||
import Badge from "~/components/Badge";
|
||||
import Button from "~/components/Button";
|
||||
@@ -18,10 +18,14 @@ import DocumentBreadcrumb from "~/components/DocumentBreadcrumb";
|
||||
import { useDocumentContext } from "~/components/DocumentContext";
|
||||
import Flex from "~/components/Flex";
|
||||
import Header from "~/components/Header";
|
||||
import {
|
||||
AppearanceAction,
|
||||
SubscribeAction,
|
||||
} from "~/components/Sharing/components/Actions";
|
||||
import Star from "~/components/Star";
|
||||
import Tooltip from "~/components/Tooltip";
|
||||
import { publishDocument } from "~/actions/definitions/documents";
|
||||
import { restoreRevision } from "~/actions/definitions/revisions";
|
||||
import { type Editor } from "~/editor";
|
||||
import env from "~/env";
|
||||
import useCurrentTeam from "~/hooks/useCurrentTeam";
|
||||
import useCurrentUser from "~/hooks/useCurrentUser";
|
||||
import useEditingFocus from "~/hooks/useEditingFocus";
|
||||
@@ -34,18 +38,14 @@ import DocumentMenu from "~/menus/DocumentMenu";
|
||||
import NewChildDocumentMenu from "~/menus/NewChildDocumentMenu";
|
||||
import TableOfContentsMenu from "~/menus/TableOfContentsMenu";
|
||||
import TemplatesMenu from "~/menus/TemplatesMenu";
|
||||
import env from "~/env";
|
||||
import type Document from "~/models/Document";
|
||||
import type Revision from "~/models/Revision";
|
||||
import type Template from "~/models/Template";
|
||||
import { documentEditPath } from "~/utils/routeHelpers";
|
||||
import { ChangesNavigation } from "./ChangesNavigation";
|
||||
import ObservingBanner from "./ObservingBanner";
|
||||
import PublicBreadcrumb from "./PublicBreadcrumb";
|
||||
import ShareButton from "./ShareButton";
|
||||
import {
|
||||
AppearanceAction,
|
||||
SubscribeAction,
|
||||
} from "~/components/Sharing/components/Actions";
|
||||
import useShare from "@shared/hooks/useShare";
|
||||
import { type Editor } from "~/editor";
|
||||
import { ChangesNavigation } from "./ChangesNavigation";
|
||||
|
||||
type Props = {
|
||||
editorRef: React.RefObject<Editor>;
|
||||
@@ -102,7 +102,7 @@ function DocumentHeader({
|
||||
// We cache this value for as long as the component is mounted so that if you
|
||||
// apply a template there is still the option to replace it until the user
|
||||
// navigates away from the doc
|
||||
const [isNew] = useState(document.isPersistedOnce);
|
||||
const [wasNew] = useState(document.isPersistedOnce);
|
||||
|
||||
const handleSave = useCallback(() => {
|
||||
onSave({
|
||||
@@ -273,7 +273,7 @@ function DocumentHeader({
|
||||
limit={isCompact ? 3 : undefined}
|
||||
/>
|
||||
)}
|
||||
{(isEditing || !user?.separateEditMode) && isNew && can.update && (
|
||||
{(isEditing || !user?.separateEditMode) && wasNew && can.update && (
|
||||
<Action>
|
||||
<TemplatesMenu
|
||||
isCompact={isCompact}
|
||||
|
||||
+10
-4
@@ -56,7 +56,8 @@ export default class RedisAdapter extends Redis {
|
||||
const decodedString = Buffer.from(url.slice(10), "base64").toString();
|
||||
customOptions = JSON.parse(decodedString);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to decode redis adapter options: ${error}`);
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Failed to decode redis adapter options: ${message}`);
|
||||
}
|
||||
|
||||
try {
|
||||
@@ -64,7 +65,8 @@ export default class RedisAdapter extends Redis {
|
||||
defaults(options, { connectionName }, customOptions, defaultOptions)
|
||||
);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to initialize redis client: ${error}`);
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
throw new Error(`Failed to initialize redis client: ${message}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -91,7 +93,7 @@ export default class RedisAdapter extends Redis {
|
||||
return;
|
||||
}
|
||||
|
||||
let pingTimeout: NodeJS.Timeout;
|
||||
let pingTimeout: NodeJS.Timeout | undefined;
|
||||
const timeoutPromise = new Promise((_, reject) => {
|
||||
pingTimeout = setTimeout(
|
||||
() => reject(new Error("ping timeout")),
|
||||
@@ -106,7 +108,11 @@ export default class RedisAdapter extends Redis {
|
||||
});
|
||||
this.disconnect(true);
|
||||
})
|
||||
.finally(() => clearTimeout(pingTimeout));
|
||||
.finally(() => {
|
||||
if (pingTimeout) {
|
||||
clearTimeout(pingTimeout);
|
||||
}
|
||||
});
|
||||
}, env.REDIS_HEALTHCHECK_INTERVAL);
|
||||
|
||||
this.on("end", () => clearInterval(healthcheck));
|
||||
|
||||
@@ -59,9 +59,9 @@ export function isInternalUrl(href: string) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given string is a link to a documement.
|
||||
* Returns true if the given string is a link to a document.
|
||||
*
|
||||
* @param options Parsing options.
|
||||
* @param url The url to check.
|
||||
* @returns True if a document, false otherwise.
|
||||
*/
|
||||
export function isDocumentUrl(url: string) {
|
||||
@@ -79,7 +79,7 @@ export function isDocumentUrl(url: string) {
|
||||
/**
|
||||
* Returns true if the given string is a link to a collection.
|
||||
*
|
||||
* @param options Parsing options.
|
||||
* @param url The url to check.
|
||||
* @returns True if a collection, false otherwise.
|
||||
*/
|
||||
export function isCollectionUrl(url: string) {
|
||||
|
||||
Reference in New Issue
Block a user