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