diff --git a/components/dashboard/package.json b/components/dashboard/package.json
index 7f235dbbe17bb6..d063106f658707 100644
--- a/components/dashboard/package.json
+++ b/components/dashboard/package.json
@@ -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",
@@ -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",
diff --git a/components/dashboard/src/components/RepositoryFinder.tsx b/components/dashboard/src/components/RepositoryFinder.tsx
index 5754857f1ad790..4b1901b2b0e3e2 100644
--- a/components/dashboard/src/components/RepositoryFinder.tsx
+++ b/components/dashboard/src/components/RepositoryFinder.tsx
@@ -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";
@@ -92,14 +92,14 @@ export default function RepositoryFinder({
id: repo.projectId || repo.url,
element: ,
isSelectable: true,
- } as DropDown2Element;
+ } as ComboboxElement;
});
},
[repos],
);
return (
-
-
-
+
);
}
diff --git a/components/dashboard/src/components/SelectIDEComponent.tsx b/components/dashboard/src/components/SelectIDEComponent.tsx
index 72434a974634a2..06c7afcff38a70 100644
--- a/components/dashboard/src/components/SelectIDEComponent.tsx
+++ b/components/dashboard/src/components/SelectIDEComponent.tsx
@@ -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";
@@ -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()),
)) {
@@ -98,7 +98,7 @@ export default function SelectIDEComponent({
}
}, [ide, ideOptions, setError]);
return (
-
-
+
);
}
@@ -141,7 +141,7 @@ const IdeOptionElementSelected: FC = ({ option, useLatest
}
return (
- {
+ const getElements = useCallback((): ComboboxElement[] => {
return (workspaceClasses || [])?.map((c) => ({
id: c.id,
element: ,
@@ -61,7 +61,7 @@ export default function SelectWorkspaceClassComponent({
return workspaceClasses.find((ws) => ws.id === (selectedWorkspaceClass || defaultClassId));
}, [selectedWorkspaceClass, workspaceClasses]);
return (
-
-
+
);
}
@@ -89,7 +89,7 @@ const WorkspaceClassDropDownElementSelected: FC DropDown2Element[];
+ getElements: (searchString: string) => ComboboxElement[];
disabled?: boolean;
loading?: boolean;
searchPlaceholder?: string;
@@ -29,7 +28,7 @@ export interface DropDown2Props {
onSearchChange?: (searchString: string) => void;
}
-export const DropDown2: FunctionComponent = ({
+export const Combobox: FunctionComponent = ({
initialValue = "",
disabled = false,
loading = false,
@@ -188,8 +187,14 @@ export const DropDown2: FunctionComponent = ({
>
{children}
-
-
+
+
@@ -213,8 +218,8 @@ export const DropDown2: FunctionComponent = ({
onChange={handleInputChange}
/>
{showInputLoadingIndicator && (
-
@@ -229,7 +234,7 @@ export const DropDown2: FunctionComponent = ({
{!showResultsLoadingIndicator && filteredOptions.length > 0 ? (
filteredOptions.map((element) => {
return (
- = ({
);
};
-type DropDown2SelectedElementProps = {
+type ComboboxSelectedItemProps = {
// Either a string of the icon source or an element
icon: ReactNode;
loading?: boolean;
@@ -259,7 +264,7 @@ type DropDown2SelectedElementProps = {
htmlTitle?: string;
};
-export const DropDown2SelectedElement: FC = ({
+export const ComboboxSelectedItem: FC = ({
icon,
loading = false,
title,
@@ -297,14 +302,14 @@ export const DropDown2SelectedElement: FC = ({
);
};
-type Dropdown2ElementProps = {
- element: DropDown2Element;
+type ComboboxItemProps = {
+ element: ComboboxElement;
isActive: boolean;
onSelected: (id: string) => void;
onFocused: (id: string) => void;
};
-export const Dropdown2Element: FC = ({ element, isActive, onSelected, onFocused }) => {
+export const ComboboxItem: FC = ({ 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`;
diff --git a/components/dashboard/src/hooks/use-debounce.ts b/components/dashboard/src/hooks/use-debounce.ts
index 71a13d1cffcf53..d4c7ccbbc7fcb2 100644
--- a/components/dashboard/src/hooks/use-debounce.ts
+++ b/components/dashboard/src/hooks/use-debounce.ts
@@ -20,7 +20,8 @@ export const useDebounce = (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]);
diff --git a/components/dashboard/tailwind.config.js b/components/dashboard/tailwind.config.js
index 185ef305f5b2cb..9b1a139fd816fa 100644
--- a/components/dashboard/tailwind.config.js
+++ b/components/dashboard/tailwind.config.js
@@ -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",
diff --git a/yarn.lock b/yarn.lock
index dd2a5fb1126782..b833ea79658f77 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -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"