Path: blob/main/components/dashboard/src/prebuilds/configuration-input/ConfigurationInput.tsx
2501 views
/**1* Copyright (c) 2024 Gitpod GmbH. All rights reserved.2* Licensed under the GNU Affero General Public License (AGPL).3* See License.AGPL.txt in the project root for license information.4*/56import { FC, useCallback, useMemo, useState } from "react";7import { useConfiguration, useListConfigurations } from "../../data/configurations/configuration-queries";8import { Combobox, ComboboxElement } from "./Combobox";9import { ComboboxSelectedItem } from "./ComboboxSelectedItem";1011type Props = {12selectedConfigurationId?: string;13disabled?: boolean;14expanded?: boolean;15onChange: (configurationId: string) => void;16};17export const ConfigurationDropdown = ({ selectedConfigurationId, disabled, expanded, onChange }: Props) => {18const [searchTerm, setSearchTerm] = useState("");19const { data, isLoading } = useListConfigurations({ searchTerm, sortBy: "creationTime", sortOrder: "desc" });20const configurations = data?.pages[0].configurations;21const { data: selectedConfiguration } = useConfiguration(selectedConfigurationId ?? ""); // we don't care if there is no data2223const handleSelectionChange = useCallback(24(selectedId: string) => {25onChange(selectedId);26},27[onChange],28);2930// Resolve the selected context url & project id props to a suggestion entry31const selectedSuggestion = useMemo(() => {32const match = configurations?.find((config) => {33return config.id === selectedConfigurationId;34});3536return match ?? selectedConfiguration;37}, [configurations, selectedConfiguration, selectedConfigurationId]);3839const getElements = useCallback(() => {40const resetFilterItem: ComboboxElement = {41id: "",42element: <SuggestedRepositoryOption repo={{ name: "Show all" }} />,43isSelectable: true,44};4546if (!configurations) {47return [resetFilterItem];48}4950const allRepositories = configurations;51// Make sure we include the user-specified configuration, even if it might not be in our current pagination52if (selectedConfiguration && !configurations.some((config) => config.id === selectedConfigurationId)) {53allRepositories.unshift(selectedConfiguration);54}5556const result = allRepositories.map((repo) => {57return {58id: repo.id,59element: <SuggestedRepositoryOption repo={repo} />,60isSelectable: true,61} as ComboboxElement;62});6364result.unshift(resetFilterItem);6566return result;67}, [configurations, selectedConfiguration, selectedConfigurationId]);6869return (70<Combobox71getElements={getElements}72expanded={expanded}73initialValue={selectedConfigurationId}74// we use this to track the search string so we can search for repos via the api and filter in useUnifiedRepositorySearch75onSelectionChange={handleSelectionChange}76disabled={disabled}77// Only consider the isLoading prop if we're including projects in list78loading={isLoading}79onSearchChange={setSearchTerm}80dropDownClassName="text-pk-content-primary"81>82<ComboboxSelectedItem83htmlTitle="Repository"84title={<div className="truncate">{selectedSuggestion?.name ?? "Select a repository"}</div>}85titleClassName="text-sm font-normal text-pk-content-primary"86loading={isLoading}87/>88</Combobox>89);90};9192type SuggestedRepositoryOptionProps = {93repo: {94name: string;95cloneUrl?: string;96};97};98const SuggestedRepositoryOption: FC<SuggestedRepositoryOptionProps> = ({ repo }) => {99const { name, cloneUrl } = repo;100101return (102<div className="flex flex-row items-center overflow-hidden" title={cloneUrl} aria-label={`Repository: ${name}`}>103{name && <span className="text-sm whitespace-nowrap">{name}</span>}104</div>105);106};107108109