Rework Search panels UI

This commit is contained in:
IRBorisov 2023-10-06 14:39:32 +03:00
parent a44a43214c
commit 8d062baa8b
11 changed files with 230 additions and 213 deletions

View File

@ -12,7 +12,7 @@ For more specific TODOs see comments in code
- система обработки ошибок backend - система обработки ошибок backend
[Tech] [Tech]
- reload react-data-table-component - multilevel modals / rework modal system
[deployment] [deployment]
- logs collection - logs collection

View File

@ -1,5 +1,5 @@
interface ButtonProps interface ButtonProps
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title'> { extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title'| 'type'> {
text?: string text?: string
icon?: React.ReactNode icon?: React.ReactNode
tooltip?: string tooltip?: string
@ -11,21 +11,19 @@ extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'child
} }
function Button({ function Button({
id, text, icon, tooltip, text, icon, tooltip,
dense, disabled, dense, disabled,
borderClass = 'border rounded', borderClass = 'border rounded',
colorClass = 'clr-btn-default', colorClass = 'clr-btn-default',
dimensions = 'w-fit h-fit', dimensions = 'w-fit h-fit',
loading, onClick, loading,
...props ...props
}: ButtonProps) { }: ButtonProps) {
const padding = dense ? 'px-1' : 'px-3 py-2'; const padding = dense ? 'px-1' : 'px-3 py-2';
const cursor = 'disabled:cursor-not-allowed ' + (loading ? 'cursor-progress ' : 'cursor-pointer '); const cursor = 'disabled:cursor-not-allowed ' + (loading ? 'cursor-progress ' : 'cursor-pointer ');
return ( return (
<button id={id} <button type='button'
type='button'
disabled={disabled ?? loading} disabled={disabled ?? loading}
onClick={onClick}
title={tooltip} title={tooltip}
className={`inline-flex items-center gap-2 align-middle justify-center select-none ${padding} ${colorClass} ${dimensions} ${borderClass} ${cursor}`} className={`inline-flex items-center gap-2 align-middle justify-center select-none ${padding} ${colorClass} ${dimensions} ${borderClass} ${cursor}`}
{...props} {...props}

View File

@ -0,0 +1,34 @@
interface SelectorButtonProps
extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'className' | 'children' | 'title' | 'type'> {
text?: string
icon?: React.ReactNode
tooltip?: string
dimensions?: string
borderClass?: string
colorClass?: string
transparent?: boolean
}
function SelectorButton({
text, icon, tooltip,
colorClass = 'clr-btn-default',
dimensions = 'w-fit h-fit',
transparent,
...props
}: SelectorButtonProps) {
const cursor = 'disabled:cursor-not-allowed cursor-pointer';
const position = `px-1 flex flex-start items-center gap-1 ${dimensions}`
return (
<button type='button'
className={`text-sm small-caps ${!transparent && 'border'} ${cursor} ${position} text-btn text-controls ${!transparent && colorClass}`}
title={tooltip}
{...props}
>
{icon && icon}
{text && <div className={'font-semibold whitespace-nowrap pb-1'}>{text}</div>}
</button>
);
}
export default SelectorButton;

View File

@ -16,7 +16,7 @@ import SelectMulti from '../Common/SelectMulti';
import TextInput from '../Common/TextInput'; import TextInput from '../Common/TextInput';
import DataTable, { IConditionalStyle } from '../DataTable'; import DataTable, { IConditionalStyle } from '../DataTable';
import HelpTerminologyControl from '../Help/HelpTerminologyControl'; import HelpTerminologyControl from '../Help/HelpTerminologyControl';
import { HelpIcon } from '../Icons'; import { HelpIcon, MagnifyingGlassIcon } from '../Icons';
import ReferenceTypeButton from './ReferenceTypeButton'; import ReferenceTypeButton from './ReferenceTypeButton';
import WordformButton from './WordformButton'; import WordformButton from './WordformButton';
@ -284,12 +284,17 @@ function DlgEditReference({ hideWindow, items, initial, onSave }: DlgEditReferen
</div>} </div>}
{type === ReferenceType.ENTITY && {type === ReferenceType.ENTITY &&
<div className='flex flex-col gap-2'> <div className='flex flex-col gap-2'>
<div className='relative'>
<div className='absolute inset-y-0 flex items-center pl-3 pointer-events-none text-controls'>
<MagnifyingGlassIcon />
</div>
<TextInput <TextInput
dimensions='w-full' dimensions='w-full pl-10'
placeholder='текст фильтра' placeholder='Поиск'
value={filter} value={filter}
onChange={event => setFilter(event.target.value)} onChange={event => setFilter(event.target.value)}
/> />
</div>
<div className='border min-h-[15.5rem] max-h-[15.5rem] text-sm overflow-y-auto'> <div className='border min-h-[15.5rem] max-h-[15.5rem] text-sm overflow-y-auto'>
<DataTable <DataTable
data={filteredData} data={filteredData}
@ -311,8 +316,9 @@ function DlgEditReference({ hideWindow, items, initial, onSave }: DlgEditReferen
</div> </div>
<div className='flex gap-4 flex-start'> <div className='flex gap-4 flex-start'>
<TextInput <TextInput
label='Отсылаемый идентификатор' label='Отсылаемая конституента'
dimensions='max-w-[18rem] min-w-[18rem] whitespace-nowrap' dimensions='max-w-[16rem] min-w-[16rem] whitespace-nowrap'
placeholder='Имя'
singleRow singleRow
value={alias} value={alias}
onChange={event => setAlias(event.target.value)} onChange={event => setAlias(event.target.value)}

View File

@ -1,12 +1,14 @@
import { useCallback } from 'react'; import { useCallback } from 'react';
import Button from '../../components/Common/Button';
import Dropdown from '../../components/Common/Dropdown'; import Dropdown from '../../components/Common/Dropdown';
import DropdownCheckbox from '../../components/Common/DropdownCheckbox'; import DropdownCheckbox from '../../components/Common/DropdownCheckbox';
import SelectorButton from '../../components/Common/SelectorButton';
import { FilterCogIcon } from '../../components/Icons'; import { FilterCogIcon } from '../../components/Icons';
import { useAuth } from '../../context/AuthContext'; import { useAuth } from '../../context/AuthContext';
import useDropdown from '../../hooks/useDropdown'; import useDropdown from '../../hooks/useDropdown';
import { LibraryFilterStrategy } from '../../models/miscelanious'; import { LibraryFilterStrategy } from '../../models/miscelanious';
import { prefixes } from '../../utils/constants';
import { describeLibraryFilter, labelLibraryFilter } from '../../utils/labels';
interface PickerStrategyProps { interface PickerStrategyProps {
value: LibraryFilterStrategy value: LibraryFilterStrategy
@ -14,65 +16,52 @@ interface PickerStrategyProps {
} }
function PickerStrategy({ value, onChange }: PickerStrategyProps) { function PickerStrategy({ value, onChange }: PickerStrategyProps) {
const pickerMenu = useDropdown(); const strategyMenu = useDropdown();
const { user } = useAuth(); const { user } = useAuth();
const handleChange = useCallback( const handleChange = useCallback(
(newValue: LibraryFilterStrategy) => { (newValue: LibraryFilterStrategy) => {
pickerMenu.hide(); strategyMenu.hide();
onChange(newValue); onChange(newValue);
}, [pickerMenu, onChange]); }, [strategyMenu, onChange]);
function isStrategyDisabled(strategy: LibraryFilterStrategy): boolean {
if (
strategy === LibraryFilterStrategy.PERSONAL ||
strategy === LibraryFilterStrategy.SUBSCRIBE ||
strategy === LibraryFilterStrategy.OWNED
) {
return !user;
} else {
return false;
}
}
return ( return (
<div ref={pickerMenu.ref} className='h-full text-right'> <div ref={strategyMenu.ref} className='h-full text-right'>
<Button <SelectorButton
icon={<FilterCogIcon color='text-controls' size={6} />} tooltip='Список фильтров'
dense transparent
tooltip='Фильтры' icon={<FilterCogIcon size={5} />}
colorClass='clr-input clr-hover text-btn' text={labelLibraryFilter(value)}
dimensions='h-full py-1 px-2 border-none' tabIndex={-1}
onClick={pickerMenu.toggle} onClick={strategyMenu.toggle}
/> />
{ pickerMenu.isActive && { strategyMenu.isActive &&
<Dropdown> <Dropdown>
{ Object.values(LibraryFilterStrategy).map(
(enumValue, index) => {
const strategy = enumValue as LibraryFilterStrategy;
return (
<DropdownCheckbox <DropdownCheckbox
setValue={() => handleChange(LibraryFilterStrategy.MANUAL)} key={`${prefixes.library_filters_list}${index}`}
value={value === LibraryFilterStrategy.MANUAL} value={value === strategy}
label='Отображать все' setValue={() => handleChange(strategy)}
/> label={labelLibraryFilter(strategy)}
<DropdownCheckbox tooltip={describeLibraryFilter(strategy)}
setValue={() => handleChange(LibraryFilterStrategy.COMMON)} disabled={isStrategyDisabled(strategy)}
value={value === LibraryFilterStrategy.COMMON} />);
label='Общедоступные' })}
tooltip='Отображать только общедоступные схемы'
/>
<DropdownCheckbox
setValue={() => handleChange(LibraryFilterStrategy.CANONICAL)}
value={value === LibraryFilterStrategy.CANONICAL}
label='Неизменные'
tooltip='Отображать только стандартные схемы'
/>
<DropdownCheckbox
setValue={() => handleChange(LibraryFilterStrategy.PERSONAL)}
value={value === LibraryFilterStrategy.PERSONAL}
label='Личные'
disabled={!user}
tooltip='Отображать только подписки и владеемые схемы'
/>
<DropdownCheckbox
setValue={() => handleChange(LibraryFilterStrategy.SUBSCRIBE)}
value={value === LibraryFilterStrategy.SUBSCRIBE}
label='Подписки'
disabled={!user}
tooltip='Отображать только подписки'
/>
<DropdownCheckbox
setValue={() => handleChange(LibraryFilterStrategy.OWNED)}
value={value === LibraryFilterStrategy.OWNED}
disabled={!user}
label='Я - Владелец!'
tooltip='Отображать только владеемые схемы'
/>
</Dropdown>} </Dropdown>}
</div> </div>
); );

View File

@ -76,12 +76,8 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setStrategy,
{filtered} из {total} {filtered} из {total}
</span> </span>
</div> </div>
<div className='flex items-center justify-center w-full ml-8'> <div className='flex items-center justify-center w-full gap-1'>
<PickerStrategy <div className='relative min-w-[10rem] select-none'>
value={strategy}
onChange={handleChangeStrategy}
/>
<div className='relative w-96 min-w-[10rem] select-none'>
<div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-controls'> <div className='absolute inset-y-0 left-0 flex items-center pl-3 pointer-events-none text-controls'>
<MagnifyingGlassIcon /> <MagnifyingGlassIcon />
</div> </div>
@ -89,10 +85,14 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setStrategy,
type='text' type='text'
value={query} value={query}
className='w-full p-2 pl-10 text-sm outline-none clr-input' className='w-full p-2 pl-10 text-sm outline-none clr-input'
placeholder='Поиск схемы...' placeholder='Поиск'
onChange={handleChangeQuery} onChange={handleChangeQuery}
/> />
</div> </div>
<PickerStrategy
value={strategy}
onChange={handleChangeStrategy}
/>
</div> </div>
</div> </div>
); );

View File

@ -1,60 +0,0 @@
import { useCallback } from 'react';
import Dropdown from '../../../components/Common/Dropdown';
import DropdownButton from '../../../components/Common/DropdownButton';
import { CogIcon } from '../../../components/Icons';
import useDropdown from '../../../hooks/useDropdown';
import { DependencyMode } from '../../../models/miscelanious';
import { labelDependencyMode } from '../../../utils/labels';
interface DependencyModePickerProps {
value: DependencyMode
onChange: (value: DependencyMode) => void
}
function DependencyModePicker({ value, onChange }: DependencyModePickerProps) {
const pickerMenu = useDropdown();
const handleChange = useCallback(
(newValue: DependencyMode) => {
pickerMenu.hide();
onChange(newValue);
}, [pickerMenu, onChange]);
return (
<div ref={pickerMenu.ref} className='h-full'>
<button
className='h-full w-[7.5rem] px-1 py-1 border clr-input clr-hover clr-btn-default text-btn inline-flex align-middle gap-1'
title='Настройка фильтрации по графу термов'
tabIndex={-1}
onClick={pickerMenu.toggle}
>
<CogIcon color='text-controls' size={5} />
<span className='text-sm font-semibold whitespace-nowrap'>{labelDependencyMode(value)}</span>
</button>
{ pickerMenu.isActive &&
<Dropdown stretchLeft >
<DropdownButton onClick={() => handleChange(DependencyMode.ALL)}>
<p><b>вся схема:</b> список всех конституент схемы</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(DependencyMode.EXPRESSION)}>
<p><b>выражение:</b> список идентификаторов из выражения</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(DependencyMode.OUTPUTS)}>
<p><b>потребители:</b> конституенты, ссылающиеся на данную</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(DependencyMode.INPUTS)}>
<p><b>поставщики:</b> конституенты, на которые ссылается данная</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(DependencyMode.EXPAND_OUTPUTS)}>
<p><b>зависимые:</b> конституенты, зависящие по цепочке</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(DependencyMode.EXPAND_INPUTS)}>
<p><b>влияющие:</b> конституенты, влияющие на данную (цепочка)</p>
</DropdownButton>
</Dropdown>}
</div>
);
}
export default DependencyModePicker;

View File

@ -1,58 +0,0 @@
import { useCallback } from 'react';
import Dropdown from '../../../components/Common/Dropdown';
import DropdownButton from '../../../components/Common/DropdownButton';
import { FilterCogIcon } from '../../../components/Icons';
import useDropdown from '../../../hooks/useDropdown';
import { CstMatchMode } from '../../../models/miscelanious';
import { labelCstMathchMode } from '../../../utils/labels';
interface MatchModePickerProps {
value: CstMatchMode
onChange: (value: CstMatchMode) => void
}
function MatchModePicker({ value, onChange }: MatchModePickerProps) {
const pickerMenu = useDropdown();
const handleChange = useCallback(
(newValue: CstMatchMode) => {
pickerMenu.hide();
onChange(newValue);
}, [pickerMenu, onChange]);
return (
<div ref={pickerMenu.ref} className='h-full'>
<button
className='h-full w-[6rem] px-1 py-1 border clr-input clr-hover clr-btn-default text-btn inline-flex align-middle gap-1'
title='Настройка атрибутов для фильтрации'
tabIndex={-1}
onClick={pickerMenu.toggle}
>
<FilterCogIcon color='text-controls' size={5} />
<span className='text-sm font-semibold whitespace-nowrap'>{labelCstMathchMode(value)}</span>
</button>
{ pickerMenu.isActive &&
<Dropdown stretchLeft>
<DropdownButton onClick={() => handleChange(CstMatchMode.ALL)}>
<p><b>везде:</b> искать во всех атрибутах</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(CstMatchMode.EXPR)}>
<p><b>выраж:</b> искать в формальных выражениях</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(CstMatchMode.TERM)}>
<p><b>термин:</b> искать в терминах</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(CstMatchMode.TEXT)}>
<p><b>текст:</b> искать в определениях и конвенциях</p>
</DropdownButton>
<DropdownButton onClick={() => handleChange(CstMatchMode.NAME)}>
<p><b>имя:</b> искать в идентификаторах конституент</p>
</DropdownButton>
</Dropdown>
}
</div>
);
}
export default MatchModePicker;

