Compare commits

..

No commits in common. "b3c8b217c08e26be3325bcff2aeb567e7e630708" and "25029a212bb63e1cc656cd08b1a69a43655656aa" have entirely different histories.

8 changed files with 54 additions and 36 deletions

View File

@ -361,11 +361,6 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
model = self._get_item()
load_metadata = input_serializer.validated_data['load_metadata']
data = utility.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
if data is None:
return Response(
status=c.HTTP_400_BAD_REQUEST,
data={'file': msg.exteorFileCorrupted()}
)
data['id'] = model.pk
serializer = s.RSFormTRSSerializer(
@ -491,17 +486,11 @@ class TrsImportView(views.APIView):
request=s.FileSerializer,
responses={
c.HTTP_201_CREATED: LibraryItemSerializer,
c.HTTP_400_BAD_REQUEST: None,
c.HTTP_403_FORBIDDEN: None
}
)
def post(self, request: Request) -> HttpResponse:
data = utility.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
if data is None:
return Response(
status=c.HTTP_400_BAD_REQUEST,
data={'file': msg.exteorFileCorrupted()}
)
owner = cast(User, self.request.user)
_prepare_rsform_data(data, request, owner)
serializer = s.RSFormTRSSerializer(
@ -537,11 +526,6 @@ def create_rsform(request: Request) -> HttpResponse:
)
data = utility.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
if data is None:
return Response(
status=c.HTTP_400_BAD_REQUEST,
data={'file': msg.exteorFileCorrupted()}
)
_prepare_rsform_data(data, request, owner)
serializer_rsform = s.RSFormTRSSerializer(data=data, context={'load_meta': True})
serializer_rsform.is_valid(raise_exception=True)

View File

@ -14,10 +14,6 @@ def operationNotInOSS(title: str):
return f'Операция не принадлежит ОСС: {title}'
def exteorFileCorrupted():
return 'Файл Экстеор не соответствует ожидаемому формату. Попробуйте сохранить файл в новой версии'
def previousResultMissing():
return 'Отсутствует результат предыдущей операции'

View File

@ -1,17 +1,13 @@
''' Utility functions. '''
import json
from io import BytesIO
from typing import Optional
from zipfile import BadZipFile, ZipFile
from zipfile import ZipFile
def read_zipped_json(data, json_filename: str) -> Optional[dict]:
''' Read JSON from zipped data. '''
try:
with ZipFile(data, 'r') as archive:
json_data = archive.read(json_filename)
except BadZipFile:
return None
def read_zipped_json(data, json_filename: str) -> dict:
''' Read JSON from zipped data '''
with ZipFile(data, 'r') as archive:
json_data = archive.read(json_filename)
result: dict = json.loads(json_data)
return result

View File

@ -41,7 +41,7 @@ function TextInput({
<input
id={id}
className={clsx(
'min-w-0 py-2',
'py-2',
'leading-tight truncate hover:text-clip',
{
'px-3': !noBorder || !disabled,

View File

@ -62,7 +62,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
id='dlg_cst_alias'
dense
label='Имя'
className='w-[7rem]'
className='w-[7rem] mr-8'
value={state.alias}
onChange={event => partialUpdate({ alias: event.target.value })}
/>

View File

@ -46,7 +46,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
hideWindow={hideWindow}
canSubmit={validated}
onSubmit={() => onRename(cstData)}
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex gap-3 justify-center items-center')}
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex justify-center items-center')}
>
<SelectSingle
id='dlg_cst_type'
@ -64,7 +64,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
id='dlg_cst_alias'
dense
label='Имя'
className='w-[7rem]'
className='w-[7rem] ml-3'
value={cstData.alias}
onChange={event => updateData({ alias: event.target.value })}
/>

View File

@ -1,11 +1,12 @@
'use client';
import { useCallback, useLayoutEffect, useMemo } from 'react';
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
import NoData from '@/components/ui/NoData';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import useWindowSize from '@/hooks/useWindowSize';
import { ConstituentaID, IConstituenta } from '@/models/rsform';
import { isMockCst } from '@/models/rsformAPI';
import { PARAMETER, prefixes } from '@/utils/constants';
@ -15,6 +16,7 @@ interface TableSideConstituentsProps {
items: IConstituenta[];
activeCst?: IConstituenta;
onOpenEdit: (cstID: ConstituentaID) => void;
denseThreshold?: number;
autoScroll?: boolean;
maxHeight: string;
}
@ -26,9 +28,13 @@ function TableSideConstituents({
activeCst,
autoScroll = true,
onOpenEdit,
maxHeight
maxHeight,
denseThreshold = 9999
}: TableSideConstituentsProps) {
const { colors } = useConceptOptions();
const windowSize = useWindowSize();
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({ expression: true });
useLayoutEffect(() => {
if (!activeCst) {
@ -48,6 +54,17 @@ function TableSideConstituents({
}
}, [activeCst, autoScroll]);
useLayoutEffect(() => {
setColumnVisibility(prev => {
const newValue = (windowSize.width ?? 0) >= denseThreshold;
if (newValue === prev.expression) {
return prev;
} else {
return { expression: newValue };
}
});
}, [windowSize, denseThreshold]);
const handleRowClicked = useCallback(
(cst: IConstituenta) => {
if (!isMockCst(cst)) {
@ -86,6 +103,25 @@ function TableSideConstituents({
{props.getValue()}
</div>
)
}),
columnHelper.accessor('definition_formal', {
id: 'expression',
header: 'Выражение',
size: 2000,
minSize: 0,
maxSize: 2000,
enableHiding: true,
cell: props => (
<div
style={{
textWrap: 'pretty',
fontSize: 12,
color: isMockCst(props.row.original) ? colors.fgWarning : undefined
}}
>
{props.getValue()}
</div>
)
})
],
[colors]
@ -126,6 +162,8 @@ function TableSideConstituents({
conditionalRowStyles={conditionalRowStyles}
headPosition='0'
enableHiding
columnVisibility={columnVisibility}
onColumnVisibilityChange={setColumnVisibility}
noDataComponent={
<NoData className='min-h-[5rem]'>
<p>Список конституент пуст</p>

View File

@ -14,6 +14,9 @@ import { animateSideView } from '@/styling/animations';
import ConstituentsSearch from './ConstituentsSearch';
import TableSideConstituents from './TableSideConstituents';
// Window width cutoff for expression show
const COLUMN_EXPRESSION_HIDE_THRESHOLD = 1500;
// Window width cutoff for dense search bar
const COLUMN_DENSE_SEARCH_THRESHOLD = 1100;
@ -44,6 +47,7 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit
activeCst={activeCst}
onOpenEdit={onOpenEdit}
autoScroll={!isBottom}
denseThreshold={COLUMN_EXPRESSION_HIDE_THRESHOLD}
/>
),
[isBottom, filteredData, activeCst, onOpenEdit, calculateHeight, accessLevel]