Skip to content

Add a filter to the New Data Source modal #789

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Apr 2, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 49 additions & 0 deletions client/packages/lowcoder/src/pages/datasource/pluginPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ import {
apiPluginsForQueryLibrary,
databasePlugins,
} from "@lowcoder-ee/constants/datasourceConstants";
import { Search } from "components/Search";
import { CreateDropdown } from "@lowcoder-ee/pages/ApplicationV2/CreateDropdown";
import React, { useState } from "react";

export const DataSourceButton = styled(AntdButton)`
&&& {
Expand Down Expand Up @@ -66,17 +69,62 @@ const SectionBody = styled.div`
gap: 8px;
`;

const OperationRightWrapper = styled.div`
display: flex;
align-items: center;
flex-shrink: 0;
margin-left: auto;
@media screen and (max-width: 500px) {
> Button {
display: none;
}
}
`;

/**
* Function source: https://stackoverflow.com/a/69623589/1394698, thanks to Jan Turoň
*
* Stripping diacritics and natively comparing the strings is much faster than using localeCompare.
* localeCompare also fails to search partials, it only searches the full string match, so is quite
* useless for a filter box.
*
* This method sacrifices some of the benefits of localeCompare, such as κόσμε == kosme and instead
* focuses solely on diacritics, which should be fine for the general use case.
*
* @param str the full string to search against (for this panel, it's always the Data Source #name)
* @param sub the filter string to search with
*/
export const localeContains = (str: string, sub: string): boolean => {
if (sub === "") return true;
if (!sub || !str.length) return false;
sub = "" + sub;
if (sub.length > str.length) return false;
let ascii = (s: string) => s.normalize("NFKD").replace(/[\u0300-\u036f]/g, "").toLowerCase();
return ascii(str).includes(ascii(sub));
}

export const PluginPanel = (props: { onSelect: (t: DataSourceTypeInfo) => void }) => {
const datasourceTypes = useSelector(getDataSourceTypes);
const currentPage = useCurrentPage();
const [searchValue, setSearchValue] = useState("");
const apiList = currentPage === "queryLibrary" ? apiPluginsForQueryLibrary : apiPlugins;

return (
<PanelWrapper>
<OperationRightWrapper>
<Search
placeholder={trans("search")}
value={searchValue}
onChange={(e) => setSearchValue(e.target.value)}
style={{ width: "192px", height: "32px", margin: "0" }}
/>
</OperationRightWrapper>
<SectionWrapper>
<SectionLabel>{trans("query.database")}</SectionLabel>
<SectionBody>
{datasourceTypes
.filter((t) => databasePlugins.includes(t.id) || t.definition?.category === "database")
.filter((t) => localeContains(t.name, searchValue))
.map((t) => {
return (
<DataSourceButton key={t.id} onClick={() => props.onSelect(t)}>
Expand All @@ -92,6 +140,7 @@ export const PluginPanel = (props: { onSelect: (t: DataSourceTypeInfo) => void }
<SectionBody>
{datasourceTypes
.filter((t) => apiList.includes(t.id) || t.definition?.category === "api")
.filter((t) => localeContains(t.name, searchValue))
.map((t) => (
<DataSourceButton key={t.id} onClick={() => props.onSelect(t)}>
{t.id && getBottomResIcon(t.id, "large", t.definition?.icon)}
Expand Down