Skip to content

Commit 5e6fa13

Browse files
Setup podkit folder and move Combobox into it (#18923)
1 parent 7d1984f commit 5e6fa13

File tree

8 files changed

+48
-34
lines changed

8 files changed

+48
-34
lines changed

components/dashboard/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@
44
"version": "0.0.0",
55
"private": true,
66
"dependencies": {
7-
"@connectrpc/connect-web": "1.1.2",
87
"@connectrpc/connect": "1.1.2",
8+
"@connectrpc/connect-web": "1.1.2",
99
"@gitpod/gitpod-protocol": "0.1.5",
1010
"@gitpod/public-api": "0.1.5",
1111
"@radix-ui/react-popover": "^1.0.7",
@@ -26,6 +26,7 @@
2626
"idb-keyval": "^6.2.0",
2727
"js-cookie": "^3.0.1",
2828
"lodash.debounce": "^4.0.8",
29+
"lucide-react": "^0.287.0",
2930
"monaco-editor": "^0.25.2",
3031
"pretty-bytes": "^6.1.0",
3132
"process": "^0.11.10",

components/dashboard/src/components/RepositoryFinder.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66

77
import { FC, useCallback, useMemo, useState } from "react";
8-
import { DropDown2, DropDown2Element, DropDown2SelectedElement } from "./DropDown2";
8+
import { Combobox, ComboboxElement, ComboboxSelectedItem } from "./podkit/combobox/Combobox";
99
import RepositorySVG from "../icons/Repository.svg";
1010
import { ReactComponent as RepositoryIcon } from "../icons/RepositoryWithColor.svg";
1111
import { SuggestedRepository } from "@gitpod/gitpod-protocol";
@@ -92,14 +92,14 @@ export default function RepositoryFinder({
9292
id: repo.projectId || repo.url,
9393
element: <SuggestedRepositoryOption repo={repo} />,
9494
isSelectable: true,
95-
} as DropDown2Element;
95+
} as ComboboxElement;
9696
});
9797
},
9898
[repos],
9999
);
100100

