mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
R: Distinguish undefined semantics vs null
This commit is contained in:
parent
9ef4d32376
commit
53b746f3c4
|
@ -31,7 +31,7 @@ const DlgUploadRSForm = React.lazy(() => import('@/features/rsform/dialogs/DlgUp
|
|||
export const GlobalDialogs = () => {
|
||||
const active = useDialogsStore(state => state.active);
|
||||
|
||||
if (active === undefined) {
|
||||
if (active === null) {
|
||||
return null;
|
||||
}
|
||||
switch (active) {
|
||||
|
|
|
@ -32,8 +32,6 @@ axiosInstance.interceptors.request.use(config => {
|
|||
});
|
||||
|
||||
// ================ Data transfer types ================
|
||||
export type DataCallback<ResponseData = undefined> = (data: ResponseData) => void;
|
||||
|
||||
export interface IFrontRequest<RequestData, ResponseData> {
|
||||
data?: RequestData;
|
||||
successMessage?: string | ((data: ResponseData) => string);
|
||||
|
|
|
@ -5,10 +5,10 @@ import { KEYS } from './configuration';
|
|||
|
||||
export const useMutationErrors = () => {
|
||||
const queryClient = useQueryClient();
|
||||
const [ignored, setIgnored] = useState<(Error | null)[]>([]);
|
||||
const [ignored, setIgnored] = useState<Error[]>([]);
|
||||
const mutationErrors = useMutationState({
|
||||
filters: { mutationKey: [KEYS.global_mutation], status: 'error' },
|
||||
select: mutation => mutation.state.error
|
||||
select: mutation => mutation.state.error!
|
||||
});
|
||||
|
||||
console.log(queryClient.getMutationCache().getAll());
|
||||
|
|
|
@ -141,7 +141,7 @@ function DataTable<TData extends RowData>({
|
|||
...restProps
|
||||
}: DataTableProps<TData>) {
|
||||
const [sorting, setSorting] = useState<SortingState>(initialSorting ? [initialSorting] : []);
|
||||
const [lastSelected, setLastSelected] = useState<string | undefined>(undefined);
|
||||
const [lastSelected, setLastSelected] = useState<string | null>(null);
|
||||
|
||||
const [pagination, setPagination] = useState<PaginationState>({
|
||||
pageIndex: 0,
|
||||
|
@ -198,7 +198,7 @@ function DataTable<TData extends RowData>({
|
|||
enableRowSelection={enableRowSelection}
|
||||
enableSorting={enableSorting}
|
||||
headPosition={headPosition}
|
||||
resetLastSelected={() => setLastSelected(undefined)}
|
||||
resetLastSelected={() => setLastSelected(null)}
|
||||
/>
|
||||
) : null}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import { Checkbox } from '../Input';
|
|||
|
||||
interface SelectRowProps<TData> {
|
||||
row: Row<TData>;
|
||||
onChangeLastSelected: (newValue: string | undefined) => void;
|
||||
onChangeLastSelected: (newValue: string) => void;
|
||||
}
|
||||
|
||||
function SelectRow<TData>({ row, onChangeLastSelected }: SelectRowProps<TData>) {
|
||||
|
|
|
@ -15,8 +15,8 @@ interface TableBodyProps<TData> {
|
|||
enableRowSelection?: boolean;
|
||||
conditionalRowStyles?: IConditionalStyle<TData>[];
|
||||
|
||||
lastSelected: string | undefined;
|
||||
onChangeLastSelected: (newValue: string | undefined) => void;
|
||||
lastSelected: string | null;
|
||||
onChangeLastSelected: (newValue: string | null) => void;
|
||||
|
||||
onRowClicked?: (rowData: TData, event: CProps.EventMouse) => void;
|
||||
onRowDoubleClicked?: (rowData: TData, event: CProps.EventMouse) => void;
|
||||
|
@ -49,7 +49,7 @@ function TableBody<TData>({
|
|||
newSelection[row.id] = !target.getIsSelected();
|
||||
});
|
||||
table.setRowSelection(prev => ({ ...prev, ...newSelection }));
|
||||
onChangeLastSelected(undefined);
|
||||
onChangeLastSelected(null);
|
||||
} else {
|
||||
onChangeLastSelected(target.id);
|
||||
target.toggleSelected(!target.getIsSelected());
|
||||
|
@ -94,7 +94,7 @@ function TableBody<TData>({
|
|||
width: noHeader && index === 0 ? `calc(var(--col-${cell.column.id}-size) * 1px)` : 'auto'
|
||||
}}
|
||||
onClick={event => handleRowClicked(row, event)}
|
||||
onDoubleClick={event => (onRowDoubleClicked ? onRowDoubleClicked(row.original, event) : undefined)}
|
||||
onDoubleClick={event => onRowDoubleClicked?.(row.original, event)}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</td>
|
||||
|
|
|
@ -6,7 +6,7 @@ import { isResponseHtml } from '@/utils/utils';
|
|||
|
||||
import { PrettyJson } from './View';
|
||||
|
||||
export type ErrorData = string | Error | AxiosError | ZodError | undefined | null;
|
||||
export type ErrorData = string | Error | AxiosError | ZodError;
|
||||
|
||||
interface InfoErrorProps {
|
||||
error: ErrorData;
|
||||
|
|
|
@ -53,7 +53,7 @@ export function SearchBar({
|
|||
className={clsx('outline-none bg-transparent', !noIcon && 'pl-10')}
|
||||
noBorder={noBorder}
|
||||
value={query}
|
||||
onChange={event => (onChangeQuery ? onChangeQuery(event.target.value) : undefined)}
|
||||
onChange={event => onChangeQuery?.(event.target.value)}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -86,7 +86,7 @@ export const schemaCloneLibraryItem = schemaLibraryItem
|
|||
alias: z.string().nonempty(errorMsg.requiredField),
|
||||
location: z.string().refine(data => validateLocation(data), { message: errorMsg.invalidLocation }),
|
||||
|
||||
items: z.array(z.number()).optional()
|
||||
items: z.array(z.number())
|
||||
});
|
||||
|
||||
export const schemaCreateLibraryItem = z
|
||||
|
@ -138,5 +138,5 @@ export const schemaVersionUpdate = z.object({
|
|||
export const schemaVersionCreate = z.object({
|
||||
version: z.string(),
|
||||
description: z.string(),
|
||||
items: z.array(z.number()).optional()
|
||||
items: z.array(z.number())
|
||||
});
|
||||
|
|
|
@ -16,32 +16,29 @@ export function useApplyLibraryFilter(filter: ILibraryFilter) {
|
|||
if (filter.folderMode && filter.location) {
|
||||
if (filter.subfolders) {
|
||||
result = result.filter(
|
||||
item => item.location == filter.location || item.location.startsWith(filter.location! + '/')
|
||||
item => item.location == filter.location || item.location.startsWith(filter.location + '/')
|
||||
);
|
||||
} else {
|
||||
result = result.filter(item => item.location == filter.location);
|
||||
}
|
||||
}
|
||||
if (filter.type) {
|
||||
result = result.filter(item => item.item_type === filter.type);
|
||||
}
|
||||
if (filter.isVisible !== undefined) {
|
||||
if (filter.isVisible !== null) {
|
||||
result = result.filter(item => filter.isVisible === item.visible);
|
||||
}
|
||||
if (filter.isOwned !== undefined) {
|
||||
if (filter.isOwned !== null) {
|
||||
result = result.filter(item => filter.isOwned === (item.owner === user.id));
|
||||
}
|
||||
if (filter.isEditor !== undefined) {
|
||||
if (filter.isEditor !== null) {
|
||||
result = result.filter(item => filter.isEditor == user.editor.includes(item.id));
|
||||
}
|
||||
if (filter.filterUser !== undefined) {
|
||||
if (filter.filterUser !== null) {
|
||||
result = result.filter(item => filter.filterUser === item.owner);
|
||||
}
|
||||
if (!filter.folderMode && filter.path) {
|
||||
result = result.filter(item => matchLibraryItemLocation(item, filter.path!));
|
||||
if (!filter.folderMode && !!filter.path) {
|
||||
result = result.filter(item => matchLibraryItemLocation(item, filter.path));
|
||||
}
|
||||
if (filter.query) {
|
||||
result = result.filter(item => matchLibraryItem(item, filter.query!));
|
||||
result = result.filter(item => matchLibraryItem(item, filter.query));
|
||||
}
|
||||
|
||||
return { filtered: result };
|
||||
|
|
|
@ -116,7 +116,7 @@ export function EditorLibraryItem({ controller }: EditorLibraryItemProps) {
|
|||
{ownerSelector.isOpen ? (
|
||||
<SelectUser
|
||||
className='w-[25rem] sm:w-[26rem] text-sm'
|
||||
value={controller.schema.owner ?? undefined}
|
||||
value={controller.schema.owner}
|
||||
onChange={onSelectUser}
|
||||
/>
|
||||
) : null}
|
||||
|
|
|
@ -9,10 +9,10 @@ import { ILibraryItem } from '../backend/types';
|
|||
import { matchLibraryItem } from '../models/libraryAPI';
|
||||
|
||||
interface SelectLibraryItemProps extends CProps.Styling {
|
||||
items?: ILibraryItem[];
|
||||
value?: ILibraryItem;
|
||||
onChange: (newValue?: ILibraryItem) => void;
|
||||
value: ILibraryItem | null;
|
||||
onChange: (newValue: ILibraryItem | null) => void;
|
||||
|
||||
items?: ILibraryItem[];
|
||||
placeholder?: string;
|
||||
noBorder?: boolean;
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ export function SelectLibraryItem({
|
|||
className={clsx('text-ellipsis', className)}
|
||||
options={options}
|
||||
value={value ? { value: value.id, label: `${value.alias}: ${value.title}` } : null}
|
||||
onChange={data => onChange(items?.find(cst => cst.id === data?.value))}
|
||||
onChange={data => onChange(items?.find(cst => cst.id === data?.value) ?? null)}
|
||||
filterOption={filter}
|
||||
placeholder={placeholder}
|
||||
{...restProps}
|
||||
|
|
|
@ -10,10 +10,10 @@ import { IVersionInfo } from '../backend/types';
|
|||
|
||||
interface SelectVersionProps extends CProps.Styling {
|
||||
id?: string;
|
||||
items?: IVersionInfo[];
|
||||
value?: number;
|
||||
onChange: (newValue?: number) => void;
|
||||
value: number | undefined;
|
||||
onChange: (newValue: number | undefined) => void;
|
||||
|
||||
items?: IVersionInfo[];
|
||||
placeholder?: string;
|
||||
noBorder?: boolean;
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ function DlgCloneLibraryItem() {
|
|||
read_only: false,
|
||||
access_policy: AccessPolicy.PUBLIC,
|
||||
location: initialLocation,
|
||||
items: undefined
|
||||
items: []
|
||||
},
|
||||
mode: 'onChange',
|
||||
reValidateMode: 'onChange'
|
||||
|
@ -165,8 +165,8 @@ function DlgCloneLibraryItem() {
|
|||
<Checkbox
|
||||
id='dlg_only_selected'
|
||||
label={`Только выбранные конституенты [${selected.length} из ${totalCount}]`}
|
||||
value={field.value !== undefined}
|
||||
onChange={value => field.onChange(value ? selected : undefined)}
|
||||
value={field.value.length > 0}
|
||||
onChange={value => field.onChange(value ? selected : [])}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -32,7 +32,7 @@ function DlgCreateVersion() {
|
|||
defaultValues: {
|
||||
version: versions.length > 0 ? nextVersion(versions[versions.length - 1].version) : '1.0.0',
|
||||
description: '',
|
||||
items: undefined
|
||||
items: []
|
||||
}
|
||||
});
|
||||
const version = useWatch({ control, name: 'version' });
|
||||
|
@ -61,8 +61,8 @@ function DlgCreateVersion() {
|
|||
<Checkbox
|
||||
id='dlg_only_selected'
|
||||
label={`Только выбранные конституенты [${selected.length} из ${totalCount}]`}
|
||||
value={field.value !== undefined}
|
||||
onChange={value => field.onChange(value ? selected : undefined)}
|
||||
value={field.value.length > 0}
|
||||
onChange={value => field.onChange(value ? selected : [])}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
|
|
|
@ -61,8 +61,8 @@ function DlgEditEditors() {
|
|||
<div className='flex items-center gap-3'>
|
||||
<Label text='Добавить' />
|
||||
<SelectUser
|
||||
filter={id => !selected.includes(id)}
|
||||
value={undefined}
|
||||
filter={id => !selected.includes(id)} //
|
||||
value={null}
|
||||
onChange={onAddEditor}
|
||||
className='w-[25rem]'
|
||||
/>
|
||||
|
|
|
@ -9,12 +9,12 @@ export class FolderNode {
|
|||
rank: number = 0;
|
||||
text: string;
|
||||
children: Map<string, FolderNode>;
|
||||
parent: FolderNode | undefined;
|
||||
parent: FolderNode | null;
|
||||
|
||||
filesInside: number = 0;
|
||||
filesTotal: number = 0;
|
||||
|
||||
constructor(text: string, parent?: FolderNode) {
|
||||
constructor(text: string, parent: FolderNode | null = null) {
|
||||
this.text = text;
|
||||
this.parent = parent;
|
||||
this.children = new Map();
|
||||
|
@ -126,7 +126,7 @@ export class FolderTree {
|
|||
}
|
||||
|
||||
private addNode(text: string, parent?: FolderNode): FolderNode {
|
||||
if (parent === undefined) {
|
||||
if (!parent) {
|
||||
const newNode = new FolderNode(text);
|
||||
this.roots.set(text, newNode);
|
||||
return newNode;
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
* Module: Models for LibraryItem.
|
||||
*/
|
||||
|
||||
import { LibraryItemType } from '../backend/types';
|
||||
|
||||
/**
|
||||
* Represents valid location headers.
|
||||
*/
|
||||
|
@ -28,17 +26,16 @@ export interface ILibraryItemReference {
|
|||
* Represents Library filter parameters.
|
||||
*/
|
||||
export interface ILibraryFilter {
|
||||
type?: LibraryItemType;
|
||||
query?: string;
|
||||
query: string;
|
||||
|
||||
folderMode?: boolean;
|
||||
subfolders?: boolean;
|
||||
path?: string;
|
||||
head?: LocationHead;
|
||||
location?: string;
|
||||
folderMode: boolean;
|
||||
subfolders: boolean;
|
||||
path: string;
|
||||
head: LocationHead | null;
|
||||
location: string;
|
||||
|
||||
isVisible?: boolean;
|
||||
isOwned?: boolean;
|
||||
isEditor?: boolean;
|
||||
filterUser?: number;
|
||||
isVisible: boolean | null;
|
||||
isOwned: boolean | null;
|
||||
isEditor: boolean | null;
|
||||
filterUser: number | null;
|
||||
}
|
||||
|
|
|
@ -54,9 +54,9 @@ function ToolbarSearch({ total, filtered }: ToolbarSearchProps) {
|
|||
const resetFilter = useLibrarySearchStore(state => state.resetFilter);
|
||||
const hasCustomFilter = useHasCustomFilter();
|
||||
|
||||
const userActive = isOwned !== undefined || isEditor !== undefined || filterUser !== undefined;
|
||||
const userActive = isOwned !== null || isEditor !== null || filterUser !== null;
|
||||
|
||||
function handleChange(newValue: LocationHead | undefined) {
|
||||
function handleChange(newValue: LocationHead | null) {
|
||||
headMenu.hide();
|
||||
setHead(newValue);
|
||||
}
|
||||
|
@ -173,7 +173,7 @@ function ToolbarSearch({ total, filtered }: ToolbarSearchProps) {
|
|||
<span>проводник...</span>
|
||||
</div>
|
||||
</DropdownButton>
|
||||
<DropdownButton className='w-[10rem]' onClick={() => handleChange(undefined)}>
|
||||
<DropdownButton className='w-[10rem]' onClick={() => handleChange(null)}>
|
||||
<div className='inline-flex items-center gap-3'>
|
||||
<IconFolder size='1rem' className='clr-text-controls' />
|
||||
<span>отображать все</span>
|
||||
|
|
|
@ -21,20 +21,20 @@ interface LibrarySearchStore {
|
|||
location: string;
|
||||
setLocation: (value: string) => void;
|
||||
|
||||
head: LocationHead | undefined;
|
||||
setHead: (value: LocationHead | undefined) => void;
|
||||
head: LocationHead | null;
|
||||
setHead: (value: LocationHead | null) => void;
|
||||
|
||||
isVisible: boolean | undefined;
|
||||
isVisible: boolean | null;
|
||||
toggleVisible: () => void;
|
||||
|
||||
isOwned: boolean | undefined;
|
||||
isOwned: boolean | null;
|
||||
toggleOwned: () => void;
|
||||
|
||||
isEditor: boolean | undefined;
|
||||
isEditor: boolean | null;
|
||||
toggleEditor: () => void;
|
||||
|
||||
filterUser: number | undefined;
|
||||
setFilterUser: (value: number | undefined) => void;
|
||||
filterUser: number | null;
|
||||
setFilterUser: (value: number | null) => void;
|
||||
|
||||
resetFilter: () => void;
|
||||
}
|
||||
|
@ -57,19 +57,19 @@ export const useLibrarySearchStore = create<LibrarySearchStore>()(
|
|||
location: '',
|
||||
setLocation: value => set(!!value ? { location: value, folderMode: true } : { location: '' }),
|
||||
|
||||
head: undefined,
|
||||
head: null,
|
||||
setHead: value => set({ head: value }),
|
||||
|
||||
isVisible: true,
|
||||
toggleVisible: () => set(state => ({ isVisible: toggleTristateFlag(state.isVisible) })),
|
||||
|
||||
isOwned: undefined,
|
||||
isOwned: null,
|
||||
toggleOwned: () => set(state => ({ isOwned: toggleTristateFlag(state.isOwned) })),
|
||||
|
||||
isEditor: undefined,
|
||||
isEditor: null,
|
||||
toggleEditor: () => set(state => ({ isEditor: toggleTristateFlag(state.isEditor) })),
|
||||
|
||||
filterUser: undefined,
|
||||
filterUser: null,
|
||||
setFilterUser: value => set({ filterUser: value }),
|
||||
|
||||
resetFilter: () =>
|
||||
|
@ -77,11 +77,11 @@ export const useLibrarySearchStore = create<LibrarySearchStore>()(
|
|||
query: '',
|
||||
path: '',
|
||||
location: '',
|
||||
head: undefined,
|
||||
head: null,
|
||||
isVisible: true,
|
||||
isOwned: undefined,
|
||||
isEditor: undefined,
|
||||
filterUser: undefined
|
||||
isOwned: null,
|
||||
isEditor: null,
|
||||
filterUser: null
|
||||
}))
|
||||
}),
|
||||
{
|
||||
|
@ -116,11 +116,11 @@ export function useHasCustomFilter(): boolean {
|
|||
!!path ||
|
||||
!!query ||
|
||||
!!location ||
|
||||
head !== undefined ||
|
||||
isEditor !== undefined ||
|
||||
isOwned !== undefined ||
|
||||
head !== null ||
|
||||
isEditor !== null ||
|
||||
isOwned !== null ||
|
||||
isVisible !== true ||
|
||||
filterUser !== undefined
|
||||
filterUser !== null
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import { NoData } from '@/components/View';
|
|||
|
||||
import { IOperation } from '../models/oss';
|
||||
|
||||
import SelectOperation from './SelectOperation';
|
||||
import { SelectOperation } from './SelectOperation';
|
||||
|
||||
interface PickMultiOperationProps extends CProps.Styling {
|
||||
value: number[];
|
||||
|
@ -25,17 +25,17 @@ const columnHelper = createColumnHelper<IOperation>();
|
|||
export function PickMultiOperation({ rows, items, value, onChange, className, ...restProps }: PickMultiOperationProps) {
|
||||
const selectedItems = value.map(itemID => items.find(item => item.id === itemID)!);
|
||||
const nonSelectedItems = items.filter(item => !value.includes(item.id));
|
||||
const [lastSelected, setLastSelected] = useState<IOperation | undefined>(undefined);
|
||||
const [lastSelected, setLastSelected] = useState<IOperation | null>(null);
|
||||
|
||||
function handleDelete(operation: number) {
|
||||
onChange(value.filter(item => item !== operation));
|
||||
}
|
||||
|
||||
function handleSelect(operation?: IOperation) {
|
||||
function handleSelect(operation: IOperation | null) {
|
||||
if (operation) {
|
||||
setLastSelected(operation);
|
||||
onChange([...value, operation.id]);
|
||||
setTimeout(() => setLastSelected(undefined), 1000);
|
||||
setTimeout(() => setLastSelected(null), 1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,15 +9,15 @@ import { IOperation } from '../models/oss';
|
|||
import { matchOperation } from '../models/ossAPI';
|
||||
|
||||
interface SelectOperationProps extends CProps.Styling {
|
||||
items?: IOperation[];
|
||||
value?: IOperation;
|
||||
onChange: (newValue?: IOperation) => void;
|
||||
value: IOperation | null;
|
||||
onChange: (newValue: IOperation | null) => void;
|
||||
|
||||
items?: IOperation[];
|
||||
placeholder?: string;
|
||||
noBorder?: boolean;
|
||||
}
|
||||
|
||||
function SelectOperation({
|
||||
export function SelectOperation({
|
||||
className,
|
||||
items,
|
||||
value,
|
||||
|
@ -41,12 +41,10 @@ function SelectOperation({
|
|||
className={clsx('text-ellipsis', className)}
|
||||
options={options}
|
||||
value={value ? { value: value.id, label: `${value.alias}: ${value.title}` } : null}
|
||||
onChange={data => onChange(items?.find(cst => cst.id === data?.value))}
|
||||
onChange={data => onChange(items?.find(cst => cst.id === data?.value) ?? null)}
|
||||
filterOption={filter}
|
||||
placeholder={placeholder}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectOperation;
|
||||
|
|
|
@ -69,7 +69,7 @@ function DlgDeleteOperation() {
|
|||
<Checkbox
|
||||
label='Удалить схему'
|
||||
titleHtml={
|
||||
!target.is_owned || target.result === undefined
|
||||
!target.is_owned || target.result === null
|
||||
? 'Привязанную схему нельзя удалить'
|
||||
: 'Удалить схему вместе с операцией'
|
||||
}
|
||||
|
|
|
@ -54,7 +54,6 @@ function DlgEditOperation() {
|
|||
},
|
||||
mode: 'onChange'
|
||||
});
|
||||
|
||||
const [activeTab, setActiveTab] = useState(TabID.CARD);
|
||||
|
||||
function onSubmit(data: IOperationUpdateDTO) {
|
||||
|
|
|
@ -46,11 +46,11 @@ function DlgRelocateConstituents() {
|
|||
mode: 'onChange'
|
||||
});
|
||||
const destination = useWatch({ control, name: 'destination' });
|
||||
const destinationItem = destination ? libraryItems.find(item => item.id === destination) : undefined;
|
||||
const destinationItem = destination ? libraryItems.find(item => item.id === destination) ?? null : null;
|
||||
|
||||
const [directionUp, setDirectionUp] = useState(true);
|
||||
const [source, setSource] = useState<ILibraryItem | undefined>(
|
||||
libraryItems.find(item => item.id === initialTarget?.result)
|
||||
const [source, setSource] = useState<ILibraryItem | null>(
|
||||
libraryItems.find(item => item.id === initialTarget?.result) ?? null
|
||||
);
|
||||
|
||||
const operation = oss.items.find(item => item.result === source?.id);
|
||||
|
@ -80,13 +80,13 @@ function DlgRelocateConstituents() {
|
|||
setValue('destination', null);
|
||||
}
|
||||
|
||||
function handleSelectSource(newValue: ILibraryItem | undefined) {
|
||||
function handleSelectSource(newValue: ILibraryItem | null) {
|
||||
setSource(newValue);
|
||||
setValue('destination', null);
|
||||
setValue('items', []);
|
||||
}
|
||||
|
||||
function handleSelectDestination(newValue: ILibraryItem | undefined) {
|
||||
function handleSelectDestination(newValue: ILibraryItem | null) {
|
||||
if (newValue) {
|
||||
setValue('destination', newValue.id);
|
||||
} else {
|
||||
|
|
|
@ -19,7 +19,7 @@ interface BadgeConstituentaProps extends CProps.Styling {
|
|||
/**
|
||||
* Displays a badge with a constituenta alias and information tooltip.
|
||||
*/
|
||||
function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstituentaProps) {
|
||||
export function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstituentaProps) {
|
||||
const setActiveCst = useTooltipsStore(state => state.setActiveCst);
|
||||
|
||||
return (
|
||||
|
@ -46,5 +46,3 @@ function BadgeConstituenta({ value, prefixID, className, style }: BadgeConstitue
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default BadgeConstituenta;
|
||||
|
|
|
@ -14,12 +14,12 @@ import { IConstituenta } from '../models/rsform';
|
|||
import { matchConstituenta } from '../models/rsformAPI';
|
||||
import { CstMatchMode } from '../stores/cstSearch';
|
||||
|
||||
import BadgeConstituenta from './BadgeConstituenta';
|
||||
import { BadgeConstituenta } from './BadgeConstituenta';
|
||||
|
||||
interface PickConstituentaProps extends CProps.Styling {
|
||||
id?: string;
|
||||
items: IConstituenta[];
|
||||
value?: IConstituenta;
|
||||
value: IConstituenta | null;
|
||||
onChange: (newValue: IConstituenta) => void;
|
||||
|
||||
rows?: number;
|
||||
|
|
|
@ -14,7 +14,7 @@ import { IConstituenta, IRSForm } from '../models/rsform';
|
|||
import { isBasicConcept, matchConstituenta } from '../models/rsformAPI';
|
||||
import { CstMatchMode } from '../stores/cstSearch';
|
||||
|
||||
import BadgeConstituenta from './BadgeConstituenta';
|
||||
import { BadgeConstituenta } from './BadgeConstituenta';
|
||||
import ToolbarGraphSelection from './ToolbarGraphSelection';
|
||||
|
||||
interface PickMultiConstituentaProps extends CProps.Styling {
|
||||
|
@ -112,7 +112,10 @@ export function PickMultiConstituenta({
|
|||
/>
|
||||
<ToolbarGraphSelection
|
||||
graph={foldedGraph}
|
||||
isCore={cstID => isBasicConcept(schema.cstByID.get(cstID)?.cst_type)}
|
||||
isCore={cstID => {
|
||||
const cst = schema.cstByID.get(cstID);
|
||||
return !!cst && isBasicConcept(cst.cst_type);
|
||||
}}
|
||||
isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited}
|
||||
value={value}
|
||||
onChange={onChange}
|
||||
|
|
|
@ -17,8 +17,8 @@ import { errorMsg } from '@/utils/labels';
|
|||
import { ICstSubstitute } from '../backend/types';
|
||||
import { IConstituenta, IRSForm } from '../models/rsform';
|
||||
|
||||
import BadgeConstituenta from './BadgeConstituenta';
|
||||
import SelectConstituenta from './SelectConstituenta';
|
||||
import { BadgeConstituenta } from './BadgeConstituenta';
|
||||
import { SelectConstituenta } from './SelectConstituenta';
|
||||
|
||||
interface IMultiSubstitution {
|
||||
original_source: ILibraryItem;
|
||||
|
@ -54,15 +54,13 @@ export function PickSubstitutions({
|
|||
className,
|
||||
...restProps
|
||||
}: PickSubstitutionsProps) {
|
||||
const [leftArgument, setLeftArgument] = useState<ILibraryItem | undefined>(
|
||||
schemas.length === 1 ? schemas[0] : undefined
|
||||
);
|
||||
const [rightArgument, setRightArgument] = useState<ILibraryItem | undefined>(
|
||||
schemas.length === 1 && allowSelfSubstitution ? schemas[0] : undefined
|
||||
const [leftArgument, setLeftArgument] = useState<ILibraryItem | null>(schemas.length === 1 ? schemas[0] : null);
|
||||
const [rightArgument, setRightArgument] = useState<ILibraryItem | null>(
|
||||
schemas.length === 1 && allowSelfSubstitution ? schemas[0] : null
|
||||
);
|
||||
|
||||
const [leftCst, setLeftCst] = useState<IConstituenta | undefined>(undefined);
|
||||
const [rightCst, setRightCst] = useState<IConstituenta | undefined>(undefined);
|
||||
const [leftCst, setLeftCst] = useState<IConstituenta | null>(null);
|
||||
const [rightCst, setRightCst] = useState<IConstituenta | null>(null);
|
||||
|
||||
const [deleteRight, setDeleteRight] = useState(true);
|
||||
const toggleDelete = () => setDeleteRight(prev => !prev);
|
||||
|
@ -135,8 +133,8 @@ export function PickSubstitutions({
|
|||
}
|
||||
}
|
||||
onChange([...value, newSubstitution]);
|
||||
setLeftCst(undefined);
|
||||
setRightCst(undefined);
|
||||
setLeftCst(null);
|
||||
setRightCst(null);
|
||||
}
|
||||
|
||||
function handleDeclineSuggestion(item: IMultiSubstitution) {
|
||||
|
|
|
@ -23,7 +23,7 @@ export const tooltipProducer = (schema: IRSForm, canClick?: boolean) => {
|
|||
}
|
||||
|
||||
if ('entity' in parse.ref) {
|
||||
const cst = schema.cstByAlias.get(parse.ref.entity);
|
||||
const cst = schema.cstByAlias.get(parse.ref.entity) ?? null;
|
||||
return {
|
||||
pos: parse.start,
|
||||
end: parse.end,
|
||||
|
@ -31,7 +31,7 @@ export const tooltipProducer = (schema: IRSForm, canClick?: boolean) => {
|
|||
create: () => domTooltipEntityReference(parse.ref as IEntityReference, cst, canClick)
|
||||
};
|
||||
} else {
|
||||
let masterText: string | undefined = undefined;
|
||||
let masterText: string | null = null;
|
||||
if (parse.ref.offset > 0) {
|
||||
const entities = findContainedNodes(parse.end, view.state.doc.length, syntaxTree(view.state), [RefEntity]);
|
||||
if (parse.ref.offset <= entities.length) {
|
||||
|
@ -62,11 +62,7 @@ export function refsHoverTooltip(schema: IRSForm, canClick?: boolean): Extension
|
|||
/**
|
||||
* Create DOM tooltip for {@link IEntityReference}.
|
||||
*/
|
||||
function domTooltipEntityReference(
|
||||
ref: IEntityReference,
|
||||
cst: IConstituenta | undefined,
|
||||
canClick?: boolean
|
||||
): TooltipView {
|
||||
function domTooltipEntityReference(ref: IEntityReference, cst: IConstituenta | null, canClick?: boolean): TooltipView {
|
||||
const dom = document.createElement('div');
|
||||
dom.className = clsx(
|
||||
'max-h-[25rem] max-w-[25rem] min-w-[10rem]',
|
||||
|
@ -122,7 +118,7 @@ function domTooltipEntityReference(
|
|||
*/
|
||||
function domTooltipSyntacticReference(
|
||||
ref: ISyntacticReference,
|
||||
masterRef: string | undefined,
|
||||
masterRef: string | null,
|
||||
canClick?: boolean
|
||||
): TooltipView {
|
||||
const dom = document.createElement('div');
|
||||
|
|
|
@ -11,15 +11,15 @@ import { matchConstituenta } from '../models/rsformAPI';
|
|||
import { CstMatchMode } from '../stores/cstSearch';
|
||||
|
||||
interface SelectConstituentaProps extends CProps.Styling {
|
||||
value?: IConstituenta;
|
||||
onChange: (newValue?: IConstituenta) => void;
|
||||
value: IConstituenta | null;
|
||||
onChange: (newValue: IConstituenta | null) => void;
|
||||
|
||||
items?: IConstituenta[];
|
||||
placeholder?: string;
|
||||
noBorder?: boolean;
|
||||
}
|
||||
|
||||
function SelectConstituenta({
|
||||
export function SelectConstituenta({
|
||||
className,
|
||||
items,
|
||||
value,
|
||||
|
@ -43,12 +43,10 @@ function SelectConstituenta({
|
|||
className={clsx('text-ellipsis', className)}
|
||||
options={options}
|
||||
value={value ? { value: value.id, label: `${value.alias}: ${describeConstituentaTerm(value)}` } : null}
|
||||
onChange={data => onChange(items?.find(cst => cst.id === data?.value))}
|
||||
onChange={data => onChange(items?.find(cst => cst.id === data?.value) ?? null)}
|
||||
filterOption={filter}
|
||||
placeholder={placeholder}
|
||||
{...restProps}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectConstituenta;
|
||||
|
|
|
@ -29,10 +29,8 @@ function TabArguments() {
|
|||
const { args, onChangeArguments } = useTemplateContext();
|
||||
const definition = useWatch({ control, name: 'definition_formal' });
|
||||
|
||||
const [selectedCst, setSelectedCst] = useState<IConstituenta | undefined>(undefined);
|
||||
const [selectedArgument, setSelectedArgument] = useState<IArgumentValue | undefined>(
|
||||
args.length > 0 ? args[0] : undefined
|
||||
);
|
||||
const [selectedCst, setSelectedCst] = useState<IConstituenta | null>(null);
|
||||
const [selectedArgument, setSelectedArgument] = useState<IArgumentValue | null>(args.length > 0 ? args[0] : null);
|
||||
|
||||
const [argumentValue, setArgumentValue] = useState('');
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ function TabTemplate() {
|
|||
} = useTemplateContext();
|
||||
|
||||
const { templates } = useTemplatesSuspense();
|
||||
const { schema: templateSchema } = useRSForm({ itemID: templateID });
|
||||
const { schema: templateSchema } = useRSForm({ itemID: templateID ?? undefined });
|
||||
|
||||
if (!templateID) {
|
||||
onChangeTemplateID(templates[0].id);
|
||||
|
@ -63,7 +63,7 @@ function TabTemplate() {
|
|||
className='w-[12rem]'
|
||||
options={templateSelector}
|
||||
value={templateID ? { value: templateID, label: templates.find(item => item.id == templateID)!.title } : null}
|
||||
onChange={data => onChangeTemplateID(data ? data.value : undefined)}
|
||||
onChange={data => onChangeTemplateID(data ? data.value : null)}
|
||||
/>
|
||||
<SelectSingle
|
||||
noBorder
|
||||
|
@ -79,7 +79,7 @@ function TabTemplate() {
|
|||
}
|
||||
: null
|
||||
}
|
||||
onChange={data => onChangeFilterCategory(data ? templateSchema?.cstByID.get(data?.value) : undefined)}
|
||||
onChange={data => onChangeFilterCategory(data ? templateSchema?.cstByID.get(data?.value) ?? null : null)}
|
||||
isClearable
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -15,14 +15,14 @@ import { DlgCstTemplateProps } from './DlgCstTemplate';
|
|||
|
||||
export interface ITemplateContext {
|
||||
args: IArgumentValue[];
|
||||
prototype?: IConstituenta;
|
||||
templateID?: number;
|
||||
filterCategory?: IConstituenta;
|
||||
prototype: IConstituenta | null;
|
||||
templateID: number | null;
|
||||
filterCategory: IConstituenta | null;
|
||||
|
||||
onChangeArguments: (newArgs: IArgumentValue[]) => void;
|
||||
onChangePrototype: (newPrototype: IConstituenta) => void;
|
||||
onChangeTemplateID: (newTemplateID: number | undefined) => void;
|
||||
onChangeFilterCategory: (newFilterCategory: IConstituenta | undefined) => void;
|
||||
onChangeTemplateID: (newTemplateID: number | null) => void;
|
||||
onChangeFilterCategory: (newFilterCategory: IConstituenta | null) => void;
|
||||
}
|
||||
|
||||
const TemplateContext = createContext<ITemplateContext | null>(null);
|
||||
|
@ -37,10 +37,10 @@ export const useTemplateContext = () => {
|
|||
export const TemplateState = ({ children }: React.PropsWithChildren) => {
|
||||
const { schema } = useDialogsStore(state => state.props as DlgCstTemplateProps);
|
||||
const { setValue } = useFormContext<ICstCreateDTO>();
|
||||
const [templateID, setTemplateID] = useState<number | undefined>(undefined);
|
||||
const [templateID, setTemplateID] = useState<number | null>(null);
|
||||
const [args, setArguments] = useState<IArgumentValue[]>([]);
|
||||
const [prototype, setPrototype] = useState<IConstituenta | undefined>(undefined);
|
||||
const [filterCategory, setFilterCategory] = useState<IConstituenta | undefined>(undefined);
|
||||
const [prototype, setPrototype] = useState<IConstituenta | null>(null);
|
||||
const [filterCategory, setFilterCategory] = useState<IConstituenta | null>(null);
|
||||
|
||||
function onChangeArguments(newArgs: IArgumentValue[]) {
|
||||
setArguments(newArgs);
|
||||
|
@ -70,9 +70,9 @@ export const TemplateState = ({ children }: React.PropsWithChildren) => {
|
|||
setValue('definition_raw', newPrototype.definition_raw);
|
||||
}
|
||||
|
||||
function onChangeTemplateID(newTemplateID: number | undefined) {
|
||||
function onChangeTemplateID(newTemplateID: number | null) {
|
||||
setTemplateID(newTemplateID);
|
||||
setPrototype(undefined);
|
||||
setPrototype(null);
|
||||
setArguments([]);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ export function TabEntityReference() {
|
|||
const { setValue, control, register } = useFormContext<IEditReferenceState>();
|
||||
const alias = useWatch({ control, name: 'entity.entity' });
|
||||
|
||||
const selectedCst = schema.cstByAlias.get(alias);
|
||||
const selectedCst = schema.cstByAlias.get(alias) ?? null;
|
||||
const term = selectedCst?.term_resolved ?? '';
|
||||
|
||||
function handleSelectConstituenta(cst: IConstituenta) {
|
||||
|
|
|
@ -20,7 +20,7 @@ export interface DlgShowASTProps {
|
|||
|
||||
function DlgShowAST() {
|
||||
const { syntaxTree, expression } = useDialogsStore(state => state.props as DlgShowASTProps);
|
||||
const [hoverID, setHoverID] = useState<number | undefined>(undefined);
|
||||
const [hoverID, setHoverID] = useState<number | null>(null);
|
||||
const hoverNode = syntaxTree.find(node => node.uid === hoverID);
|
||||
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
|
@ -47,7 +47,7 @@ function DlgShowAST() {
|
|||
<ASTFlow
|
||||
data={syntaxTree}
|
||||
onNodeEnter={node => setHoverID(Number(node.id))}
|
||||
onNodeLeave={() => setHoverID(undefined)}
|
||||
onNodeLeave={() => setHoverID(null)}
|
||||
onChangeDragging={setIsDragging}
|
||||
/>
|
||||
</ReactFlowProvider>
|
||||
|
|
|
@ -11,8 +11,7 @@ export function applyLayout(nodes: Node<ISyntaxTreeNode>[], edges: Edge[]) {
|
|||
rankdir: 'TB',
|
||||
ranksep: 40,
|
||||
nodesep: 40,
|
||||
ranker: 'network-simplex',
|
||||
align: undefined
|
||||
ranker: 'network-simplex'
|
||||
});
|
||||
nodes.forEach(node => {
|
||||
dagreGraph.setNode(node.id, { width: 2 * PARAMETER.graphNodeRadius, height: 2 * PARAMETER.graphNodeRadius });
|
||||
|
|
|
@ -17,8 +17,7 @@ export function applyLayout(nodes: Node<TMGraphNode>[], edges: Edge[]) {
|
|||
rankdir: 'BT',
|
||||
ranksep: VERT_SEPARATION,
|
||||
nodesep: HOR_SEPARATION,
|
||||
ranker: 'network-simplex',
|
||||
align: undefined
|
||||
ranker: 'network-simplex'
|
||||
});
|
||||
nodes.forEach(node => {
|
||||
dagreGraph.setNode(node.id, { width: NODE_WIDTH, height: NODE_HEIGHT });
|
||||
|
|
|
@ -17,7 +17,7 @@ function DlgUploadRSForm() {
|
|||
const { itemID } = useDialogsStore(state => state.props as DlgUploadRSFormProps);
|
||||
const { upload } = useUploadTRS();
|
||||
const [loadMetadata, setLoadMetadata] = useState(false);
|
||||
const [file, setFile] = useState<File | undefined>();
|
||||
const [file, setFile] = useState<File | null>(null);
|
||||
|
||||
const handleSubmit = () => {
|
||||
if (file) {
|
||||
|
@ -34,7 +34,7 @@ function DlgUploadRSForm() {
|
|||
if (event.target.files && event.target.files.length > 0) {
|
||||
setFile(event.target.files[0]);
|
||||
} else {
|
||||
setFile(undefined);
|
||||
setFile(null);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ export function describeConstituenta(cst: IConstituenta): string {
|
|||
/**
|
||||
* Generates description for term of a given {@link IConstituenta}.
|
||||
*/
|
||||
export function describeConstituentaTerm(cst?: IConstituenta): string {
|
||||
export function describeConstituentaTerm(cst: IConstituenta | null): string {
|
||||
if (!cst) {
|
||||
return '!Конституента отсутствует!';
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ export function labelConstituenta(cst: IConstituenta) {
|
|||
/**
|
||||
* Generates label for {@link IVersionInfo} of {@link IRSForm}.
|
||||
*/
|
||||
export function labelVersion(schema?: IRSForm) {
|
||||
export function labelVersion(schema: IRSForm | undefined) {
|
||||
const version = schema?.versions.find(ver => ver.id === schema?.version);
|
||||
return version ? version.version : 'актуальная';
|
||||
}
|
||||
|
|
|
@ -122,9 +122,9 @@ export class TMGraph {
|
|||
this.nodeByAlias.set(alias, nodeToAnnotate);
|
||||
}
|
||||
|
||||
private processArguments(args: IArgumentInfo[]): TMGraphNode | undefined {
|
||||
private processArguments(args: IArgumentInfo[]): TMGraphNode | null {
|
||||
if (args.length === 0) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
const argsNodes = args.map(argument => this.parseToNode(argument.typification));
|
||||
if (args.length === 1) {
|
||||
|
@ -133,16 +133,16 @@ export class TMGraph {
|
|||
return this.addCartesianNode(argsNodes.map(node => node.id));
|
||||
}
|
||||
|
||||
private processResult(result: string): TMGraphNode | undefined {
|
||||
private processResult(result: string): TMGraphNode | null {
|
||||
if (!result || result === PARAMETER.logicLabel) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
return this.parseToNode(result);
|
||||
}
|
||||
|
||||
private combineResults(result: TMGraphNode | undefined, args: TMGraphNode | undefined): TMGraphNode | undefined {
|
||||
private combineResults(result: TMGraphNode | null, args: TMGraphNode | null): TMGraphNode | null {
|
||||
if (!result && !args) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
if (!result) {
|
||||
return this.addBooleanNode(args!.id);
|
||||
|
|
|
@ -164,7 +164,7 @@ export function guessCstType(hint: string, defaultType: CstType = CstType.TERM):
|
|||
/**
|
||||
* Evaluate if {@link CstType} is basic concept.
|
||||
*/
|
||||
export function isBasicConcept(type?: CstType): boolean {
|
||||
export function isBasicConcept(type: CstType): boolean {
|
||||
// prettier-ignore
|
||||
switch (type) {
|
||||
case CstType.BASE: return true;
|
||||
|
@ -175,7 +175,6 @@ export function isBasicConcept(type?: CstType): boolean {
|
|||
case CstType.FUNCTION: return false;
|
||||
case CstType.PREDICATE: return false;
|
||||
case CstType.THEOREM: return false;
|
||||
case undefined: return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@ import { useRSEdit } from '../RSEditContext';
|
|||
import { ViewConstituents } from '../ViewConstituents';
|
||||
|
||||
import EditorControls from './EditorControls';
|
||||
import FormConstituenta from './FormConstituenta';
|
||||
import { FormConstituenta } from './FormConstituenta';
|
||||
import ToolbarConstituenta from './ToolbarConstituenta';
|
||||
|
||||
// Threshold window width to switch layout.
|
||||
|
|
|
@ -23,7 +23,7 @@ import { RefsInput } from '../../../components/RefsInput';
|
|||
import { labelCstTypification, labelTypification } from '../../../labels';
|
||||
import { IConstituenta, IRSForm } from '../../../models/rsform';
|
||||
import { isBaseSet, isBasicConcept, isFunctional } from '../../../models/rsformAPI';
|
||||
import EditorRSExpression from '../EditorRSExpression';
|
||||
import { EditorRSExpression } from '../EditorRSExpression';
|
||||
|
||||
interface FormConstituentaProps {
|
||||
id?: string;
|
||||
|
@ -32,10 +32,10 @@ interface FormConstituentaProps {
|
|||
|
||||
activeCst: IConstituenta;
|
||||
schema: IRSForm;
|
||||
onOpenEdit?: (cstID: number) => void;
|
||||
onOpenEdit: (cstID: number) => void;
|
||||
}
|
||||
|
||||
function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpenEdit }: FormConstituentaProps) {
|
||||
export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpenEdit }: FormConstituentaProps) {
|
||||
const { cstUpdate } = useCstUpdate();
|
||||
const showTypification = useDialogsStore(state => state.showShowTypeGraph);
|
||||
const { isModified, setIsModified } = useModificationStore();
|
||||
|
@ -49,7 +49,7 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen
|
|||
formState: { isDirty }
|
||||
} = useForm<ICstUpdateDTO>({ resolver: zodResolver(schemaCstUpdate) });
|
||||
|
||||
const [localParse, setLocalParse] = useState<IExpressionParseDTO | undefined>(undefined);
|
||||
const [localParse, setLocalParse] = useState<IExpressionParseDTO | null>(null);
|
||||
|
||||
const typification = useMemo(
|
||||
() =>
|
||||
|
@ -88,7 +88,7 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen
|
|||
}
|
||||
});
|
||||
setForceComment(false);
|
||||
setLocalParse(undefined);
|
||||
setLocalParse(null);
|
||||
}, [activeCst, schema, toggleReset, reset]);
|
||||
|
||||
useLayoutEffect(() => {
|
||||
|
@ -252,5 +252,3 @@ function FormConstituenta({ disabled, id, toggleReset, schema, activeCst, onOpen
|
|||
</form>
|
||||
);
|
||||
}
|
||||
|
||||
export default FormConstituenta;
|
||||
|
|
|
@ -32,7 +32,7 @@ import { IConstituenta } from '../../../models/rsform';
|
|||
import { RSTabID, useRSEdit } from '../RSEditContext';
|
||||
|
||||
interface ToolbarConstituentaProps {
|
||||
activeCst?: IConstituenta;
|
||||
activeCst: IConstituenta | null;
|
||||
disabled: boolean;
|
||||
|
||||
onSubmit: () => void;
|
||||
|
@ -103,7 +103,9 @@ function ToolbarConstituenta({
|
|||
title='Создать конституенту после данной'
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
disabled={!controller.isContentEditable || isProcessing}
|
||||
onClick={() => controller.createCst(activeCst?.cst_type, false)}
|
||||
onClick={() =>
|
||||
activeCst ? controller.createCst(activeCst.cst_type, false) : controller.createCstDefault()
|
||||
}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={isModified ? tooltipText.unsaved : prepareTooltip('Клонировать конституенту', 'Alt + V')}
|
||||
|
|
|
@ -6,7 +6,6 @@ import { ReactCodeMirrorRef } from '@uiw/react-codemirror';
|
|||
|
||||
import { BadgeHelp, HelpTopic } from '@/features/help';
|
||||
|
||||
import { DataCallback } from '@/backend/apiTransport';
|
||||
import { Overlay } from '@/components/Container';
|
||||
import { CProps } from '@/components/props';
|
||||
import { useDialogsStore } from '@/stores/dialogs';
|
||||
|
@ -24,10 +23,10 @@ import { getDefinitionPrefix } from '../../../models/rsformAPI';
|
|||
import { transformAST } from '../../../models/rslangAPI';
|
||||
import { useRSEdit } from '../RSEditContext';
|
||||
|
||||
import ParsingResult from './ParsingResult';
|
||||
import RSEditorControls from './RSEditControls';
|
||||
import StatusBar from './StatusBar';
|
||||
import ToolbarRSExpression from './ToolbarRSExpression';
|
||||
import { ParsingResult } from './ParsingResult';
|
||||
import { RSEditorControls } from './RSEditControls';
|
||||
import { StatusBar } from './StatusBar';
|
||||
import { ToolbarRSExpression } from './ToolbarRSExpression';
|
||||
|
||||
interface EditorRSExpressionProps {
|
||||
id?: string;
|
||||
|
@ -41,12 +40,12 @@ interface EditorRSExpressionProps {
|
|||
disabled?: boolean;
|
||||
toggleReset?: boolean;
|
||||
|
||||
onChangeLocalParse: (typification: IExpressionParseDTO | undefined) => void;
|
||||
onOpenEdit?: (cstID: number) => void;
|
||||
onChangeLocalParse: (typification: IExpressionParseDTO) => void;
|
||||
onOpenEdit: (cstID: number) => void;
|
||||
onShowTypeGraph: (event: CProps.EventMouse) => void;
|
||||
}
|
||||
|
||||
function EditorRSExpression({
|
||||
export function EditorRSExpression({
|
||||
activeCst,
|
||||
disabled,
|
||||
value,
|
||||
|
@ -61,7 +60,7 @@ function EditorRSExpression({
|
|||
|
||||
const [isModified, setIsModified] = useState(false);
|
||||
const rsInput = useRef<ReactCodeMirrorRef>(null);
|
||||
const [parseData, setParseData] = useState<IExpressionParseDTO | undefined>(undefined);
|
||||
const [parseData, setParseData] = useState<IExpressionParseDTO | null>(null);
|
||||
|
||||
const isProcessing = useMutatingRSForm();
|
||||
const showControls = usePreferencesStore(state => state.showExpressionControls);
|
||||
|
@ -72,7 +71,7 @@ function EditorRSExpression({
|
|||
function checkConstituenta(
|
||||
expression: string,
|
||||
activeCst: IConstituenta,
|
||||
onSuccess?: DataCallback<IExpressionParseDTO>
|
||||
onSuccess?: (data: IExpressionParseDTO) => void
|
||||
) {
|
||||
const data: ICheckConstituentaDTO = {
|
||||
definition_formal: expression,
|
||||
|
@ -87,7 +86,7 @@ function EditorRSExpression({
|
|||
|
||||
useEffect(() => {
|
||||
setIsModified(false);
|
||||
setParseData(undefined);
|
||||
setParseData(null);
|
||||
}, [activeCst, toggleReset]);
|
||||
|
||||
function handleChange(newValue: string) {
|
||||
|
@ -200,5 +199,3 @@ function EditorRSExpression({
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default EditorRSExpression;
|
||||
|
|
|
@ -3,13 +3,13 @@ import { describeRSError } from '../../../labels';
|
|||
import { getRSErrorPrefix } from '../../../models/rslangAPI';
|
||||
|
||||
interface ParsingResultProps {
|
||||
data: IExpressionParseDTO | undefined;
|
||||
data: IExpressionParseDTO | null;
|
||||
disabled?: boolean;
|
||||
isOpen: boolean;
|
||||
onShowError: (error: IRSErrorDescription) => void;
|
||||
}
|
||||
|
||||
function ParsingResult({ isOpen, data, disabled, onShowError }: ParsingResultProps) {
|
||||
export function ParsingResult({ isOpen, data, disabled, onShowError }: ParsingResultProps) {
|
||||
const errorCount = data ? data.errors.reduce((total, error) => (error.isCritical ? total + 1 : total), 0) : 0;
|
||||
const warningsCount = data ? data.errors.length - errorCount : 0;
|
||||
|
||||
|
@ -46,5 +46,3 @@ function ParsingResult({ isOpen, data, disabled, onShowError }: ParsingResultPro
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default ParsingResult;
|
||||
|
|
|
@ -87,7 +87,7 @@ interface RSEditorControlsProps {
|
|||
onEdit: (id: TokenID, key?: string) => void;
|
||||
}
|
||||
|
||||
function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsProps) {
|
||||
export function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsProps) {
|
||||
return (
|
||||
<div
|
||||
className={clsx(
|
||||
|
@ -149,5 +149,3 @@ function RSEditorControls({ isOpen, disabled, onEdit }: RSEditorControlsProps) {
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default RSEditorControls;
|
||||
|
|
|
@ -15,14 +15,14 @@ import { ExpressionStatus, IConstituenta } from '../../../models/rsform';
|
|||
import { inferStatus } from '../../../models/rsformAPI';
|
||||
|
||||
interface StatusBarProps {
|
||||
processing?: boolean;
|
||||
isModified?: boolean;
|
||||
parseData?: IExpressionParseDTO;
|
||||
processing: boolean;
|
||||
isModified: boolean;
|
||||
parseData: IExpressionParseDTO | null;
|
||||
activeCst: IConstituenta;
|
||||
onAnalyze: () => void;
|
||||
}
|
||||
|
||||
function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }: StatusBarProps) {
|
||||
export function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }: StatusBarProps) {
|
||||
const status = (() => {
|
||||
if (isModified) {
|
||||
return ExpressionStatus.UNKNOWN;
|
||||
|
@ -66,5 +66,3 @@ function StatusBar({ isModified, processing, activeCst, parseData, onAnalyze }:
|
|||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default StatusBar;
|
||||
|
|
|
@ -12,7 +12,7 @@ interface ToolbarRSExpressionProps {
|
|||
showTypeGraph: (event: CProps.EventMouse) => void;
|
||||
}
|
||||
|
||||
function ToolbarRSExpression({ disabled, showTypeGraph, showAST }: ToolbarRSExpressionProps) {
|
||||
export function ToolbarRSExpression({ disabled, showTypeGraph, showAST }: ToolbarRSExpressionProps) {
|
||||
const isProcessing = useMutatingRSForm();
|
||||
const showControls = usePreferencesStore(state => state.showExpressionControls);
|
||||
const toggleControls = usePreferencesStore(state => state.toggleShowExpressionControls);
|
||||
|
@ -39,5 +39,3 @@ function ToolbarRSExpression({ disabled, showTypeGraph, showAST }: ToolbarRSExpr
|
|||
</Overlay>
|
||||
);
|
||||
}
|
||||
|
||||
export default ToolbarRSExpression;
|
||||
|
|
|
@ -1 +1 @@
|
|||
export { default } from './EditorRSExpression';
|
||||
export { EditorRSExpression } from './EditorRSExpression';
|
||||
|
|
|
@ -30,7 +30,7 @@ function ToolbarVersioning({ blockReload }: ToolbarVersioningProps) {
|
|||
if (!controller.schema.version || !window.confirm(promptText.restoreArchive)) {
|
||||
return;
|
||||
}
|
||||
void versionRestore({ versionID: controller.schema.version }).then(() => controller.navigateVersion(undefined));
|
||||
void versionRestore({ versionID: controller.schema.version }).then(() => controller.navigateVersion());
|
||||
}
|
||||
|
||||
function handleCreateVersion() {
|
||||
|
@ -50,7 +50,7 @@ function ToolbarVersioning({ blockReload }: ToolbarVersioningProps) {
|
|||
showEditVersions({
|
||||
itemID: controller.schema.id,
|
||||
afterDelete: targetVersion => {
|
||||
if (targetVersion === controller.activeVersion) controller.navigateVersion(undefined);
|
||||
if (targetVersion === controller.activeVersion) controller.navigateVersion();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ function EditorRSList() {
|
|||
}
|
||||
// prettier-ignore
|
||||
switch (code) {
|
||||
case 'Backquote': controller.createCst(undefined, false); return true;
|
||||
case 'Backquote': controller.createCstDefault(); return true;
|
||||
|
||||
case 'Digit1': controller.createCst(CstType.BASE, true); return true;
|
||||
case 'Digit2': controller.createCst(CstType.STRUCTURED, true); return true;
|
||||
|
@ -150,7 +150,7 @@ function EditorRSList() {
|
|||
selected={rowSelection}
|
||||
setSelected={handleRowSelection}
|
||||
onEdit={controller.navigateCst}
|
||||
onCreateNew={() => controller.createCst(undefined, false)}
|
||||
onCreateNew={controller.createCstDefault}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
@ -11,7 +11,7 @@ import useWindowSize from '@/hooks/useWindowSize';
|
|||
import { PARAMETER, prefixes } from '@/utils/constants';
|
||||
import { truncateToSymbol } from '@/utils/utils';
|
||||
|
||||
import BadgeConstituenta from '../../../components/BadgeConstituenta';
|
||||
import { BadgeConstituenta } from '../../../components/BadgeConstituenta';
|
||||
import { labelCstTypification } from '../../../labels';
|
||||
import { IConstituenta } from '../../../models/rsform';
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ export function ToolbarRSList() {
|
|||
titleHtml={prepareTooltip('Добавить новую конституенту...', 'Alt + `')}
|
||||
icon={<IconNewItem size='1.25rem' className='icon-green' />}
|
||||
disabled={isProcessing}
|
||||
onClick={() => controller.createCst(undefined, false)}
|
||||
onClick={controller.createCstDefault}
|
||||
/>
|
||||
<MiniButton
|
||||
titleHtml={prepareTooltip('Клонировать конституенту', 'Alt + V')}
|
||||
|
|
|
@ -68,12 +68,12 @@ function TGFlow() {
|
|||
const [nodes, setNodes, onNodesChange] = useNodesState([]);
|
||||
const [edges, setEdges] = useEdgesState([]);
|
||||
|
||||
const [focusCst, setFocusCst] = useState<IConstituenta | undefined>(undefined);
|
||||
const [focusCst, setFocusCst] = useState<IConstituenta | null>(null);
|
||||
const filteredGraph = produceFilteredGraph(controller.schema, filter, focusCst);
|
||||
const [hidden, setHidden] = useState<number[]>([]);
|
||||
|
||||
const [isDragging, setIsDragging] = useState(false);
|
||||
const [hoverID, setHoverID] = useState<number | undefined>(undefined);
|
||||
const [hoverID, setHoverID] = useState<number | null>(null);
|
||||
const hoverCst = hoverID && controller.schema.cstByID.get(hoverID);
|
||||
const [hoverCstDebounced] = useDebounce(hoverCst, PARAMETER.graphPopupDelay);
|
||||
const [hoverLeft, setHoverLeft] = useState(true);
|
||||
|
@ -102,7 +102,7 @@ function TGFlow() {
|
|||
}
|
||||
});
|
||||
setHidden(newDismissed);
|
||||
setHoverID(undefined);
|
||||
setHoverID(null);
|
||||
}, [controller.schema, filteredGraph]);
|
||||
|
||||
const resetNodes = useCallback(() => {
|
||||
|
@ -227,7 +227,7 @@ function TGFlow() {
|
|||
if (event.key === 'Escape') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
setFocusCst(undefined);
|
||||
setFocusCst(null);
|
||||
handleSetSelected([]);
|
||||
return;
|
||||
}
|
||||
|
@ -252,11 +252,15 @@ function TGFlow() {
|
|||
}, PARAMETER.graphRefreshDelay);
|
||||
}
|
||||
|
||||
function handleSetFocus(cstID: number | undefined) {
|
||||
const target = cstID !== undefined ? controller.schema.cstByID.get(cstID) : cstID;
|
||||
setFocusCst(prev => (prev === target ? undefined : target));
|
||||
if (target) {
|
||||
controller.setSelected([]);
|
||||
function handleSetFocus(cstID: number | null) {
|
||||
if (cstID === null) {
|
||||
setFocusCst(null);
|
||||
} else {
|
||||
const target = controller.schema.cstByID.get(cstID) ?? null;
|
||||
setFocusCst(prev => (prev === target ? null : target));
|
||||
if (target) {
|
||||
controller.setSelected([]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -304,7 +308,10 @@ function TGFlow() {
|
|||
{!focusCst ? (
|
||||
<ToolbarGraphSelection
|
||||
graph={controller.schema.graph}
|
||||
isCore={cstID => isBasicConcept(controller.schema.cstByID.get(cstID)?.cst_type)}
|
||||
isCore={cstID => {
|
||||
const cst = controller.schema.cstByID.get(cstID);
|
||||
return !!cst && isBasicConcept(cst.cst_type);
|
||||
}}
|
||||
isOwned={
|
||||
controller.schema.inheritance.length > 0
|
||||
? cstID => !controller.schema.cstByID.get(cstID)?.is_inherited
|
||||
|
@ -318,7 +325,7 @@ function TGFlow() {
|
|||
{focusCst ? (
|
||||
<ToolbarFocusedCst
|
||||
center={focusCst}
|
||||
reset={() => handleSetFocus(undefined)}
|
||||
reset={() => handleSetFocus(null)}
|
||||
showInputs={filter.focusShowInputs}
|
||||
showOutputs={filter.focusShowOutputs}
|
||||
toggleShowInputs={() =>
|
||||
|
@ -395,7 +402,7 @@ function TGFlow() {
|
|||
onNodeDragStart={() => setIsDragging(true)}
|
||||
onNodeDragStop={() => setIsDragging(false)}
|
||||
onNodeMouseEnter={(event, node) => handleNodeEnter(event, Number(node.id))}
|
||||
onNodeMouseLeave={() => setHoverID(undefined)}
|
||||
onNodeMouseLeave={() => setHoverID(null)}
|
||||
onNodeClick={(event, node) => handleNodeClick(event, Number(node.id))}
|
||||
onNodeDoubleClick={(event, node) => handleNodeDoubleClick(event, Number(node.id))}
|
||||
/>
|
||||
|
@ -408,7 +415,7 @@ function TGFlow() {
|
|||
export default TGFlow;
|
||||
|
||||
// ====== Internals =========
|
||||
function produceFilteredGraph(schema: IRSForm, params: GraphFilterParams, focusCst: IConstituenta | undefined) {
|
||||
function produceFilteredGraph(schema: IRSForm, params: GraphFilterParams, focusCst: IConstituenta | null) {
|
||||
const filtered = schema.graph.clone();
|
||||
const allowedTypes: CstType[] = (() => {
|
||||
const result: CstType[] = [];
|
||||
|
|
|
@ -11,8 +11,7 @@ export function applyLayout(nodes: Node<TGNodeData>[], edges: Edge[], subLabels?
|
|||
rankdir: 'TB',
|
||||
ranksep: subLabels ? 60 : 40,
|
||||
nodesep: subLabels ? 100 : 20,
|
||||
ranker: 'network-simplex',
|
||||
align: undefined
|
||||
ranker: 'network-simplex'
|
||||
});
|
||||
nodes.forEach(node => {
|
||||
dagreGraph.setNode(node.id, { width: 2 * PARAMETER.graphNodeRadius, height: 2 * PARAMETER.graphNodeRadius });
|
||||
|
|
|
@ -31,7 +31,7 @@ export enum RSTabID {
|
|||
export interface IRSEditContext extends ILibraryItemEditor {
|
||||
schema: IRSForm;
|
||||
selected: number[];
|
||||
activeCst?: IConstituenta;
|
||||
activeCst: IConstituenta | null;
|
||||
activeVersion?: number;
|
||||
|
||||
isOwned: boolean;
|
||||
|
@ -41,7 +41,7 @@ export interface IRSEditContext extends ILibraryItemEditor {
|
|||
isAttachedToOSS: boolean;
|
||||
canDeleteSelected: boolean;
|
||||
|
||||
navigateVersion: (versionID: number | undefined) => void;
|
||||
navigateVersion: (versionID?: number) => void;
|
||||
navigateRSForm: ({ tab, activeID }: { tab: RSTabID; activeID?: number }) => void;
|
||||
navigateCst: (cstID: number) => void;
|
||||
navigateOss: (ossID: number, newTab?: boolean) => void;
|
||||
|
@ -56,7 +56,8 @@ export interface IRSEditContext extends ILibraryItemEditor {
|
|||
|
||||
moveUp: () => void;
|
||||
moveDown: () => void;
|
||||
createCst: (type: CstType | undefined, skipDialog: boolean, definition?: string) => void;
|
||||
createCst: (type: CstType, skipDialog: boolean, definition?: string) => void;
|
||||
createCstDefault: () => void;
|
||||
cloneCst: () => void;
|
||||
promptDeleteCst: () => void;
|
||||
promptTemplate: () => void;
|
||||
|
@ -103,7 +104,7 @@ export const RSEditState = ({
|
|||
const [selected, setSelected] = useState<number[]>([]);
|
||||
const canDeleteSelected = selected.length > 0 && selected.every(id => !schema.cstByID.get(id)?.is_inherited);
|
||||
|
||||
const activeCst = selected.length === 0 ? undefined : schema.cstByID.get(selected[selected.length - 1]);
|
||||
const activeCst = selected.length === 0 ? null : schema.cstByID.get(selected[selected.length - 1])!;
|
||||
|
||||
const { cstCreate } = useCstCreate();
|
||||
const { cstMove } = useCstMove();
|
||||
|
@ -124,7 +125,7 @@ export const RSEditState = ({
|
|||
[schema, adjustRole, isOwned, user, adminMode]
|
||||
);
|
||||
|
||||
function navigateVersion(versionID: number | undefined) {
|
||||
function navigateVersion(versionID?: number) {
|
||||
router.push(urls.schema(schema.id, versionID));
|
||||
}
|
||||
|
||||
|
@ -164,7 +165,7 @@ export const RSEditState = ({
|
|||
if (!window.confirm(promptText.deleteLibraryItem)) {
|
||||
return;
|
||||
}
|
||||
const ossID = schema.oss.length > 0 ? schema.oss[0].id : undefined;
|
||||
const ossID = schema.oss.length > 0 ? schema.oss[0].id : null;
|
||||
void deleteItem(schema.id).then(() => {
|
||||
if (ossID) {
|
||||
router.push(urls.oss(ossID));
|
||||
|
@ -242,7 +243,7 @@ export const RSEditState = ({
|
|||
});
|
||||
}
|
||||
|
||||
function createCst(type: CstType | undefined, skipDialog: boolean, definition?: string) {
|
||||
function createCst(type: CstType | null, skipDialog: boolean, definition?: string) {
|
||||
const targetType = type ?? activeCst?.cst_type ?? CstType.BASE;
|
||||
const data: ICstCreateDTO = {
|
||||
insert_after: activeCst?.id ?? null,
|
||||
|
@ -286,7 +287,7 @@ export const RSEditState = ({
|
|||
selected: selected,
|
||||
afterDelete: (schema, deleted) => {
|
||||
const isEmpty = deleted.length === schema.items.length;
|
||||
const nextActive = isEmpty ? undefined : getNextActiveOnDelete(activeCst?.id, schema.items, deleted);
|
||||
const nextActive = isEmpty ? null : getNextActiveOnDelete(activeCst?.id ?? null, schema.items, deleted);
|
||||
setSelected(nextActive ? [nextActive] : []);
|
||||
if (!nextActive) {
|
||||
navigateRSForm({ tab: RSTabID.CST_LIST });
|
||||
|
@ -338,6 +339,7 @@ export const RSEditState = ({
|
|||
moveUp,
|
||||
moveDown,
|
||||
createCst,
|
||||
createCstDefault: () => createCst(null, false),
|
||||
cloneCst,
|
||||
promptDeleteCst,
|
||||
|
||||
|
@ -350,18 +352,14 @@ export const RSEditState = ({
|
|||
};
|
||||
|
||||
// ====== Internals =========
|
||||
function getNextActiveOnDelete(
|
||||
activeID: number | undefined,
|
||||
items: IConstituenta[],
|
||||
deleted: number[]
|
||||
): number | undefined {
|
||||
function getNextActiveOnDelete(activeID: number | null, items: IConstituenta[], deleted: number[]): number | null {
|
||||
if (items.length === deleted.length) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
let activeIndex = items.findIndex(cst => cst.id === activeID);
|
||||
if (activeIndex === -1) {
|
||||
return undefined;
|
||||
return null;
|
||||
}
|
||||
|
||||
while (activeIndex < items.length && deleted.find(id => id === items[activeIndex].id)) {
|
||||
|
|
|
@ -71,7 +71,7 @@ function applyGraphQuery(target: IRSForm, pivot: number, mode: DependencyMode):
|
|||
if (mode === DependencyMode.ALL) {
|
||||
return target.items;
|
||||
}
|
||||
const ids: number[] | undefined = (() => {
|
||||
const ids = (() => {
|
||||
switch (mode) {
|
||||
case DependencyMode.OUTPUTS: {
|
||||
return target.graph.nodes.get(pivot)?.outputs;
|
||||
|
@ -86,7 +86,6 @@ function applyGraphQuery(target: IRSForm, pivot: number, mode: DependencyMode):
|
|||
return target.graph.expandAllInputs([pivot]);
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
})();
|
||||
if (ids) {
|
||||
return target.items.filter(cst => ids.find(id => id === cst.id));
|
||||
|
|
|
@ -34,7 +34,7 @@ function SelectGraphFilter({ value, dense, onChange, ...restProps }: SelectGraph
|
|||
hideTitle={menu.isOpen}
|
||||
className='h-full pr-2'
|
||||
icon={<DependencyIcon value={value} size='1rem' />}
|
||||
text={dense || size.isSmall ? undefined : labelCstSource(value)}
|
||||
text={!dense && !size.isSmall ? labelCstSource(value) : undefined}
|
||||
onClick={menu.toggle}
|
||||
/>
|
||||
<Dropdown stretchLeft isOpen={menu.isOpen}>
|
||||
|
|
|
@ -7,7 +7,7 @@ import { NoData, TextContent } from '@/components/View';
|
|||
import { APP_COLORS } from '@/styling/colors';
|
||||
import { PARAMETER, prefixes } from '@/utils/constants';
|
||||
|
||||
import BadgeConstituenta from '../../../components/BadgeConstituenta';
|
||||
import { BadgeConstituenta } from '../../../components/BadgeConstituenta';
|
||||
import { describeConstituenta } from '../../../labels';
|
||||
import { IConstituenta } from '../../../models/rsform';
|
||||
|
||||
|
@ -15,7 +15,7 @@ const DESCRIPTION_MAX_SYMBOLS = 280;
|
|||
|
||||
interface TableSideConstituentsProps {
|
||||
items: IConstituenta[];
|
||||
activeCst?: IConstituenta;
|
||||
activeCst: IConstituenta | null;
|
||||
onOpenEdit: (cstID: number) => void;
|
||||
autoScroll?: boolean;
|
||||
maxHeight: string;
|
||||
|
@ -54,7 +54,6 @@ function TableSideConstituents({
|
|||
header: () => <span className='pl-3'>Имя</span>,
|
||||
size: 65,
|
||||
minSize: 65,
|
||||
footer: undefined,
|
||||
cell: props => (
|
||||
<BadgeConstituenta className='mr-[-0.5rem]' value={props.row.original} prefixID={prefixes.cst_side_table} />
|
||||
)
|
||||
|
@ -81,19 +80,19 @@ function TableSideConstituents({
|
|||
|
||||
const conditionalRowStyles: IConditionalStyle<IConstituenta>[] = [
|
||||
{
|
||||
when: (cst: IConstituenta) => !!activeCst && cst.id === activeCst?.id,
|
||||
when: (cst: IConstituenta) => !!activeCst && cst.id === activeCst.id,
|
||||
style: {
|
||||
backgroundColor: APP_COLORS.bgSelected
|
||||
}
|
||||
},
|
||||
{
|
||||
when: (cst: IConstituenta) => !!activeCst && cst.spawner === activeCst?.id && cst.id !== activeCst?.id,
|
||||
when: (cst: IConstituenta) => !!activeCst && cst.spawner === activeCst.id && cst.id !== activeCst.id,
|
||||
style: {
|
||||
backgroundColor: APP_COLORS.bgOrange50
|
||||
}
|
||||
},
|
||||
{
|
||||
when: (cst: IConstituenta) => activeCst?.id !== undefined && cst.spawn.includes(activeCst.id),
|
||||
when: (cst: IConstituenta) => !!activeCst && cst.spawn.includes(activeCst.id),
|
||||
style: {
|
||||
backgroundColor: APP_COLORS.bgGreen50
|
||||
}
|
||||
|
|
|
@ -49,7 +49,7 @@ export function ViewConstituents({ isBottom, isMounted }: ViewConstituentsProps)
|
|||
}}
|
||||
>
|
||||
<ConstituentsSearch
|
||||
dense={windowSize.width && windowSize.width < COLUMN_DENSE_SEARCH_THRESHOLD ? true : undefined}
|
||||
dense={!!windowSize.width && windowSize.width < COLUMN_DENSE_SEARCH_THRESHOLD}
|
||||
schema={schema}
|
||||
activeID={activeCst?.id}
|
||||
onChange={setFilteredData}
|
||||
|
|
|
@ -10,7 +10,7 @@ import { useUsers } from '../backend/useUsers';
|
|||
import { matchUser } from '../models/userAPI';
|
||||
|
||||
interface SelectUserProps extends CProps.Styling {
|
||||
value?: number;
|
||||
value: number | null;
|
||||
onChange: (newValue: number) => void;
|
||||
filter?: (userID: number) => boolean;
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ export interface GenericDialogProps {
|
|||
}
|
||||
|
||||
interface DialogsStore {
|
||||
active: DialogType | undefined;
|
||||
active: DialogType | null;
|
||||
props: unknown;
|
||||
hideDialog: () => void;
|
||||
|
||||
|
@ -87,12 +87,12 @@ interface DialogsStore {
|
|||
}
|
||||
|
||||
export const useDialogsStore = create<DialogsStore>()(set => ({
|
||||
active: undefined,
|
||||
props: undefined,
|
||||
active: null,
|
||||
props: null,
|
||||
hideDialog: () => {
|
||||
set(state => {
|
||||
(state.props as GenericDialogProps | undefined)?.onHide?.();
|
||||
return { active: undefined, props: undefined };
|
||||
(state.props as GenericDialogProps | null)?.onHide?.();
|
||||
return { active: null, props: null };
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -113,7 +113,7 @@ export const useDialogsStore = create<DialogsStore>()(set => ({
|
|||
showCloneLibraryItem: props => set({ active: DialogType.CLONE_LIBRARY_ITEM, props: props }),
|
||||
showCreateVersion: props => set({ active: DialogType.CREATE_VERSION, props: props }),
|
||||
showDeleteOperation: props => set({ active: DialogType.DELETE_OPERATION, props: props }),
|
||||
showGraphParams: () => set({ active: DialogType.GRAPH_PARAMETERS, props: undefined }),
|
||||
showGraphParams: () => set({ active: DialogType.GRAPH_PARAMETERS, props: null }),
|
||||
showRelocateConstituents: props => set({ active: DialogType.RELOCATE_CONSTITUENTS, props: props }),
|
||||
showRenameCst: props => set({ active: DialogType.RENAME_CONSTITUENTA, props: props }),
|
||||
showQR: props => set({ active: DialogType.SHOW_QR_CODE, props: props }),
|
||||
|
|
|
@ -3,11 +3,11 @@ import { create } from 'zustand';
|
|||
import { IConstituenta } from '@/features/rsform/models/rsform';
|
||||
|
||||
interface TooltipsStore {
|
||||
activeCst: IConstituenta | undefined;
|
||||
setActiveCst: (value: IConstituenta | undefined) => void;
|
||||
activeCst: IConstituenta | null;
|
||||
setActiveCst: (value: IConstituenta | null) => void;
|
||||
}
|
||||
|
||||
export const useTooltipsStore = create<TooltipsStore>()(set => ({
|
||||
activeCst: undefined,
|
||||
activeCst: null,
|
||||
setActiveCst: value => set({ activeCst: value })
|
||||
}));
|
||||
|
|
|
@ -110,20 +110,20 @@ export function promptUnsaved(): boolean {
|
|||
}
|
||||
|
||||
/**
|
||||
* Toggle tristate flag: undefined - true - false.
|
||||
* Toggle tristate flag: null - true - false.
|
||||
*/
|
||||
export function toggleTristateFlag(prev: boolean | undefined): boolean | undefined {
|
||||
if (prev === undefined) {
|
||||
export function toggleTristateFlag(prev: boolean | null): boolean | null {
|
||||
if (prev === null) {
|
||||
return true;
|
||||
}
|
||||
return prev ? false : undefined;
|
||||
return prev ? false : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle tristate color: gray - green - red .
|
||||
*/
|
||||
export function tripleToggleColor(value: boolean | undefined): string {
|
||||
if (value === undefined) {
|
||||
export function tripleToggleColor(value: boolean | null): string {
|
||||
if (value === null) {
|
||||
return 'clr-text-controls';
|
||||
}
|
||||
return value ? 'text-ok-600' : 'text-warn-600';
|
||||
|
|
Loading…
Reference in New Issue
Block a user