Compare commits
3 Commits
25029a212b
...
b3c8b217c0
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b3c8b217c0 | ||
![]() |
afe3ec0adb | ||
![]() |
a4e2d2c25f |
|
@ -361,6 +361,11 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
|
||||||
model = self._get_item()
|
model = self._get_item()
|
||||||
load_metadata = input_serializer.validated_data['load_metadata']
|
load_metadata = input_serializer.validated_data['load_metadata']
|
||||||
data = utility.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
|
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
|
data['id'] = model.pk
|
||||||
|
|
||||||
serializer = s.RSFormTRSSerializer(
|
serializer = s.RSFormTRSSerializer(
|
||||||
|
@ -486,11 +491,17 @@ class TrsImportView(views.APIView):
|
||||||
request=s.FileSerializer,
|
request=s.FileSerializer,
|
||||||
responses={
|
responses={
|
||||||
c.HTTP_201_CREATED: LibraryItemSerializer,
|
c.HTTP_201_CREATED: LibraryItemSerializer,
|
||||||
|
c.HTTP_400_BAD_REQUEST: None,
|
||||||
c.HTTP_403_FORBIDDEN: None
|
c.HTTP_403_FORBIDDEN: None
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
def post(self, request: Request) -> HttpResponse:
|
def post(self, request: Request) -> HttpResponse:
|
||||||
data = utility.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
|
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)
|
owner = cast(User, self.request.user)
|
||||||
_prepare_rsform_data(data, request, owner)
|
_prepare_rsform_data(data, request, owner)
|
||||||
serializer = s.RSFormTRSSerializer(
|
serializer = s.RSFormTRSSerializer(
|
||||||
|
@ -526,6 +537,11 @@ def create_rsform(request: Request) -> HttpResponse:
|
||||||
)
|
)
|
||||||
|
|
||||||
data = utility.read_zipped_json(request.FILES['file'].file, utils.EXTEOR_INNER_FILENAME)
|
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)
|
_prepare_rsform_data(data, request, owner)
|
||||||
serializer_rsform = s.RSFormTRSSerializer(data=data, context={'load_meta': True})
|
serializer_rsform = s.RSFormTRSSerializer(data=data, context={'load_meta': True})
|
||||||
serializer_rsform.is_valid(raise_exception=True)
|
serializer_rsform.is_valid(raise_exception=True)
|
||||||
|
|
|
@ -14,6 +14,10 @@ def operationNotInOSS(title: str):
|
||||||
return f'Операция не принадлежит ОСС: {title}'
|
return f'Операция не принадлежит ОСС: {title}'
|
||||||
|
|
||||||
|
|
||||||
|
def exteorFileCorrupted():
|
||||||
|
return 'Файл Экстеор не соответствует ожидаемому формату. Попробуйте сохранить файл в новой версии'
|
||||||
|
|
||||||
|
|
||||||
def previousResultMissing():
|
def previousResultMissing():
|
||||||
return 'Отсутствует результат предыдущей операции'
|
return 'Отсутствует результат предыдущей операции'
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,17 @@
|
||||||
''' Utility functions. '''
|
''' Utility functions. '''
|
||||||
import json
|
import json
|
||||||
from io import BytesIO
|
from io import BytesIO
|
||||||
from zipfile import ZipFile
|
from typing import Optional
|
||||||
|
from zipfile import BadZipFile, ZipFile
|
||||||
|
|
||||||
|
|
||||||
def read_zipped_json(data, json_filename: str) -> dict:
|
def read_zipped_json(data, json_filename: str) -> Optional[dict]:
|
||||||
''' Read JSON from zipped data '''
|
''' Read JSON from zipped data. '''
|
||||||
with ZipFile(data, 'r') as archive:
|
try:
|
||||||
json_data = archive.read(json_filename)
|
with ZipFile(data, 'r') as archive:
|
||||||
|
json_data = archive.read(json_filename)
|
||||||
|
except BadZipFile:
|
||||||
|
return None
|
||||||
result: dict = json.loads(json_data)
|
result: dict = json.loads(json_data)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,7 @@ function TextInput({
|
||||||
<input
|
<input
|
||||||
id={id}
|
id={id}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'py-2',
|
'min-w-0 py-2',
|
||||||
'leading-tight truncate hover:text-clip',
|
'leading-tight truncate hover:text-clip',
|
||||||
{
|
{
|
||||||
'px-3': !noBorder || !disabled,
|
'px-3': !noBorder || !disabled,
|
||||||
|
|
|
@ -62,7 +62,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
id='dlg_cst_alias'
|
id='dlg_cst_alias'
|
||||||
dense
|
dense
|
||||||
label='Имя'
|
label='Имя'
|
||||||
className='w-[7rem] mr-8'
|
className='w-[7rem]'
|
||||||
value={state.alias}
|
value={state.alias}
|
||||||
onChange={event => partialUpdate({ alias: event.target.value })}
|
onChange={event => partialUpdate({ alias: event.target.value })}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -46,7 +46,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={validated}
|
canSubmit={validated}
|
||||||
onSubmit={() => onRename(cstData)}
|
onSubmit={() => onRename(cstData)}
|
||||||
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex justify-center items-center')}
|
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex gap-3 justify-center items-center')}
|
||||||
>
|
>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
id='dlg_cst_type'
|
id='dlg_cst_type'
|
||||||
|
@ -64,7 +64,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
id='dlg_cst_alias'
|
id='dlg_cst_alias'
|
||||||
dense
|
dense
|
||||||
label='Имя'
|
label='Имя'
|
||||||
className='w-[7rem] ml-3'
|
className='w-[7rem]'
|
||||||
value={cstData.alias}
|
value={cstData.alias}
|
||||||
onChange={event => updateData({ alias: event.target.value })}
|
onChange={event => updateData({ alias: event.target.value })}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useCallback, useLayoutEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
import BadgeConstituenta from '@/components/info/BadgeConstituenta';
|
||||||
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/ui/DataTable';
|
||||||
import NoData from '@/components/ui/NoData';
|
import NoData from '@/components/ui/NoData';
|
||||||
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
import { useConceptOptions } from '@/context/ConceptOptionsContext';
|
||||||
import useWindowSize from '@/hooks/useWindowSize';
|
|
||||||
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
import { ConstituentaID, IConstituenta } from '@/models/rsform';
|
||||||
import { isMockCst } from '@/models/rsformAPI';
|
import { isMockCst } from '@/models/rsformAPI';
|
||||||
import { PARAMETER, prefixes } from '@/utils/constants';
|
import { PARAMETER, prefixes } from '@/utils/constants';
|
||||||
|
@ -16,7 +15,6 @@ interface TableSideConstituentsProps {
|
||||||
items: IConstituenta[];
|
items: IConstituenta[];
|
||||||
activeCst?: IConstituenta;
|
activeCst?: IConstituenta;
|
||||||
onOpenEdit: (cstID: ConstituentaID) => void;
|
onOpenEdit: (cstID: ConstituentaID) => void;
|
||||||
denseThreshold?: number;
|
|
||||||
autoScroll?: boolean;
|
autoScroll?: boolean;
|
||||||
maxHeight: string;
|
maxHeight: string;
|
||||||
}
|
}
|
||||||
|
@ -28,13 +26,9 @@ function TableSideConstituents({
|
||||||
activeCst,
|
activeCst,
|
||||||
autoScroll = true,
|
autoScroll = true,
|
||||||
onOpenEdit,
|
onOpenEdit,
|
||||||
maxHeight,
|
maxHeight
|
||||||
denseThreshold = 9999
|
|
||||||
}: TableSideConstituentsProps) {
|
}: TableSideConstituentsProps) {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
const windowSize = useWindowSize();
|
|
||||||
|
|
||||||
const [columnVisibility, setColumnVisibility] = useState<VisibilityState>({ expression: true });
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!activeCst) {
|
if (!activeCst) {
|
||||||
|
@ -54,17 +48,6 @@ function TableSideConstituents({
|
||||||
}
|
}
|
||||||
}, [activeCst, autoScroll]);
|
}, [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(
|
const handleRowClicked = useCallback(
|
||||||
(cst: IConstituenta) => {
|
(cst: IConstituenta) => {
|
||||||
if (!isMockCst(cst)) {
|
if (!isMockCst(cst)) {
|
||||||
|
@ -103,25 +86,6 @@ function TableSideConstituents({
|
||||||
{props.getValue()}
|
{props.getValue()}
|
||||||
</div>
|
</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]
|
[colors]
|
||||||
|
@ -162,8 +126,6 @@ function TableSideConstituents({
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
enableHiding
|
enableHiding
|
||||||
columnVisibility={columnVisibility}
|
|
||||||
onColumnVisibilityChange={setColumnVisibility}
|
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<NoData className='min-h-[5rem]'>
|
<NoData className='min-h-[5rem]'>
|
||||||
<p>Список конституент пуст</p>
|
<p>Список конституент пуст</p>
|
||||||
|
|
|
@ -14,9 +14,6 @@ import { animateSideView } from '@/styling/animations';
|
||||||
import ConstituentsSearch from './ConstituentsSearch';
|
import ConstituentsSearch from './ConstituentsSearch';
|
||||||
import TableSideConstituents from './TableSideConstituents';
|
import TableSideConstituents from './TableSideConstituents';
|
||||||
|
|
||||||
// Window width cutoff for expression show
|
|
||||||
const COLUMN_EXPRESSION_HIDE_THRESHOLD = 1500;
|
|
||||||
|
|
||||||
// Window width cutoff for dense search bar
|
// Window width cutoff for dense search bar
|
||||||
const COLUMN_DENSE_SEARCH_THRESHOLD = 1100;
|
const COLUMN_DENSE_SEARCH_THRESHOLD = 1100;
|
||||||
|
|
||||||
|
@ -47,7 +44,6 @@ function ViewConstituents({ expression, schema, activeCst, isBottom, onOpenEdit
|
||||||
activeCst={activeCst}
|
activeCst={activeCst}
|
||||||
onOpenEdit={onOpenEdit}
|
onOpenEdit={onOpenEdit}
|
||||||
autoScroll={!isBottom}
|
autoScroll={!isBottom}
|
||||||
denseThreshold={COLUMN_EXPRESSION_HIDE_THRESHOLD}
|
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[isBottom, filteredData, activeCst, onOpenEdit, calculateHeight, accessLevel]
|
[isBottom, filteredData, activeCst, onOpenEdit, calculateHeight, accessLevel]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user