mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-25 20:40:36 +03:00
F: Improve buttons accessibility
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
Some checks are pending
Frontend CI / build (22.x) (push) Waiting to run
This commit is contained in:
parent
575b7a29f2
commit
e144d20f2d
|
@ -23,6 +23,7 @@ export function ToggleNavigation() {
|
|||
onClick={toggleNoNavigation}
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-content={noNavigationAnimation ? 'Показать навигацию' : 'Скрыть навигацию'}
|
||||
aria-label={noNavigationAnimation ? 'Показать навигацию' : 'Скрыть навигацию'}
|
||||
>
|
||||
{!noNavigationAnimation ? <IconPin size='0.75rem' /> : null}
|
||||
{noNavigationAnimation ? <IconUnpin size='0.75rem' /> : null}
|
||||
|
@ -35,6 +36,7 @@ export function ToggleNavigation() {
|
|||
onClick={toggleDarkMode}
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-content={darkMode ? 'Тема: Темная' : 'Тема: Светлая'}
|
||||
aria-label={darkMode ? 'Тема: Темная' : 'Тема: Светлая'}
|
||||
>
|
||||
{darkMode ? <IconDarkTheme size='0.75rem' /> : null}
|
||||
{!darkMode ? <IconLightTheme size='0.75rem' /> : null}
|
||||
|
|
|
@ -85,27 +85,28 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
|||
/>
|
||||
<DropdownButton
|
||||
text={darkMode ? 'Тема: Темная' : 'Тема: Светлая'}
|
||||
icon={darkMode ? <IconDarkTheme size='1rem' /> : <IconLightTheme size='1rem' />}
|
||||
title='Переключение темы оформления'
|
||||
icon={darkMode ? <IconDarkTheme size='1rem' /> : <IconLightTheme size='1rem' />}
|
||||
onClick={handleToggleDarkMode}
|
||||
/>
|
||||
<DropdownButton
|
||||
text={showHelp ? 'Помощь: Вкл' : 'Помощь: Выкл'}
|
||||
icon={showHelp ? <IconHelp size='1rem' /> : <IconHelpOff size='1rem' />}
|
||||
title='Отображение иконок подсказок'
|
||||
icon={showHelp ? <IconHelp size='1rem' /> : <IconHelpOff size='1rem' />}
|
||||
onClick={toggleShowHelp}
|
||||
/>
|
||||
{user.is_staff ? (
|
||||
<DropdownButton
|
||||
text={adminMode ? 'Админ: Вкл' : 'Админ: Выкл'}
|
||||
icon={adminMode ? <IconAdmin size='1rem' /> : <IconAdminOff size='1rem' />}
|
||||
title='Работа в режиме администратора'
|
||||
icon={adminMode ? <IconAdmin size='1rem' /> : <IconAdminOff size='1rem' />}
|
||||
onClick={toggleAdminMode}
|
||||
/>
|
||||
) : null}
|
||||
{user.is_staff ? (
|
||||
<DropdownButton
|
||||
text='REST API' //
|
||||
title='Переход к backend API'
|
||||
icon={<IconRESTapi size='1rem' />}
|
||||
className='border-t'
|
||||
onClick={gotoRestApi}
|
||||
|
@ -114,6 +115,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
|||
{user.is_staff ? (
|
||||
<DropdownButton
|
||||
text='База данных' //
|
||||
title='Переход к администрированию базы данных'
|
||||
icon={<IconDatabase size='1rem' />}
|
||||
onClick={gotoAdmin}
|
||||
/>
|
||||
|
@ -121,6 +123,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
|||
{user?.is_staff ? (
|
||||
<DropdownButton
|
||||
text='Иконки' //
|
||||
title='Переход к странице иконок'
|
||||
icon={<IconImage size='1rem' />}
|
||||
onClick={gotoIcons}
|
||||
/>
|
||||
|
@ -128,6 +131,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
|||
{user.is_staff ? (
|
||||
<DropdownButton
|
||||
text='Структура БД' //
|
||||
title='Переход к странице структуры БД'
|
||||
icon={<IconDBStructure size='1rem' />}
|
||||
onClick={gotoDatabaseSchema}
|
||||
className='border-b'
|
||||
|
@ -135,6 +139,7 @@ export function UserDropdown({ isOpen, hideDropdown }: UserDropdownProps) {
|
|||
) : null}
|
||||
<DropdownButton
|
||||
text='Выйти...'
|
||||
title='Выход из приложения'
|
||||
className='font-semibold'
|
||||
icon={<IconLogout size='1rem' />}
|
||||
onClick={logoutAndRedirect}
|
||||
|
|
|
@ -38,7 +38,6 @@ export function Button({
|
|||
return (
|
||||
<button
|
||||
type='button'
|
||||
disabled={disabled ?? loading}
|
||||
className={clsx(
|
||||
'inline-flex gap-2 items-center justify-center',
|
||||
'font-medium select-none disabled:cursor-auto',
|
||||
|
@ -53,6 +52,8 @@ export function Button({
|
|||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
disabled={disabled ?? loading}
|
||||
aria-label={!text ? title : undefined}
|
||||
{...restProps}
|
||||
>
|
||||
{icon ? icon : null}
|
||||
|
|
|
@ -49,6 +49,7 @@ export function MiniButton({
|
|||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
aria-label={title}
|
||||
{...restProps}
|
||||
>
|
||||
{icon}
|
||||
|
|
|
@ -46,6 +46,7 @@ export function DropdownButton({
|
|||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
aria-label={title}
|
||||
{...restProps}
|
||||
>
|
||||
{icon ? icon : null}
|
||||
|
|
|
@ -55,12 +55,12 @@ export function CheckboxTristate({
|
|||
cursor,
|
||||
className
|
||||
)}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
disabled={disabled}
|
||||
{...restProps}
|
||||
>
|
||||
<div
|
||||
|
|
|
@ -54,12 +54,12 @@ export function Checkbox({
|
|||
cursor,
|
||||
className
|
||||
)}
|
||||
disabled={disabled}
|
||||
onClick={handleClick}
|
||||
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
disabled={disabled}
|
||||
{...restProps}
|
||||
>
|
||||
<div
|
||||
|
|
|
@ -99,6 +99,7 @@ export function SelectTree<ItemType>({
|
|||
>
|
||||
{foldable.has(item) ? (
|
||||
<MiniButton
|
||||
aria-label={!folded.includes(item) ? 'Свернуть' : 'Развернуть'}
|
||||
className={clsx('absolute left-1', !folded.includes(item) ? 'top-1.5' : 'top-1')}
|
||||
noPadding
|
||||
noHover
|
||||
|
|
|
@ -105,9 +105,9 @@ export function ModalForm({
|
|||
) : null}
|
||||
|
||||
<MiniButton
|
||||
noPadding
|
||||
aria-label='Закрыть'
|
||||
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
||||
aria-label='Закрыть'
|
||||
noPadding
|
||||
icon={<IconClose size='1.25rem' />}
|
||||
className='absolute z-pop top-2 right-2'
|
||||
onClick={hideDialog}
|
||||
|
|
|
@ -49,9 +49,9 @@ export function ModalView({
|
|||
) : null}
|
||||
|
||||
<MiniButton
|
||||
noPadding
|
||||
aria-label='Закрыть'
|
||||
titleHtml={prepareTooltip('Закрыть диалоговое окно', 'ESC')}
|
||||
aria-label='Закрыть'
|
||||
noPadding
|
||||
icon={<IconClose size='1.25rem' />}
|
||||
className='absolute z-pop top-2 right-2'
|
||||
onClick={hideDialog}
|
||||
|
|
|
@ -14,7 +14,15 @@ interface TabLabelProps extends Omit<TabPropsImpl, 'children'>, Titled {
|
|||
/**
|
||||
* Displays a tab header with a label.
|
||||
*/
|
||||
export function TabLabel({ label, title, titleHtml, hideTitle, className, ...otherProps }: TabLabelProps) {
|
||||
export function TabLabel({
|
||||
label,
|
||||
title,
|
||||
titleHtml,
|
||||
hideTitle,
|
||||
className,
|
||||
role = 'tab',
|
||||
...otherProps
|
||||
}: TabLabelProps) {
|
||||
return (
|
||||
<TabImpl
|
||||
className={clsx(
|
||||
|
@ -31,6 +39,7 @@ export function TabLabel({ label, title, titleHtml, hideTitle, className, ...oth
|
|||
data-tooltip-html={titleHtml}
|
||||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
role={role}
|
||||
{...otherProps}
|
||||
>
|
||||
{label}
|
||||
|
|
|
@ -50,6 +50,7 @@ export function ValueIcon({
|
|||
...restProps
|
||||
}: ValueIconProps) {
|
||||
// TODO: use CSS instead of threshold
|
||||
// TODO: do not add button if onClick is disabled
|
||||
const isSmall = !smallThreshold || String(value).length < smallThreshold;
|
||||
return (
|
||||
<div
|
||||
|
@ -66,7 +67,7 @@ export function ValueIcon({
|
|||
data-tooltip-content={title}
|
||||
data-tooltip-hidden={hideTitle}
|
||||
>
|
||||
<MiniButton noHover noPadding icon={icon} disabled={disabled} onClick={onClick} />
|
||||
<MiniButton noHover noPadding icon={icon} onClick={onClick} disabled={disabled} />
|
||||
<span id={id} className={clsx({ 'text-xs': !isSmall }, textClassName)}>
|
||||
{value}
|
||||
</span>
|
||||
|
|
|
@ -64,20 +64,20 @@ export function LoginPage() {
|
|||
id='username'
|
||||
autoComplete='username'
|
||||
label='Логин или email'
|
||||
{...register('username')}
|
||||
autoFocus
|
||||
allowEnter
|
||||
spellCheck={false}
|
||||
defaultValue={initialName}
|
||||
{...register('username')}
|
||||
error={errors.username}
|
||||
/>
|
||||
<TextInput
|
||||
id='password'
|
||||
{...register('password')}
|
||||
type='password'
|
||||
autoComplete='current-password'
|
||||
label='Пароль'
|
||||
allowEnter
|
||||
{...register('password')}
|
||||
error={errors.password}
|
||||
/>
|
||||
|
||||
|
|
|
@ -85,9 +85,9 @@ export function EditorLibraryItem({ schema, isAttachedToOSS }: EditorLibraryItem
|
|||
<div className='flex flex-col'>
|
||||
<div className='relative flex justify-stretch sm:mb-1 max-w-120 gap-3'>
|
||||
<MiniButton
|
||||
title='Открыть в библиотеке'
|
||||
noHover
|
||||
noPadding
|
||||
title='Открыть в библиотеке'
|
||||
icon={<IconFolderOpened size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleOpenLibrary}
|
||||
/>
|
||||
|
|
|
@ -67,22 +67,22 @@ export function MenuRole({ isOwned, isEditor }: MenuRoleProps) {
|
|||
text={labelUserRole(UserRole.EDITOR)}
|
||||
title={describeUserRole(UserRole.EDITOR)}
|
||||
icon={<IconRole role={UserRole.EDITOR} size='1rem' />}
|
||||
disabled={!isOwned && !isEditor}
|
||||
onClick={() => handleChangeMode(UserRole.EDITOR)}
|
||||
disabled={!isOwned && !isEditor}
|
||||
/>
|
||||
<DropdownButton
|
||||
text={labelUserRole(UserRole.OWNER)}
|
||||
title={describeUserRole(UserRole.OWNER)}
|
||||
icon={<IconRole role={UserRole.OWNER} size='1rem' />}
|
||||
disabled={!isOwned}
|
||||
onClick={() => handleChangeMode(UserRole.OWNER)}
|
||||
disabled={!isOwned}
|
||||
/>
|
||||
<DropdownButton
|
||||
text={labelUserRole(UserRole.ADMIN)}
|
||||
title={describeUserRole(UserRole.ADMIN)}
|
||||
icon={<IconRole role={UserRole.ADMIN} size='1rem' />}
|
||||
disabled={!user.is_staff}
|
||||
onClick={() => handleChangeMode(UserRole.ADMIN)}
|
||||
disabled={!user.is_staff}
|
||||
/>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
|
|
@ -30,8 +30,8 @@ export function MiniSelectorOSS({ items, onSelect, className, ...restProps }: Mi
|
|||
return (
|
||||
<div ref={ossMenu.ref} className={clsx('relative flex items-center', className)} {...restProps}>
|
||||
<MiniButton
|
||||
icon={<IconOSS size='1.25rem' className='icon-primary' />}
|
||||
title='Операционные схемы'
|
||||
icon={<IconOSS size='1.25rem' className='icon-primary' />}
|
||||
hideTitle={ossMenu.isOpen}
|
||||
onClick={onToggle}
|
||||
/>
|
||||
|
@ -40,9 +40,9 @@ export function MiniSelectorOSS({ items, onSelect, className, ...restProps }: Mi
|
|||
<Label text='Список ОСС' className='border-b px-3 py-1' />
|
||||
{items.map((reference, index) => (
|
||||
<DropdownButton
|
||||
className='min-w-20'
|
||||
key={`${prefixes.oss_list}${index}`}
|
||||
text={reference.alias}
|
||||
className='min-w-20'
|
||||
onClick={event => onSelect(event, reference)}
|
||||
/>
|
||||
))}
|
||||
|
|
|
@ -114,8 +114,8 @@ export function PickSchema({
|
|||
/>
|
||||
<div className='relative' ref={locationMenu.ref}>
|
||||
<MiniButton
|
||||
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
|
||||
title='Фильтр по расположению'
|
||||
icon={<IconFolderTree size='1.25rem' className={!!filterLocation ? 'icon-green' : 'icon-primary'} />}
|
||||
className='mt-1'
|
||||
onClick={() => locationMenu.toggle()}
|
||||
/>
|
||||
|
|
|
@ -52,10 +52,10 @@ export function SelectLocationHead({
|
|||
return (
|
||||
<DropdownButton
|
||||
key={`${prefixes.location_head_list}${index}`}
|
||||
onClick={() => handleChange(head)}
|
||||
title={describeLocationHead(head)}
|
||||
icon={<IconLocationHead value={head} size='1rem' />}
|
||||
text={labelLocationHead(head)}
|
||||
title={describeLocationHead(head)}
|
||||
onClick={() => handleChange(head)}
|
||||
icon={<IconLocationHead value={head} size='1rem' />}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
|
|
|
@ -48,13 +48,14 @@ export function ToolbarItemAccess({
|
|||
<Label text='Доступ' className='self-center select-none' />
|
||||
<div className='ml-auto cc-icons'>
|
||||
<SelectAccessPolicy
|
||||
disabled={role <= UserRole.EDITOR || isProcessing || isAttachedToOSS}
|
||||
value={policy}
|
||||
onChange={handleSetAccessPolicy}
|
||||
disabled={role <= UserRole.EDITOR || isProcessing || isAttachedToOSS}
|
||||
/>
|
||||
|
||||
<MiniButton
|
||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||
aria-label='Переключатель отображения библиотеки'
|
||||
icon={<IconItemVisibility value={visible} />}
|
||||
onClick={toggleVisible}
|
||||
disabled={role === UserRole.READER || isProcessing}
|
||||
|
@ -62,6 +63,7 @@ export function ToolbarItemAccess({
|
|||
|
||||
<MiniButton
|
||||
title={readOnly ? 'Изменение: запрещено' : 'Изменение: разрешено'}
|
||||
aria-label='Переключатель режима изменения'
|
||||
icon={
|
||||
readOnly ? (
|
||||
<IconImmutable size='1.25rem' className='text-sec-600' />
|
||||
|
|
|
@ -56,13 +56,15 @@ export function ToolbarItemCard({ className, schema, onSubmit, isMutable, delete
|
|||
{isMutable || isModified ? (
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
disabled={!canSave}
|
||||
aria-label='Сохранить изменения'
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
onClick={onSubmit}
|
||||
disabled={!canSave}
|
||||
/>
|
||||
) : null}
|
||||
<MiniButton
|
||||
titleHtml={tooltipText.shareItem(schema.access_policy === AccessPolicy.PUBLIC)}
|
||||
aria-label='Поделиться схемой'
|
||||
icon={<IconShare size='1.25rem' className='icon-primary' />}
|
||||
onClick={sharePage}
|
||||
disabled={schema.access_policy !== AccessPolicy.PUBLIC}
|
||||
|
@ -71,8 +73,8 @@ export function ToolbarItemCard({ className, schema, onSubmit, isMutable, delete
|
|||
<MiniButton
|
||||
title='Удалить схему'
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={!isMutable || isProcessing || role < UserRole.OWNER}
|
||||
onClick={deleteSchema}
|
||||
disabled={!isMutable || isProcessing || role < UserRole.OWNER}
|
||||
/>
|
||||
) : null}
|
||||
<BadgeHelp topic={HelpTopic.UI_RS_CARD} offset={4} />
|
||||
|
|
|
@ -95,6 +95,7 @@ export function DlgCloneLibraryItem() {
|
|||
render={({ field }) => (
|
||||
<MiniButton
|
||||
title={field.value ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||
aria-label='Переключатель отображения библиотеки'
|
||||
icon={<IconItemVisibility value={field.value} />}
|
||||
onClick={() => field.onChange(!field.value)}
|
||||
/>
|
||||
|
|
|
@ -47,12 +47,12 @@ export function DlgEditEditors() {
|
|||
<div className='self-center text-sm font-semibold'>
|
||||
<span>Всего редакторов [{selected.length}]</span>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Очистить список'
|
||||
noHover
|
||||
className='py-0 align-middle'
|
||||
icon={<IconRemove size='1.5rem' className='icon-red' />}
|
||||
disabled={selected.length === 0}
|
||||
onClick={() => setSelected([])}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -107,14 +107,15 @@ export function DlgEditVersions() {
|
|||
<MiniButton
|
||||
type='submit'
|
||||
title={isValid ? 'Сохранить изменения' : errorMsg.versionTaken}
|
||||
disabled={!isDirty || !isValid || isProcessing}
|
||||
aria-label='Сохранить изменения'
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
disabled={!isDirty || !isValid || isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Сбросить несохраненные изменения'
|
||||
disabled={!isDirty}
|
||||
onClick={() => reset()}
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
disabled={!isDirty}
|
||||
/>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
@ -66,9 +66,9 @@ export function TableVersions({ processing, items, onDelete, selected, onSelect
|
|||
className='align-middle'
|
||||
noHover
|
||||
noPadding
|
||||
disabled={processing}
|
||||
icon={<IconRemove size='1.25rem' className='icon-red' />}
|
||||
onClick={event => handleDeleteVersion(event, props.row.original.id)}
|
||||
disabled={processing}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
|
|
@ -185,6 +185,7 @@ export function FormCreateItem() {
|
|||
render={({ field }) => (
|
||||
<MiniButton
|
||||
title={field.value ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||
aria-label='Переключатель отображения библиотеки'
|
||||
icon={<IconItemVisibility value={field.value} />}
|
||||
onClick={() => field.onChange(!field.value)}
|
||||
/>
|
||||
|
|
|
@ -56,8 +56,8 @@ export function LibraryPage() {
|
|||
<ToolbarSearch className='top-0 h-9' total={libraryItems.length} filtered={filtered.length} />
|
||||
<div className='relative cc-fade-in flex'>
|
||||
<MiniButton
|
||||
className='absolute z-tooltip -top-8 right-6'
|
||||
title='Выгрузить в формате CSV'
|
||||
className='absolute z-tooltip -top-8 right-6'
|
||||
icon={<IconCSV size='1.25rem' className='icon-green' />}
|
||||
onClick={handleDownloadCSV}
|
||||
/>
|
||||
|
|
|
@ -98,17 +98,20 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
|||
<Dropdown isOpen={userMenu.isOpen}>
|
||||
<DropdownButton
|
||||
text='Я - Владелец'
|
||||
title='Фильтровать схемы, в которых текущий пользователь является владельцем'
|
||||
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
|
||||
onClick={toggleOwned}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Я - Редактор'
|
||||
title='Фильтровать схемы, в которых текущий пользователя является редактором'
|
||||
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
|
||||
onClick={toggleEditor}
|
||||
/>
|
||||
<SelectUser
|
||||
noBorder
|
||||
aria-label='Выбор пользователя для фильтра по владельцу'
|
||||
placeholder='Выберите владельца'
|
||||
noBorder
|
||||
className='min-w-60 text-sm mx-1 mb-1'
|
||||
value={filterUser}
|
||||
onChange={setFilterUser}
|
||||
|
@ -155,13 +158,14 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
|||
|
||||
<Dropdown isOpen={headMenu.isOpen} stretchLeft>
|
||||
<DropdownButton
|
||||
title='Переключение в режим Проводник'
|
||||
text='проводник...'
|
||||
title='Переключение в режим Проводник'
|
||||
icon={<IconFolderTree size='1rem' className='clr-text-controls' />}
|
||||
onClick={handleToggleFolder}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='отображать все'
|
||||
title='Очистить фильтр по расположению'
|
||||
icon={<IconFolder size='1rem' className='clr-text-controls' />}
|
||||
onClick={() => handleChange(null)}
|
||||
/>
|
||||
|
@ -169,9 +173,9 @@ export function ToolbarSearch({ className, total, filtered }: ToolbarSearchProps
|
|||
return (
|
||||
<DropdownButton
|
||||
key={`${prefixes.location_head_list}${index}`}
|
||||
onClick={() => handleChange(head)}
|
||||
title={describeLocationHead(head)}
|
||||
text={labelLocationHead(head)}
|
||||
title={describeLocationHead(head)}
|
||||
onClick={() => handleChange(head)}
|
||||
icon={<IconLocationHead value={head} size='1rem' />}
|
||||
/>
|
||||
);
|
||||
|
|
|
@ -35,11 +35,12 @@ export function useLibraryColumns() {
|
|||
id: 'location',
|
||||
header: () => (
|
||||
<MiniButton
|
||||
titleHtml='Переключение в режим Проводник'
|
||||
aria-label='Переключатель режима Проводник'
|
||||
noPadding
|
||||
noHover
|
||||
className='pl-2 max-h-4 -translate-y-0.5'
|
||||
onClick={handleToggleFolder}
|
||||
titleHtml='Переключение в режим Проводник'
|
||||
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
|
||||
/>
|
||||
),
|
||||
|
|
|
@ -71,21 +71,23 @@ export function ViewSideLocation({ isVisible, onRenameLocation }: ViewSideLocati
|
|||
<div className='cc-icons'>
|
||||
{canRename ? (
|
||||
<MiniButton
|
||||
icon={<IconFolderEdit size='1.25rem' className='icon-primary' />}
|
||||
titleHtml='<b>Редактирование пути</b><br/>Перемещаются только Ваши схемы<br/>в указанной папке (и подпапках)'
|
||||
aria-label='Редактирование расположения'
|
||||
icon={<IconFolderEdit size='1.25rem' className='icon-primary' />}
|
||||
onClick={onRenameLocation}
|
||||
/>
|
||||
) : null}
|
||||
{!!location ? (
|
||||
<MiniButton
|
||||
title={subfolders ? 'Вложенные папки: Вкл' : 'Вложенные папки: Выкл'}
|
||||
aria-label='Переключатель отображения вложенных папок'
|
||||
icon={<IconShowSubfolders value={subfolders} />}
|
||||
onClick={toggleSubfolders}
|
||||
/>
|
||||
) : null}
|
||||
<MiniButton
|
||||
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||
title='Переключение в режим Поиск'
|
||||
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||
onClick={toggleFolderMode}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -81,22 +81,22 @@ export function PickMultiOperation({ rows, items, value, onChange, className, ..
|
|||
cell: props => (
|
||||
<div className='flex gap-1 w-fit'>
|
||||
<MiniButton
|
||||
title='Удалить'
|
||||
noHover
|
||||
className='px-0'
|
||||
title='Удалить'
|
||||
icon={<IconRemove size='1rem' className='icon-red' />}
|
||||
onClick={() => handleDelete(props.row.original.id)}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Переместить выше'
|
||||
noHover
|
||||
className='px-0'
|
||||
title='Выше'
|
||||
icon={<IconMoveUp size='1rem' className='icon-primary' />}
|
||||
onClick={() => handleMoveUp(props.row.original.id)}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Переместить ниже'
|
||||
noHover
|
||||
title='Ниже'
|
||||
className='px-0'
|
||||
icon={<IconMoveDown size='1rem' className='icon-primary' />}
|
||||
onClick={() => handleMoveDown(props.row.original.id)}
|
||||
|
|
|
@ -65,8 +65,8 @@ export function FormOSS() {
|
|||
{...register('title')}
|
||||
label='Полное название'
|
||||
className='mb-3'
|
||||
disabled={!isMutable}
|
||||
error={errors.title}
|
||||
disabled={!isMutable}
|
||||
/>
|
||||
<div className='relative flex justify-between gap-3 mb-3'>
|
||||
<TextInput
|
||||
|
@ -74,8 +74,8 @@ export function FormOSS() {
|
|||
{...register('alias')}
|
||||
label='Сокращение'
|
||||
className='w-64'
|
||||
disabled={!isMutable}
|
||||
error={errors.alias}
|
||||
disabled={!isMutable}
|
||||
/>
|
||||
<ToolbarItemAccess
|
||||
className='absolute top-18 right-2'
|
||||
|
@ -93,16 +93,16 @@ export function FormOSS() {
|
|||
{...register('comment')}
|
||||
label='Описание'
|
||||
rows={3}
|
||||
disabled={!isMutable || isProcessing}
|
||||
error={errors.comment}
|
||||
disabled={!isMutable || isProcessing}
|
||||
/>
|
||||
{isMutable || isModified ? (
|
||||
<SubmitButton
|
||||
text='Сохранить изменения'
|
||||
className='self-center mt-4'
|
||||
loading={isProcessing}
|
||||
disabled={!isModified}
|
||||
icon={<IconSave size='1.25rem' />}
|
||||
disabled={!isModified}
|
||||
/>
|
||||
) : null}
|
||||
</form>
|
||||
|
|
|
@ -178,17 +178,18 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
|||
text='Редактировать'
|
||||
title='Редактировать операцию'
|
||||
icon={<IconEdit2 size='1rem' className='icon-primary' />}
|
||||
disabled={!isMutable || isProcessing}
|
||||
onClick={handleEditOperation}
|
||||
disabled={!isMutable || isProcessing}
|
||||
/>
|
||||
|
||||
{operation?.result ? (
|
||||
<DropdownButton
|
||||
text='Открыть схему'
|
||||
titleHtml={prepareTooltip('Открыть привязанную КС', 'Двойной клик')}
|
||||
aria-label='Открыть привязанную КС'
|
||||
icon={<IconRSForm size='1rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleOpenSchema}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
) : null}
|
||||
{isMutable && !operation?.result && operation?.arguments.length === 0 ? (
|
||||
|
@ -196,8 +197,8 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
|||
text='Создать схему'
|
||||
title='Создать пустую схему'
|
||||
icon={<IconNewRSForm size='1rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleInputCreate}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
) : null}
|
||||
{isMutable && operation?.operation_type === OperationType.INPUT ? (
|
||||
|
@ -205,8 +206,8 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
|||
text={!operation?.result ? 'Загрузить схему' : 'Изменить схему'}
|
||||
title='Выбрать схему для загрузки'
|
||||
icon={<IconConnect size='1rem' className='icon-primary' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleEditSchema}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
) : null}
|
||||
{isMutable && !operation?.result && operation?.operation_type === OperationType.SYNTHESIS ? (
|
||||
|
@ -217,9 +218,10 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
|||
? 'Активировать операцию<br/>и получить синтезированную КС'
|
||||
: 'Необходимо предоставить все аргументы'
|
||||
}
|
||||
aria-label='Активировать операцию и получить синтезированную КС'
|
||||
icon={<IconExecute size='1rem' className='icon-green' />}
|
||||
disabled={isProcessing || !readyForSynthesis}
|
||||
onClick={handleOperationExecute}
|
||||
disabled={isProcessing || !readyForSynthesis}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
@ -227,17 +229,18 @@ export function NodeContextMenu({ isOpen, operation, cursorX, cursorY, onHide }:
|
|||
<DropdownButton
|
||||
text='Конституенты'
|
||||
titleHtml='Перенос конституент</br>между схемами'
|
||||
aria-label='Перенос конституент между схемами'
|
||||
icon={<IconChild size='1rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleRelocateConstituents}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
<DropdownButton
|
||||
text='Удалить операцию'
|
||||
icon={<IconDestroy size='1rem' className='icon-red' />}
|
||||
disabled={!isMutable || isProcessing || !operation || !canDelete(operation)}
|
||||
onClick={handleDeleteOperation}
|
||||
disabled={!isMutable || isProcessing || !operation || !canDelete(operation)}
|
||||
/>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
|
|
@ -143,12 +143,13 @@ export function ToolbarOssGraph({
|
|||
onClick={onResetPositions}
|
||||
/>
|
||||
<MiniButton
|
||||
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
|
||||
title='Сбросить вид'
|
||||
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleFitView}
|
||||
/>
|
||||
<MiniButton
|
||||
title={showGrid ? 'Скрыть сетку' : 'Отобразить сетку'}
|
||||
aria-label='Переключатель отображения сетки'
|
||||
icon={
|
||||
showGrid ? (
|
||||
<IconGrid size='1.25rem' className='icon-green' />
|
||||
|
@ -160,6 +161,7 @@ export function ToolbarOssGraph({
|
|||
/>
|
||||
<MiniButton
|
||||
title={edgeStraight ? 'Связи: прямые' : 'Связи: безье'}
|
||||
aria-label='Переключатель формы связей'
|
||||
icon={
|
||||
edgeStraight ? (
|
||||
<IconLineStraight size='1.25rem' className='icon-primary' />
|
||||
|
@ -171,6 +173,7 @@ export function ToolbarOssGraph({
|
|||
/>
|
||||
<MiniButton
|
||||
title={edgeAnimate ? 'Анимация: вкл' : 'Анимация: выкл'}
|
||||
aria-label='Переключатель анимации связей'
|
||||
icon={
|
||||
edgeAnimate ? (
|
||||
<IconAnimation size='1.25rem' className='icon-primary' />
|
||||
|
@ -186,33 +189,37 @@ export function ToolbarOssGraph({
|
|||
<div className='cc-icons'>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
aria-label='Сохранить изменения'
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleSavePositions}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Новая операция', 'Ctrl + Q')}
|
||||
aria-label='Новая операция'
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={onCreate}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Активировать операцию'
|
||||
icon={<IconExecute size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing || selected.length !== 1 || !readyForSynthesis}
|
||||
onClick={handleOperationExecute}
|
||||
disabled={isProcessing || selected.length !== 1 || !readyForSynthesis}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Редактировать выбранную', 'Двойной клик')}
|
||||
aria-label='Редактировать выбранную'
|
||||
icon={<IconEdit2 size='1.25rem' className='icon-primary' />}
|
||||
disabled={selected.length !== 1 || isProcessing}
|
||||
onClick={handleEditOperation}
|
||||
disabled={selected.length !== 1 || isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Удалить выбранную', 'Delete')}
|
||||
aria-label='Удалить выбранную'
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={selected.length !== 1 || isProcessing || !selectedOperation || !canDelete(selectedOperation)}
|
||||
onClick={onDelete}
|
||||
disabled={selected.length !== 1 || isProcessing || !selectedOperation || !canDelete(selectedOperation)}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
@ -47,6 +47,7 @@ export function MenuEditOss() {
|
|||
<DropdownButton
|
||||
text='Конституенты'
|
||||
titleHtml='Перенос конституент</br>между схемами'
|
||||
aria-label='Перенос конституент между схемами'
|
||||
icon={<IconChild size='1rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleRelocate}
|
||||
|
|
|
@ -61,6 +61,7 @@ export function MenuMain() {
|
|||
<Dropdown isOpen={schemaMenu.isOpen} margin='mt-3'>
|
||||
<DropdownButton
|
||||
text='Поделиться'
|
||||
title='Скопировать ссылку в буфер обмена'
|
||||
icon={<IconShare size='1rem' className='icon-primary' />}
|
||||
onClick={handleShare}
|
||||
/>
|
||||
|
@ -74,8 +75,8 @@ export function MenuMain() {
|
|||
<DropdownButton
|
||||
text='Удалить схему'
|
||||
icon={<IconDestroy size='1rem' className='icon-red' />}
|
||||
disabled={isProcessing || role < UserRole.OWNER}
|
||||
onClick={handleDelete}
|
||||
disabled={isProcessing || role < UserRole.OWNER}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
|
@ -196,14 +196,14 @@ export function PickSubstitutions({
|
|||
props.row.original.is_suggestion ? (
|
||||
<div className='max-w-fit'>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Принять предложение'
|
||||
noHover
|
||||
icon={<IconAccept size='1rem' className='icon-green' />}
|
||||
onClick={() => handleAcceptSuggestion(props.row.original)}
|
||||
/>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Игнорировать предложение'
|
||||
noHover
|
||||
icon={<IconRemove size='1rem' className='icon-red' />}
|
||||
onClick={() => handleDeclineSuggestion(props.row.original)}
|
||||
/>
|
||||
|
@ -211,8 +211,8 @@ export function PickSubstitutions({
|
|||
) : (
|
||||
<div className='max-w-fit'>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Удалить'
|
||||
noHover
|
||||
icon={<IconRemove size='1rem' className='icon-red' />}
|
||||
onClick={() => handleDeleteSubstitution(props.row.original)}
|
||||
/>
|
||||
|
@ -257,8 +257,8 @@ export function PickSubstitutions({
|
|||
title='Добавить в таблицу отождествлений'
|
||||
className='grow-0'
|
||||
icon={<IconReplace size='1.5rem' className='icon-primary' />}
|
||||
disabled={!leftCst || !rightCst || (leftCst === rightCst && !allowSelfSubstitution)}
|
||||
onClick={addSubstitution}
|
||||
disabled={!leftCst || !rightCst || (leftCst === rightCst && !allowSelfSubstitution)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -46,54 +46,55 @@ export function ToolbarGraphSelection({
|
|||
return (
|
||||
<div className={clsx('cc-icons', className)} {...restProps}>
|
||||
<MiniButton
|
||||
titleHtml='Сбросить выделение'
|
||||
title='Сбросить выделение'
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange([])}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить все влияющие'
|
||||
title='Выделить все влияющие'
|
||||
icon={<IconGraphCollapse size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange([...selected, ...graph.expandAllInputs(selected)])}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить все зависимые'
|
||||
title='Выделить все зависимые'
|
||||
icon={<IconGraphExpand size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange([...selected, ...graph.expandAllOutputs(selected)])}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='<b>Максимизация</b> <br/>дополнение выделения конституентами, <br/>зависимыми только от выделенных'
|
||||
aria-label='Максимизация - дополнение выделения конституентами, зависимыми только от выделенных'
|
||||
icon={<IconGraphMaximize size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange(graph.maximizePart(selected))}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить поставщиков'
|
||||
title='Выделить поставщиков'
|
||||
icon={<IconGraphInputs size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange([...selected, ...graph.expandInputs(selected)])}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить потребителей'
|
||||
title='Выделить потребителей'
|
||||
icon={<IconGraphOutputs size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange([...selected, ...graph.expandOutputs(selected)])}
|
||||
disabled={emptySelection}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Инвертировать'
|
||||
title='Инвертировать'
|
||||
icon={<IconGraphInverse size='1.25rem' className='icon-primary' />}
|
||||
onClick={() => onChange([...graph.nodes.keys()].filter(item => !selected.includes(item)))}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml='Выделить ядро'
|
||||
title='Выделить ядро'
|
||||
icon={<IconGraphCore size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleSelectCore}
|
||||
/>
|
||||
{isOwned ? (
|
||||
<MiniButton
|
||||
titleHtml='Выделить собственные'
|
||||
title='Выделить собственные'
|
||||
icon={<IconPredecessor size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleSelectOwned}
|
||||
/>
|
||||
|
|
|
@ -43,8 +43,20 @@ export function FormCreateCst({ schema }: FormCreateCstProps) {
|
|||
return (
|
||||
<>
|
||||
<div className='flex items-center self-center gap-3'>
|
||||
<SelectCstType id='dlg_cst_type' className='w-64' value={cst_type} onChange={handleTypeChange} />
|
||||
<TextInput id='dlg_cst_alias' dense label='Имя' className='w-28' {...register('alias')} error={errors.alias} />
|
||||
<SelectCstType
|
||||
id='dlg_cst_type' //
|
||||
className='w-64'
|
||||
value={cst_type}
|
||||
onChange={handleTypeChange}
|
||||
/>
|
||||
<TextInput
|
||||
id='dlg_cst_alias' //
|
||||
dense
|
||||
label='Имя'
|
||||
className='w-28'
|
||||
{...register('alias')}
|
||||
error={errors.alias}
|
||||
/>
|
||||
<BadgeHelp topic={HelpTopic.CC_CONSTITUENTA} offset={16} contentClass='sm:max-w-160' />
|
||||
</div>
|
||||
|
||||
|
|
|
@ -133,8 +133,8 @@ export function TabArguments() {
|
|||
noHover
|
||||
className='py-0'
|
||||
icon={<IconAccept size='1.5rem' className='icon-green' />}
|
||||
disabled={!argumentValue || !selectedArgument}
|
||||
onClick={() => handleAssignArgument(selectedArgument!, argumentValue)}
|
||||
disabled={!argumentValue || !selectedArgument}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Очистить поле'
|
||||
|
|
|
@ -143,18 +143,18 @@ export function DlgEditWordForms() {
|
|||
/>
|
||||
<div className='flex flex-col self-center gap-1'>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Определить граммемы'
|
||||
noHover
|
||||
icon={<IconMoveRight size='1.25rem' className='icon-primary' />}
|
||||
disabled={isProcessing || !inputText}
|
||||
onClick={handleParse}
|
||||
disabled={isProcessing || !inputText}
|
||||
/>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Генерировать словоформу'
|
||||
noHover
|
||||
icon={<IconMoveLeft size='1.25rem' className='icon-primary' />}
|
||||
disabled={isProcessing || inputGrams.length == 0}
|
||||
onClick={handleInflect}
|
||||
disabled={isProcessing || inputGrams.length == 0}
|
||||
/>
|
||||
</div>
|
||||
<SelectMultiGrammeme
|
||||
|
@ -168,29 +168,29 @@ export function DlgEditWordForms() {
|
|||
<div className='flex justify-between'>
|
||||
<div className='cc-icons'>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Внести словоформу'
|
||||
noHover
|
||||
icon={<IconAccept size='1.5rem' className='icon-green' />}
|
||||
disabled={isProcessing || !inputText || inputGrams.length == 0}
|
||||
onClick={handleAddForm}
|
||||
disabled={isProcessing || !inputText || inputGrams.length == 0}
|
||||
/>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Генерировать стандартные словоформы'
|
||||
noHover
|
||||
icon={<IconMoveDown size='1.5rem' className='icon-primary' />}
|
||||
disabled={isProcessing || !inputText}
|
||||
onClick={handleGenerateLexeme}
|
||||
disabled={isProcessing || !inputText}
|
||||
/>
|
||||
</div>
|
||||
<div className='mt-3 mb-2 mx-auto text-sm font-semibold'>
|
||||
<span>Заданные вручную словоформы [{forms.length}]</span>
|
||||
<MiniButton
|
||||
noHover
|
||||
title='Сбросить все словоформы'
|
||||
noHover
|
||||
className='py-0 align-middle'
|
||||
icon={<IconRemove size='1.5rem' className='icon-red' />}
|
||||
disabled={isProcessing || forms.length === 0}
|
||||
onClick={handleResetAll}
|
||||
disabled={isProcessing || forms.length === 0}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -47,10 +47,10 @@ export function TableWordForms({ forms, setForms, onFormSelect }: TableWordForms
|
|||
size: 0,
|
||||
cell: props => (
|
||||
<MiniButton
|
||||
title='Удалить словоформу'
|
||||
noHover
|
||||
noPadding
|
||||
className='align-middle'
|
||||
title='Удалить словоформу'
|
||||
icon={<IconRemove size='1.25rem' className='icon-red' />}
|
||||
onClick={() => handleDeleteRow(props.row.index)}
|
||||
/>
|
||||
|
|
|
@ -87,20 +87,20 @@ export function EditorConstituenta() {
|
|||
<ToolbarConstituenta
|
||||
className='cc-tab-tools right-1/2 translate-x-0 xs:right-4 xs:-translate-x-1/2 md:right-1/2 md:translate-x-0 cc-animate-position'
|
||||
activeCst={activeCst}
|
||||
disabled={disabled}
|
||||
onSubmit={initiateSubmit}
|
||||
onReset={() => setToggleReset(prev => !prev)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<div className='mx-0 md:mx-auto pt-8 md:w-195 shrink-0 xs:pt-0'>
|
||||
{activeCst ? (
|
||||
<FormConstituenta
|
||||
id={globalIDs.constituenta_editor}
|
||||
disabled={disabled}
|
||||
toggleReset={toggleReset}
|
||||
activeCst={activeCst}
|
||||
schema={schema}
|
||||
onOpenEdit={navigateCst}
|
||||
disabled={disabled}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
|
|
|
@ -136,7 +136,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
|||
<form id={id} className='relative cc-column mt-1 px-6 py-1' onSubmit={event => void handleSubmit(onSubmit)(event)}>
|
||||
{!disabled || isProcessing ? (
|
||||
<MiniButton
|
||||
title={isModified ? tooltipText.unsaved : `Редактировать словоформы термина`}
|
||||
title={isModified ? tooltipText.unsaved : 'Редактировать словоформы термина'}
|
||||
aria-label='Редактировать словоформы термина'
|
||||
noHover
|
||||
onClick={handleEditTermForms}
|
||||
className='absolute z-pop top-0 left-[calc(7ch+4px)]'
|
||||
|
@ -152,8 +153,9 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
|||
</div>
|
||||
{!disabled || isProcessing ? (
|
||||
<MiniButton
|
||||
noHover
|
||||
title={isModified ? tooltipText.unsaved : 'Переименовать конституенту'}
|
||||
aria-label='Переименовать конституенту'
|
||||
noHover
|
||||
onClick={handleRenameCst}
|
||||
icon={<IconEdit size='1rem' className='icon-primary' />}
|
||||
disabled={isModified}
|
||||
|
@ -175,8 +177,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
|||
value={field.value ?? ''}
|
||||
initialValue={activeCst.term_raw}
|
||||
resolved={activeCst.term_resolved}
|
||||
disabled={disabled}
|
||||
onChange={newValue => field.onChange(newValue)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -214,12 +216,12 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
|||
}
|
||||
value={field.value ?? ''}
|
||||
activeCst={activeCst}
|
||||
disabled={disabled || activeCst.is_inherited}
|
||||
toggleReset={toggleReset}
|
||||
onChange={newValue => field.onChange(newValue)}
|
||||
onChangeLocalParse={setLocalParse}
|
||||
onOpenEdit={onOpenEdit}
|
||||
onShowTypeGraph={handleTypeGraph}
|
||||
disabled={disabled || activeCst.is_inherited}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -240,8 +242,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
|||
value={field.value ?? ''}
|
||||
initialValue={activeCst.definition_raw}
|
||||
resolved={activeCst.definition_resolved}
|
||||
disabled={disabled}
|
||||
onChange={newValue => field.onChange(newValue)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
@ -275,8 +277,8 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
|||
<div className='relative mx-auto flex'>
|
||||
<SubmitButton
|
||||
text='Сохранить изменения'
|
||||
disabled={disabled || !isModified}
|
||||
icon={<IconSave size='1.25rem' />}
|
||||
disabled={disabled || !isModified}
|
||||
/>
|
||||
<div className='absolute z-pop top-1/2 -translate-y-1/2 left-full cc-icons'>
|
||||
{activeCst.has_inherited_children && !activeCst.is_inherited ? (
|
||||
|
|
|
@ -98,33 +98,35 @@ export function ToolbarConstituenta({
|
|||
<>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сохранить изменения', 'Ctrl + S')}
|
||||
aria-label='Сохранить изменения'
|
||||
icon={<IconSave size='1.25rem' className='icon-primary' />}
|
||||
disabled={disabled || !isModified}
|
||||
onClick={onSubmit}
|
||||
disabled={disabled || !isModified}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Сбросить несохраненные изменения'
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
disabled={disabled || !isModified}
|
||||
onClick={onReset}
|
||||
disabled={disabled || !isModified}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Создать конституенту после данной'
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
onClick={() => (activeCst ? createCst(activeCst.cst_type, false) : createCstDefault())}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={isModified ? tooltipText.unsaved : prepareTooltip('Клонировать конституенту', 'Alt + V')}
|
||||
aria-label='Клонировать конституенту'
|
||||
icon={<IconClone size='1.25rem' className='icon-green' />}
|
||||
disabled={disabled || isModified}
|
||||
onClick={cloneCst}
|
||||
disabled={disabled || isModified}
|
||||
/>
|
||||
<MiniButton
|
||||
title='Удалить редактируемую конституенту'
|
||||
disabled={disabled || !canDeleteSelected}
|
||||
onClick={promptDeleteCst}
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={disabled || !canDeleteSelected}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
@ -139,15 +141,17 @@ export function ToolbarConstituenta({
|
|||
<>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
|
||||
aria-label='Переместить вверх'
|
||||
icon={<IconMoveUp size='1.25rem' className='icon-primary' />}
|
||||
disabled={disabled || isModified || schema.items.length < 2}
|
||||
onClick={moveUp}
|
||||
disabled={disabled || isModified || schema.items.length < 2}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
|
||||
aria-label='Переместить вниз'
|
||||
icon={<IconMoveDown size='1.25rem' className='icon-primary' />}
|
||||
disabled={disabled || isModified || schema.items.length < 2}
|
||||
onClick={moveDown}
|
||||
disabled={disabled || isModified || schema.items.length < 2}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
|
|
@ -157,9 +157,9 @@ export function EditorRSExpression({
|
|||
<div className='relative cc-fade-in'>
|
||||
<ToolbarRSExpression
|
||||
className='absolute -top-2 right-0'
|
||||
disabled={disabled}
|
||||
showAST={handleShowAST}
|
||||
showTypeGraph={onShowTypeGraph}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<StatusBar
|
||||
|
@ -174,27 +174,27 @@ export function EditorRSExpression({
|
|||
<RSInput
|
||||
ref={rsInput}
|
||||
value={value}
|
||||
schema={schema}
|
||||
minHeight='3.75rem'
|
||||
maxHeight='8rem'
|
||||
disabled={disabled}
|
||||
onChange={handleChange}
|
||||
onAnalyze={handleCheckExpression}
|
||||
schema={schema}
|
||||
onOpenEdit={onOpenEdit}
|
||||
disabled={disabled}
|
||||
{...restProps}
|
||||
/>
|
||||
|
||||
<RSEditorControls
|
||||
isOpen={showControls && (!disabled || (isProcessing && !activeCst.is_inherited))}
|
||||
disabled={disabled}
|
||||
onEdit={handleEdit}
|
||||
disabled={disabled}
|
||||
/>
|
||||
|
||||
<ParsingResult
|
||||
isOpen={!!parseData && parseData.errors.length > 0}
|
||||
data={parseData}
|
||||
disabled={disabled}
|
||||
onShowError={error => onShowError(error, parseData?.prefixLen ?? 0)}
|
||||
disabled={disabled}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -108,9 +108,9 @@ export function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsP
|
|||
key={`${prefixes.rsedit_btn}${hotkey}`}
|
||||
text={text}
|
||||
titleHtml={`<kbd>[${hotkey}]</kbd>`}
|
||||
className='hidden xs:inline'
|
||||
onInsert={onEdit}
|
||||
disabled={disabled}
|
||||
className='hidden xs:inline'
|
||||
/>
|
||||
))}
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ export function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps)
|
|||
<button
|
||||
type='button'
|
||||
tabIndex={-1}
|
||||
disabled={disabled}
|
||||
onClick={() => onInsert(token)}
|
||||
className={clsx(
|
||||
'h-5 sm:h-6',
|
||||
|
@ -30,6 +29,7 @@ export function RSTokenButton({ token, disabled, onInsert }: RSTokenButtonProps)
|
|||
)}
|
||||
data-tooltip-id={globalIDs.tooltip}
|
||||
data-tooltip-html={describeToken(token)}
|
||||
disabled={disabled}
|
||||
>
|
||||
{label ? <span className='whitespace-nowrap'>{label}</span> : null}
|
||||
</button>
|
||||
|
|
|
@ -78,8 +78,8 @@ export function FormRSForm() {
|
|||
{...register('title')}
|
||||
label='Полное название'
|
||||
className='mb-3'
|
||||
disabled={!isContentEditable}
|
||||
error={errors.title}
|
||||
disabled={!isContentEditable}
|
||||
/>
|
||||
<div className='flex justify-between gap-3 mb-3'>
|
||||
<TextInput
|
||||
|
@ -87,8 +87,8 @@ export function FormRSForm() {
|
|||
{...register('alias')}
|
||||
label='Сокращение'
|
||||
className='w-64'
|
||||
disabled={!isContentEditable}
|
||||
error={errors.alias}
|
||||
disabled={!isContentEditable}
|
||||
/>
|
||||
<div className='relative flex flex-col gap-2'>
|
||||
<ToolbarVersioning
|
||||
|
@ -122,16 +122,16 @@ export function FormRSForm() {
|
|||
{...register('comment')}
|
||||
label='Описание'
|
||||
rows={3}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
error={errors.comment}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
/>
|
||||
{isContentEditable || isDirty ? (
|
||||
<SubmitButton
|
||||
text='Сохранить изменения'
|
||||
className='self-center mt-4'
|
||||
loading={isProcessing}
|
||||
disabled={!isDirty}
|
||||
icon={<IconSave size='1.25rem' />}
|
||||
disabled={!isDirty}
|
||||
/>
|
||||
) : null}
|
||||
</form>
|
||||
|
|
|
@ -69,21 +69,23 @@ export function ToolbarVersioning({ blockReload, className }: ToolbarVersioningP
|
|||
? 'Откатить к версии'
|
||||
: 'Переключитесь на <br/>неактуальную версию'
|
||||
}
|
||||
disabled={isContentEditable || blockReload}
|
||||
aria-label='Откатить к выбранной версии'
|
||||
onClick={handleRestoreVersion}
|
||||
icon={<IconUpload size='1.25rem' className='icon-red' />}
|
||||
disabled={isContentEditable || blockReload}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={isContentEditable ? 'Создать версию' : 'Переключитесь <br/>на актуальную версию'}
|
||||
disabled={!isContentEditable}
|
||||
aria-label={isContentEditable ? 'Создать версию' : 'Переключить на актуальную версию'}
|
||||
onClick={handleCreateVersion}
|
||||
icon={<IconNewVersion size='1.25rem' className='icon-green' />}
|
||||
disabled={!isContentEditable}
|
||||
/>
|
||||
<MiniButton
|
||||
title={schema.versions.length === 0 ? 'Список версий пуст' : 'Редактировать версии'}
|
||||
disabled={schema.versions.length === 0}
|
||||
onClick={handleEditVersions}
|
||||
icon={<IconVersions size='1.25rem' className='icon-primary' />}
|
||||
disabled={schema.versions.length === 0}
|
||||
/>
|
||||
</>
|
||||
) : null}
|
||||
|
|
|
@ -55,29 +55,32 @@ export function ToolbarRSList({ className }: ToolbarRSListProps) {
|
|||
) : null}
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Сбросить выделение', 'ESC')}
|
||||
aria-label='Сбросить выделение'
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
disabled={selected.length === 0}
|
||||
onClick={deselectAll}
|
||||
disabled={selected.length === 0}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Переместить вверх', 'Alt + вверх')}
|
||||
aria-label='Переместить вверх'
|
||||
icon={<IconMoveUp size='1.25rem' className='icon-primary' />}
|
||||
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
|
||||
onClick={moveUp}
|
||||
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Переместить вниз', 'Alt + вниз')}
|
||||
aria-label='Переместить вниз'
|
||||
icon={<IconMoveDown size='1.25rem' className='icon-primary' />}
|
||||
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
|
||||
onClick={moveDown}
|
||||
disabled={isProcessing || selected.length === 0 || selected.length === schema.items.length}
|
||||
/>
|
||||
<div ref={insertMenu.ref} className='relative'>
|
||||
<MiniButton
|
||||
title='Добавить пустую конституенту'
|
||||
hideTitle={insertMenu.isOpen}
|
||||
icon={<IconOpenList size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={insertMenu.toggle}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<Dropdown isOpen={insertMenu.isOpen} className='-translate-x-1/2'>
|
||||
{Object.values(CstType).map(typeStr => (
|
||||
|
@ -93,21 +96,24 @@ export function ToolbarRSList({ className }: ToolbarRSListProps) {
|
|||
</div>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Добавить новую конституенту...', 'Alt + `')}
|
||||
aria-label='Добавить новую конституенту'
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={createCstDefault}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Клонировать конституенту', 'Alt + V')}
|
||||
aria-label='Клонировать конституенту'
|
||||
icon={<IconClone size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing || selected.length !== 1}
|
||||
onClick={cloneCst}
|
||||
disabled={isProcessing || selected.length !== 1}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Удалить выбранные', 'Delete')}
|
||||
aria-label='Удалить выбранные'
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={isProcessing || !canDeleteSelected}
|
||||
onClick={promptDeleteCst}
|
||||
disabled={isProcessing || !canDeleteSelected}
|
||||
/>
|
||||
<BadgeHelp topic={HelpTopic.UI_RS_LIST} offset={5} />
|
||||
</div>
|
||||
|
|
|
@ -44,7 +44,7 @@ export function ToolbarFocusedCst() {
|
|||
</div>
|
||||
|
||||
<MiniButton
|
||||
titleHtml='Сбросить фокус'
|
||||
title='Сбросить фокус'
|
||||
icon={<IconReset size='1.25rem' className='icon-primary' />}
|
||||
onClick={resetSelection}
|
||||
/>
|
||||
|
|
|
@ -99,8 +99,8 @@ export function ToolbarTermGraph() {
|
|||
onClick={showParams}
|
||||
/>
|
||||
<MiniButton
|
||||
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
|
||||
title='Граф целиком'
|
||||
icon={<IconFitImage size='1.25rem' className='icon-primary' />}
|
||||
onClick={handleFitView}
|
||||
/>
|
||||
<MiniButton
|
||||
|
@ -129,16 +129,16 @@ export function ToolbarTermGraph() {
|
|||
<MiniButton
|
||||
title='Новая конституента'
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={handleCreateCst}
|
||||
disabled={isProcessing}
|
||||
/>
|
||||
) : null}
|
||||
{isContentEditable ? (
|
||||
<MiniButton
|
||||
title='Удалить выбранные'
|
||||
icon={<IconDestroy size='1.25rem' className='icon-red' />}
|
||||
disabled={!canDeleteSelected || isProcessing}
|
||||
onClick={handleDeleteCst}
|
||||
disabled={!canDeleteSelected || isProcessing}
|
||||
/>
|
||||
) : null}
|
||||
<MiniButton
|
||||
|
|
|
@ -135,15 +135,16 @@ export function MenuEditSchema() {
|
|||
text='Шаблоны'
|
||||
title='Создать конституенту из шаблона'
|
||||
icon={<IconTemplates size='1rem' className='icon-green' />}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
onClick={handleTemplates}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Встраивание'
|
||||
titleHtml='Импортировать совокупность <br/>конституент из другой схемы'
|
||||
aria-label='Импортировать совокупность конституент из другой схемы'
|
||||
icon={<IconInlineSynthesis size='1rem' className='icon-green' />}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
onClick={handleInlineSynthesis}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
/>
|
||||
|
||||
<Divider margins='mx-3 my-1' />
|
||||
|
@ -151,27 +152,31 @@ export function MenuEditSchema() {
|
|||
<DropdownButton
|
||||
text='Упорядочить список'
|
||||
titleHtml='Упорядочить список, исходя из <br/>логики типов и связей конституент'
|
||||
aria-label='Упорядочить список, исходя из логики типов и связей конституент'
|
||||
icon={<IconSortList size='1rem' className='icon-primary' />}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
onClick={handleRestoreOrder}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Порядковые имена'
|
||||
titleHtml='Присвоить порядковые имена <br/>и обновить выражения'
|
||||
aria-label='Присвоить порядковые имена и обновить выражения'
|
||||
icon={<IconGenerateNames size='1rem' className='icon-primary' />}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
onClick={handleReindex}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Порождение структуры'
|
||||
titleHtml='Раскрыть структуру типизации <br/>выделенной конституенты'
|
||||
aria-label='Раскрыть структуру типизации выделенной конституенты'
|
||||
icon={<IconGenerateStructure size='1rem' className='icon-primary' />}
|
||||
disabled={!isContentEditable || isProcessing || !activeCst || !canProduceStructure(activeCst)}
|
||||
onClick={() => handleProduceStructure(activeCst)}
|
||||
disabled={!isContentEditable || isProcessing || !activeCst || !canProduceStructure(activeCst)}
|
||||
/>
|
||||
<DropdownButton
|
||||
text='Отождествление'
|
||||
titleHtml='Заменить вхождения <br/>одной конституенты на другую'
|
||||
aria-label='Заменить вхождения одной конституенты на другую'
|
||||
icon={<IconReplace size='1rem' className='icon-red' />}
|
||||
onClick={handleSubstituteCst}
|
||||
disabled={!isContentEditable || isProcessing}
|
||||
|
|
|
@ -129,6 +129,7 @@ export function MenuMain() {
|
|||
<DropdownButton
|
||||
text='Поделиться'
|
||||
titleHtml={tooltipText.shareItem(schema.access_policy === AccessPolicy.PUBLIC)}
|
||||
aria-label='Скопировать ссылку в буфер обмена'
|
||||
icon={<IconShare size='1rem' className='icon-primary' />}
|
||||
onClick={handleShare}
|
||||
disabled={schema.access_policy !== AccessPolicy.PUBLIC}
|
||||
|
|
|
@ -41,6 +41,7 @@ export function ConstituentsSearch({ dense }: ConstituentsSearchProps) {
|
|||
<MiniButton
|
||||
noHover
|
||||
titleHtml={`Наследованные: <b>${includeInherited ? 'отображать' : 'скрывать'}</b>`}
|
||||
aria-label={`Отображение наследованных: ${includeInherited ? 'отображать' : 'скрывать'}`}
|
||||
icon={<IconChild size='1rem' className={includeInherited ? 'icon-primary' : 'clr-text-controls'} />}
|
||||
className='h-fit self-center'
|
||||
onClick={toggleInherited}
|
||||
|
|
|
@ -46,10 +46,10 @@ export function SelectGraphFilter({ value, dense, className, onChange, ...restPr
|
|||
const source = value as DependencyMode;
|
||||
return (
|
||||
<DropdownButton
|
||||
className={!dense ? 'w-72' : undefined}
|
||||
key={`${prefixes.cst_source_list}${index}`}
|
||||
onClick={() => handleChange(source)}
|
||||
className={!dense ? 'w-72' : undefined}
|
||||
icon={<IconDependencyMode value={source} size='1rem' />}
|
||||
onClick={() => handleChange(source)}
|
||||
>
|
||||
{!dense ? (
|
||||
<span>
|
||||
|
|
|
@ -45,10 +45,10 @@ export function SelectMatchMode({ value, dense, className, onChange, ...restProp
|
|||
const matchMode = value as CstMatchMode;
|
||||
return (
|
||||
<DropdownButton
|
||||
className={!dense ? 'w-80' : undefined}
|
||||
key={`${prefixes.cst_source_list}${index}`}
|
||||
onClick={() => handleChange(matchMode)}
|
||||
className={!dense ? 'w-80' : undefined}
|
||||
icon={<IconCstMatchMode value={matchMode} size='1rem' />}
|
||||
onClick={() => handleChange(matchMode)}
|
||||
>
|
||||
{!dense ? (
|
||||
<span>
|
||||
|
|
Loading…
Reference in New Issue
Block a user