Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GUI Strict null check fixes part 1 #3097

Merged
merged 6 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion gui/src/components/AccountDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ function AccountDialog() {
{profiles.map((option, idx) => (
<StyledListboxOption
key={idx}
selected={selectedProfile.id === option.id}
selected={selectedProfile?.id === option.id}
value={option.id}
className="w-full"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ import { providers } from "../../../pages/AddNewModel/configs/providers";
import { setDefaultModel } from "../../../redux/slices/stateSlice";
import AddModelButtonSubtext from "../../AddModelButtonSubtext";

const { anthropic: chatProvider, mistral: autocompleteProvider } = providers;
const { anthropic, mistral } = providers;
const chatProvider = anthropic!;
const autocompleteProvider = mistral!;

const {
claude35Sonnet: chatModel,
claude3Haiku: repoMapModel,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,7 @@ interface OllamaStatusProps {
isOllamaConnected: boolean;
}

const {
ollama: { downloadUrl },
} = providers;
const downloadUrl = providers.ollama!.downloadUrl!;

export function OllamaStatus({ isOllamaConnected }: OllamaStatusProps) {
const ideMessenger = useContext(IdeMessengerContext);
Expand Down
12 changes: 7 additions & 5 deletions gui/src/components/dialogs/AddDocsDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -123,21 +123,23 @@ function AddDocsDialog() {
}

const handleSelectSuggestion = (docsResult: PackageDocsResult) => {
if (docsResult.error) {
if (docsResult.error || !docsResult.details) {
setTitle(docsResult.packageInfo.name);
setStartUrl("");
urlRef.current?.focus();
return;
}
const suggestedTitle =
docsResult.details.title ?? docsResult.packageInfo.name;
if (docsResult.details?.docsLinkWarning) {
setTitle(docsResult.packageInfo.name);
setTitle(suggestedTitle);
setStartUrl(docsResult.details.docsLink);
urlRef.current?.focus();
return;
}
const siteIndexingConfig: SiteIndexingConfig = {
startUrl: docsResult.details.docsLink,
title: docsResult.details.title,
title: suggestedTitle,
faviconUrl: undefined,
};

Expand Down Expand Up @@ -185,7 +187,7 @@ function AddDocsDialog() {
}}
>
<div className="pr-1">
{error || details.docsLinkWarning ? (
{error || details?.docsLinkWarning ? (
<div>
<PencilIcon
data-tooltip-id={id + "-edit"}
Expand All @@ -210,7 +212,7 @@ function AddDocsDialog() {
<span className="lines lines-1">{name}</span>
</div>
<div>
{error ? (
{error || !details?.docsLink ? (
<span className="text-vsc-foreground-muted italic">
No docs link found
</span>
Expand Down
31 changes: 16 additions & 15 deletions gui/src/components/find/FindWidget.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
const [open, setOpen] = useState<boolean>(false);
const openWidget = useCallback(() => {
setOpen(true);
inputRef?.current.select();
inputRef?.current?.select();
}, [setOpen, inputRef]);

// Search settings and results
Expand All @@ -92,7 +92,7 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
const scrollToMatch = useCallback(
(match: SearchMatch) => {
setCurrentMatch(match);
searchRef.current.scrollTo({
searchRef?.current?.scrollTo({
top: match.overlayRectangle.top - searchRef.current.clientHeight / 2,
left: match.overlayRectangle.left - searchRef.current.clientWidth / 2,
behavior: "smooth",
Expand Down Expand Up @@ -173,8 +173,10 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
(scrollTo: ScrollToMatchOption = "none", clearFirst = false) => {
if (clearFirst) setMatches([]);

const searchContainer = searchRef.current;

const _query = debouncedInput.current; // trimStart - decided no because spaces should be fully searchable
if (!searchRef.current || !_query) {
if (!searchContainer || !_query) {
setMatches([]);
return;
}
Expand Down Expand Up @@ -215,7 +217,7 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
textNodes.forEach((textNode, idx) => {
// Hacky way to detect code blocks that be wider than client and cause absolute positioning to fail
const highlightFullLine =
textNode.parentElement.className.includes("hljs");
textNode.parentElement?.className.includes("hljs");

let nodeTextValue = caseSensitive
? textNode.nodeValue
Expand All @@ -232,13 +234,9 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
startIndex = endIndex;

const top =
rect.top +
searchRef.current.clientTop +
searchRef.current.scrollTop;
rect.top + searchContainer.clientTop + searchContainer.scrollTop;
const left =
rect.left +
searchRef.current.clientLeft +
searchRef.current.scrollLeft;
rect.left + searchContainer.clientLeft + searchContainer.scrollLeft;

// Build a match result and push to matches
const newMatch: SearchMatch = {
Expand All @@ -248,7 +246,7 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
top,
left: highlightFullLine ? 2 : left,
width: highlightFullLine
? searchRef.current.clientWidth - 4
? searchContainer.clientWidth - 4
: rect.width, // equivalent of adding 2 px x padding
height: rect.height,
},
Expand Down Expand Up @@ -294,7 +292,9 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
scrollToMatch(filteredMatches[0]);
}
if (scrollTo === "closest") {
scrollToMatch(closestMatchToMiddle);
if (closestMatchToMiddle) {
scrollToMatch(closestMatchToMiddle);
}
}
if (scrollTo === "none") {
if (closestMatchToMiddle) {
Expand Down Expand Up @@ -333,13 +333,14 @@ export const useFindWidget = (searchRef: RefObject<HTMLDivElement>) => {
// Could consider doing any window click but I only handled search div here
// Since usually only clicks in search div will cause content changes in search div
useEffect(() => {
if (!open || !searchRef.current) return;
const searchContainer = searchRef.current;
if (!open || !searchContainer) return;
const handleSearchRefClick = () => {
refreshSearch("none");
};
searchRef.current.addEventListener("click", handleSearchRefClick);
searchContainer.addEventListener("click", handleSearchRefClick);
return () => {
searchRef.current.removeEventListener("click", handleSearchRefClick);
searchContainer.removeEventListener("click", handleSearchRefClick);
};
}, [searchRef.current, refreshSearch, open]);

Expand Down
12 changes: 8 additions & 4 deletions gui/src/components/mainInput/ContextItemsPeek.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { ChevronDownIcon, ChevronRightIcon } from "@heroicons/react/24/outline";
import { ContextItemWithId } from "core";
import { ctxItemToRifWithContents } from "core/commands/util";
import { useContext, useState } from "react";
import { useContext, useMemo, useState } from "react";
import { AnimatedEllipsis, lightGray, vscBackground } from "..";
import { IdeMessengerContext } from "../../context/IdeMessenger";
import FileIcon from "../FileIcon";
Expand Down Expand Up @@ -124,9 +124,13 @@ function ContextItemsPeek({
}: ContextItemsPeekProps) {
const [open, setOpen] = useState(false);

const ctxItems = contextItems?.filter(
(ctxItem) => !ctxItem.name.includes(INSTRUCTIONS_BASE_ITEM.name),
);
const ctxItems = useMemo(() => {
return (
contextItems?.filter(
(ctxItem) => !ctxItem.name.includes(INSTRUCTIONS_BASE_ITEM.name),
) ?? []
);
}, [contextItems]);

const isGatheringContext = useSelector(
(store: RootState) => store.state.context.isGathering,
Expand Down
11 changes: 6 additions & 5 deletions gui/src/components/mainInput/InputToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
import { ToolTip } from "../gui/Tooltip";
import ModelSelect from "../modelSelection/ModelSelect";

const StyledDiv = styled.div<{ isHidden: boolean }>`
const StyledDiv = styled.div<{ isHidden?: boolean }>`
padding-top: 4px;
justify-content: space-between;
gap: 1px;
Expand Down Expand Up @@ -117,8 +117,9 @@ function InputToolbar(props: InputToolbarProps) {
style={{ display: "none" }}
accept=".jpg,.jpeg,.png,.gif,.svg,.webp"
onChange={(e) => {
for (const file of e.target.files) {
props.onImageFileSelected(file);
const files = e.target?.files ?? [];
for (const file of files) {
props.onImageFileSelected?.(file);
}
}}
/>
Expand Down Expand Up @@ -157,9 +158,9 @@ function InputToolbar(props: InputToolbarProps) {
</HoverItem>
) : (
<HoverItem
className={props.activeKey === "Meta" && "underline"}
className={props.activeKey === "Meta" ? "underline" : ""}
onClick={(e) =>
props.onEnter({
props.onEnter?.({
useCodebase: true,
noContext: !useActiveFile,
})
Expand Down
53 changes: 33 additions & 20 deletions gui/src/components/mainInput/TipTapEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,10 @@ const HoverTextDiv = styled.div`
`;

const IMAGE_RESOLUTION = 1024;
function getDataUrlForFile(file: File, img): string {
function getDataUrlForFile(
file: File,
img: HTMLImageElement,
): string | undefined {
const targetWidth = IMAGE_RESOLUTION;
const targetHeight = IMAGE_RESOLUTION;
const scaleFactor = Math.min(
Expand All @@ -145,6 +148,10 @@ function getDataUrlForFile(file: File, img): string {
canvas.height = img.height * scaleFactor;

const ctx = canvas.getContext("2d");
if (!ctx) {
console.error("Error getting image data url: 2d context not found");
return;
}
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);

const downsizedDataUrl = canvas.toDataURL("image/jpeg", 0.7);
Expand Down Expand Up @@ -293,6 +300,9 @@ function TipTapEditor(props: TipTapEditorProps) {
return await new Promise((resolve) => {
img.onload = function () {
const dataUrl = getDataUrlForFile(file, img);
if (!dataUrl) {
return;
}

let image = new window.Image();
image.src = dataUrl;
Expand Down Expand Up @@ -327,26 +337,29 @@ function TipTapEditor(props: TipTapEditorProps) {
handleDOMEvents: {
paste(view, event) {
const model = defaultModelRef.current;
const items = event.clipboardData.items;
for (const item of items) {
const file = item.getAsFile();
file &&
modelSupportsImages(
model.provider,
model.model,
model.title,
model.capabilities,
) &&
handleImageFile(file).then((resp) => {
if (!resp) return;
const [img, dataUrl] = resp;
const { schema } = view.state;
const node = schema.nodes.image.create({
src: dataUrl,
if (!model) return;
const items = event.clipboardData?.items;
if (items) {
for (const item of items) {
const file = item.getAsFile();
file &&
modelSupportsImages(
model.provider,
model.model,
model.title,
model.capabilities,
) &&
handleImageFile(file).then((resp) => {
if (!resp) return;
const [img, dataUrl] = resp;
const { schema } = view.state;
const node = schema.nodes.image.create({
src: dataUrl,
});
const tr = view.state.tr.insert(0, node);
view.dispatch(tr);
});
const tr = view.state.tr.insert(0, node);
view.dispatch(tr);
});
}
}
},
},
Expand Down
8 changes: 4 additions & 4 deletions gui/src/components/mainInput/handleMetaKeyIssues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@ export const handleJetBrainsOSRMetaKeyIssues = (

const handlers: Record<string, () => void> = {
Backspace: () => handleJetBrainsMetaBackspace(editor),
ArrowLeft: () => selection.modify(alter, "backward", "lineboundary"),
ArrowRight: () => selection.modify(alter, "forward", "lineboundary"),
ArrowDown: () => selection.modify(alter, "forward", "documentboundary"),
ArrowLeft: () => selection?.modify(alter, "backward", "lineboundary"),
ArrowRight: () => selection?.modify(alter, "forward", "lineboundary"),
ArrowDown: () => selection?.modify(alter, "forward", "documentboundary"),
ArrowUp: () => {
selection.modify(alter, "backward", "documentboundary");
selection?.modify(alter, "backward", "documentboundary");
},
};

Expand Down
Loading
Loading