View File

@ -1,22 +1,28 @@
import { useCallback, useLayoutEffect, useMemo, useState } from 'react'; import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
import Dropdown from '../../../components/Common/Dropdown';
import DropdownButton from '../../../components/Common/DropdownButton';
import SelectorButton from '../../../components/Common/SelectorButton';
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '../../../components/DataTable'; import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '../../../components/DataTable';
import { MagnifyingGlassIcon } from '../../../components/Icons'; import { CogIcon, FilterCogIcon, MagnifyingGlassIcon } from '../../../components/Icons';
import { useRSForm } from '../../../context/RSFormContext'; import { useRSForm } from '../../../context/RSFormContext';
import { useConceptTheme } from '../../../context/ThemeContext'; import { useConceptTheme } from '../../../context/ThemeContext';
import useDropdown from '../../../hooks/useDropdown';
import useLocalStorage from '../../../hooks/useLocalStorage'; import useLocalStorage from '../../../hooks/useLocalStorage';
import useWindowSize from '../../../hooks/useWindowSize'; import useWindowSize from '../../../hooks/useWindowSize';
import { DependencyMode } from '../../../models/miscelanious'; import { DependencyMode as CstSource } from '../../../models/miscelanious';
import { CstMatchMode } from '../../../models/miscelanious'; import { CstMatchMode } from '../../../models/miscelanious';
import { applyGraphFilter } from '../../../models/miscelanious'; import { applyGraphFilter } from '../../../models/miscelanious';
import { CstType, extractGlobals, IConstituenta, matchConstituenta } from '../../../models/rsform'; import { CstType, extractGlobals, IConstituenta, matchConstituenta } from '../../../models/rsform';
import { createMockConstituenta } from '../../../models/rsform'; import { createMockConstituenta } from '../../../models/rsform';
import { colorfgCstStatus } from '../../../utils/color'; import { colorfgCstStatus } from '../../../utils/color';
import { prefixes } from '../../../utils/constants'; import { prefixes } from '../../../utils/constants';
import { describeConstituenta } from '../../../utils/labels'; import {
describeConstituenta, describeCstMathchMode,
describeCstSource, labelCstMathchMode,
labelCstSource
} from '../../../utils/labels';
import ConstituentaTooltip from './ConstituentaTooltip'; import ConstituentaTooltip from './ConstituentaTooltip';
import DependencyModePicker from './DependencyModePicker';
import MatchModePicker from './MatchModePicker';
// Height that should be left to accomodate navigation panel + bottom margin // Height that should be left to accomodate navigation panel + bottom margin
const LOCAL_NAVIGATION_H = '2.1rem'; const LOCAL_NAVIGATION_H = '2.1rem';
@ -46,10 +52,13 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
const [filterMatch, setFilterMatch] = useLocalStorage('side-filter-match', CstMatchMode.ALL); const [filterMatch, setFilterMatch] = useLocalStorage('side-filter-match', CstMatchMode.ALL);
const [filterText, setFilterText] = useLocalStorage('side-filter-text', ''); const [filterText, setFilterText] = useLocalStorage('side-filter-text', '');
const [filterSource, setFilterSource] = useLocalStorage('side-filter-dependency', DependencyMode.ALL); const [filterSource, setFilterSource] = useLocalStorage('side-filter-dependency', CstSource.ALL);
const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []); const [filteredData, setFilteredData] = useState<IConstituenta[]>(schema?.items ?? []);
const matchModeMenu = useDropdown();
const sourceMenu = useDropdown();
useLayoutEffect( useLayoutEffect(
() => { () => {
setColumnVisibility(prev => { setColumnVisibility(prev => {
@ -69,7 +78,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
return; return;
} }
let filtered: IConstituenta[] = []; let filtered: IConstituenta[] = [];
if (filterSource === DependencyMode.EXPRESSION) { if (filterSource === CstSource.EXPRESSION) {
const aliases = extractGlobals(expression); const aliases = extractGlobals(expression);
filtered = schema.items.filter((cst) => aliases.has(cst.alias)); filtered = schema.items.filter((cst) => aliases.has(cst.alias));
const names = filtered.map(cst => cst.alias) const names = filtered.map(cst => cst.alias)
@ -113,6 +122,18 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
} }
}, [onOpenEdit]); }, [onOpenEdit]);
const handleMatchModeChange = useCallback(
(newValue: CstMatchMode) => {
matchModeMenu.hide();
setFilterMatch(newValue);
}, [matchModeMenu, setFilterMatch]);
const handleSourceChange = useCallback(
(newValue: CstSource) => {
sourceMenu.hide();
setFilterSource(newValue);
}, [sourceMenu, setFilterSource]);
const columns = useMemo( const columns = useMemo(
() => [ () => [
columnHelper.accessor('alias', { columnHelper.accessor('alias', {
@ -196,18 +217,59 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
</div> </div>
<input type='text' <input type='text'
className='w-[14rem] pr-2 pl-8 py-1 outline-none select-none hover:text-clip clr-input' className='w-[14rem] pr-2 pl-8 py-1 outline-none select-none hover:text-clip clr-input'
placeholder='текст фильтра' placeholder='Поиск'
value={filterText} value={filterText}
onChange={event => setFilterText(event.target.value)} onChange={event => setFilterText(event.target.value)}
/> />
<MatchModePicker <div ref={matchModeMenu.ref}>
value={filterMatch} <SelectorButton
onChange={setFilterMatch} tooltip='Настройка атрибутов для фильтрации'
transparent
icon={<FilterCogIcon size={5} />}
text={labelCstMathchMode(filterMatch)}
tabIndex={-1}
onClick={matchModeMenu.toggle}
/> />
<DependencyModePicker { matchModeMenu.isActive &&
value={filterSource} <Dropdown stretchLeft>
onChange={setFilterSource} { Object.values(CstMatchMode).filter(value => !isNaN(Number(value))).map(
(value, index) => {
const matchMode = value as CstMatchMode;
return (
<DropdownButton
key={`${prefixes.cst_match_mode_list}${index}`}
onClick={() => handleMatchModeChange(matchMode)}
>
<p><span className='font-semibold'>{labelCstMathchMode(matchMode)}:</span> {describeCstMathchMode(matchMode)}</p>
</DropdownButton>);
})}
</Dropdown>}
</div>
<div ref={sourceMenu.ref}>
<SelectorButton
tooltip='Настройка фильтрации по графу термов'
transparent
icon={<CogIcon size={4} />}
text={labelCstSource(filterSource)}
tabIndex={-1}
onClick={sourceMenu.toggle}
/> />
{ sourceMenu.isActive &&
<Dropdown stretchLeft>
{ Object.values(CstSource).filter(value => !isNaN(Number(value))).map(
(value, index) => {
const source = value as CstSource;
return (
<DropdownButton
key={`${prefixes.cst_source_list}${index}`}
onClick={() => handleSourceChange(source)}
>
<p><span className='font-semibold'>{labelCstSource(source)}:</span> {describeCstSource(source)}</p>
</DropdownButton>);
})}
</Dropdown>}
</div>
</div> </div>
<div className='overflow-y-auto text-sm' style={{maxHeight : `${maxHeight}`}}> <div className='overflow-y-auto text-sm' style={{maxHeight : `${maxHeight}`}}>
<DataTable <DataTable

View File

@ -36,6 +36,9 @@ export const prefixes = {
cst_list: 'cst-list-', cst_list: 'cst-list-',
cst_wordform_list: 'cst-wordform-list-', cst_wordform_list: 'cst-wordform-list-',
cst_status_list: 'cst-status-list-', cst_status_list: 'cst-status-list-',
cst_match_mode_list: 'cst-match-mode-list-',
cst_source_list: 'cst-source-list-',
library_filters_list: 'library-filters-list',
topic_list: 'topic-list-', topic_list: 'topic-list-',
library_list: 'library-list-', library_list: 'library-list-',
wordform_list: 'wordform-list' wordform_list: 'wordform-list'

View File

@ -1,7 +1,7 @@
// =========== Modules contains all text descriptors ========== // =========== Modules contains all text descriptors ==========
import { GramData,Grammeme, ReferenceType } from '../models/language'; import { GramData,Grammeme, ReferenceType } from '../models/language';
import { CstMatchMode, DependencyMode, HelpTopic } from '../models/miscelanious'; import { CstMatchMode, DependencyMode, HelpTopic, LibraryFilterStrategy } from '../models/miscelanious';
import { CstClass, CstType, ExpressionStatus, IConstituenta } from '../models/rsform'; import { CstClass, CstType, ExpressionStatus, IConstituenta } from '../models/rsform';
import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from '../models/rslang'; import { IFunctionArg, IRSErrorDescription, ISyntaxTreeNode, ParsingStatus, RSErrorType, TokenID } from '../models/rslang';
@ -128,17 +128,27 @@ export function describeToken(id: TokenID): string {
export function labelCstMathchMode(mode: CstMatchMode): string { export function labelCstMathchMode(mode: CstMatchMode): string {
switch (mode) { switch (mode) {
case CstMatchMode.ALL: return 'везде'; case CstMatchMode.ALL: return 'общий';
case CstMatchMode.EXPR: return 'выраж'; case CstMatchMode.EXPR: return 'выражение';
case CstMatchMode.TERM: return 'термин'; case CstMatchMode.TERM: return 'термин';
case CstMatchMode.TEXT: return 'текст'; case CstMatchMode.TEXT: return 'текст';
case CstMatchMode.NAME: return 'имя'; case CstMatchMode.NAME: return 'имя';
} }
} }
export function labelDependencyMode(mode: DependencyMode): string { export function describeCstMathchMode(mode: CstMatchMode): string {
switch (mode) { switch (mode) {
case DependencyMode.ALL: return 'вся схема'; case CstMatchMode.ALL: return 'искать во всех атрибутах';
case CstMatchMode.EXPR: return 'искать в формальных выражениях';
case CstMatchMode.TERM: return 'искать в терминах';
case CstMatchMode.TEXT: return 'искать в определениях и конвенциях';
case CstMatchMode.NAME: return 'искать в идентификаторах конституент';
}
}
export function labelCstSource(mode: DependencyMode): string {
switch (mode) {
case DependencyMode.ALL: return 'не ограничен';
case DependencyMode.EXPRESSION: return 'выражение'; case DependencyMode.EXPRESSION: return 'выражение';
case DependencyMode.OUTPUTS: return 'потребители'; case DependencyMode.OUTPUTS: return 'потребители';
case DependencyMode.INPUTS: return 'поставщики'; case DependencyMode.INPUTS: return 'поставщики';
@ -147,6 +157,39 @@ export function labelDependencyMode(mode: DependencyMode): string {
} }
} }
export function describeCstSource(mode: DependencyMode): string {
switch (mode) {
case DependencyMode.ALL: return 'все конституенты';
case DependencyMode.EXPRESSION: return 'идентификаторы из выражения';
case DependencyMode.OUTPUTS: return 'конституенты, ссылающиеся на данную';
case DependencyMode.INPUTS: return 'конституенты, на которые ссылается данная';
case DependencyMode.EXPAND_INPUTS: return 'конституенты, зависящие по цепочке';
case DependencyMode.EXPAND_OUTPUTS: return 'конституенты, влияющие на данную по цепочке';
}
}
export function labelLibraryFilter(strategy: LibraryFilterStrategy): string {
switch (strategy) {
case LibraryFilterStrategy.MANUAL: return 'отображать все';
case LibraryFilterStrategy.COMMON: return 'общедоступные';
case LibraryFilterStrategy.CANONICAL: return 'неизменные';
case LibraryFilterStrategy.PERSONAL: return 'личные';
case LibraryFilterStrategy.SUBSCRIBE: return 'подписки';
case LibraryFilterStrategy.OWNED: return 'владелец';
}
}
export function describeLibraryFilter(strategy: LibraryFilterStrategy): string {
switch (strategy) {
case LibraryFilterStrategy.MANUAL: return 'Отображать все схемы';
case LibraryFilterStrategy.COMMON: return 'Отображать общедоступные схемы';
case LibraryFilterStrategy.CANONICAL: return 'Отображать стандартные схемы';
case LibraryFilterStrategy.PERSONAL: return 'Отображать подписки и владеемые схемы';
case LibraryFilterStrategy.SUBSCRIBE: return 'Отображать подписки';
case LibraryFilterStrategy.OWNED: return 'Отображать владеемые схемы';
}
}
export const mapLableLayout: Map<string, string> = export const mapLableLayout: Map<string, string> =
new Map([ new Map([
['forceatlas2', 'Граф: Атлас 2D'], ['forceatlas2', 'Граф: Атлас 2D'],