@@ -11,6 +11,9 @@ import {
11
11
apiPluginsForQueryLibrary ,
12
12
databasePlugins ,
13
13
} from "@lowcoder-ee/constants/datasourceConstants" ;
14
+ import { Search } from "components/Search" ;
15
+ import { CreateDropdown } from "@lowcoder-ee/pages/ApplicationV2/CreateDropdown" ;
16
+ import React , { useState } from "react" ;
14
17
15
18
export const DataSourceButton = styled ( AntdButton ) `
16
19
&&& {
@@ -66,17 +69,62 @@ const SectionBody = styled.div`
66
69
gap: 8px;
67
70
` ;
68
71
72
+ const OperationRightWrapper = styled . div `
73
+ display: flex;
74
+ align-items: center;
75
+ flex-shrink: 0;
76
+ margin-left: auto;
77
+ @media screen and (max-width: 500px) {
78
+ > Button {
79
+ display: none;
80
+ }
81
+ }
82
+ ` ;
83
+
84
+ /**
85
+ * Function source: https://stackoverflow.com/a/69623589/1394698, thanks to Jan Turoň
86
+ *
87
+ * Stripping diacritics and natively comparing the strings is much faster than using localeCompare.
88
+ * localeCompare also fails to search partials, it only searches the full string match, so is quite
89
+ * useless for a filter box.
90
+ *
91
+ * This method sacrifices some of the benefits of localeCompare, such as κόσμε == kosme and instead
92
+ * focuses solely on diacritics, which should be fine for the general use case.
93
+ *
94
+ * @param str the full string to search against (for this panel, it's always the Data Source #name)
95
+ * @param sub the filter string to search with
96
+ */
97
+ export const localeContains = ( str : string , sub : string ) : boolean => {
98
+ if ( sub === "" ) return true ;
99
+ if ( ! sub || ! str . length ) return false ;
100
+ sub = "" + sub ;
101
+ if ( sub . length > str . length ) return false ;
102
+ let ascii = ( s : string ) => s . normalize ( "NFKD" ) . replace ( / [ \u0300 - \u036f ] / g, "" ) . toLowerCase ( ) ;
103
+ return ascii ( str ) . includes ( ascii ( sub ) ) ;
104
+ }
105
+
69
106
export const PluginPanel = ( props : { onSelect : ( t : DataSourceTypeInfo ) => void } ) => {
70
107
const datasourceTypes = useSelector ( getDataSourceTypes ) ;
71
108
const currentPage = useCurrentPage ( ) ;
109
+ const [ searchValue , setSearchValue ] = useState ( "" ) ;
72
110
const apiList = currentPage === "queryLibrary" ? apiPluginsForQueryLibrary : apiPlugins ;
111
+
73
112
return (
74
113
< PanelWrapper >
114
+ < OperationRightWrapper >
115
+ < Search
116
+ placeholder = { trans ( "search" ) }
117
+ value = { searchValue }
118
+ onChange = { ( e ) => setSearchValue ( e . target . value ) }
119
+ style = { { width : "192px" , height : "32px" , margin : "0" } }
120
+ />
121
+ </ OperationRightWrapper >
75
122
< SectionWrapper >
76
123
< SectionLabel > { trans ( "query.database" ) } </ SectionLabel >
77
124
< SectionBody >
78
125
{ datasourceTypes
79
126
. filter ( ( t ) => databasePlugins . includes ( t . id ) || t . definition ?. category === "database" )
127
+ . filter ( ( t ) => localeContains ( t . name , searchValue ) )
80
128
. map ( ( t ) => {
81
129
return (
82
130
< DataSourceButton key = { t . id } onClick = { ( ) => props . onSelect ( t ) } >
@@ -92,6 +140,7 @@ export const PluginPanel = (props: { onSelect: (t: DataSourceTypeInfo) => void }
92
140
< SectionBody >
93
141
{ datasourceTypes
94
142
. filter ( ( t ) => apiList . includes ( t . id ) || t . definition ?. category === "api" )
143
+ . filter ( ( t ) => localeContains ( t . name , searchValue ) )
95
144
. map ( ( t ) => (
96
145
< DataSourceButton key = { t . id } onClick = { ( ) => props . onSelect ( t ) } >
97
146
{ t . id && getBottomResIcon ( t . id , "large" , t . definition ?. icon ) }
0 commit comments