Skip to content

Commit

Permalink
Setup podkit folder and move Combobox into it (#18923)
Browse files Browse the repository at this point in the history
  • Loading branch information
selfcontained authored Oct 16, 2023
1 parent 7d1984f commit 5e6fa13
Show file tree
Hide file tree
Showing 8 changed files with 48 additions and 34 deletions.
3 changes: 2 additions & 1 deletion components/dashboard/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
"version": "0.0.0",
"private": true,
"dependencies": {
"@connectrpc/connect-web": "1.1.2",
"@connectrpc/connect": "1.1.2",
"@connectrpc/connect-web": "1.1.2",
"@gitpod/gitpod-protocol": "0.1.5",
"@gitpod/public-api": "0.1.5",
"@radix-ui/react-popover": "^1.0.7",
Expand All @@ -26,6 +26,7 @@
"idb-keyval": "^6.2.0",
"js-cookie": "^3.0.1",
"lodash.debounce": "^4.0.8",
"lucide-react": "^0.287.0",
"monaco-editor": "^0.25.2",
"pretty-bytes": "^6.1.0",
"process": "^0.11.10",
Expand Down
10 changes: 5 additions & 5 deletions components/dashboard/src/components/RepositoryFinder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
*/

import { FC, useCallback, useMemo, useState } from "react";
import { DropDown2, DropDown2Element, DropDown2SelectedElement } from "./DropDown2";
import { Combobox, ComboboxElement, ComboboxSelectedItem } from "./podkit/combobox/Combobox";
import RepositorySVG from "../icons/Repository.svg";
import { ReactComponent as RepositoryIcon } from "../icons/RepositoryWithColor.svg";
import { SuggestedRepository } from "@gitpod/gitpod-protocol";
Expand Down Expand Up @@ -92,14 +92,14 @@ export default function RepositoryFinder({
id: repo.projectId || repo.url,
element: <SuggestedRepositoryOption repo={repo} />,
isSelectable: true,
} as DropDown2Element;
} as ComboboxElement;
});
},
[repos],
);

