mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Refactoring: improve id's and labels
Do not use html labels without inputs
This commit is contained in:
parent
38cd91765a
commit
56cb7236ca
|
@ -13,6 +13,7 @@ import ConstituentaBadge from './ConstituentaBadge';
|
|||
import FlexColumn from './ui/FlexColumn';
|
||||
|
||||
interface ConstituentaPickerProps {
|
||||
id?: string;
|
||||
prefixID?: string;
|
||||
data?: IConstituenta[];
|
||||
rows?: number;
|
||||
|
@ -29,6 +30,7 @@ interface ConstituentaPickerProps {
|
|||
const columnHelper = createColumnHelper<IConstituenta>();
|
||||
|
||||
function ConstituentaPicker({
|
||||
id,
|
||||
data,
|
||||
value,
|
||||
initialFilter = '',
|
||||
|
@ -85,13 +87,19 @@ function ConstituentaPicker({
|
|||
);
|
||||
|
||||
return (
|
||||
<div>
|
||||
<SearchBar value={filterText} onChange={newValue => setFilterText(newValue)} />
|
||||
<div className='border divide-y'>
|
||||
<SearchBar
|
||||
id={id ? `${id}__search` : undefined}
|
||||
noBorder
|
||||
value={filterText}
|
||||
onChange={newValue => setFilterText(newValue)}
|
||||
/>
|
||||
<DataTable
|
||||
id={id}
|
||||
dense
|
||||
noHeader
|
||||
noFooter
|
||||
className='overflow-y-auto text-sm border select-none'
|
||||
className='overflow-y-auto text-sm select-none'
|
||||
style={{ maxHeight: size, minHeight: size }}
|
||||
data={filteredData}
|
||||
columns={columns}
|
||||
|
|
|
@ -9,7 +9,7 @@ interface ConstituentaTooltipProps {
|
|||
|
||||
function ConstituentaTooltip({ data, anchor }: ConstituentaTooltipProps) {
|
||||
return (
|
||||
<Tooltip clickable anchorSelect={anchor} className='max-w-[30rem]'>
|
||||
<Tooltip clickable layer='z-modal-tooltip' anchorSelect={anchor} className='max-w-[30rem]'>
|
||||
<InfoConstituenta data={data} onClick={event => event.stopPropagation()} />
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
|
@ -14,7 +14,7 @@ import {
|
|||
useReactTable,
|
||||
type VisibilityState
|
||||
} from '@tanstack/react-table';
|
||||
import { useState } from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { CProps } from '../props';
|
||||
import DefaultNoData from './DefaultNoData';
|
||||
|
@ -33,7 +33,9 @@ export interface IConditionalStyle<TData> {
|
|||
export interface DataTableProps<TData extends RowData>
|
||||
extends CProps.Styling,
|
||||
Pick<TableOptions<TData>, 'data' | 'columns' | 'onRowSelectionChange' | 'onColumnVisibilityChange'> {
|
||||
id?: string;
|
||||
dense?: boolean;
|
||||
rows?: number;
|
||||
headPosition?: string;
|
||||
noHeader?: boolean;
|
||||
noFooter?: boolean;
|
||||
|
@ -66,9 +68,11 @@ export interface DataTableProps<TData extends RowData>
|
|||
* No sticky header if omitted
|
||||
*/
|
||||
function DataTable<TData extends RowData>({
|
||||
id,
|
||||
style,
|
||||
className,
|
||||
dense,
|
||||
rows,
|
||||
headPosition,
|
||||
conditionalRowStyles,
|
||||
noFooter,
|
||||
|
@ -120,8 +124,20 @@ function DataTable<TData extends RowData>({
|
|||
|
||||
const isEmpty = tableImpl.getRowModel().rows.length === 0;
|
||||
|
||||
// TODO: refactor formula for different font sizes and pagination tools
|
||||
const fixedSize = useMemo(() => {
|
||||
if (!rows) {
|
||||
return undefined;
|
||||
}
|
||||
if (dense) {
|
||||
return `calc(2px + (2px + 1.6875rem)*${rows} + ${noHeader ? '0px' : '(2px + 2.1875rem)'})`;
|
||||
} else {
|
||||
return `calc(2px + (2px + 2.1875rem)*${rows + (noHeader ? 0 : 1)})`;
|
||||
}
|
||||
}, [rows, dense, noHeader]);
|
||||
|
||||
return (
|
||||
<div className={className} style={style}>
|
||||
<div id={id} className={className} style={{ minHeight: fixedSize, maxHeight: fixedSize, ...style }}>
|
||||
<table className='w-full'>
|
||||
{!noHeader ? (
|
||||
<TableHeader
|
||||
|
@ -146,6 +162,7 @@ function DataTable<TData extends RowData>({
|
|||
|
||||
{enablePagination && !isEmpty ? (
|
||||
<PaginationTools
|
||||
id={id ? `${id}__pagination` : undefined}
|
||||
table={tableImpl}
|
||||
paginationOptions={paginationOptions}
|
||||
onChangePaginationOption={onChangePaginationOption}
|
||||
|
|
|
@ -8,12 +8,18 @@ import { BiChevronLeft, BiChevronRight, BiFirstPage, BiLastPage } from 'react-ic
|
|||
import { prefixes } from '@/utils/constants';
|
||||
|
||||
interface PaginationToolsProps<TData> {
|
||||
id?: string;
|
||||
table: Table<TData>;
|
||||
paginationOptions: number[];
|
||||
onChangePaginationOption?: (newValue: number) => void;
|
||||
}
|
||||
|
||||
function PaginationTools<TData>({ table, paginationOptions, onChangePaginationOption }: PaginationToolsProps<TData>) {
|
||||
function PaginationTools<TData>({
|
||||
id,
|
||||
table,
|
||||
paginationOptions,
|
||||
onChangePaginationOption
|
||||
}: PaginationToolsProps<TData>) {
|
||||
const handlePaginationOptionsChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLSelectElement>) => {
|
||||
const perPage = Number(event.target.value);
|
||||
|
@ -55,6 +61,7 @@ function PaginationTools<TData>({ table, paginationOptions, onChangePaginationOp
|
|||
<BiChevronLeft size='1.5rem' />
|
||||
</button>
|
||||
<input
|
||||
id={id ? `${id}__page` : undefined}
|
||||
title='Номер страницы. Выделите для ручного ввода'
|
||||
className='w-6 text-center clr-app'
|
||||
value={table.getState().pagination.pageIndex + 1}
|
||||
|
@ -83,6 +90,7 @@ function PaginationTools<TData>({ table, paginationOptions, onChangePaginationOp
|
|||
</button>
|
||||
</div>
|
||||
<select
|
||||
id={id ? `${id}__per_page` : undefined}
|
||||
value={table.getState().pagination.pageSize}
|
||||
onChange={handlePaginationOptionsChange}
|
||||
className='mx-2 cursor-pointer clr-app'
|
||||
|
|
|
@ -52,14 +52,14 @@ function TableBody<TData>({
|
|||
style={conditionalRowStyles && getRowStyles(row)}
|
||||
>
|
||||
{enableRowSelection ? (
|
||||
<td key={`select-${row.id}`} className='pl-3 pr-1 border-y align-middle'>
|
||||
<td key={`select-${row.id}`} className='pl-3 pr-1 align-middle border-y'>
|
||||
<SelectRow row={row} />
|
||||
</td>
|
||||
) : null}
|
||||
{row.getVisibleCells().map((cell: Cell<TData, unknown>) => (
|
||||
<td
|
||||
key={cell.id}
|
||||
className='px-2 border-y align-middle'
|
||||
className='px-2 align-middle border-y'
|
||||
style={{
|
||||
cursor: onRowClicked || onRowDoubleClicked ? 'pointer' : 'auto',
|
||||
paddingBottom: dense ? '0.25rem' : '0.5rem',
|
||||
|
|
|
@ -147,7 +147,7 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
|||
|
||||
return (
|
||||
<div className={clsx('flex flex-col gap-2', className, cursor)} style={style}>
|
||||
<Label text={label} htmlFor={id} />
|
||||
<Label text={label} />
|
||||
<CodeMirror
|
||||
className='font-math'
|
||||
id={id}
|
||||
|
|
|
@ -182,7 +182,7 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
|||
</AnimatePresence>
|
||||
|
||||
<div className={clsx('flex flex-col gap-2', cursor)}>
|
||||
<Label text={label} htmlFor={id} />
|
||||
<Label text={label} />
|
||||
<CodeMirror
|
||||
id={id}
|
||||
ref={thisRef}
|
||||
|
|
|
@ -15,7 +15,6 @@ export interface CheckboxProps extends Omit<CProps.Button, 'value' | 'onClick'>
|
|||
}
|
||||
|
||||
function Checkbox({
|
||||
id,
|
||||
disabled,
|
||||
label,
|
||||
title,
|
||||
|
@ -47,7 +46,6 @@ function Checkbox({
|
|||
return (
|
||||
<button
|
||||
type='button'
|
||||
id={id}
|
||||
className={clsx(
|
||||
'flex items-center gap-2', // prettier: split lines
|
||||
'outline-none',
|
||||
|
@ -78,9 +76,7 @@ function Checkbox({
|
|||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<label className={clsx('text-start text-sm whitespace-nowrap', cursor)} htmlFor={id}>
|
||||
{label}
|
||||
</label>
|
||||
{label ? <span className={clsx('text-start text-sm whitespace-nowrap', cursor)}>{label}</span> : null}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ export interface CheckboxTristateProps extends Omit<CheckboxProps, 'value' | 'se
|
|||
}
|
||||
|
||||
function CheckboxTristate({
|
||||
id,
|
||||
disabled,
|
||||
label,
|
||||
title,
|
||||
|
@ -50,7 +49,6 @@ function CheckboxTristate({
|
|||
return (
|
||||
<button
|
||||
type='button'
|
||||
id={id}
|
||||
className={clsx(
|
||||
'flex items-center gap-2', // prettier: split lines
|
||||
'outline-none',
|
||||
|
@ -86,9 +84,7 @@ function CheckboxTristate({
|
|||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
<label className={clsx('text-start text-sm whitespace-nowrap', cursor)} htmlFor={id}>
|
||||
{label}
|
||||
</label>
|
||||
{label ? <span className={clsx('text-start text-sm whitespace-nowrap', cursor)}>{label}</span> : null}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ interface FileInputProps extends Omit<CProps.Input, 'accept' | 'type'> {
|
|||
onChange?: (event: React.ChangeEvent<HTMLInputElement>) => void;
|
||||
}
|
||||
|
||||
function FileInput({ label, acceptType, title, className, style, onChange, ...restProps }: FileInputProps) {
|
||||
function FileInput({ id, label, acceptType, title, className, style, onChange, ...restProps }: FileInputProps) {
|
||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||
const [fileName, setFileName] = useState('');
|
||||
|
||||
|
@ -37,6 +37,7 @@ function FileInput({ label, acceptType, title, className, style, onChange, ...re
|
|||
return (
|
||||
<div className={clsx('py-2', 'flex flex-col gap-2 items-center', className)} style={style}>
|
||||
<input
|
||||
id={id}
|
||||
type='file'
|
||||
ref={inputRef}
|
||||
style={{ display: 'none' }}
|
||||
|
@ -45,7 +46,7 @@ function FileInput({ label, acceptType, title, className, style, onChange, ...re
|
|||
{...restProps}
|
||||
/>
|
||||
<Button text={label} icon={<BiUpload size='1.25rem' />} onClick={handleUploadClick} title={title} />
|
||||
<Label text={fileName} />
|
||||
<Label text={fileName} htmlFor={id} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -10,11 +10,19 @@ function Label({ text, className, ...restProps }: LabelProps) {
|
|||
if (!text) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<label className={clsx('text-sm font-medium whitespace-nowrap', className)} {...restProps}>
|
||||
{text}
|
||||
</label>
|
||||
);
|
||||
if (restProps.htmlFor) {
|
||||
return (
|
||||
<label className={clsx('text-sm font-medium whitespace-nowrap', className)} {...restProps}>
|
||||
{text}
|
||||
</label>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span className={clsx('text-sm font-medium whitespace-nowrap', className)} {...restProps}>
|
||||
{text}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default Label;
|
||||
|
|
|
@ -8,7 +8,7 @@ interface LabeledValueProps {
|
|||
function LabeledValue({ id, label, text, title }: LabeledValueProps) {
|
||||
return (
|
||||
<div className='flex justify-between gap-3'>
|
||||
<label title={title}>{label}</label>
|
||||
<span title={title}>{label}</span>
|
||||
<span id={id}>{text}</span>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -6,17 +6,19 @@ import TextInput from './TextInput';
|
|||
|
||||
interface SearchBarProps extends CProps.Styling {
|
||||
value: string;
|
||||
id?: string;
|
||||
onChange?: (newValue: string) => void;
|
||||
noBorder?: boolean;
|
||||
}
|
||||
|
||||
function SearchBar({ value, onChange, noBorder, ...restProps }: SearchBarProps) {
|
||||
function SearchBar({ id, value, onChange, noBorder, ...restProps }: SearchBarProps) {
|
||||
return (
|
||||
<div {...restProps}>
|
||||
<Overlay position='top-[-0.125rem] left-3 translate-y-1/2' className='pointer-events-none clr-text-controls'>
|
||||
<BiSearchAlt2 size='1.25rem' />
|
||||
</Overlay>
|
||||
<TextInput
|
||||
id={id}
|
||||
noOutline
|
||||
placeholder='Поиск'
|
||||
type='search'
|
||||
|
|
|
@ -65,15 +65,26 @@ function DlgCloneLibraryItem({ hideWindow, base }: DlgCloneLibraryItemProps) {
|
|||
onSubmit={handleSubmit}
|
||||
className={clsx('px-6 py-2', classnames.flex_col)}
|
||||
>
|
||||
<TextInput label='Полное название' value={title} onChange={event => setTitle(event.target.value)} />
|
||||
<TextInput
|
||||
id='dlg_full_name'
|
||||
label='Полное название'
|
||||
value={title}
|
||||
onChange={event => setTitle(event.target.value)}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_alias'
|
||||
label='Сокращение'
|
||||
value={alias}
|
||||
className='max-w-sm'
|
||||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<TextArea label='Комментарий' value={comment} onChange={event => setComment(event.target.value)} />
|
||||
<Checkbox label='Общедоступная схема' value={common} setValue={value => setCommon(value)} />
|
||||
<TextArea
|
||||
id='dlg_comment'
|
||||
label='Комментарий'
|
||||
value={comment}
|
||||
onChange={event => setComment(event.target.value)}
|
||||
/>
|
||||
<Checkbox id='dlg_is_common' label='Общедоступная схема' value={common} setValue={value => setCommon(value)} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -214,6 +214,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
|||
</div>
|
||||
|
||||
<ConstituentaPicker
|
||||
id='dlg_argument_picker'
|
||||
value={selectedCst}
|
||||
data={schema?.items}
|
||||
onSelectValue={handleSelectConstituenta}
|
||||
|
|
|
@ -18,6 +18,7 @@ function ConstituentaTab({ state, partialUpdate }: ConstituentaTabProps) {
|
|||
<>
|
||||
<div className='flex self-center gap-3 pr-2'>
|
||||
<SelectSingle
|
||||
id='dlg_cst_type'
|
||||
className='min-w-[14rem]'
|
||||
options={SelectorCstType}
|
||||
placeholder='Выберите тип'
|
||||
|
@ -25,6 +26,7 @@ function ConstituentaTab({ state, partialUpdate }: ConstituentaTabProps) {
|
|||
onChange={data => partialUpdate({ cst_type: data?.value ?? CstType.TERM })}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_cst_alias'
|
||||
dense
|
||||
label='Имя'
|
||||
className='w-[7rem]'
|
||||
|
@ -33,6 +35,7 @@ function ConstituentaTab({ state, partialUpdate }: ConstituentaTabProps) {
|
|||
/>
|
||||
</div>
|
||||
<TextArea
|
||||
id='dlg_cst_term'
|
||||
spellCheck
|
||||
label='Термин'
|
||||
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
||||
|
@ -41,6 +44,7 @@ function ConstituentaTab({ state, partialUpdate }: ConstituentaTabProps) {
|
|||
onChange={event => partialUpdate({ term_raw: event.target.value })}
|
||||
/>
|
||||
<RSInput
|
||||
id='dlg_cst_expression'
|
||||
label='Формальное определение'
|
||||
placeholder='Родоструктурное выражение, задающее формальное определение'
|
||||
height='5.1rem'
|
||||
|
@ -48,6 +52,7 @@ function ConstituentaTab({ state, partialUpdate }: ConstituentaTabProps) {
|
|||
onChange={value => partialUpdate({ definition_formal: value })}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_cst_definition'
|
||||
label='Текстовое определение'
|
||||
placeholder='Лингвистическая интерпретация формального выражения'
|
||||
rows={2}
|
||||
|
@ -56,6 +61,7 @@ function ConstituentaTab({ state, partialUpdate }: ConstituentaTabProps) {
|
|||
onChange={event => partialUpdate({ definition_raw: event.target.value })}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_cst_convention'
|
||||
spellCheck
|
||||
label='Конвенция / Комментарий'
|
||||
placeholder='Договоренность об интерпретации или пояснение к схеме'
|
||||
|
|
|
@ -105,7 +105,7 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
|||
isClearable
|
||||
/>
|
||||
<SelectSingle
|
||||
placeholder='Выберите источник'
|
||||
placeholder='Источник'
|
||||
className='w-[12rem]'
|
||||
options={templateSelector}
|
||||
value={
|
||||
|
@ -117,6 +117,7 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
|||
/>
|
||||
</div>
|
||||
<ConstituentaPicker
|
||||
id='dlg_template_picker'
|
||||
value={state.prototype}
|
||||
data={filteredData}
|
||||
onSelectValue={cst => partialUpdate({ prototype: cst })}
|
||||
|
@ -124,6 +125,7 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
|||
rows={9}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_template_term'
|
||||
disabled
|
||||
spellCheck
|
||||
placeholder='Шаблон конституенты не выбран'
|
||||
|
@ -132,6 +134,7 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
|||
value={prototypeInfo}
|
||||
/>
|
||||
<RSInput
|
||||
id='dlg_template_expression'
|
||||
disabled
|
||||
placeholder='Выберите шаблон из списка'
|
||||
height='5.1rem'
|
||||
|
|
|
@ -57,6 +57,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
>
|
||||
<div className='flex self-center gap-6'>
|
||||
<SelectSingle
|
||||
id='dlg_cst_type'
|
||||
placeholder='Выберите тип'
|
||||
className='min-w-[15rem]'
|
||||
options={SelectorCstType}
|
||||
|
@ -64,6 +65,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
onChange={data => updateCstData({ cst_type: data?.value ?? CstType.BASE })}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_cst_alias'
|
||||
dense
|
||||
label='Имя'
|
||||
className='w-[7rem]'
|
||||
|
@ -72,6 +74,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
/>
|
||||
</div>
|
||||
<TextArea
|
||||
id='dlg_cst_term'
|
||||
spellCheck
|
||||
label='Термин'
|
||||
placeholder='Схемный или предметный термин, обозначающий данное понятие или утверждение'
|
||||
|
@ -80,6 +83,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
onChange={event => updateCstData({ term_raw: event.target.value })}
|
||||
/>
|
||||
<RSInput
|
||||
id='dlg_cst_expression'
|
||||
label='Формальное определение'
|
||||
placeholder='Родоструктурное выражение, задающее формальное определение'
|
||||
height='5.1rem'
|
||||
|
@ -87,6 +91,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
onChange={value => updateCstData({ definition_formal: value })}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_cst_definition'
|
||||
spellCheck
|
||||
label='Текстовое определение'
|
||||
placeholder='Лингвистическая интерпретация формального выражения'
|
||||
|
@ -95,6 +100,7 @@ function DlgCreateCst({ hideWindow, initial, schema, onCreate }: DlgCreateCstPro
|
|||
onChange={event => updateCstData({ definition_raw: event.target.value })}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_cst_convention'
|
||||
spellCheck
|
||||
label='Конвенция / Комментарий'
|
||||
placeholder='Договоренность об интерпретации или пояснение'
|
||||
|
|
|
@ -41,6 +41,7 @@ function DlgCreateVersion({ hideWindow, versions, onCreate }: DlgCreateVersionPr
|
|||
className={clsx('w-[30rem]', 'py-2 px-6', classnames.flex_col)}
|
||||
>
|
||||
<TextInput
|
||||
id='dlg_version'
|
||||
dense
|
||||
label='Версия'
|
||||
className='w-[16rem]'
|
||||
|
@ -48,6 +49,7 @@ function DlgCreateVersion({ hideWindow, versions, onCreate }: DlgCreateVersionPr
|
|||
onChange={event => setVersion(event.target.value)}
|
||||
/>
|
||||
<TextArea
|
||||
id='dlg_description'
|
||||
spellCheck
|
||||
label='Описание'
|
||||
rows={3}
|
||||
|
|
|
@ -61,6 +61,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
|||
return (
|
||||
<FlexColumn>
|
||||
<ConstituentaPicker
|
||||
id='dlg_reference_entity_picker'
|
||||
initialFilter={initial.text}
|
||||
value={selectedCst}
|
||||
data={items}
|
||||
|
@ -74,6 +75,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
|||
|
||||
<div className='flex gap-3'>
|
||||
<TextInput
|
||||
id='dlg_reference_alias'
|
||||
dense
|
||||
label='Конституента'
|
||||
placeholder='Имя'
|
||||
|
@ -81,7 +83,16 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
|||
value={alias}
|
||||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<TextInput disabled dense noBorder label='Термин' className='flex-grow text-sm' value={term} title={term} />
|
||||
<TextInput
|
||||
id='dlg_reference_term'
|
||||
disabled
|
||||
dense
|
||||
noBorder
|
||||
label='Термин'
|
||||
className='flex-grow text-sm'
|
||||
value={term}
|
||||
title={term}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<SelectWordForm selected={selectedGrams} setSelected={setSelectedGrams} />
|
||||
|
@ -89,6 +100,7 @@ function EntityTab({ initial, items, setIsValid, setReference }: EntityTabProps)
|
|||
<div className='flex items-center gap-4'>
|
||||
<Label text='Словоформа' />
|
||||
<SelectGrammeme
|
||||
id='dlg_reference_grammemes'
|
||||
placeholder='Выберите граммемы'
|
||||
className='flex-grow'
|
||||
menuPlacement='top'
|
||||
|
|
|
@ -45,6 +45,7 @@ function SyntacticTab({ initial, setIsValid, setReference }: SyntacticTabProps)
|
|||
return (
|
||||
<div className='flex flex-col gap-2'>
|
||||
<TextInput
|
||||
id='dlg_reference_offset'
|
||||
type='number'
|
||||
dense
|
||||
label='Смещение'
|
||||
|
@ -53,6 +54,7 @@ function SyntacticTab({ initial, setIsValid, setReference }: SyntacticTabProps)
|
|||
onChange={event => setOffset(event.target.valueAsNumber)}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_main_ref'
|
||||
disabled // prettier: split lines
|
||||
dense
|
||||
noBorder
|
||||
|
@ -60,6 +62,7 @@ function SyntacticTab({ initial, setIsValid, setReference }: SyntacticTabProps)
|
|||
value={mainLink}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_reference_nominal'
|
||||
spellCheck
|
||||
label='Начальная форма'
|
||||
placeholder='зависимое слово в начальной форме'
|
||||
|
|
|
@ -81,6 +81,7 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
|||
/>
|
||||
<div className='flex'>
|
||||
<TextInput
|
||||
id='dlg_version'
|
||||
dense
|
||||
label='Версия'
|
||||
className='w-[16rem] mr-3'
|
||||
|
@ -101,6 +102,7 @@ function DlgEditVersions({ hideWindow, versions, onDelete, onUpdate }: DlgEditVe
|
|||
/>
|
||||
</div>
|
||||
<TextArea
|
||||
id='dlg_description'
|
||||
spellCheck
|
||||
label='Описание'
|
||||
rows={3}
|
||||
|
|
|
@ -48,6 +48,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
|||
className={clsx('w-[30rem]', 'py-6 px-6 flex gap-6 justify-center items-center')}
|
||||
>
|
||||
<SelectSingle
|
||||
id='dlg_cst_type'
|
||||
placeholder='Выберите тип'
|
||||
className='min-w-[16rem] self-center'
|
||||
options={SelectorCstType}
|
||||
|
@ -58,6 +59,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
|||
onChange={data => updateData({ cst_type: data?.value ?? CstType.BASE })}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_cst_alias'
|
||||
dense
|
||||
label='Имя'
|
||||
className='w-[7rem]'
|
||||
|
|
|
@ -1,38 +1,51 @@
|
|||
/**
|
||||
* Module: API for miscellaneous frontend model types. Future targets for refactoring aimed at extracting modules.
|
||||
*/
|
||||
import { DependencyMode } from './miscellaneous';
|
||||
import { DependencyMode, ILibraryFilter, LibraryFilterStrategy } from './miscellaneous';
|
||||
import { IConstituenta, IRSForm } from './rsform';
|
||||
|
||||
/**
|
||||
* Filter list of {@link ILibraryItem} to a given query.
|
||||
* Filter list of {@link ILibraryItem} to a given graph query.
|
||||
*/
|
||||
export function applyGraphFilter(target: IRSForm, start: number, mode: DependencyMode): IConstituenta[] {
|
||||
if (mode === DependencyMode.ALL) {
|
||||
return target.items;
|
||||
}
|
||||
let ids: number[] | undefined = undefined;
|
||||
switch (mode) {
|
||||
case DependencyMode.OUTPUTS: {
|
||||
ids = target.graph.nodes.get(start)?.outputs;
|
||||
break;
|
||||
const ids: number[] | undefined = (() => {
|
||||
switch (mode) {
|
||||
case DependencyMode.OUTPUTS: {
|
||||
return target.graph.nodes.get(start)?.outputs;
|
||||
}
|
||||
case DependencyMode.INPUTS: {
|
||||
return target.graph.nodes.get(start)?.inputs;
|
||||
}
|
||||
case DependencyMode.EXPAND_OUTPUTS: {
|
||||
return target.graph.expandOutputs([start]);
|
||||
}
|
||||
case DependencyMode.EXPAND_INPUTS: {
|
||||
return target.graph.expandInputs([start]);
|
||||
}
|
||||
}
|
||||
case DependencyMode.INPUTS: {
|
||||
ids = target.graph.nodes.get(start)?.inputs;
|
||||
break;
|
||||
}
|
||||
case DependencyMode.EXPAND_OUTPUTS: {
|
||||
ids = target.graph.expandOutputs([start]);
|
||||
break;
|
||||
}
|
||||
case DependencyMode.EXPAND_INPUTS: {
|
||||
ids = target.graph.expandInputs([start]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!ids) {
|
||||
return target.items;
|
||||
return undefined;
|
||||
})();
|
||||
if (ids) {
|
||||
return target.items.filter(cst => ids.find(id => id === cst.id));
|
||||
} else {
|
||||
return target.items.filter(cst => ids!.find(id => id === cst.id));
|
||||
return target.items;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter list of {@link ILibraryItem} to a given text query.
|
||||
*/
|
||||
export function filterFromStrategy(strategy: LibraryFilterStrategy): ILibraryFilter {
|
||||
// prettier-ignore
|
||||
switch (strategy) {
|
||||
case LibraryFilterStrategy.MANUAL: return {};
|
||||
case LibraryFilterStrategy.COMMON: return { is_common: true };
|
||||
case LibraryFilterStrategy.CANONICAL: return { is_canonical: true };
|
||||
case LibraryFilterStrategy.PERSONAL: return { is_personal: true };
|
||||
case LibraryFilterStrategy.SUBSCRIBE: return { is_subscribed: true };
|
||||
case LibraryFilterStrategy.OWNED: return { is_owned: true };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,6 +85,7 @@ function CreateRSFormPage() {
|
|||
<h1>Создание концептуальной схемы</h1>
|
||||
<Overlay position='top-[-2.4rem] right-[-1rem]'>
|
||||
<input
|
||||
id='schema_file'
|
||||
ref={inputRef}
|
||||
type='file'
|
||||
style={{ display: 'none' }}
|
||||
|
@ -100,6 +101,7 @@ function CreateRSFormPage() {
|
|||
{fileName ? <Label text={`Загружен файл: ${fileName}`} /> : null}
|
||||
|
||||
<TextInput
|
||||
id='schema_title'
|
||||
required={!file}
|
||||
label='Полное название'
|
||||
placeholder={file && 'Загрузить из файла'}
|
||||
|
@ -107,6 +109,7 @@ function CreateRSFormPage() {
|
|||
onChange={event => setTitle(event.target.value)}
|
||||
/>
|
||||
<TextInput
|
||||
id='schema_alias'
|
||||
required={!file}
|
||||
label='Сокращение'
|
||||
placeholder={file && 'Загрузить из файла'}
|
||||
|
@ -117,12 +120,18 @@ function CreateRSFormPage() {
|
|||
onChange={event => setAlias(event.target.value)}
|
||||
/>
|
||||
<TextArea
|
||||
id='schema_comment'
|
||||
label='Комментарий'
|
||||
placeholder={file && 'Загрузить из файла'}
|
||||
value={comment}
|
||||
onChange={event => setComment(event.target.value)}
|
||||
/>
|
||||
<Checkbox label='Общедоступная схема' value={common} setValue={value => setCommon(value ?? false)} />
|
||||
<Checkbox
|
||||
id='schema_common'
|
||||
label='Общедоступная схема'
|
||||
value={common}
|
||||
setValue={value => setCommon(value ?? false)}
|
||||
/>
|
||||
<div className='flex justify-around gap-6 py-3'>
|
||||
<SubmitButton text='Создать схему' loading={processing} className='min-w-[10rem]' />
|
||||
<Button text='Отмена' className='min-w-[10rem]' onClick={() => handleCancel()} />
|
||||
|
|
|
@ -11,6 +11,7 @@ import useLocalStorage from '@/hooks/useLocalStorage';
|
|||
import useQueryStrings from '@/hooks/useQueryStrings';
|
||||
import { ILibraryItem } from '@/models/library';
|
||||
import { ILibraryFilter, LibraryFilterStrategy } from '@/models/miscellaneous';
|
||||
import { filterFromStrategy } from '@/models/miscellaneousAPI';
|
||||
|
||||
import SearchPanel from './SearchPanel';
|
||||
import ViewLibrary from './ViewLibrary';
|
||||
|
@ -45,7 +46,7 @@ function LibraryPage() {
|
|||
: LibraryFilterStrategy.MANUAL;
|
||||
setQuery('');
|
||||
setStrategy(inputStrategy);
|
||||
setFilter(ApplyStrategy(inputStrategy));
|
||||
setFilter(filterFromStrategy(inputStrategy));
|
||||
}, [user, router, setQuery, setFilter, setStrategy, strategy, searchFilter]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
@ -86,16 +87,3 @@ function LibraryPage() {
|
|||
}
|
||||
|
||||
export default LibraryPage;
|
||||
|
||||
// ====== Internals =======
|
||||
function ApplyStrategy(strategy: LibraryFilterStrategy): ILibraryFilter {
|
||||
// prettier-ignore
|
||||
switch (strategy) {
|
||||
case LibraryFilterStrategy.MANUAL: return {};
|
||||
case LibraryFilterStrategy.COMMON: return { is_common: true };
|
||||
case LibraryFilterStrategy.CANONICAL: return { is_canonical: true };
|
||||
case LibraryFilterStrategy.PERSONAL: return { is_personal: true };
|
||||
case LibraryFilterStrategy.SUBSCRIBE: return { is_subscribed: true };
|
||||
case LibraryFilterStrategy.OWNED: return { is_owned: true };
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,7 +68,13 @@ function SearchPanel({ total, filtered, query, setQuery, strategy, setFilter }:
|
|||
</span>
|
||||
</div>
|
||||
<PickerStrategy value={strategy} onChange={handleChangeStrategy} />
|
||||
<SearchBar noBorder className='mx-auto min-w-[10rem]' value={query} onChange={handleChangeQuery} />
|
||||
<SearchBar
|
||||
id='library_search'
|
||||
noBorder
|
||||
className='mx-auto min-w-[10rem]'
|
||||
value={query}
|
||||
onChange={handleChangeQuery}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ interface ViewLibraryProps {
|
|||
|
||||
const columnHelper = createColumnHelper<ILibraryItem>();
|
||||
|
||||
function ViewLibrary({ items, resetQuery: cleanQuery }: ViewLibraryProps) {
|
||||
function ViewLibrary({ items, resetQuery }: ViewLibraryProps) {
|
||||
const router = useConceptNavigation();
|
||||
const intl = useIntl();
|
||||
const { user } = useAuth();
|
||||
|
@ -121,6 +121,7 @@ function ViewLibrary({ items, resetQuery: cleanQuery }: ViewLibraryProps) {
|
|||
</div>
|
||||
</div>
|
||||
<DataTable
|
||||
id='library_data'
|
||||
columns={columns}
|
||||
data={items}
|
||||
headPosition='2.2rem'
|
||||
|
@ -130,7 +131,7 @@ function ViewLibrary({ items, resetQuery: cleanQuery }: ViewLibraryProps) {
|
|||
<p>Список схем пуст</p>
|
||||
<p className='flex gap-6'>
|
||||
<TextURL text='Создать схему' href='/library/create' />
|
||||
<TextURL text='Очистить фильтр' onClick={cleanQuery} />
|
||||
<TextURL text='Очистить фильтр' onClick={resetQuery} />
|
||||
</p>
|
||||
</FlexColumn>
|
||||
}
|
||||
|
|
|
@ -68,19 +68,21 @@ function LoginPage() {
|
|||
<img alt='Концепт Портал' src={resources.logo} className='max-h-[2.5rem] min-w-[2.5rem] mb-3' />
|
||||
<TextInput
|
||||
id='username'
|
||||
label='Имя пользователя'
|
||||
autoComplete='username'
|
||||
autoFocus
|
||||
required
|
||||
allowEnter
|
||||
label='Имя пользователя'
|
||||
value={username}
|
||||
onChange={event => setUsername(event.target.value)}
|
||||
/>
|
||||
<TextInput
|
||||
id='password'
|
||||
type='password'
|
||||
label='Пароль'
|
||||
autoComplete='current-password'
|
||||
required
|
||||
allowEnter
|
||||
label='Пароль'
|
||||
value={password}
|
||||
onChange={event => setPassword(event.target.value)}
|
||||
/>
|
||||
|
|
|
@ -82,8 +82,9 @@ function PasswordChangePage() {
|
|||
<TextInput
|
||||
id='new_password'
|
||||
type='password'
|
||||
allowEnter
|
||||
label='Новый пароль'
|
||||
autoComplete='new-password'
|
||||
allowEnter
|
||||
colors={passwordColor}
|
||||
value={newPassword}
|
||||
onChange={event => {
|
||||
|
@ -93,8 +94,9 @@ function PasswordChangePage() {
|
|||
<TextInput
|
||||
id='new_password_repeat'
|
||||
type='password'
|
||||
allowEnter
|
||||
label='Повторите новый'
|
||||
autoComplete='new-password'
|
||||
allowEnter
|
||||
colors={passwordColor}
|
||||
value={newPasswordRepeat}
|
||||
onChange={event => {
|
||||
|
|
|
@ -127,6 +127,7 @@ function FormConstituenta({
|
|||
onSubmit={handleSubmit}
|
||||
>
|
||||
<RefsInput
|
||||
id='cst_term'
|
||||
label='Термин'
|
||||
placeholder='Обозначение, используемое в текстовых определениях данной схемы'
|
||||
items={schema?.items}
|
||||
|
@ -137,6 +138,7 @@ function FormConstituenta({
|
|||
onChange={newValue => setTerm(newValue)}
|
||||
/>
|
||||
<TextArea
|
||||
id='cst_typification'
|
||||
dense
|
||||
noBorder
|
||||
disabled
|
||||
|
@ -149,6 +151,7 @@ function FormConstituenta({
|
|||
}}
|
||||
/>
|
||||
<EditorRSExpression
|
||||
id='cst_expression'
|
||||
label='Формальное определение'
|
||||
placeholder='Родоструктурное выражение'
|
||||
value={expression}
|
||||
|
@ -161,6 +164,7 @@ function FormConstituenta({
|
|||
setTypification={setTypification}
|
||||
/>
|
||||
<RefsInput
|
||||
id='cst_definition'
|
||||
label='Текстовое определение'
|
||||
placeholder='Текстовый вариант формального определения'
|
||||
height='3.8rem'
|
||||
|
@ -172,6 +176,7 @@ function FormConstituenta({
|
|||
onChange={newValue => setTextDefinition(newValue)}
|
||||
/>
|
||||
<TextArea
|
||||
id='cst_convention'
|
||||
spellCheck
|
||||
label='Конвенция / Комментарий'
|
||||
placeholder='Договоренность об интерпретации или пояснение'
|
||||
|
|
|
@ -101,6 +101,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
onSubmit={handleSubmit}
|
||||
>
|
||||
<TextInput
|
||||
id='schema_title'
|
||||
required
|
||||
label='Полное название'
|
||||
value={title}
|
||||
|
@ -109,6 +110,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
/>
|
||||
<div className='flex justify-between w-full gap-3'>
|
||||
<TextInput
|
||||
id='schema_alias'
|
||||
required
|
||||
label='Сокращение'
|
||||
className='w-[14rem]'
|
||||
|
@ -149,6 +151,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
</div>
|
||||
</div>
|
||||
<TextArea
|
||||
id='schema_comment'
|
||||
label='Комментарий'
|
||||
rows={3}
|
||||
value={comment}
|
||||
|
@ -157,6 +160,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
/>
|
||||
<div className='flex justify-between whitespace-nowrap'>
|
||||
<Checkbox
|
||||
id='schema_common'
|
||||
label='Общедоступная схема'
|
||||
title='Общедоступные схемы видны всем пользователям и могут быть изменены'
|
||||
disabled={!controller.isContentEditable}
|
||||
|
@ -164,6 +168,7 @@ function FormRSForm({ id, isModified, setIsModified }: FormRSFormProps) {
|
|||
setValue={value => setCommon(value)}
|
||||
/>
|
||||
<Checkbox
|
||||
id='schema_immutable'
|
||||
label='Неизменная схема'
|
||||
title='Только администраторы могут присваивать схемам неизменный статус'
|
||||
disabled={!controller.isContentEditable || !user?.is_staff}
|
||||
|
|
|
@ -75,7 +75,13 @@ function ConstituentsSearch({ schema, activeID, activeExpression, setFiltered }:
|
|||
|
||||
return (
|
||||
<div className='flex border-b clr-input'>
|
||||
<SearchBar noBorder className='min-w-[6rem] pr-2 flex-grow' value={filterText} onChange={setFilterText} />
|
||||
<SearchBar
|
||||
id='constituents_search'
|
||||
noBorder
|
||||
className='min-w-[6rem] pr-2 flex-grow'
|
||||
value={filterText}
|
||||
onChange={setFilterText}
|
||||
/>
|
||||
|
||||
<div ref={matchModeMenu.ref}>
|
||||
<SelectorButton
|
||||
|
|
|
@ -85,6 +85,7 @@ function RegisterPage() {
|
|||
|
||||
<TextInput
|
||||
id='username'
|
||||
autoComplete='username'
|
||||
required
|
||||
label='Имя пользователя (логин)'
|
||||
pattern={patterns.login}
|
||||
|
@ -96,6 +97,7 @@ function RegisterPage() {
|
|||
<TextInput
|
||||
id='password'
|
||||
type='password'
|
||||
autoComplete='new-password'
|
||||
required
|
||||
label='Пароль'
|
||||
className='w-[15rem]'
|
||||
|
@ -104,9 +106,10 @@ function RegisterPage() {
|
|||
/>
|
||||
<TextInput
|
||||
id='password2'
|
||||
required
|
||||
type='password'
|
||||
label='Повторите пароль'
|
||||
autoComplete='new-password'
|
||||
required
|
||||
className='w-[15rem]'
|
||||
value={password2}
|
||||
onChange={event => setPassword2(event.target.value)}
|
||||
|
@ -116,6 +119,7 @@ function RegisterPage() {
|
|||
<FlexColumn className='w-[15rem]'>
|
||||
<TextInput
|
||||
id='email'
|
||||
autoComplete='email'
|
||||
required
|
||||
label='Электронная почта (email)'
|
||||
title='электронная почта в корректном формате, например: i.petrov@mycompany.ru.com'
|
||||
|
@ -125,12 +129,14 @@ function RegisterPage() {
|
|||
<TextInput
|
||||
id='first_name'
|
||||
label='Отображаемое имя'
|
||||
autoComplete='given-name'
|
||||
value={firstName}
|
||||
onChange={event => setFirstName(event.target.value)}
|
||||
/>
|
||||
<TextInput
|
||||
id='last_name'
|
||||
label='Отображаемая фамилия'
|
||||
autoComplete='family-name'
|
||||
value={lastName}
|
||||
onChange={event => setLastName(event.target.value)}
|
||||
/>
|
||||
|
@ -138,7 +144,7 @@ function RegisterPage() {
|
|||
</div>
|
||||
|
||||
<div className='flex gap-1 text-sm'>
|
||||
<Checkbox label='Принимаю условия' value={acceptPrivacy} setValue={setAcceptPrivacy} />
|
||||
<Checkbox id='accept_terms' label='Принимаю условия' value={acceptPrivacy} setValue={setAcceptPrivacy} />
|
||||
<TextURL text='обработки персональных данных...' href={'/manuals?topic=privacy'} />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -70,16 +70,18 @@ function EditorPassword() {
|
|||
<TextInput
|
||||
id='old_password'
|
||||
type='password'
|
||||
allowEnter
|
||||
label='Старый пароль'
|
||||
autoComplete='current-password'
|
||||
allowEnter
|
||||
value={oldPassword}
|
||||
onChange={event => setOldPassword(event.target.value)}
|
||||
/>
|
||||
<TextInput
|
||||
id='new_password'
|
||||
type='password'
|
||||
allowEnter
|
||||
label='Новый пароль'
|
||||
autoComplete='new-password'
|
||||
allowEnter
|
||||
colors={passwordColor}
|
||||
value={newPassword}
|
||||
onChange={event => {
|
||||
|
@ -89,8 +91,9 @@ function EditorPassword() {
|
|||
<TextInput
|
||||
id='new_password_repeat'
|
||||
type='password'
|
||||
allowEnter
|
||||
label='Повторите новый'
|
||||
autoComplete='new-password'
|
||||
allowEnter
|
||||
colors={passwordColor}
|
||||
value={newPasswordRepeat}
|
||||
onChange={event => {
|
||||
|
|
|
@ -49,9 +49,17 @@ function EditorProfile() {
|
|||
|
||||
return (
|
||||
<form onSubmit={handleSubmit} className={clsx('min-w-[18rem]', 'px-6 py-2', classnames.flex_col)}>
|
||||
<TextInput id='username' disabled label='Логин' title='Логин изменить нельзя' value={username} />
|
||||
<TextInput
|
||||
id='username'
|
||||
autoComplete='username'
|
||||
disabled
|
||||
label='Логин'
|
||||
title='Логин изменить нельзя'
|
||||
value={username}
|
||||
/>
|
||||
<TextInput
|
||||
id='first_name'
|
||||
autoComplete='off'
|
||||
allowEnter
|
||||
label='Имя'
|
||||
value={first_name}
|
||||
|
@ -59,6 +67,7 @@ function EditorProfile() {
|
|||
/>
|
||||
<TextInput
|
||||
id='last_name'
|
||||
autoComplete='off'
|
||||
allowEnter
|
||||
label='Фамилия'
|
||||
value={last_name}
|
||||
|
@ -66,6 +75,7 @@ function EditorProfile() {
|
|||
/>
|
||||
<TextInput
|
||||
id='email'
|
||||
autoComplete='off'
|
||||
allowEnter
|
||||
label='Электронная почта'
|
||||
value={email}
|
||||
|
|
|
@ -88,33 +88,33 @@ export const urls = {
|
|||
* Global unique IDs.
|
||||
*/
|
||||
export const globalIDs = {
|
||||
tooltip: 'global-tooltip',
|
||||
password_tooltip: 'password-tooltip',
|
||||
main_scroll: 'main-scroll',
|
||||
library_item_editor: 'library-item-editor',
|
||||
constituenta_editor: 'constituenta-editor'
|
||||
tooltip: 'global_tooltip',
|
||||
password_tooltip: 'password_tooltip',
|
||||
main_scroll: 'main_scroll',
|
||||
library_item_editor: 'library_item_editor',
|
||||
constituenta_editor: 'constituenta_editor'
|
||||
};
|
||||
|
||||
/**
|
||||
* Prefixes for generating unique keys for lists.
|
||||
*/
|
||||
export const prefixes = {
|
||||
page_size: 'page-size-',
|
||||
cst_list: 'cst-list-',
|
||||
cst_side_table: 'cst-side-table-',
|
||||
cst_hidden_list: 'cst-hidden-list-',
|
||||
cst_modal_list: 'cst-modal-list-',
|
||||
cst_template_ist: 'cst-template-list-',
|
||||
cst_wordform_list: 'cst-wordform-list-',
|
||||
cst_status_list: 'cst-status-list-',
|
||||
cst_match_mode_list: 'cst-match-mode-list-',
|
||||
cst_source_list: 'cst-source-list-',
|
||||
cst_delete_list: 'cst-delete-list-',
|
||||
cst_dependant_list: 'cst-dependant-list-',
|
||||
csttype_list: 'csttype-',
|
||||
library_filters_list: 'library-filters-list-',
|
||||
topic_list: 'topic-list-',
|
||||
library_list: 'library-list-',
|
||||
wordform_list: 'wordform-list-',
|
||||
rsedit_btn: 'rsedit-btn-'
|
||||
page_size: 'page_size_',
|
||||
cst_list: 'cst_list_',
|
||||
cst_side_table: 'cst_side_table_',
|
||||
cst_hidden_list: 'cst_hidden_list_',
|
||||
cst_modal_list: 'cst_modal_list_',
|
||||
cst_template_ist: 'cst_template_list_',
|
||||
cst_wordform_list: 'cst_wordform_list_',
|
||||
cst_status_list: 'cst_status_list_',
|
||||
cst_match_mode_list: 'cst_match_mode_list_',
|
||||
cst_source_list: 'cst_source_list_',
|
||||
cst_delete_list: 'cst_delete_list_',
|
||||
cst_dependant_list: 'cst_dependant_list_',
|
||||
csttype_list: 'csttype_',
|
||||
library_filters_list: 'library_filters_list_',
|
||||
topic_list: 'topic_list_',
|
||||
library_list: 'library_list_',
|
||||
wordform_list: 'wordform_list_',
|
||||
rsedit_btn: 'rsedit_btn_'
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue
Block a user