diff --git a/packages/datalib/src/filterName.ts b/packages/datalib/src/filterName.ts index 674be806..a99dbda6 100644 --- a/packages/datalib/src/filterName.ts +++ b/packages/datalib/src/filterName.ts @@ -1,5 +1,44 @@ -export function filterName(filter: string, name: string) { +import _ from 'lodash'; + +// original C# variant +// public bool Match(string value) +// { +// if (String.IsNullOrEmpty(Filter)) return false; +// if (String.IsNullOrEmpty(value)) return true; + +// var camelVariants = new HashSet(); +// camelVariants.Add(new String(value.Where(Char.IsUpper).ToArray())); +// if (value.All(x => Char.IsUpper(x) || x == '_')) +// { +// var sb = new StringBuilder(); +// for (int i = 0; i < value.Length; i++) +// { +// if (Char.IsUpper(value[i]) && (i == 0 || value[i - 1] == '_')) sb.Append(value[i]); +// } +// camelVariants.Add(sb.ToString()); +// } +// else +// { +// string s = value, s0; +// do +// { +// s0 = s; +// s = Regex.Replace(s, "([A-Z])([A-Z])([A-Z])", "$1$3"); +// } while (s0 != s); +// camelVariants.Add(new String(s.Where(Char.IsUpper).ToArray())); +// } + +// bool camelMatch = camelVariants.Any(x => DoMatch(Filter, x)); +// if (Filter.All(Char.IsUpper)) return camelMatch; +// return DoMatch(Filter, value) || camelMatch; +// } + +export function filterName(filter: string, ...names: string[]) { if (!filter) return true; - if (!name) return false; - return name.toUpperCase().includes(filter.toUpperCase()); + + // const camelVariants = [name.replace(/[^A-Z]/g, '')] + const tokens = filter.split(' ').map(x => x.trim()); + + return !!_.compact(names).find(name => !tokens.find(token => !name.toUpperCase().includes(token.toUpperCase()))); + // return name.toUpperCase().includes(filter.toUpperCase()); } diff --git a/packages/web/src/appobj/AppObjectList.js b/packages/web/src/appobj/AppObjectList.js index f13bb942..bb433f00 100644 --- a/packages/web/src/appobj/AppObjectList.js +++ b/packages/web/src/appobj/AppObjectList.js @@ -1,23 +1,92 @@ import React from 'react'; -import styled from 'styled-components'; -import { showMenu } from '../modals/DropDownMenu'; +import _ from 'lodash'; import { AppObjectCore } from './AppObjects'; import { useSetOpenedTabs } from '../utility/globalState'; +import styled from 'styled-components'; +import { ExpandIcon } from '../icons'; -export function AppObjectList({ list, makeAppObj, SubItems = undefined, onObjectClick = undefined }) { +const SubItemsDiv = styled.div` + margin-left: 16px; +`; + +const ExpandIconHolder = styled.span` + margin-right: 5px; + position: relative; + top: -3px; +`; + +// function ExpandIcon({ isBlank, isExpanded, isHover }) { +// if (column.foreignKey) { +// return ( +// +// ); +// } +// return ; +// } + +function AppObjectListItem({ makeAppObj, data, filter, appobj, onObjectClick, SubItems }) { + const [isExpanded, setIsExpanded] = React.useState(false); + const [isHover, setIsHover] = React.useState(false); + + const { matcher } = appobj; + if (matcher && !matcher(filter)) return null; + if (onObjectClick) appobj.onClick = onObjectClick; + if (SubItems) { + appobj.onClick = () => setIsExpanded(!isExpanded); + } + + let res = ( + setIsHover(true)} + onMouseLeave={() => setIsHover(false)} + prefix={ + SubItems ? ( + + + + ) : null + } + /> + ); + if (SubItems && isExpanded) { + res = ( + <> + {res} + + + + + ); + } + return res; +} + +export function AppObjectList({ + list, + makeAppObj, + SubItems = undefined, + onObjectClick = undefined, + filter = undefined, +}) { const setOpenedTabs = useSetOpenedTabs(); - return (list || []).map(x => { - const appobj = makeAppObj(x, { setOpenedTabs }); - if (onObjectClick) appobj.onClick = onObjectClick; - let res = ; - if (SubItems) { - res = ( - <> - {res} - - - ); - } - return res; + return (list || []).map(data => { + const appobj = makeAppObj(data, { setOpenedTabs }); + return ( + + ); }); } diff --git a/packages/web/src/appobj/AppObjects.js b/packages/web/src/appobj/AppObjects.js index f787d042..b059c3bc 100644 --- a/packages/web/src/appobj/AppObjects.js +++ b/packages/web/src/appobj/AppObjects.js @@ -23,7 +23,18 @@ const IconWrap = styled.span` margin-right: 10px; `; -export function AppObjectCore({ title, Icon, Menu, data, makeAppObj, onClick, isBold, component = 'div' }) { +export function AppObjectCore({ + title, + Icon, + Menu, + data, + makeAppObj, + onClick, + isBold, + component = 'div', + prefix = null, + ...other +}) { const setOpenedTabs = useSetOpenedTabs(); const handleContextMenu = event => { @@ -36,7 +47,13 @@ export function AppObjectCore({ title, Icon, Menu, data, makeAppObj, onClick, is const Component = component == 'div' ? AppObjectDiv : AppObjectSpan; return ( - onClick(data) : undefined} isBold={isBold}> + onClick(data) : undefined} + isBold={isBold} + {...other} + > + {prefix} diff --git a/packages/web/src/appobj/connectionAppObject.js b/packages/web/src/appobj/connectionAppObject.js index 3c279864..e7b1255c 100644 --- a/packages/web/src/appobj/connectionAppObject.js +++ b/packages/web/src/appobj/connectionAppObject.js @@ -4,6 +4,7 @@ import { DropDownMenuItem } from '../modals/DropDownMenu'; import showModal from '../modals/showModal'; import ConnectionModal from '../modals/ConnectionModal'; import axios from '../utility/axios'; +import { filterName } from '@dbgate/datalib'; function getIcon(engine) { switch (engine) { @@ -38,6 +39,7 @@ export default function connectionAppObject({ _id, server, displayName, engine } const title = displayName || server; const key = _id; const Icon = getIcon(engine); + const matcher = filter => filterName(filter, displayName, server); - return { title, key, Icon, Menu }; + return { title, key, Icon, Menu, matcher }; } diff --git a/packages/web/src/datagrid/ColumnManager.js b/packages/web/src/datagrid/ColumnManager.js index 6533e686..9247591e 100644 --- a/packages/web/src/datagrid/ColumnManager.js +++ b/packages/web/src/datagrid/ColumnManager.js @@ -2,7 +2,7 @@ import React from 'react'; import styled from 'styled-components'; import ColumnLabel from './ColumnLabel'; import { filterName } from '@dbgate/datalib'; -import { FontIcon } from '../icons'; +import { ExpandIcon } from '../icons'; const Wrapper = styled.div``; @@ -21,9 +21,9 @@ const SearchBoxWrapper = styled.div` `; const Button = styled.button` -// -webkit-appearance: none; -// -moz-appearance: none; -// appearance: none; + // -webkit-appearance: none; + // -moz-appearance: none; + // appearance: none; // width: 50px; `; @@ -32,17 +32,17 @@ const Input = styled.input` min-width: 90px; `; -function ExpandIcon({ display, column, isHover, ...other }) { - if (column.foreignKey) { - return ( - - ); - } - return ; -} +// function ExpandIcon({ display, column, isHover, ...other }) { +// if (column.foreignKey) { +// return ( +// +// ); +// } +// return ; +// } /** * @param {object} props @@ -55,9 +55,9 @@ function ColumnManagerRow(props) { return ( setIsHover(true)} onMouseLeave={() => setIsHover(false)}> display.toggleExpandedColumn(column.uniqueName)} /> ; } +export function ExpandIcon({ isBlank = false, isExpanded = false, isSelected = false, ...other }) { + if (isBlank) { + return ; + } + return ; +} + export const TableIcon = props => getIconImage('table2.svg', props); export const ViewIcon = props => getIconImage('view2.svg', props); export const DatabaseIcon = props => getIconImage('database.svg', props); @@ -87,11 +94,11 @@ export const LinkedServerIcon = props => getIconImage('linkedserver.svg', props) export const EmptyIcon = props => getIconImage('data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=', props); -export const TimesRedIcon = props => ; -export const TimesGreenCircleIcon = props => ; -export const GrayFilterIcon = props => ; -export const ExclamationTriangleIcon = props => ; -export const HourGlassIcon = props => ; -export const InfoBlueCircleIcon = props => ; +export const TimesRedIcon = props => ; +export const TimesGreenCircleIcon = props => ; +export const GrayFilterIcon = props => ; +export const ExclamationTriangleIcon = props => ; +export const HourGlassIcon = props => ; +export const InfoBlueCircleIcon = props => ; -export const SpinnerIcon = props => ; +export const SpinnerIcon = props => ; diff --git a/packages/web/src/widgets/DatabaseWidget.js b/packages/web/src/widgets/DatabaseWidget.js index e392b431..14086cf5 100644 --- a/packages/web/src/widgets/DatabaseWidget.js +++ b/packages/web/src/widgets/DatabaseWidget.js @@ -24,7 +24,6 @@ const MainContainer = styled.div` const OuterContainer = styled.div` flex: 1 1 0; - // min-height: 10px; overflow: hidden; width: ${theme.leftPanel.width}px; position: relative; @@ -71,16 +70,16 @@ function ConnectionList() { url: 'connections/list', reloadTrigger: 'connection-list-changed', }); + const [filter, setFilter] = React.useState(''); return ( <> - - - + setFilter(e.target.value)} /> + - + );