return (
<DropDown2
<Combobox
getElements={getElements}
expanded={expanded}
// we use this to track the search string so we can search for repos via the api and filter in useUnifiedRepositorySearch
Expand All @@ -110,7 +110,7 @@ export default function RepositoryFinder({
searchPlaceholder="Paste repository URL or type to find suggestions"
onSearchChange={setSearchString}
>
<DropDown2SelectedElement
<ComboboxSelectedItem
icon={RepositorySVG}
htmlTitle={displayContextUrl(selectedContextURL) || "Repository"}
title={
Expand All @@ -130,7 +130,7 @@ export default function RepositoryFinder({
}
loading={isLoading}
/>
</DropDown2>
</Combobox>
);
}

Expand Down
10 changes: 5 additions & 5 deletions components/dashboard/src/components/SelectIDEComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import { IDEOption, IDEOptions } from "@gitpod/gitpod-protocol/lib/ide-protocol";
import { FC, useCallback, useEffect, useMemo } from "react";
import { DropDown2, DropDown2Element, DropDown2SelectedElement } from "./DropDown2";
import { Combobox, ComboboxElement, ComboboxSelectedItem } from "./podkit/combobox/Combobox";
import Editor from "../icons/Editor.svg";
import { useIDEOptions } from "../data/ide-options/ide-options-query";

Expand Down Expand Up @@ -58,7 +58,7 @@ export default function SelectIDEComponent({
if (!options) {
return [];
}
const result: DropDown2Element[] = [];
const result: ComboboxElement[] = [];
for (const ide of options.filter((ide) =>
`${ide.label}${ide.title}${ide.notes}${ide.id}`.toLowerCase().includes(search.toLowerCase()),
)) {
Expand Down Expand Up @@ -98,7 +98,7 @@ export default function SelectIDEComponent({
}
}, [ide, ideOptions, setError]);
return (
<DropDown2
<Combobox
getElements={getElements}
onSelectionChange={internalOnSelectionChange}
searchPlaceholder={"Select Editor"}
Expand All @@ -110,7 +110,7 @@ export default function SelectIDEComponent({
useLatest={!!useLatest}
loading={ideOptionsLoading || loading}
/>
</DropDown2>
</Combobox>
);
}

Expand Down Expand Up @@ -141,7 +141,7 @@ const IdeOptionElementSelected: FC<IdeOptionElementProps> = ({ option, useLatest
}

return (
<DropDown2SelectedElement
<ComboboxSelectedItem
icon={Editor}
loading={loading}
htmlTitle={title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import { SupportedWorkspaceClass } from "@gitpod/gitpod-protocol/lib/workspace-class";
import { FC, useCallback, useEffect, useMemo } from "react";
import WorkspaceClass from "../icons/WorkspaceClass.svg";
import { DropDown2, DropDown2Element, DropDown2SelectedElement } from "./DropDown2";
import { Combobox, ComboboxElement, ComboboxSelectedItem } from "./podkit/combobox/Combobox";
import { useWorkspaceClasses } from "../data/workspaces/workspace-classes-query";

interface SelectWorkspaceClassProps {
Expand All @@ -27,7 +27,7 @@ export default function SelectWorkspaceClassComponent({
}: SelectWorkspaceClassProps) {
const { data: workspaceClasses, isLoading: workspaceClassesLoading } = useWorkspaceClasses();

const getElements = useCallback((): DropDown2Element[] => {
const getElements = useCallback((): ComboboxElement[] => {
return (workspaceClasses || [])?.map((c) => ({
id: c.id,
element: <WorkspaceClassDropDownElement wsClass={c} />,
Expand Down Expand Up @@ -61,7 +61,7 @@ export default function SelectWorkspaceClassComponent({
return workspaceClasses.find((ws) => ws.id === (selectedWorkspaceClass || defaultClassId));
}, [selectedWorkspaceClass, workspaceClasses]);
return (
<DropDown2
<Combobox
getElements={getElements}
onSelectionChange={internalOnSelectionChange}
searchPlaceholder="Select class"
Expand All @@ -73,7 +73,7 @@ export default function SelectWorkspaceClassComponent({
wsClass={selectedWsClass}
loading={workspaceClassesLoading || loading}
/>
</DropDown2>
</Combobox>
);
}

Expand All @@ -89,7 +89,7 @@ const WorkspaceClassDropDownElementSelected: FC<WorkspaceClassDropDownElementSel
const title = wsClass?.displayName ?? "Select class";

return (
<DropDown2SelectedElement
<ComboboxSelectedItem
icon={WorkspaceClass}
loading={loading}
htmlTitle={title}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@
*/

import React, { FC, FunctionComponent, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from "react";
import Arrow from "./Arrow";
import classNames from "classnames";
import { ReactComponent as Spinner } from "../icons/Spinner.svg";
import * as RadixPopover from "@radix-ui/react-popover";
import { ChevronDown, CircleDashed } from "lucide-react";
import classNames from "classnames";

export interface DropDown2Element {
export interface ComboboxElement {
id: string;
element: JSX.Element;
isSelectable?: boolean;
}

export interface DropDown2Props {
export interface ComboboxProps {
initialValue?: string;
getElements: (searchString: string) => DropDown2Element[];
getElements: (searchString: string) => ComboboxElement[];
disabled?: boolean;
loading?: boolean;
searchPlaceholder?: string;
Expand All @@ -29,7 +28,7 @@ export interface DropDown2Props {
onSearchChange?: (searchString: string) => void;
}

export const DropDown2: FunctionComponent<DropDown2Props> = ({
export const Combobox: FunctionComponent<ComboboxProps> = ({
initialValue = "",
disabled = false,
loading = false,
Expand Down Expand Up @@ -188,8 +187,14 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
>
{children}
<div className="flex-grow" />
<div className="mr-2">
<Arrow direction={showDropDown ? "up" : "down"} />
<div
className={classNames(
// TODO: work on abstracting icon colors once we have a few places using lucide icons
"mr-2 text-gray-400 dark:text-gray-500 group-hover:text-gray-600 dark:group-hover:text-gray-400 transition-transform",
showDropDown && "rotate-180 transition-all",
)}
>
<ChevronDown />
</div>
</RadixPopover.Trigger>
<RadixPopover.Portal>
Expand All @@ -213,8 +218,8 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
onChange={handleInputChange}
/>
{showInputLoadingIndicator && (
<div className="absolute top-0 right-0 h-full flex items-center pr-2">
<Spinner className="h-4 w-4 opacity-25 animate-spin" />
<div className="absolute top-0 right-0 h-full flex items-center pr-2 animate-fade-in-fast">
<CircleDashed className="opacity-10 animate-spin-slow" />
</div>
)}
</div>
Expand All @@ -229,7 +234,7 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
{!showResultsLoadingIndicator && filteredOptions.length > 0 ? (
filteredOptions.map((element) => {
return (
<Dropdown2Element
<ComboboxItem
key={element.id}
element={element}
isActive={element.id === selectedElementTemp}
Expand All @@ -250,7 +255,7 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
);
};

type DropDown2SelectedElementProps = {
type ComboboxSelectedItemProps = {
// Either a string of the icon source or an element
icon: ReactNode;
loading?: boolean;
Expand All @@ -259,7 +264,7 @@ type DropDown2SelectedElementProps = {
htmlTitle?: string;
};

export const DropDown2SelectedElement: FC<DropDown2SelectedElementProps> = ({
export const ComboboxSelectedItem: FC<ComboboxSelectedItemProps> = ({
icon,
loading = false,
title,
Expand Down Expand Up @@ -297,14 +302,14 @@ export const DropDown2SelectedElement: FC<DropDown2SelectedElementProps> = ({
);
};

type Dropdown2ElementProps = {
element: DropDown2Element;
type ComboboxItemProps = {
element: ComboboxElement;
isActive: boolean;
onSelected: (id: string) => void;
onFocused: (id: string) => void;
};

export const Dropdown2Element: FC<Dropdown2ElementProps> = ({ element, isActive, onSelected, onFocused }) => {
export const ComboboxItem: FC<ComboboxItemProps> = ({ element, isActive, onSelected, onFocused }) => {
let selectionClasses = `dark:bg-gray-800 cursor-pointer`;
if (isActive) {
selectionClasses = `bg-gray-200 dark:bg-gray-700 cursor-pointer focus:outline-none focus:ring-0`;
Expand Down
3 changes: 2 additions & 1 deletion components/dashboard/src/hooks/use-debounce.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@ export const useDebounce = <T>(value: T, delay = 500, options?: DebounceOptions)
return debounce(setDebouncedValue, delay, {
leading: options?.leading || false,
trailing: options?.trailing || true,
maxWait: options?.maxWait ?? undefined,
// ensures debounced value is updated at least every 1s
maxWait: options?.maxWait ?? 1000,
});
}, [delay, options?.leading, options?.maxWait, options?.trailing]);

Expand Down
2 changes: 2 additions & 0 deletions components/dashboard/tailwind.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ module.exports = {
animation: {
"toast-in-right": "toast-in-right 0.3s ease-in-out",
"fade-in": "fade-in 3s linear",
"fade-in-fast": "fade-in .3s ease-in-out",
"spin-slow": "spin 2s linear infinite",
},
transitionProperty: {
width: "width",
Expand Down
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -10374,6 +10374,11 @@ lru_map@^0.3.3:
resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz"
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=

lucide-react@^0.287.0:
version "0.287.0"
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.287.0.tgz#efa49872a91fa97b7ef650c4b40396b6880d0088"
integrity sha512-auxP2bTGiMoELzX+6ItTeNzLmhGd/O+PHBsrXV2YwPXYCxarIFJhiMOSzFT9a1GWeYPSZtnWdLr79IVXr/5JqQ==

lz-string@^1.4.4:
version "1.4.4"
resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz"
Expand Down

0 comments on commit 5e6fa13

Please sign in to comment.