101101
return (
102-
<DropDown2
102+
<Combobox
103103
getElements={getElements}
104104
expanded={expanded}
105105
// we use this to track the search string so we can search for repos via the api and filter in useUnifiedRepositorySearch
@@ -110,7 +110,7 @@ export default function RepositoryFinder({
110110
searchPlaceholder="Paste repository URL or type to find suggestions"
111111
onSearchChange={setSearchString}
112112
>
113-
<DropDown2SelectedElement
113+
<ComboboxSelectedItem
114114
icon={RepositorySVG}
115115
htmlTitle={displayContextUrl(selectedContextURL) || "Repository"}
116116
title={
@@ -130,7 +130,7 @@ export default function RepositoryFinder({
130130
}
131131
loading={isLoading}
132132
/>
133-
</DropDown2>
133+
</Combobox>
134134
);
135135
}
136136

components/dashboard/src/components/SelectIDEComponent.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

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

@@ -58,7 +58,7 @@ export default function SelectIDEComponent({
5858
if (!options) {
5959
return [];
6060
}
61-
const result: DropDown2Element[] = [];
61+
const result: ComboboxElement[] = [];
6262
for (const ide of options.filter((ide) =>
6363
`${ide.label}${ide.title}${ide.notes}${ide.id}`.toLowerCase().includes(search.toLowerCase()),
6464
)) {
@@ -98,7 +98,7 @@ export default function SelectIDEComponent({
9898
}
9999
}, [ide, ideOptions, setError]);
100100
return (
101-
<DropDown2
101+
<Combobox
102102
getElements={getElements}
103103
onSelectionChange={internalOnSelectionChange}
104104
searchPlaceholder={"Select Editor"}
@@ -110,7 +110,7 @@ export default function SelectIDEComponent({
110110
useLatest={!!useLatest}
111111
loading={ideOptionsLoading || loading}
112112
/>
113-
</DropDown2>
113+
</Combobox>
114114
);
115115
}
116116

@@ -141,7 +141,7 @@ const IdeOptionElementSelected: FC<IdeOptionElementProps> = ({ option, useLatest
141141
}
142142

143143
return (
144-
<DropDown2SelectedElement
144+
<ComboboxSelectedItem
145145
icon={Editor}
146146
loading={loading}
147147
htmlTitle={title}

components/dashboard/src/components/SelectWorkspaceClassComponent.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import { SupportedWorkspaceClass } from "@gitpod/gitpod-protocol/lib/workspace-class";
88
import { FC, useCallback, useEffect, useMemo } from "react";
99
import WorkspaceClass from "../icons/WorkspaceClass.svg";
10-
import { DropDown2, DropDown2Element, DropDown2SelectedElement } from "./DropDown2";
10+
import { Combobox, ComboboxElement, ComboboxSelectedItem } from "./podkit/combobox/Combobox";
1111
import { useWorkspaceClasses } from "../data/workspaces/workspace-classes-query";
1212

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

30-
const getElements = useCallback((): DropDown2Element[] => {
30+
const getElements = useCallback((): ComboboxElement[] => {
3131
return (workspaceClasses || [])?.map((c) => ({
3232
id: c.id,
3333
element: <WorkspaceClassDropDownElement wsClass={c} />,
@@ -61,7 +61,7 @@ export default function SelectWorkspaceClassComponent({
6161
return workspaceClasses.find((ws) => ws.id === (selectedWorkspaceClass || defaultClassId));
6262
}, [selectedWorkspaceClass, workspaceClasses]);
6363
return (
64-
<DropDown2
64+
<Combobox
6565
getElements={getElements}
6666
onSelectionChange={internalOnSelectionChange}
6767
searchPlaceholder="Select class"
@@ -73,7 +73,7 @@ export default function SelectWorkspaceClassComponent({
7373
wsClass={selectedWsClass}
7474
loading={workspaceClassesLoading || loading}
7575
/>
76-
</DropDown2>
76+
</Combobox>
7777
);
7878
}
7979

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

9191
return (
92-
<DropDown2SelectedElement
92+
<ComboboxSelectedItem
9393
icon={WorkspaceClass}
9494
loading={loading}
9595
htmlTitle={title}

components/dashboard/src/components/DropDown2.tsx renamed to components/dashboard/src/components/podkit/combobox/Combobox.tsx

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,19 @@
55
*/
66

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

13-
export interface DropDown2Element {
12+
export interface ComboboxElement {
1413
id: string;
1514
element: JSX.Element;
1615
isSelectable?: boolean;
1716
}
1817

19-
export interface DropDown2Props {
18+
export interface ComboboxProps {
2019
initialValue?: string;
21-
getElements: (searchString: string) => DropDown2Element[];
20+
getElements: (searchString: string) => ComboboxElement[];
2221
disabled?: boolean;
2322
loading?: boolean;
2423
searchPlaceholder?: string;
@@ -29,7 +28,7 @@ export interface DropDown2Props {
2928
onSearchChange?: (searchString: string) => void;
3029
}
3130

32-
export const DropDown2: FunctionComponent<DropDown2Props> = ({
31+
export const Combobox: FunctionComponent<ComboboxProps> = ({
3332
initialValue = "",
3433
disabled = false,
3534
loading = false,
@@ -188,8 +187,14 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
188187
>
189188
{children}
190189
<div className="flex-grow" />
191-
<div className="mr-2">
192-
<Arrow direction={showDropDown ? "up" : "down"} />
190+
<div
191+
className={classNames(
192+
// TODO: work on abstracting icon colors once we have a few places using lucide icons
193+
"mr-2 text-gray-400 dark:text-gray-500 group-hover:text-gray-600 dark:group-hover:text-gray-400 transition-transform",
194+
showDropDown && "rotate-180 transition-all",
195+
)}
196+
>
197+
<ChevronDown />
193198
</div>
194199
</RadixPopover.Trigger>
195200
<RadixPopover.Portal>
@@ -213,8 +218,8 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
213218
onChange={handleInputChange}
214219
/>
215220
{showInputLoadingIndicator && (
216-
<div className="absolute top-0 right-0 h-full flex items-center pr-2">
217-
<Spinner className="h-4 w-4 opacity-25 animate-spin" />
221+
<div className="absolute top-0 right-0 h-full flex items-center pr-2 animate-fade-in-fast">
222+
<CircleDashed className="opacity-10 animate-spin-slow" />
218223
</div>
219224
)}
220225
</div>
@@ -229,7 +234,7 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
229234
{!showResultsLoadingIndicator && filteredOptions.length > 0 ? (
230235
filteredOptions.map((element) => {
231236
return (
232-
<Dropdown2Element
237+
<ComboboxItem
233238
key={element.id}
234239
element={element}
235240
isActive={element.id === selectedElementTemp}
@@ -250,7 +255,7 @@ export const DropDown2: FunctionComponent<DropDown2Props> = ({
250255
);
251256
};
252257

253-
type DropDown2SelectedElementProps = {
258+
type ComboboxSelectedItemProps = {
254259
// Either a string of the icon source or an element
255260
icon: ReactNode;
256261
loading?: boolean;
@@ -259,7 +264,7 @@ type DropDown2SelectedElementProps = {
259264
htmlTitle?: string;
260265
};
261266

262-
export const DropDown2SelectedElement: FC<DropDown2SelectedElementProps> = ({
267+
export const ComboboxSelectedItem: FC<ComboboxSelectedItemProps> = ({
263268
icon,
264269
loading = false,
265270
title,
@@ -297,14 +302,14 @@ export const DropDown2SelectedElement: FC<DropDown2SelectedElementProps> = ({
297302
);
298303
};
299304

300-
type Dropdown2ElementProps = {
301-
element: DropDown2Element;
305+
type ComboboxItemProps = {
306+
element: ComboboxElement;
302307
isActive: boolean;
303308
onSelected: (id: string) => void;
304309
onFocused: (id: string) => void;
305310
};
306311

307-
export const Dropdown2Element: FC<Dropdown2ElementProps> = ({ element, isActive, onSelected, onFocused }) => {
312+
export const ComboboxItem: FC<ComboboxItemProps> = ({ element, isActive, onSelected, onFocused }) => {
308313
let selectionClasses = `dark:bg-gray-800 cursor-pointer`;
309314
if (isActive) {
310315
selectionClasses = `bg-gray-200 dark:bg-gray-700 cursor-pointer focus:outline-none focus:ring-0`;

components/dashboard/src/hooks/use-debounce.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ export const useDebounce = <T>(value: T, delay = 500, options?: DebounceOptions)
2020
return debounce(setDebouncedValue, delay, {
2121
leading: options?.leading || false,
2222
trailing: options?.trailing || true,
23-
maxWait: options?.maxWait ?? undefined,
23+
// ensures debounced value is updated at least every 1s
24+
maxWait: options?.maxWait ?? 1000,
2425
});
2526
}, [delay, options?.leading, options?.maxWait, options?.trailing]);
2627

components/dashboard/tailwind.config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ module.exports = {
6565
animation: {
6666
"toast-in-right": "toast-in-right 0.3s ease-in-out",
6767
"fade-in": "fade-in 3s linear",
68+
"fade-in-fast": "fade-in .3s ease-in-out",
69+
"spin-slow": "spin 2s linear infinite",
6870
},
6971
transitionProperty: {
7072
width: "width",

yarn.lock

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10374,6 +10374,11 @@ lru_map@^0.3.3:
1037410374
resolved "https://registry.npmjs.org/lru_map/-/lru_map-0.3.3.tgz"
1037510375
integrity sha1-tcg1G5Rky9dQM1p5ZQoOwOVhGN0=
1037610376

10377+
lucide-react@^0.287.0:
10378+
version "0.287.0"
10379+
resolved "https://registry.yarnpkg.com/lucide-react/-/lucide-react-0.287.0.tgz#efa49872a91fa97b7ef650c4b40396b6880d0088"
10380+
integrity sha512-auxP2bTGiMoELzX+6ItTeNzLmhGd/O+PHBsrXV2YwPXYCxarIFJhiMOSzFT9a1GWeYPSZtnWdLr79IVXr/5JqQ==
10381+
1037710382
lz-string@^1.4.4:
1037810383
version "1.4.4"
1037910384
resolved "https://registry.npmjs.org/lz-string/-/lz-string-1.4.4.tgz"

0 commit comments

Comments
 (0)