Compare commits
4 Commits
55f54b97f7
...
fdfbc35f1a
Author | SHA1 | Date | |
---|---|---|---|
![]() |
fdfbc35f1a | ||
![]() |
e1d8c99ebf | ||
![]() |
693cf5d391 | ||
![]() |
2f33a140b7 |
|
@ -14,8 +14,9 @@ function ToggleNavigationButton() {
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'absolute top-0 right-0 z-navigation flex items-center justify-center',
|
'absolute top-0 right-0 z-navigation flex items-center justify-center',
|
||||||
'clr-btn-nav',
|
'clr-hover',
|
||||||
'select-none'
|
'select-none',
|
||||||
|
'min-h-[2rem]'
|
||||||
)}
|
)}
|
||||||
onClick={toggleNoNavigation}
|
onClick={toggleNoNavigation}
|
||||||
initial={false}
|
initial={false}
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { findAliasAt } from '@/utils/codemirror';
|
||||||
const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => {
|
const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => {
|
||||||
return EditorView.domEventHandlers({
|
return EditorView.domEventHandlers({
|
||||||
click: (event: MouseEvent, view: EditorView) => {
|
click: (event: MouseEvent, view: EditorView) => {
|
||||||
if (!event.ctrlKey) {
|
if (!event.ctrlKey && !event.metaKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ import { findReferenceAt } from '@/utils/codemirror';
|
||||||
const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => {
|
const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => {
|
||||||
return EditorView.domEventHandlers({
|
return EditorView.domEventHandlers({
|
||||||
click: (event: MouseEvent, view: EditorView) => {
|
click: (event: MouseEvent, view: EditorView) => {
|
||||||
if (!event.ctrlKey) {
|
if (!event.ctrlKey && !event.metaKey) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { prefixes } from '@/utils/constants';
|
||||||
import { describeConstituenta } from '@/utils/labels';
|
import { describeConstituenta } from '@/utils/labels';
|
||||||
|
|
||||||
import BadgeConstituenta from '../info/BadgeConstituenta';
|
import BadgeConstituenta from '../info/BadgeConstituenta';
|
||||||
import FlexColumn from '../ui/FlexColumn';
|
import NoData from '../ui/NoData';
|
||||||
|
|
||||||
interface PickConstituentaProps {
|
interface PickConstituentaProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -106,10 +106,10 @@ function PickConstituenta({
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<NoData className='min-h-[6rem]'>
|
||||||
<p>Список конституент пуст</p>
|
<p>Список конституент пуст</p>
|
||||||
<p>Измените параметры фильтра</p>
|
<p>Измените параметры фильтра</p>
|
||||||
</FlexColumn>
|
</NoData>
|
||||||
}
|
}
|
||||||
onRowClicked={onSelectValue}
|
onRowClicked={onSelectValue}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { isBasicConcept } from '@/models/rsformAPI';
|
||||||
import { describeConstituenta } from '@/utils/labels';
|
import { describeConstituenta } from '@/utils/labels';
|
||||||
|
|
||||||
import BadgeConstituenta from '../info/BadgeConstituenta';
|
import BadgeConstituenta from '../info/BadgeConstituenta';
|
||||||
import FlexColumn from '../ui/FlexColumn';
|
import NoData from '../ui/NoData';
|
||||||
import GraphSelectionToolbar from './GraphSelectionToolbar';
|
import GraphSelectionToolbar from './GraphSelectionToolbar';
|
||||||
|
|
||||||
interface PickMultiConstituentaProps {
|
interface PickMultiConstituentaProps {
|
||||||
|
@ -103,9 +103,9 @@ function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelect
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
onRowSelectionChange={handleRowSelection}
|
onRowSelectionChange={handleRowSelection}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='items-center p-3'>
|
<NoData>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
</FlexColumn>
|
</NoData>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -104,7 +104,7 @@ function PickSchema({ id, initialFilter = '', rows = 4, value, onSelectValue }:
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<FlexColumn className='dense p-3 items-center min-h-[6rem]'>
|
||||||
<p>Список схем пуст</p>
|
<p>Список схем пуст</p>
|
||||||
<p>Измените параметры фильтра</p>
|
<p>Измените параметры фильтра</p>
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
IconRemove,
|
IconRemove,
|
||||||
IconReplace
|
IconReplace
|
||||||
} from '../Icons';
|
} from '../Icons';
|
||||||
|
import NoData from '../ui/NoData';
|
||||||
|
|
||||||
interface PickSubstitutionsProps {
|
interface PickSubstitutionsProps {
|
||||||
prefixID: string;
|
prefixID: string;
|
||||||
|
@ -259,10 +260,10 @@ function PickSubstitutions({
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<span className='p-2 text-center min-h-[2rem]'>
|
<NoData className='min-h-[2rem]'>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
<p>Добавьте отождествление</p>
|
<p>Добавьте отождествление</p>
|
||||||
</span>
|
</NoData>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,7 +37,7 @@ function SelectAccessPolicy({ value, disabled, stretchLeft, onChange }: SelectAc
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title={`Доступ: ${labelAccessPolicy(value)}`}
|
title={`Доступ: ${labelAccessPolicy(value)}`}
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full disabled:cursor-auto'
|
className='h-full'
|
||||||
icon={<PolicyIcon value={value} size='1.25rem' />}
|
icon={<PolicyIcon value={value} size='1.25rem' />}
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
|
@ -38,7 +38,7 @@ function SelectItemType({ value, disabled, stretchLeft, onChange }: SelectItemTy
|
||||||
transparent
|
transparent
|
||||||
title={describeLibraryItemType(value)}
|
title={describeLibraryItemType(value)}
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full py-1 px-2 disabled:cursor-auto rounded-lg'
|
className='h-full px-2 py-1 rounded-lg'
|
||||||
icon={<ItemTypeIcon value={value} size='1.25rem' />}
|
icon={<ItemTypeIcon value={value} size='1.25rem' />}
|
||||||
text={labelLibraryItemType(value)}
|
text={labelLibraryItemType(value)}
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
|
|
41
rsconcept/frontend/src/components/select/SelectLocation.tsx
Normal file
41
rsconcept/frontend/src/components/select/SelectLocation.tsx
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
|
import { FolderTree } from '@/models/FolderTree';
|
||||||
|
import { LocationHead } from '@/models/library';
|
||||||
|
|
||||||
|
import { IconFolderTree } from '../Icons';
|
||||||
|
import MiniButton from '../ui/MiniButton';
|
||||||
|
|
||||||
|
interface SelectLocationProps {
|
||||||
|
value: string;
|
||||||
|
onChange: (newValue: string) => void;
|
||||||
|
|
||||||
|
folderTree: FolderTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectLocation({ value, onChange, folderTree }: SelectLocationProps) {
|
||||||
|
const menu = useDropdown();
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(newValue: LocationHead) => {
|
||||||
|
menu.hide();
|
||||||
|
onChange(newValue);
|
||||||
|
},
|
||||||
|
[menu, onChange]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={menu.ref} className='h-full text-right'>
|
||||||
|
<MiniButton
|
||||||
|
title='Проводник...'
|
||||||
|
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||||
|
onClick={() => menu.toggle}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectLocation;
|
|
@ -14,7 +14,7 @@ import DropdownButton from '../ui/DropdownButton';
|
||||||
|
|
||||||
interface SelectLocationHeadProps {
|
interface SelectLocationHeadProps {
|
||||||
value: LocationHead;
|
value: LocationHead;
|
||||||
onChange: (value: LocationHead) => void;
|
onChange: (newValue: LocationHead) => void;
|
||||||
excluded?: LocationHead[];
|
excluded?: LocationHead[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,7 @@ import clsx from 'clsx';
|
||||||
|
|
||||||
import { CProps } from '../props';
|
import { CProps } from '../props';
|
||||||
|
|
||||||
export interface FlexColumnProps extends CProps.Div {}
|
function FlexColumn({ className, children, ...restProps }: CProps.Div) {
|
||||||
|
|
||||||
function FlexColumn({ className, children, ...restProps }: FlexColumnProps) {
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('cc-column', className)} {...restProps}>
|
<div className={clsx('cc-column', className)} {...restProps}>
|
||||||
{children}
|
{children}
|
||||||
|
|
13
rsconcept/frontend/src/components/ui/NoData.tsx
Normal file
13
rsconcept/frontend/src/components/ui/NoData.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
|
function NoData({ className, children, ...restProps }: CProps.Div) {
|
||||||
|
return (
|
||||||
|
<div className={clsx('p-3 flex flex-col items-center text-center select-none w-full', className)} {...restProps}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoData;
|
|
@ -18,9 +18,9 @@ function TextURL({ text, href, title, color = 'clr-text-url', onClick }: TextURL
|
||||||
);
|
);
|
||||||
} else if (onClick) {
|
} else if (onClick) {
|
||||||
return (
|
return (
|
||||||
<span tabIndex={-1} className={design} onClick={onClick}>
|
<button type='button' tabIndex={-1} className={design} onClick={onClick}>
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</button>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -101,7 +101,6 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||||
icon={<VisibilityIcon value={visible} />}
|
icon={<VisibilityIcon value={visible} />}
|
||||||
onClick={() => setVisible(prev => !prev)}
|
onClick={() => setVisible(prev => !prev)}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import RSInput from '@/components/RSInput';
|
||||||
import PickConstituenta from '@/components/select/PickConstituenta';
|
import PickConstituenta from '@/components/select/PickConstituenta';
|
||||||
import DataTable, { IConditionalStyle } from '@/components/ui/DataTable';
|
import DataTable, { IConditionalStyle } from '@/components/ui/DataTable';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
import NoData from '@/components/ui/NoData';
|
||||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { IConstituenta, IRSForm } from '@/models/rsform';
|
import { IConstituenta, IRSForm } from '@/models/rsform';
|
||||||
|
@ -160,7 +161,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
data={state.arguments}
|
data={state.arguments}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
noDataComponent={<p className={clsx('min-h-[3.6rem]', 'p-2', 'text-center')}>Аргументы отсутствуют</p>}
|
noDataComponent={<NoData className='min-h-[3.6rem]'>Аргументы отсутствуют</NoData>}
|
||||||
onRowClicked={handleSelectArgument}
|
onRowClicked={handleSelectArgument}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { IconRemove } from '@/components/Icons';
|
||||||
import BadgeWordForm from '@/components/info/BadgeWordForm';
|
import BadgeWordForm from '@/components/info/BadgeWordForm';
|
||||||
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
import NoData from '@/components/ui/NoData';
|
||||||
import { IWordForm } from '@/models/language';
|
import { IWordForm } from '@/models/language';
|
||||||
|
|
||||||
interface WordFormsTableProps {
|
interface WordFormsTableProps {
|
||||||
|
@ -78,10 +79,10 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<span className='p-2 text-center min-h-[2rem]'>
|
<NoData className='min-h-[2rem]'>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
<p>Добавьте словоформу</p>
|
<p>Добавьте словоформу</p>
|
||||||
</span>
|
</NoData>
|
||||||
}
|
}
|
||||||
onRowClicked={onFormSelect}
|
onRowClicked={onFormSelect}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -10,6 +10,7 @@ import { IconDownload } from '@/components/Icons';
|
||||||
import InfoError from '@/components/info/InfoError';
|
import InfoError from '@/components/info/InfoError';
|
||||||
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||||
import SelectItemType from '@/components/select/SelectItemType';
|
import SelectItemType from '@/components/select/SelectItemType';
|
||||||
|
import SelectLocation from '@/components/select/SelectLocation';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
|
@ -30,7 +31,7 @@ import { information } from '@/utils/labels';
|
||||||
function FormCreateItem() {
|
function FormCreateItem() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { createItem, processingError, setProcessingError, processing } = useLibrary();
|
const { createItem, processingError, setProcessingError, processing, folders } = useLibrary();
|
||||||
|
|
||||||
const [itemType, setItemType] = useState(LibraryItemType.RSFORM);
|
const [itemType, setItemType] = useState(LibraryItemType.RSFORM);
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
|
@ -98,6 +99,11 @@ function FormCreateItem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSelectLocation = useCallback((newValue: string) => {
|
||||||
|
setHead(newValue.substring(0, 2) as LocationHead);
|
||||||
|
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')} onSubmit={handleSubmit}>
|
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||||
<h1>
|
<h1>
|
||||||
|
@ -154,7 +160,6 @@ function FormCreateItem() {
|
||||||
<div className='ml-auto cc-icons'>
|
<div className='ml-auto cc-icons'>
|
||||||
<SelectAccessPolicy value={policy} onChange={setPolicy} />
|
<SelectAccessPolicy value={policy} onChange={setPolicy} />
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||||
icon={<VisibilityIcon value={visible} />}
|
icon={<VisibilityIcon value={visible} />}
|
||||||
onClick={() => setVisible(prev => !prev)}
|
onClick={() => setVisible(prev => !prev)}
|
||||||
|
@ -180,6 +185,11 @@ function FormCreateItem() {
|
||||||
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{user?.is_staff ? (
|
||||||
|
<div className='self-start mt-[-0.25rem] ml-[-1.5rem]'>
|
||||||
|
<SelectLocation folderTree={folders} value={location} onChange={handleSelectLocation} />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<TextArea
|
<TextArea
|
||||||
id='dlg_cst_body'
|
id='dlg_cst_body'
|
||||||
label='Путь'
|
label='Путь'
|
||||||
|
|
|
@ -54,7 +54,7 @@ function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }:
|
||||||
(event: CProps.EventMouse, target: FolderNode) => {
|
(event: CProps.EventMouse, target: FolderNode) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
navigator.clipboard
|
navigator.clipboard
|
||||||
.writeText(target.getPath())
|
.writeText(target.getPath())
|
||||||
.then(() => toast.success(information.pathReady))
|
.then(() => toast.success(information.pathReady))
|
||||||
|
|
|
@ -164,7 +164,7 @@ function LibraryTable({ items, resetQuery, folderMode, toggleFolderMode }: Libra
|
||||||
className={clsx('text-xs sm:text-sm cc-scroll-y', { 'border-l border-b': folderMode })}
|
className={clsx('text-xs sm:text-sm cc-scroll-y', { 'border-l border-b': folderMode })}
|
||||||
style={{ maxHeight: tableHeight }}
|
style={{ maxHeight: tableHeight }}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<FlexColumn className='dense p-3 items-center min-h-[6rem]'>
|
||||||
<p>Список схем пуст</p>
|
<p>Список схем пуст</p>
|
||||||
<p className='flex gap-6'>
|
<p className='flex gap-6'>
|
||||||
<TextURL text='Создать схему' href='/library/create' />
|
<TextURL text='Создать схему' href='/library/create' />
|
||||||
|
|
|
@ -5,19 +5,16 @@ import { useCallback } from 'react';
|
||||||
|
|
||||||
import { LocationIcon, SubscribeIcon, VisibilityIcon } from '@/components/DomainIcons';
|
import { LocationIcon, SubscribeIcon, VisibilityIcon } from '@/components/DomainIcons';
|
||||||
import { IconEditor, IconFilterReset, IconFolder, IconFolderTree, IconOwner } from '@/components/Icons';
|
import { IconEditor, IconFilterReset, IconFolder, IconFolderTree, IconOwner } from '@/components/Icons';
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
|
||||||
import { CProps } from '@/components/props';
|
import { CProps } from '@/components/props';
|
||||||
import Dropdown from '@/components/ui/Dropdown';
|
import Dropdown from '@/components/ui/Dropdown';
|
||||||
import DropdownButton from '@/components/ui/DropdownButton';
|
import DropdownButton from '@/components/ui/DropdownButton';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import Overlay from '@/components/ui/Overlay';
|
|
||||||
import SearchBar from '@/components/ui/SearchBar';
|
import SearchBar from '@/components/ui/SearchBar';
|
||||||
import SelectorButton from '@/components/ui/SelectorButton';
|
import SelectorButton from '@/components/ui/SelectorButton';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
import { LocationHead } from '@/models/library';
|
import { LocationHead } from '@/models/library';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { prefixes } from '@/utils/constants';
|
||||||
import { PARAMETER, prefixes } from '@/utils/constants';
|
|
||||||
import { describeLocationHead, labelLocationHead } from '@/utils/labels';
|
import { describeLocationHead, labelLocationHead } from '@/utils/labels';
|
||||||
import { tripleToggleColor } from '@/utils/utils';
|
import { tripleToggleColor } from '@/utils/utils';
|
||||||
|
|
||||||
|
@ -90,7 +87,7 @@ function SearchPanel({
|
||||||
|
|
||||||
const handleFolderClick = useCallback(
|
const handleFolderClick = useCallback(
|
||||||
(event: CProps.EventMouse) => {
|
(event: CProps.EventMouse) => {
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey || event.metaKey) {
|
||||||
toggleFolderMode();
|
toggleFolderMode();
|
||||||
} else {
|
} else {
|
||||||
headMenu.toggle();
|
headMenu.toggle();
|
||||||
|
@ -218,14 +215,6 @@ function SearchPanel({
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<Overlay position='top-[-0.75rem] right-0'>
|
|
||||||
<BadgeHelp
|
|
||||||
topic={HelpTopic.UI_LIBRARY}
|
|
||||||
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'text-sm')}
|
|
||||||
offset={5}
|
|
||||||
place='right-start'
|
|
||||||
/>
|
|
||||||
</Overlay>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -221,8 +221,8 @@ function FormConstituenta({
|
||||||
<button
|
<button
|
||||||
key='cst_disable_comment'
|
key='cst_disable_comment'
|
||||||
id='cst_disable_comment'
|
id='cst_disable_comment'
|
||||||
tabIndex={-1}
|
|
||||||
type='button'
|
type='button'
|
||||||
|
tabIndex={-1}
|
||||||
className='self-start cc-label clr-text-url hover:underline'
|
className='self-start cc-label clr-text-url hover:underline'
|
||||||
onClick={() => setForceComment(true)}
|
onClick={() => setForceComment(true)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -39,7 +39,6 @@ function AccessToolbar({ visible, toggleVisible, readOnly, toggleReadOnly, contr
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||||
icon={<VisibilityIcon value={visible} />}
|
icon={<VisibilityIcon value={visible} />}
|
||||||
onClick={toggleVisible}
|
onClick={toggleVisible}
|
||||||
|
@ -47,7 +46,6 @@ function AccessToolbar({ visible, toggleVisible, readOnly, toggleReadOnly, contr
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
|
||||||
title={readOnly ? 'Изменение: запрещено' : 'Изменение: разрешено'}
|
title={readOnly ? 'Изменение: запрещено' : 'Изменение: разрешено'}
|
||||||
icon={
|
icon={
|
||||||
readOnly ? (
|
readOnly ? (
|
||||||
|
|
|
@ -13,6 +13,7 @@ import useDropdown from '@/hooks/useDropdown';
|
||||||
import { ILibraryItemData, ILibraryItemEditor } from '@/models/library';
|
import { ILibraryItemData, ILibraryItemEditor } from '@/models/library';
|
||||||
import { UserID, UserLevel } from '@/models/user';
|
import { UserID, UserLevel } from '@/models/user';
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
|
import { prompts } from '@/utils/labels';
|
||||||
|
|
||||||
import LabeledValue from '../../../components/ui/LabeledValue';
|
import LabeledValue from '../../../components/ui/LabeledValue';
|
||||||
|
|
||||||
|
@ -34,11 +35,7 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
if (newValue === item?.owner) {
|
if (newValue === item?.owner) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (
|
if (!window.confirm(prompts.ownerChange)) {
|
||||||
!window.confirm(
|
|
||||||
'Вы уверены, что хотите изменить владельца? Вы потеряете право управления данной схемой. Данное действие отменить нельзя'
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
controller.setOwner(newValue);
|
controller.setOwner(newValue);
|
||||||
|
@ -59,7 +56,11 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
/>
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
) : null}
|
) : null}
|
||||||
<LabeledValue className='max-w-[30rem] sm:mb-1 text-ellipsis' label='Путь' text={item?.location ?? ''} />
|
<LabeledValue
|
||||||
|
className='max-w-[30rem] sm:mb-1 text-ellipsis' //
|
||||||
|
label='Путь'
|
||||||
|
text={item?.location ?? ''}
|
||||||
|
/>
|
||||||
|
|
||||||
{accessLevel >= UserLevel.OWNER ? (
|
{accessLevel >= UserLevel.OWNER ? (
|
||||||
<Overlay position='top-[-0.5rem] left-[5.5rem] cc-icons'>
|
<Overlay position='top-[-0.5rem] left-[5.5rem] cc-icons'>
|
||||||
|
@ -82,7 +83,11 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
) : null}
|
) : null}
|
||||||
<LabeledValue className='sm:mb-1' label='Владелец' text={getUserLabel(item?.owner ?? null)} />
|
<LabeledValue
|
||||||
|
className='sm:mb-1' //
|
||||||
|
label='Владелец'
|
||||||
|
text={getUserLabel(item?.owner ?? null)}
|
||||||
|
/>
|
||||||
|
|
||||||
{accessLevel >= UserLevel.OWNER ? (
|
{accessLevel >= UserLevel.OWNER ? (
|
||||||
<Overlay position='top-[-0.5rem] left-[5.5rem] cc-icons'>
|
<Overlay position='top-[-0.5rem] left-[5.5rem] cc-icons'>
|
||||||
|
@ -97,12 +102,22 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
||||||
</div>
|
</div>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
) : null}
|
) : null}
|
||||||
<LabeledValue id='editor_stats' className='sm:mb-1' label='Редакторы' text={item?.editors.length ?? 0} />
|
<LabeledValue
|
||||||
|
id='editor_stats' //
|
||||||
|
className='sm:mb-1'
|
||||||
|
label='Редакторы'
|
||||||
|
text={item?.editors.length ?? 0}
|
||||||
|
/>
|
||||||
<Tooltip anchorSelect='#editor_stats' layer='z-modalTooltip'>
|
<Tooltip anchorSelect='#editor_stats' layer='z-modalTooltip'>
|
||||||
<InfoUsers items={item?.editors ?? []} prefix={prefixes.user_editors} />
|
<InfoUsers items={item?.editors ?? []} prefix={prefixes.user_editors} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
||||||
<LabeledValue id='sub_stats' className='sm:mb-1' label='Отслеживают' text={item?.subscribers.length ?? 0} />
|
<LabeledValue
|
||||||
|
id='sub_stats' //
|
||||||
|
className='sm:mb-1'
|
||||||
|
label='Отслеживают'
|
||||||
|
text={item?.subscribers.length ?? 0}
|
||||||
|
/>
|
||||||
<Tooltip anchorSelect='#sub_stats' layer='z-modalTooltip'>
|
<Tooltip anchorSelect='#sub_stats' layer='z-modalTooltip'>
|
||||||
<InfoUsers items={item?.subscribers ?? []} prefix={prefixes.user_subs} />
|
<InfoUsers items={item?.subscribers ?? []} prefix={prefixes.user_subs} />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
|
|
|
@ -6,7 +6,8 @@ import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
||||||
import { CProps } from '@/components/props';
|
import { CProps } from '@/components/props';
|
||||||
import DataTable, { createColumnHelper, RowSelectionState, VisibilityState } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, RowSelectionState, VisibilityState } from '@/components/ui/DataTable';
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import NoData from '@/components/ui/NoData';
|
||||||
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
||||||
|
@ -135,12 +136,12 @@ function RSTable({ items, maxHeight, enableSelection, selected, setSelected, onE
|
||||||
rowSelection={selected}
|
rowSelection={selected}
|
||||||
onRowSelectionChange={setSelected}
|
onRowSelectionChange={setSelected}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='items-center p-3'>
|
<NoData>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
<p className='cursor-pointer clr-text-primary hover:underline' onClick={() => onCreateNew()}>
|
<p>
|
||||||
Создать новую конституенту
|
<TextURL text='Создать конституенту...' onClick={onCreateNew} />
|
||||||
</p>
|
</p>
|
||||||
</FlexColumn>
|
</NoData>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
|
@ -98,10 +98,11 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori
|
||||||
const id = `${prefixes.cst_hidden_list}${cst.alias}`;
|
const id = `${prefixes.cst_hidden_list}${cst.alias}`;
|
||||||
return (
|
return (
|
||||||
<div key={`wrap-${id}`}>
|
<div key={`wrap-${id}`}>
|
||||||
<div
|
<button
|
||||||
|
type='button'
|
||||||
key={id}
|
key={id}
|
||||||
id={id}
|
id={id}
|
||||||
className='min-w-[3rem] rounded-md text-center cursor-pointer select-none'
|
className='min-w-[3rem] rounded-md text-center select-none'
|
||||||
style={{
|
style={{
|
||||||
backgroundColor: colorBgGraphNode(cst, adjustedColoring, colors),
|
backgroundColor: colorBgGraphNode(cst, adjustedColoring, colors),
|
||||||
...(localSelected.includes(cstID) ? { outlineWidth: '2px', outlineStyle: 'solid' } : {})
|
...(localSelected.includes(cstID) ? { outlineWidth: '2px', outlineStyle: 'solid' } : {})
|
||||||
|
@ -110,7 +111,7 @@ function ViewHidden({ items, selected, toggleSelection, setFocus, schema, colori
|
||||||
onDoubleClick={() => onEdit(cstID)}
|
onDoubleClick={() => onEdit(cstID)}
|
||||||
>
|
>
|
||||||
{cst.alias}
|
{cst.alias}
|
||||||
</div>
|
</button>
|
||||||
<ConstituentaTooltip data={cst} anchor={`#${id}`} />
|
<ConstituentaTooltip data={cst} anchor={`#${id}`} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
||||||
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
|
||||||
|
import NoData from '@/components/ui/NoData';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
||||||
|
@ -155,10 +155,10 @@ function ConstituentsTable({ items, activeCst, onOpenEdit, maxHeight, denseThres
|
||||||
columnVisibility={columnVisibility}
|
columnVisibility={columnVisibility}
|
||||||
onColumnVisibilityChange={setColumnVisibility}
|
onColumnVisibilityChange={setColumnVisibility}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<div className={clsx('min-h-[5rem]', 'p-3', 'text-center', 'select-none')}>
|
<NoData className='min-h-[5rem]'>
|
||||||
<p>Список конституент пуст</p>
|
<p>Список конституент пуст</p>
|
||||||
<p>Измените параметры фильтра</p>
|
<p>Измените параметры фильтра</p>
|
||||||
</div>
|
</NoData>
|
||||||
}
|
}
|
||||||
onRowClicked={handleRowClicked}
|
onRowClicked={handleRowClicked}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -6,6 +6,7 @@ import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
||||||
|
import NoData from '@/components/ui/NoData';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { ILibraryItem } from '@/models/library';
|
import { ILibraryItem } from '@/models/library';
|
||||||
import { animateSideView } from '@/styling/animations';
|
import { animateSideView } from '@/styling/animations';
|
||||||
|
@ -74,7 +75,7 @@ function ViewSubscriptions({ items }: ViewSubscriptionsProps) {
|
||||||
id: 'time_update',
|
id: 'time_update',
|
||||||
desc: true
|
desc: true
|
||||||
}}
|
}}
|
||||||
noDataComponent={<div className='h-[10rem]'>Отслеживаемые схемы отсутствуют</div>}
|
noDataComponent={<NoData className='h-[10rem]'>Отслеживаемые схемы отсутствуют</NoData>}
|
||||||
onRowClicked={openRSForm}
|
onRowClicked={openRSForm}
|
||||||
/>
|
/>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
@ -942,7 +942,9 @@ export const prompts = {
|
||||||
promptUnsaved: 'Присутствуют несохраненные изменения. Продолжить без их учета?',
|
promptUnsaved: 'Присутствуют несохраненные изменения. Продолжить без их учета?',
|
||||||
deleteLibraryItem: 'Вы уверены, что хотите удалить данную схему?',
|
deleteLibraryItem: 'Вы уверены, что хотите удалить данную схему?',
|
||||||
generateWordforms: 'Данное действие приведет к перезаписи словоформ при совпадении граммем. Продолжить?',
|
generateWordforms: 'Данное действие приведет к перезаписи словоформ при совпадении граммем. Продолжить?',
|
||||||
restoreArchive: 'При восстановлении архивной версии актуальная схему будет заменена. Продолжить?'
|
restoreArchive: 'При восстановлении архивной версии актуальная схему будет заменена. Продолжить?',
|
||||||
|
ownerChange:
|
||||||
|
'Вы уверены, что хотите изменить владельца? Вы потеряете право управления данной схемой. Данное действие отменить нельзя'
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============== INTERNAL LABELS FOR DEVELOPERS TEXT ================
|
// ============== INTERNAL LABELS FOR DEVELOPERS TEXT ================
|
||||||
|
|
Loading…
Reference in New Issue
Block a user