F: Wire crucial attribute for frontend
This commit is contained in:
parent
f78bda5057
commit
e3b20551d5
|
@ -84,15 +84,18 @@ class TestVersionViews(EndpointTester):
|
||||||
alias='A1',
|
alias='A1',
|
||||||
cst_type='axiom',
|
cst_type='axiom',
|
||||||
definition_formal='X1=X1',
|
definition_formal='X1=X1',
|
||||||
order=1
|
order=1,
|
||||||
|
crucial=True
|
||||||
)
|
)
|
||||||
version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
|
version_id = self._create_version({'version': '1.0.0', 'description': 'test'})
|
||||||
a1.definition_formal = 'X1=X2'
|
a1.definition_formal = 'X1=X2'
|
||||||
|
a1.crucial = False
|
||||||
a1.save()
|
a1.save()
|
||||||
|
|
||||||
response = self.executeOK(schema=self.owned_id, version=version_id)
|
response = self.executeOK(schema=self.owned_id, version=version_id)
|
||||||
loaded_a1 = response.data['items'][1]
|
loaded_a1 = response.data['items'][1]
|
||||||
self.assertEqual(loaded_a1['definition_formal'], 'X1=X1')
|
self.assertEqual(loaded_a1['definition_formal'], 'X1=X1')
|
||||||
|
self.assertEqual(loaded_a1['crucial'], True)
|
||||||
self.assertEqual(loaded_a1['parse']['status'], 'verified')
|
self.assertEqual(loaded_a1['parse']['status'], 'verified')
|
||||||
|
|
||||||
|
|
||||||
|
|
37
rsconcept/frontend/src/components/control/text-button.tsx
Normal file
37
rsconcept/frontend/src/components/control/text-button.tsx
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
import { globalIDs } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { type Button as ButtonStyle } from '../props';
|
||||||
|
import { cn } from '../utils';
|
||||||
|
|
||||||
|
interface TextButtonProps extends ButtonStyle {
|
||||||
|
/** Text to display second. */
|
||||||
|
text: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customizable `button` with text, transparent background and no additional styling.
|
||||||
|
*/
|
||||||
|
export function TextButton({ text, title, titleHtml, hideTitle, className, ...restProps }: TextButtonProps) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
tabIndex={-1}
|
||||||
|
type='button'
|
||||||
|
className={cn(
|
||||||
|
'self-start cc-label cc-hover-underline',
|
||||||
|
'font-medium text-primary select-none disabled:text-foreground',
|
||||||
|
'cursor-pointer disabled:cursor-default',
|
||||||
|
'outline-hidden',
|
||||||
|
'select-text',
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
data-tooltip-id={!!title || !!titleHtml ? globalIDs.tooltip : undefined}
|
||||||
|
data-tooltip-html={titleHtml}
|
||||||
|
data-tooltip-content={title}
|
||||||
|
data-tooltip-hidden={hideTitle}
|
||||||
|
aria-label={!text ? title : undefined}
|
||||||
|
{...restProps}
|
||||||
|
>
|
||||||
|
{text}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
|
@ -30,7 +30,7 @@ export function TextURL({ text, href, title, color = 'text-primary', onClick }:
|
||||||
);
|
);
|
||||||
} else if (onClick) {
|
} else if (onClick) {
|
||||||
return (
|
return (
|
||||||
<button type='button' tabIndex={-1} className={design} onClick={onClick}>
|
<button type='button' tabIndex={-1} className={design} title={title} onClick={onClick}>
|
||||||
{text}
|
{text}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|
|
@ -2,7 +2,6 @@ import {
|
||||||
IconChild,
|
IconChild,
|
||||||
IconClone,
|
IconClone,
|
||||||
IconDestroy,
|
IconDestroy,
|
||||||
IconEdit,
|
|
||||||
IconFilter,
|
IconFilter,
|
||||||
IconGraphSelection,
|
IconGraphSelection,
|
||||||
IconKeyboard,
|
IconKeyboard,
|
||||||
|
@ -114,8 +113,7 @@ export function HelpRSEditor() {
|
||||||
<h2>Термин и Текстовое определение</h2>
|
<h2>Термин и Текстовое определение</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li>
|
<li>
|
||||||
<IconEdit className='inline-icon' /> редактирование{' '}
|
<kbd>Клик</kbd> редактирование <LinkTopic text='Имени' topic={HelpTopic.CC_CONSTITUENTA} /> /{' '}
|
||||||
<LinkTopic text='Имени' topic={HelpTopic.CC_CONSTITUENTA} /> /{' '}
|
|
||||||
<LinkTopic text='Термина' topic={HelpTopic.CC_CONSTITUENTA} />
|
<LinkTopic text='Термина' topic={HelpTopic.CC_CONSTITUENTA} />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
|
|
|
@ -77,6 +77,7 @@ export function ToolbarSchema({
|
||||||
const targetType = activeCst?.cst_type ?? CstType.BASE;
|
const targetType = activeCst?.cst_type ?? CstType.BASE;
|
||||||
const data: ICreateConstituentaDTO = {
|
const data: ICreateConstituentaDTO = {
|
||||||
insert_after: activeCst?.id ?? null,
|
insert_after: activeCst?.id ?? null,
|
||||||
|
crucial: false,
|
||||||
cst_type: targetType,
|
cst_type: targetType,
|
||||||
alias: generateAlias(targetType, schema),
|
alias: generateAlias(targetType, schema),
|
||||||
term_raw: '',
|
term_raw: '',
|
||||||
|
@ -96,6 +97,7 @@ export function ToolbarSchema({
|
||||||
itemID: schema.id,
|
itemID: schema.id,
|
||||||
data: {
|
data: {
|
||||||
insert_after: activeCst.id,
|
insert_after: activeCst.id,
|
||||||
|
crucial: activeCst.crucial,
|
||||||
cst_type: activeCst.cst_type,
|
cst_type: activeCst.cst_type,
|
||||||
alias: generateAlias(activeCst.cst_type, schema),
|
alias: generateAlias(activeCst.cst_type, schema),
|
||||||
term_raw: activeCst.term_raw,
|
term_raw: activeCst.term_raw,
|
||||||
|
|
|
@ -276,6 +276,7 @@ export const schemaConstituentaBasics = z.strictObject({
|
||||||
id: z.coerce.number(),
|
id: z.coerce.number(),
|
||||||
alias: z.string().nonempty(errorMsg.requiredField),
|
alias: z.string().nonempty(errorMsg.requiredField),
|
||||||
convention: z.string(),
|
convention: z.string(),
|
||||||
|
crucial: z.boolean(),
|
||||||
cst_type: schemaCstType,
|
cst_type: schemaCstType,
|
||||||
definition_formal: z.string(),
|
definition_formal: z.string(),
|
||||||
definition_raw: z.string(),
|
definition_raw: z.string(),
|
||||||
|
@ -321,7 +322,8 @@ export const schemaVersionCreatedResponse = z.strictObject({
|
||||||
export const schemaCreateConstituenta = schemaConstituentaBasics
|
export const schemaCreateConstituenta = schemaConstituentaBasics
|
||||||
.pick({
|
.pick({
|
||||||
cst_type: true,
|
cst_type: true,
|
||||||
term_forms: true
|
term_forms: true,
|
||||||
|
crucial: true
|
||||||
})
|
})
|
||||||
.extend({
|
.extend({
|
||||||
alias: z.string().max(limits.len_alias, errorMsg.aliasLength).nonempty(errorMsg.requiredField),
|
alias: z.string().max(limits.len_alias, errorMsg.aliasLength).nonempty(errorMsg.requiredField),
|
||||||
|
@ -342,6 +344,7 @@ export const schemaUpdateConstituenta = z.strictObject({
|
||||||
item_data: z.strictObject({
|
item_data: z.strictObject({
|
||||||
alias: z.string().max(limits.len_alias, errorMsg.aliasLength).nonempty(errorMsg.requiredField).optional(),
|
alias: z.string().max(limits.len_alias, errorMsg.aliasLength).nonempty(errorMsg.requiredField).optional(),
|
||||||
cst_type: schemaCstType.optional(),
|
cst_type: schemaCstType.optional(),
|
||||||
|
crucial: z.boolean().optional(),
|
||||||
convention: z.string().max(limits.len_description, errorMsg.descriptionLength).optional(),
|
convention: z.string().max(limits.len_description, errorMsg.descriptionLength).optional(),
|
||||||
definition_formal: z.string().max(limits.len_description, errorMsg.descriptionLength).optional(),
|
definition_formal: z.string().max(limits.len_description, errorMsg.descriptionLength).optional(),
|
||||||
definition_raw: z.string().max(limits.len_description, errorMsg.descriptionLength).optional(),
|
definition_raw: z.string().max(limits.len_description, errorMsg.descriptionLength).optional(),
|
||||||
|
|
|
@ -47,6 +47,7 @@ export interface TermForm {
|
||||||
/** Represents Constituenta. */
|
/** Represents Constituenta. */
|
||||||
export interface IConstituenta {
|
export interface IConstituenta {
|
||||||
id: number;
|
id: number;
|
||||||
|
crucial: boolean;
|
||||||
alias: string;
|
alias: string;
|
||||||
convention: string;
|
convention: string;
|
||||||
cst_type: CstType;
|
cst_type: CstType;
|
||||||
|
|
|
@ -107,7 +107,7 @@ export function EditorConstituenta() {
|
||||||
isNarrow={isNarrow}
|
isNarrow={isNarrow}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className='mx-0 min-w-140 md:mx-auto pt-8 md:w-195 shrink-0 xs:pt-0'>
|
<div className='mx-0 min-w-120 md:mx-auto pt-8 md:w-195 shrink-0 xs:pt-0'>
|
||||||
{activeCst ? (
|
{activeCst ? (
|
||||||
<FormConstituenta
|
<FormConstituenta
|
||||||
key={activeCst.id}
|
key={activeCst.id}
|
||||||
|
|
|
@ -6,8 +6,9 @@ import { Controller, useForm } from 'react-hook-form';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
import { zodResolver } from '@hookform/resolvers/zod';
|
import { zodResolver } from '@hookform/resolvers/zod';
|
||||||
|
|
||||||
import { MiniButton, SubmitButton } from '@/components/control';
|
import { SubmitButton } from '@/components/control';
|
||||||
import { IconChild, IconEdit, IconPredecessor, IconSave } from '@/components/icons';
|
import { TextButton } from '@/components/control/text-button';
|
||||||
|
import { IconChild, IconPredecessor, IconSave } from '@/components/icons';
|
||||||
import { TextArea } from '@/components/input';
|
import { TextArea } from '@/components/input';
|
||||||
import { Indicator } from '@/components/view';
|
import { Indicator } from '@/components/view';
|
||||||
import { useDialogsStore } from '@/stores/dialogs';
|
import { useDialogsStore } from '@/stores/dialogs';
|
||||||
|
@ -159,32 +160,30 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form id={id} className='relative cc-column mt-1 px-6 py-1' onSubmit={event => void handleSubmit(onSubmit)(event)}>
|
<form
|
||||||
{!disabled || isProcessing ? (
|
id={id}
|
||||||
<MiniButton
|
className='relative cc-column mt-1 px-6 pb-1 pt-8'
|
||||||
title={isModified ? tooltipText.unsaved : 'Редактировать словоформы термина'}
|
onSubmit={event => void handleSubmit(onSubmit)(event)}
|
||||||
aria-label='Редактировать словоформы термина'
|
>
|
||||||
|
<div className='absolute z-pop top-0 left-6 flex select-text font-medium whitespace-nowrap pt-1'>
|
||||||
|
<TextButton
|
||||||
|
text='Термин' //
|
||||||
|
title={disabled ? undefined : isModified ? tooltipText.unsaved : 'Редактировать словоформы термина'}
|
||||||
onClick={handleEditTermForms}
|
onClick={handleEditTermForms}
|
||||||
className='absolute z-pop top-0 left-[calc(7ch+4px)]'
|
disabled={isModified || disabled}
|
||||||
icon={<IconEdit size='1rem' className='icon-primary' />}
|
|
||||||
disabled={isModified}
|
|
||||||
/>
|
/>
|
||||||
) : null}
|
|
||||||
|
|
||||||
<div className='absolute z-pop top-0 left-[calc(7ch+4px+3rem)] flex select-none'>
|
<TextButton
|
||||||
<div className='pt-1 text-sm font-medium min-w-16 whitespace-nowrap select-text cursor-default'>
|
text='Имя' //
|
||||||
<span>Имя </span>
|
className='ml-6'
|
||||||
<span className='ml-1'>{activeCst?.alias ?? ''}</span>
|
title={disabled ? undefined : isModified ? tooltipText.unsaved : 'Переименовать конституенту'}
|
||||||
|
onClick={handleRenameCst}
|
||||||
|
disabled={isModified || disabled}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className='ml-2 text-sm font-medium min-w-16 whitespace-nowrap select-text cursor-default'>
|
||||||
|
{activeCst?.alias ?? ''}
|
||||||
</div>
|
</div>
|
||||||
{!disabled || isProcessing ? (
|
|
||||||
<MiniButton
|
|
||||||
title={isModified ? tooltipText.unsaved : 'Переименовать конституенту'}
|
|
||||||
aria-label='Переименовать конституенту'
|
|
||||||
onClick={handleRenameCst}
|
|
||||||
icon={<IconEdit size='1rem' className='icon-primary' />}
|
|
||||||
disabled={isModified}
|
|
||||||
/>
|
|
||||||
) : null}
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Controller
|
<Controller
|
||||||
|
@ -193,7 +192,7 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
render={({ field }) => (
|
render={({ field }) => (
|
||||||
<RefsInput
|
<RefsInput
|
||||||
id='cst_term'
|
id='cst_term'
|
||||||
label='Термин'
|
aria-label='Термин'
|
||||||
maxHeight='8rem'
|
maxHeight='8rem'
|
||||||
placeholder={disabled ? '' : 'Обозначение для текстовых определений'}
|
placeholder={disabled ? '' : 'Обозначение для текстовых определений'}
|
||||||
schema={schema}
|
schema={schema}
|
||||||
|
@ -285,14 +284,10 @@ export function FormConstituenta({ disabled, id, toggleReset, schema, activeCst,
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!showConvention && (!disabled || isProcessing) ? (
|
{!showConvention && (!disabled || isProcessing) ? (
|
||||||
<button
|
<TextButton
|
||||||
type='button'
|
text='Добавить комментарий' //
|
||||||
tabIndex={-1}
|
|
||||||
className='self-start cc-label text-primary hover:underline select-none'
|
|
||||||
onClick={() => setForceComment(true)}
|
onClick={() => setForceComment(true)}
|
||||||
>
|
/>
|
||||||
Добавить комментарий
|
|
||||||
</button>
|
|
||||||
) : null}
|
) : null}
|
||||||
|
|
||||||
{!disabled || isProcessing ? (
|
{!disabled || isProcessing ? (
|
||||||
|
|
|
@ -41,11 +41,11 @@ export function StatusBar({ className, isModified, processing, activeCst, parseD
|
||||||
})();
|
})();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn('pl-34 xs:pl-8 flex gap-1', className)}>
|
<div className={cn('pl-22 xs:pl-8 flex gap-1', className)}>
|
||||||
<div
|
<div
|
||||||
tabIndex={0}
|
tabIndex={0}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'w-40 h-7',
|
'w-32 h-7',
|
||||||
'px-2 flex items-center justify-center',
|
'px-2 flex items-center justify-center',
|
||||||
'border',
|
'border',
|
||||||
'select-none',
|
'select-none',
|
||||||
|
@ -64,9 +64,9 @@ export function StatusBar({ className, isModified, processing, activeCst, parseD
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{!processing ? (
|
{!processing ? (
|
||||||
<div className='cc-fade-in flex items-center gap-2'>
|
<div className='cc-fade-in flex items-center gap-1'>
|
||||||
<IconExpressionStatus size='1rem' value={status} />
|
<IconExpressionStatus size='1rem' value={status} />
|
||||||
<span className='pb-0.5 font-controls pr-2'>{labelExpressionStatus(status)}</span>
|
<span className='font-controls pr-1 text-sm'>{labelExpressionStatus(status)}</span>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -225,6 +225,7 @@ export const RSEditState = ({
|
||||||
definition_formal: definition ?? '',
|
definition_formal: definition ?? '',
|
||||||
definition_raw: '',
|
definition_raw: '',
|
||||||
convention: '',
|
convention: '',
|
||||||
|
crucial: false,
|
||||||
term_forms: []
|
term_forms: []
|
||||||
};
|
};
|
||||||
if (skipDialog) {
|
if (skipDialog) {
|
||||||
|
@ -248,6 +249,7 @@ export const RSEditState = ({
|
||||||
definition_formal: activeCst.definition_formal,
|
definition_formal: activeCst.definition_formal,
|
||||||
definition_raw: activeCst.definition_raw,
|
definition_raw: activeCst.definition_raw,
|
||||||
convention: activeCst.convention,
|
convention: activeCst.convention,
|
||||||
|
crucial: activeCst.crucial,
|
||||||
term_forms: activeCst.term_forms
|
term_forms: activeCst.term_forms
|
||||||
}
|
}
|
||||||
}).then(onCreateCst);
|
}).then(onCreateCst);
|
||||||
|
|
|
@ -40,6 +40,12 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@utility cc-hover-underline {
|
||||||
|
&:hover:not(:disabled) {
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@utility focus-outline {
|
@utility focus-outline {
|
||||||
--focus-color: var(--color-ring);
|
--focus-color: var(--color-ring);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user