Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
gitpod-io
GitHub Repository: gitpod-io/gitpod
Path: blob/main/components/dashboard/src/prebuilds/configuration-input/ConfigurationInput.tsx
2501 views
1
/**
2
* Copyright (c) 2024 Gitpod GmbH. All rights reserved.
3
* Licensed under the GNU Affero General Public License (AGPL).
4
* See License.AGPL.txt in the project root for license information.
5
*/
6
7
import { FC, useCallback, useMemo, useState } from "react";
8
import { useConfiguration, useListConfigurations } from "../../data/configurations/configuration-queries";
9
import { Combobox, ComboboxElement } from "./Combobox";
10
import { ComboboxSelectedItem } from "./ComboboxSelectedItem";
11
12
type Props = {
13
selectedConfigurationId?: string;
14
disabled?: boolean;
15
expanded?: boolean;
16
onChange: (configurationId: string) => void;
17
};
18
export const ConfigurationDropdown = ({ selectedConfigurationId, disabled, expanded, onChange }: Props) => {
19
const [searchTerm, setSearchTerm] = useState("");
20
const { data, isLoading } = useListConfigurations({ searchTerm, sortBy: "creationTime", sortOrder: "desc" });
21
const configurations = data?.pages[0].configurations;
22
const { data: selectedConfiguration } = useConfiguration(selectedConfigurationId ?? ""); // we don't care if there is no data
23
24
const handleSelectionChange = useCallback(
25
(selectedId: string) => {
26
onChange(selectedId);
27
},
28
[onChange],
29
);
30
31
// Resolve the selected context url & project id props to a suggestion entry
32
const selectedSuggestion = useMemo(() => {
33
const match = configurations?.find((config) => {
34
return config.id === selectedConfigurationId;
35
});
36
37
return match ?? selectedConfiguration;
38
}, [configurations, selectedConfiguration, selectedConfigurationId]);
39
40
const getElements = useCallback(() => {
41
const resetFilterItem: ComboboxElement = {
42
id: "",
43
element: <SuggestedRepositoryOption repo={{ name: "Show all" }} />,
44
isSelectable: true,
45
};
46
47
if (!configurations) {
48
return [resetFilterItem];
49
}
50
51
const allRepositories = configurations;
52
// Make sure we include the user-specified configuration, even if it might not be in our current pagination
53
if (selectedConfiguration && !configurations.some((config) => config.id === selectedConfigurationId)) {
54
allRepositories.unshift(selectedConfiguration);
55
}
56
57
const result = allRepositories.map((repo) => {
58
return {
59
id: repo.id,
60
element: <SuggestedRepositoryOption repo={repo} />,
61
isSelectable: true,
62
} as ComboboxElement;
63
});
64
65
result.unshift(resetFilterItem);
66
67
return result;
68
}, [configurations, selectedConfiguration, selectedConfigurationId]);
69
70
return (
71
<Combobox
72
getElements={getElements}
73
expanded={expanded}
74
initialValue={selectedConfigurationId}
75
// we use this to track the search string so we can search for repos via the api and filter in useUnifiedRepositorySearch
76
onSelectionChange={handleSelectionChange}
77
disabled={disabled}
78
// Only consider the isLoading prop if we're including projects in list
79
loading={isLoading}
80
onSearchChange={setSearchTerm}
81
dropDownClassName="text-pk-content-primary"
82
>
83
<ComboboxSelectedItem
84
htmlTitle="Repository"
85
title={<div className="truncate">{selectedSuggestion?.name ?? "Select a repository"}</div>}
86
titleClassName="text-sm font-normal text-pk-content-primary"
87
loading={isLoading}
88
/>
89
</Combobox>
90
);
91
};
92
93
type SuggestedRepositoryOptionProps = {
94
repo: {
95
name: string;
96
cloneUrl?: string;
97
};
98
};
99
const SuggestedRepositoryOption: FC<SuggestedRepositoryOptionProps> = ({ repo }) => {
100
const { name, cloneUrl } = repo;
101
102
return (
103
<div className="flex flex-row items-center overflow-hidden" title={cloneUrl} aria-label={`Repository: ${name}`}>
104
{name && <span className="text-sm whitespace-nowrap">{name}</span>}
105
</div>
106
);
107
};
108
109