UNPKG

@finos/legend-application-pure-ide

Version:
115 lines 10.6 kB
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime"; /** * Copyright (c) 2020-present, Goldman Sachs * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import { observer } from 'mobx-react-lite'; import { FileCoordinate, trimPathLeadingSlash, } from '../../server/models/File.js'; import { flowResult } from 'mobx'; import { CaseSensitiveIcon, ChevronDownIcon, ChevronRightIcon, CloseIcon, clsx, CollapseTreeIcon, ExpandTreeIcon, FileAltIcon, PanelLoadingIndicator, RefreshIcon, RegexIcon, TimesIcon, } from '@finos/legend-art'; import { useApplicationStore } from '@finos/legend-application'; import { usePureIDEStore } from '../PureIDEStoreProvider.js'; import { useEffect, useMemo, useRef } from 'react'; import { debounce } from '@finos/legend-shared'; import { PANEL_MODE } from '../../stores/PureIDEConfig.js'; const TextSearchResultEntryDisplay = observer((props) => { const { searchResult, result } = props; const ideStore = usePureIDEStore(); const applicationStore = useApplicationStore(); const goToResult = (coordinate) => () => flowResult(ideStore.loadFile(result.sourceId, new FileCoordinate(result.sourceId, coordinate.startLine, coordinate.startColumn))).catch(applicationStore.alertUnhandledError); const dismissResultForFile = () => searchResult.dismissSearchEntry(result); const dismissCoordinate = (coordinate) => () => { result.dismissCoordinate(coordinate); if (!result.coordinates.length) { searchResult.dismissSearchEntry(result); } }; return (_jsxs("div", { className: "text-search-panel__entry", children: [_jsxs("div", { className: "text-search-panel__entry__header", onClick: () => result.setIsExpanded(!result.isExpanded), children: [_jsxs("div", { className: "text-search-panel__entry__header__title", children: [_jsx("div", { className: "text-search-panel__entry__header__title__expander", children: result.isExpanded ? _jsx(ChevronDownIcon, {}) : _jsx(ChevronRightIcon, {}) }), _jsx("div", { className: "text-search-panel__entry__header__title__label", children: _jsx(FileAltIcon, {}) }), _jsx("div", { className: "text-search-panel__entry__header__title__content", children: trimPathLeadingSlash(result.sourceId) })] }), _jsxs("div", { className: "text-search-panel__entry__header__actions", children: [_jsx("div", { className: "text-search-panel__entry__header__action text-search-panel__entry__header__action--with-counter", children: _jsx("div", { className: "text-search-panel__entry__header__action__counter", children: result.coordinates.length }) }), _jsx("button", { className: "text-search-panel__entry__header__action text-search-panel__entry__header__action--hidden", tabIndex: -1, title: "Dismiss", onClick: dismissResultForFile, children: _jsx(TimesIcon, {}) })] })] }), result.isExpanded && (_jsx("div", { className: "text-search-panel__entry__content", children: result.coordinates.map((coordinate) => (_jsxs("div", { className: "text-search-panel__entry__content__item", children: [_jsxs("div", { className: "text-search-panel__entry__content__item__label text-search-panel__entry__content__item__label--full", title: coordinate.preview ? `${coordinate.preview.before}${coordinate.preview.found.replaceAll(/\n/g, '\u21B5')}${coordinate.preview.after}` : 'Go To Result', onClick: goToResult(coordinate), children: [coordinate.preview && (_jsxs("div", { className: "text-search-panel__entry__content__item__label__content", children: [_jsx("div", { className: "text-search-panel__entry__content__item__label__coordinates", children: `[${coordinate.startLine}:${coordinate.startColumn}]` }), _jsxs("div", { className: "text-search-panel__entry__content__item__label__preview", children: [_jsx("span", { className: "text-search-panel__entry__content__item__label__preview__text", children: coordinate.preview.before }), _jsx("span", { className: "text-search-panel__entry__content__item__label__preview__text text-search-panel__entry__content__item__label__preview__text--found", children: coordinate.preview.found.replaceAll(/\n/g, '\u21B5') }), _jsx("span", { className: "text-search-panel__entry__content__item__label__preview__text", children: coordinate.preview.after })] })] })), !coordinate.preview && (_jsx(_Fragment, { children: `line: ${coordinate.startLine} - column: ${coordinate.startColumn}` }))] }), _jsx("div", { className: "text-search-panel__entry__content__item__actions", children: _jsx("button", { className: "text-search-panel__entry__content__item__action text-search-panel__entry__content__item__action--hidden", tabIndex: -1, title: "Dismiss", onClick: dismissCoordinate(coordinate), children: _jsx(TimesIcon, {}) }) })] }, coordinate.uuid))) }))] })); }); const TextSearchResultDisplay = observer((props) => { const { searchResult } = props; const ideStore = usePureIDEStore(); const applicationStore = useApplicationStore(); const showExpandAction = searchResult.searchEntries.some((entry) => !entry.isExpanded); const refresh = () => { flowResult(ideStore.textSearchState.search()).catch(applicationStore.alertUnhandledError); }; const clear = () => { ideStore.textSearchState.setText(''); ideStore.textSearchState.setResult(undefined); }; const expandAll = () => { searchResult.searchEntries.forEach((entry) => entry.setIsExpanded(true)); }; const collapseAll = () => { searchResult.searchEntries.forEach((entry) => entry.setIsExpanded(false)); }; return (_jsxs("div", { className: "text-search-panel__content", children: [_jsxs("div", { className: "text-search-panel__content__header", children: [_jsx("div", { className: "text-search-panel__content__header__title", children: !searchResult.searchEntries.length ? `No result` : `${searchResult.numberOfResults} result(s) in ${searchResult.numberOfFiles} files` }), _jsxs("div", { className: "text-search-panel__content__header__actions", children: [_jsx("button", { className: "text-search-panel__content__header__action", tabIndex: -1, title: "Refresh", onClick: refresh, children: _jsx(RefreshIcon, {}) }), _jsx("button", { className: "text-search-panel__content__header__action", tabIndex: -1, title: "Clear", onClick: clear, children: _jsx(CloseIcon, {}) }), !showExpandAction && (_jsx("button", { className: "text-search-panel__content__header__action", tabIndex: -1, title: "Collapse All", onClick: collapseAll, children: _jsx(CollapseTreeIcon, {}) })), showExpandAction && (_jsx("button", { className: "text-search-panel__content__header__action", tabIndex: -1, title: "Expand All", onClick: expandAll, children: _jsx(ExpandTreeIcon, {}) }))] })] }), _jsx("div", { className: "text-search-panel__content__results", children: searchResult.searchEntries.map((searchEntry) => (_jsx(TextSearchResultEntryDisplay, { searchResult: searchResult, result: searchEntry }, searchEntry.uuid))) })] })); }); export const TextSearchPanel = observer(() => { const ideStore = usePureIDEStore(); const searchInputRef = useRef(null); const searchState = ideStore.textSearchState; const toggleCaseSensitive = () => searchState.setCaseSensitive(!searchState.isCaseSensitive); const toggleRegExp = () => searchState.setRegExp(!searchState.isRegExp); const debouncedSearch = useMemo(() => debounce(() => searchState.search(), 300), [searchState]); const onSearchTextChange = (event) => { const value = event.target.value; searchState.setText(value); debouncedSearch.cancel(); if (!value) { searchState.setResult(undefined); } else { debouncedSearch(); } }; const onSearchKeyDown = (event) => { if (event.code === 'Enter') { debouncedSearch.cancel(); if (searchState.text) { debouncedSearch(); } } else if (event.code === 'Escape') { searchInputRef.current?.select(); } }; useEffect(() => { if (searchInputRef.current) { searchState.setSearchInput(searchInputRef.current); } return () => searchState.setSearchInput(undefined); }, [searchState]); useEffect(() => { if (ideStore.panelGroupDisplayState.isOpen && ideStore.activePanelMode === PANEL_MODE.SEARCH) { searchState.focus(); } }, [ searchState, ideStore.panelGroupDisplayState.isOpen, ideStore.activePanelMode, ]); return (_jsxs("div", { className: "text-search-panel", children: [_jsx(PanelLoadingIndicator, { isLoading: ideStore.textSearchState.loadState.isInProgress }), _jsx("div", { className: "text-search-panel__header", children: _jsxs("div", { className: "text-search-panel__searcher__input__container", children: [_jsx("input", { ref: searchInputRef, autoFocus: true, className: "text-search-panel__searcher__input input--dark", onChange: onSearchTextChange, onKeyDown: onSearchKeyDown, value: searchState.text, placeholder: "Search" }), _jsxs("div", { className: "text-search-panel__searcher__input__actions", children: [_jsx("button", { className: clsx('text-search-panel__searcher__input__action', { 'text-search-panel__searcher__input__action--active': searchState.isCaseSensitive, }), tabIndex: -1, title: "Match Case", onClick: toggleCaseSensitive, children: _jsx(CaseSensitiveIcon, {}) }), _jsx("button", { className: clsx('text-search-panel__searcher__input__action', { 'text-search-panel__searcher__input__action--active': searchState.isRegExp, }), tabIndex: -1, title: "Use Regular Expression", onClick: toggleRegExp, children: _jsx(RegexIcon, {}) })] })] }) }), ideStore.textSearchState.result && (_jsx(TextSearchResultDisplay, { searchResult: ideStore.textSearchState.result }))] })); }); //# sourceMappingURL=TextSearchPanel.js.map