mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 04:50:36 +03:00
F: Implement RSForm and OSS attribute sync
This commit is contained in:
parent
e059dc2394
commit
b929b051cc
|
@ -94,9 +94,9 @@ class LibraryItemDetailsSerializer(serializers.ModelSerializer):
|
|||
|
||||
class UserTargetSerializer(serializers.Serializer):
|
||||
''' Serializer: Target single User. '''
|
||||
user = PKField(many=False, queryset=User.objects.all())
|
||||
user = PKField(many=False, queryset=User.objects.all().only('pk'))
|
||||
|
||||
|
||||
class UsersListSerializer(serializers.Serializer):
|
||||
''' Serializer: List of Users. '''
|
||||
users = PKField(many=True, queryset=User.objects.all())
|
||||
users = PKField(many=True, queryset=User.objects.all().only('pk'))
|
||||
|
|
|
@ -183,57 +183,6 @@ class TestLibraryViewset(EndpointTester):
|
|||
self.unowned.refresh_from_db()
|
||||
self.assertEqual(self.unowned.location, data['location'])
|
||||
|
||||
@decl_endpoint('/api/library/{item}/add-editor', method='patch')
|
||||
def test_add_editor(self):
|
||||
time_update = self.owned.time_update
|
||||
|
||||
data = {'user': self.invalid_user}
|
||||
self.executeBadData(data=data, item=self.owned.pk)
|
||||
|
||||
data = {'user': self.user.pk}
|
||||
self.executeNotFound(data=data, item=self.invalid_item)
|
||||
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||
|
||||
self.executeOK(data=data, item=self.owned.pk)
|
||||
self.owned.refresh_from_db()
|
||||
self.assertEqual(self.owned.time_update, time_update)
|
||||
self.assertEqual(self.owned.editors(), [self.user])
|
||||
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(self.owned.editors(), [self.user])
|
||||
|
||||
data = {'user': self.user2.pk}
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(set(self.owned.editors()), set([self.user, self.user2]))
|
||||
|
||||
|
||||
@decl_endpoint('/api/library/{item}/remove-editor', method='patch')
|
||||
def test_remove_editor(self):
|
||||
time_update = self.owned.time_update
|
||||
|
||||
data = {'user': self.invalid_user}
|
||||
self.executeBadData(data=data, item=self.owned.pk)
|
||||
|
||||
data = {'user': self.user.pk}
|
||||
self.executeNotFound(data=data, item=self.invalid_item)
|
||||
self.executeForbidden(data=data, item=self.unowned.pk)
|
||||
|
||||
self.executeOK(data=data, item=self.owned.pk)
|
||||
self.owned.refresh_from_db()
|
||||
self.assertEqual(self.owned.time_update, time_update)
|
||||
self.assertEqual(self.owned.editors(), [])
|
||||
|
||||
Editor.add(item=self.owned, user=self.user)
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(self.owned.editors(), [])
|
||||
|
||||
Editor.add(item=self.owned, user=self.user)
|
||||
Editor.add(item=self.owned, user=self.user2)
|
||||
data = {'user': self.user2.pk}
|
||||
self.executeOK(data=data)
|
||||
self.assertEqual(self.owned.editors(), [self.user])
|
||||
|
||||
|
||||
@decl_endpoint('/api/library/{item}/set-editors', method='patch')
|
||||
def test_set_editors(self):
|
||||
time_update = self.owned.time_update
|
||||
|
|
|
@ -13,6 +13,7 @@ from rest_framework.decorators import action
|
|||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
|
||||
from apps.oss.models import OperationSchema
|
||||
from apps.rsform.models import RSForm
|
||||
from apps.rsform.serializers import RSFormParseSerializer
|
||||
from apps.users.models import User
|
||||
|
@ -52,8 +53,6 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
|||
'set_owner',
|
||||
'set_access_policy',
|
||||
'set_location',
|
||||
'add_editor',
|
||||
'remove_editor',
|
||||
'set_editors'
|
||||
]:
|
||||
access_level = permissions.ItemOwner
|
||||
|
@ -165,29 +164,19 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
|||
item = self._get_item()
|
||||
serializer = s.UserTargetSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
new_owner = serializer.validated_data['user']
|
||||
m.LibraryItem.objects.filter(pk=item.pk).update(owner=new_owner)
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
new_owner = serializer.validated_data['user'].pk
|
||||
if new_owner == item.owner_id:
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
with transaction.atomic():
|
||||
if item.item_type == m.LibraryItemType.OPERATION_SCHEMA:
|
||||
owned_schemas = OperationSchema(item).owned_schemas().only('owner')
|
||||
for schema in owned_schemas:
|
||||
schema.owner_id = new_owner
|
||||
m.LibraryItem.objects.bulk_update(owned_schemas, ['owner'])
|
||||
item.owner_id = new_owner
|
||||
item.save(update_fields=['owner'])
|
||||
|
||||
@extend_schema(
|
||||
summary='set AccessPolicy for item',
|
||||
tags=['Library'],
|
||||
request=s.AccessPolicySerializer,
|
||||
responses={
|
||||
c.HTTP_200_OK: None,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='set-access-policy')
|
||||
def set_access_policy(self, request: Request, pk):
|
||||
''' Endpoint: Set item AccessPolicy. '''
|
||||
item = self._get_item()
|
||||
serializer = s.AccessPolicySerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
new_policy = serializer.validated_data['access_policy']
|
||||
m.LibraryItem.objects.filter(pk=item.pk).update(access_policy=new_policy)
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
@extend_schema(
|
||||
|
@ -208,49 +197,52 @@ class LibraryViewSet(viewsets.ModelViewSet):
|
|||
serializer = s.LocationSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
location: str = serializer.validated_data['location']
|
||||
if location == item.location:
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
if location.startswith(m.LocationHead.LIBRARY) and not self.request.user.is_staff:
|
||||
return Response(status=c.HTTP_403_FORBIDDEN)
|
||||
m.LibraryItem.objects.filter(pk=item.pk).update(location=location)
|
||||
|
||||
with transaction.atomic():
|
||||
if item.item_type == m.LibraryItemType.OPERATION_SCHEMA:
|
||||
owned_schemas = OperationSchema(item).owned_schemas().only('location')
|
||||
for schema in owned_schemas:
|
||||
schema.location = location
|
||||
m.LibraryItem.objects.bulk_update(owned_schemas, ['location'])
|
||||
item.location = location
|
||||
item.save(update_fields=['location'])
|
||||
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
@extend_schema(
|
||||
summary='add editor for item',
|
||||
summary='set AccessPolicy for item',
|
||||
tags=['Library'],
|
||||
request=s.UserTargetSerializer,
|
||||
request=s.AccessPolicySerializer,
|
||||
responses={
|
||||
c.HTTP_200_OK: None,
|
||||
c.HTTP_400_BAD_REQUEST: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='add-editor')
|
||||
def add_editor(self, request: Request, pk):
|
||||
''' Endpoint: Add editor for item. '''
|
||||
@action(detail=True, methods=['patch'], url_path='set-access-policy')
|
||||
def set_access_policy(self, request: Request, pk):
|
||||
''' Endpoint: Set item AccessPolicy. '''
|
||||
item = self._get_item()
|
||||
serializer = s.UserTargetSerializer(data=request.data)
|
||||
serializer = s.AccessPolicySerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
new_editor = serializer.validated_data['user']
|
||||
m.Editor.add(item=item, user=new_editor)
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
new_policy = serializer.validated_data['access_policy']
|
||||
if new_policy == item.access_policy:
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
with transaction.atomic():
|
||||
if item.item_type == m.LibraryItemType.OPERATION_SCHEMA:
|
||||
owned_schemas = OperationSchema(item).owned_schemas().only('access_policy')
|
||||
for schema in owned_schemas:
|
||||
schema.access_policy = new_policy
|
||||
m.LibraryItem.objects.bulk_update(owned_schemas, ['access_policy'])
|
||||
item.access_policy = new_policy
|
||||
item.save(update_fields=['access_policy'])
|
||||
|
||||
@extend_schema(
|
||||
summary='remove editor for item',
|
||||
tags=['Library'],
|
||||
request=s.UserTargetSerializer,
|
||||
responses={
|
||||
c.HTTP_200_OK: None,
|
||||
c.HTTP_403_FORBIDDEN: None,
|
||||
c.HTTP_404_NOT_FOUND: None
|
||||
}
|
||||
)
|
||||
@action(detail=True, methods=['patch'], url_path='remove-editor')
|
||||
def remove_editor(self, request: Request, pk):
|
||||
''' Endpoint: Remove editor for item. '''
|
||||
item = self._get_item()
|
||||
serializer = s.UserTargetSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
editor = serializer.validated_data['user']
|
||||
m.Editor.remove(item=item, user=editor)
|
||||
return Response(status=c.HTTP_200_OK)
|
||||
|
||||
@extend_schema(
|
||||
|
|
|
@ -51,6 +51,14 @@ class OperationSchema:
|
|||
''' Operation substitutions. '''
|
||||
return Substitution.objects.filter(operation__oss=self.model)
|
||||
|
||||
def owned_schemas(self) -> QuerySet[LibraryItem]:
|
||||
''' Get QuerySet containing all result schemas owned by current OSS. '''
|
||||
return LibraryItem.objects.filter(
|
||||
producer__oss=self.model,
|
||||
owner_id=self.model.owner_id,
|
||||
location=self.model.location
|
||||
)
|
||||
|
||||
def update_positions(self, data: list[dict]):
|
||||
''' Update positions. '''
|
||||
lookup = {x['id']: x for x in data}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
''' Tests for REST API. '''
|
||||
from .t_change_attributes import *
|
||||
from .t_oss import *
|
||||
|
|
107
rsconcept/backend/apps/oss/tests/s_views/t_change_attributes.py
Normal file
107
rsconcept/backend/apps/oss/tests/s_views/t_change_attributes.py
Normal file
|
@ -0,0 +1,107 @@
|
|||
''' Testing API: Change attributes of OSS and RSForms. '''
|
||||
|
||||
from rest_framework import status
|
||||
|
||||
from apps.library.models import AccessPolicy, LocationHead
|
||||
from apps.oss.models import Operation, OperationSchema, OperationType
|
||||
from apps.rsform.models import RSForm
|
||||
from apps.users.models import User
|
||||
from shared.EndpointTester import EndpointTester, decl_endpoint
|
||||
|
||||
|
||||
class TestChangeAttributes(EndpointTester):
|
||||
''' Testing LibraryItem view when OSS is associated with RSForms. '''
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user3 = User.objects.create(
|
||||
username='UserTest3',
|
||||
email='anotheranother@test.com',
|
||||
password='password'
|
||||
)
|
||||
|
||||
self.owned = OperationSchema.create(
|
||||
title='Test',
|
||||
alias='T1',
|
||||
owner=self.user,
|
||||
location=LocationHead.LIBRARY
|
||||
)
|
||||
self.owned_id = self.owned.model.pk
|
||||
|
||||
self.ks1 = RSForm.create(
|
||||
alias='KS1',
|
||||
title='Test1',
|
||||
owner=self.user,
|
||||
location=LocationHead.USER
|
||||
)
|
||||
self.ks2 = RSForm.create(
|
||||
alias='KS2',
|
||||
title='Test2',
|
||||
owner=self.user2,
|
||||
location=LocationHead.LIBRARY
|
||||
)
|
||||
|
||||
self.operation1 = self.owned.create_operation(
|
||||
alias='1',
|
||||
operation_type=OperationType.INPUT,
|
||||
result=self.ks1.model
|
||||
)
|
||||
self.operation2 = self.owned.create_operation(
|
||||
alias='2',
|
||||
operation_type=OperationType.INPUT,
|
||||
result=self.ks2.model
|
||||
)
|
||||
|
||||
self.operation3 = self.owned.create_operation(
|
||||
alias='3',
|
||||
operation_type=OperationType.SYNTHESIS
|
||||
)
|
||||
self.owned.execute_operation(self.operation3)
|
||||
self.operation3.refresh_from_db()
|
||||
self.ks3 = self.operation3.result
|
||||
|
||||
|
||||
@decl_endpoint('/api/library/{item}/set-owner', method='patch')
|
||||
def test_set_owner(self):
|
||||
data = {'user': self.user3.pk}
|
||||
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
|
||||
self.owned.refresh_from_db()
|
||||
self.ks1.refresh_from_db()
|
||||
self.ks2.refresh_from_db()
|
||||
self.ks3.refresh_from_db()
|
||||
self.assertEqual(self.owned.model.owner, self.user3)
|
||||
self.assertEqual(self.ks1.model.owner, self.user)
|
||||
self.assertEqual(self.ks2.model.owner, self.user2)
|
||||
self.assertEqual(self.ks3.owner, self.user3)
|
||||
|
||||
@decl_endpoint('/api/library/{item}/set-location', method='patch')
|
||||
def test_set_location(self):
|
||||
data = {'location': '/U/temp'}
|
||||
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
|
||||
self.owned.refresh_from_db()
|
||||
self.ks1.refresh_from_db()
|
||||
self.ks2.refresh_from_db()
|
||||
self.ks3.refresh_from_db()
|
||||
self.assertEqual(self.owned.model.location, data['location'])
|
||||
self.assertNotEqual(self.ks1.model.location, data['location'])
|
||||
self.assertNotEqual(self.ks2.model.location, data['location'])
|
||||
self.assertEqual(self.ks3.location, data['location'])
|
||||
|
||||
@decl_endpoint('/api/library/{item}/set-access-policy', method='patch')
|
||||
def test_set_access_policy(self):
|
||||
data = {'access_policy': AccessPolicy.PROTECTED}
|
||||
|
||||
self.executeOK(data=data, item=self.owned_id)
|
||||
|
||||
self.owned.refresh_from_db()
|
||||
self.ks1.refresh_from_db()
|
||||
self.ks2.refresh_from_db()
|
||||
self.ks3.refresh_from_db()
|
||||
self.assertEqual(self.owned.model.access_policy, data['access_policy'])
|
||||
self.assertNotEqual(self.ks1.model.access_policy, data['access_policy'])
|
||||
self.assertNotEqual(self.ks2.model.access_policy, data['access_policy'])
|
||||
self.assertEqual(self.ks3.access_policy, data['access_policy'])
|
|
@ -250,9 +250,8 @@ LOGGING = {
|
|||
'root': {
|
||||
'handlers': ['console'],
|
||||
'level': os.getenv('DJANGO_LOG_LEVEL', 'INFO')
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if len(sys.argv) > 1 and sys.argv[1] == 'test':
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
''' Utils: base tester class for endpoints. '''
|
||||
import logging
|
||||
|
||||
from django.db import connection
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APIClient, APIRequestFactory, APITestCase
|
||||
|
||||
|
@ -40,6 +43,9 @@ class EndpointTester(APITestCase):
|
|||
self.client = APIClient()
|
||||
self.client.force_authenticate(user=self.user)
|
||||
|
||||
self.logger = logging.getLogger('django.db.backends')
|
||||
self.logger.setLevel(logging.DEBUG)
|
||||
|
||||
def setUpFullUsers(self):
|
||||
self.factory = APIRequestFactory()
|
||||
self.user = User.objects.create_user(
|
||||
|
@ -71,6 +77,16 @@ class EndpointTester(APITestCase):
|
|||
def logout(self):
|
||||
self.client.logout()
|
||||
|
||||
def start_db_log(self):
|
||||
''' Warning! Do not use this second time before calling stop_db_log. '''
|
||||
''' Warning! Do not forget to enable global logging in settings. '''
|
||||
logging.disable(logging.NOTSET)
|
||||
connection.force_debug_cursor = True
|
||||
|
||||
def stop_db_log(self):
|
||||
connection.force_debug_cursor = False
|
||||
logging.disable(logging.CRITICAL)
|
||||
|
||||
def set_params(self, **kwargs):
|
||||
''' Given named argument values resolve current endpoint_mask. '''
|
||||
if self.endpoint_mask and len(kwargs) > 0:
|
||||
|
|
|
@ -17,25 +17,36 @@ interface MiniSelectorOSSProps {
|
|||
|
||||
function MiniSelectorOSS({ items, onSelect }: MiniSelectorOSSProps) {
|
||||
const ossMenu = useDropdown();
|
||||
|
||||
function onToggle(event: CProps.EventMouse) {
|
||||
if (items.length > 1) {
|
||||
ossMenu.toggle();
|
||||
} else {
|
||||
onSelect(event, items[0]);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ossMenu.ref} className='flex items-center'>
|
||||
<MiniButton
|
||||
icon={<IconOSS size='1.25rem' className='icon-primary' />}
|
||||
title='Связанные операционные схемы'
|
||||
title='Операционные схемы'
|
||||
hideTitle={ossMenu.isOpen}
|
||||
onClick={() => ossMenu.toggle()}
|
||||
onClick={onToggle}
|
||||
/>
|
||||
<Dropdown isOpen={ossMenu.isOpen}>
|
||||
<Label text='Список ОСС' className='border-b px-3 py-1' />
|
||||
{items.map((reference, index) => (
|
||||
<DropdownButton
|
||||
className='min-w-[5rem]'
|
||||
key={`${prefixes.oss_list}${index}`}
|
||||
text={reference.alias}
|
||||
onClick={event => onSelect(event, reference)}
|
||||
/>
|
||||
))}
|
||||
</Dropdown>
|
||||
{items.length > 1 ? (
|
||||
<Dropdown isOpen={ossMenu.isOpen}>
|
||||
<Label text='Список ОСС' className='border-b px-3 py-1' />
|
||||
{items.map((reference, index) => (
|
||||
<DropdownButton
|
||||
className='min-w-[5rem]'
|
||||
key={`${prefixes.oss_list}${index}`}
|
||||
text={reference.alias}
|
||||
onClick={event => onSelect(event, reference)}
|
||||
/>
|
||||
))}
|
||||
</Dropdown>
|
||||
) : null}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ export interface ILibraryItemEditor {
|
|||
|
||||
isMutable: boolean;
|
||||
isProcessing: boolean;
|
||||
isAttachedToOSS: boolean;
|
||||
|
||||
setOwner: (newOwner: UserID) => void;
|
||||
setAccessPolicy: (newPolicy: AccessPolicy) => void;
|
||||
|
|
|
@ -15,7 +15,7 @@ import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
|
|||
import DlgCreateOperation from '@/dialogs/DlgCreateOperation';
|
||||
import DlgEditEditors from '@/dialogs/DlgEditEditors';
|
||||
import DlgEditOperation from '@/dialogs/DlgEditOperation';
|
||||
import { AccessPolicy, LibraryItemID } from '@/models/library';
|
||||
import { AccessPolicy, ILibraryItemEditor, LibraryItemID } from '@/models/library';
|
||||
import { Position2D } from '@/models/miscellaneous';
|
||||
import {
|
||||
IOperationCreateData,
|
||||
|
@ -37,12 +37,13 @@ export interface ICreateOperationPrompt {
|
|||
callback: (newID: OperationID) => void;
|
||||
}
|
||||
|
||||
export interface IOssEditContext {
|
||||
export interface IOssEditContext extends ILibraryItemEditor {
|
||||
schema?: IOperationSchema;
|
||||
selected: OperationID[];
|
||||
|
||||
isMutable: boolean;
|
||||
isProcessing: boolean;
|
||||
isAttachedToOSS: boolean;
|
||||
|
||||
showTooltip: boolean;
|
||||
setShowTooltip: React.Dispatch<React.SetStateAction<boolean>>;
|
||||
|
@ -319,6 +320,7 @@ export const OssEditState = ({ selected, setSelected, children }: OssEditStatePr
|
|||
|
||||
isMutable,
|
||||
isProcessing: model.processing,
|
||||
isAttachedToOSS: false,
|
||||
|
||||
toggleSubscribe,
|
||||
setOwner,
|
||||
|
|
|
@ -4,6 +4,7 @@ import { useIntl } from 'react-intl';
|
|||
import { IconEdit } from '@/components/Icons';
|
||||
import InfoUsers from '@/components/info/InfoUsers';
|
||||
import SelectUser from '@/components/select/SelectUser';
|
||||
import LabeledValue from '@/components/ui/LabeledValue';
|
||||
import MiniButton from '@/components/ui/MiniButton';
|
||||
import Overlay from '@/components/ui/Overlay';
|
||||
import Tooltip from '@/components/ui/Tooltip';
|
||||
|
@ -15,8 +16,6 @@ import { UserID, UserLevel } from '@/models/user';
|
|||
import { prefixes } from '@/utils/constants';
|
||||
import { prompts } from '@/utils/labels';
|
||||
|
||||
import LabeledValue from '@/components/ui/LabeledValue';
|
||||
|
||||
interface EditorLibraryItemProps {
|
||||
item?: ILibraryItemData;
|
||||
isModified?: boolean;
|
||||
|
@ -48,11 +47,11 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
|||
{accessLevel >= UserLevel.OWNER ? (
|
||||
<Overlay position='top-[-0.5rem] left-[2.3rem] cc-icons'>
|
||||
<MiniButton
|
||||
title='Изменить путь'
|
||||
title={controller.isAttachedToOSS ? 'Путь наследуется от ОСС' : 'Изменить путь'}
|
||||
noHover
|
||||
onClick={() => controller.promptLocation()}
|
||||
icon={<IconEdit size='1rem' className='mt-1 icon-primary' />}
|
||||
disabled={isModified || controller.isProcessing}
|
||||
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS}
|
||||
/>
|
||||
</Overlay>
|
||||
) : null}
|
||||
|
@ -66,11 +65,11 @@ function EditorLibraryItem({ item, isModified, controller }: EditorLibraryItemPr
|
|||
<Overlay position='top-[-0.5rem] left-[5.5rem] cc-icons'>
|
||||
<div className='flex items-start'>
|
||||
<MiniButton
|
||||
title='Изменить владельца'
|
||||
title={controller.isAttachedToOSS ? 'Владелец наследуется от ОСС' : 'Изменить владельца'}
|
||||
noHover
|
||||
onClick={() => ownerSelector.toggle()}
|
||||
icon={<IconEdit size='1rem' className='mt-1 icon-primary' />}
|
||||
disabled={isModified || controller.isProcessing}
|
||||
disabled={isModified || controller.isProcessing || controller.isAttachedToOSS}
|
||||
/>
|
||||
{ownerSelector.isOpen ? (
|
||||
<SelectUser
|
||||
|
|
|
@ -33,7 +33,7 @@ function ToolbarItemAccess({ visible, toggleVisible, readOnly, toggleReadOnly, c
|
|||
<Label text='Доступ' className='self-center select-none' />
|
||||
<div className='ml-auto cc-icons'>
|
||||
<SelectAccessPolicy
|
||||
disabled={accessLevel <= UserLevel.EDITOR || controller.isProcessing}
|
||||
disabled={accessLevel <= UserLevel.EDITOR || controller.isProcessing || controller.isAttachedToOSS}
|
||||
value={policy}
|
||||
onChange={newPolicy => controller.setAccessPolicy(newPolicy)}
|
||||
/>
|
||||
|
|
|
@ -26,6 +26,7 @@ import DlgSubstituteCst from '@/dialogs/DlgSubstituteCst';
|
|||
import DlgUploadRSForm from '@/dialogs/DlgUploadRSForm';
|
||||
import {
|
||||
AccessPolicy,
|
||||
ILibraryItemEditor,
|
||||
ILibraryUpdateData,
|
||||
IVersionData,
|
||||
LibraryItemID,
|
||||
|
@ -55,13 +56,14 @@ import { promptUnsaved } from '@/utils/utils';
|
|||
|
||||
import { RSTabID } from './RSTabs';
|
||||
|
||||
export interface IRSEditContext {
|
||||
export interface IRSEditContext extends ILibraryItemEditor {
|
||||
schema?: IRSForm;
|
||||
selected: ConstituentaID[];
|
||||
|
||||
isMutable: boolean;
|
||||
isContentEditable: boolean;
|
||||
isProcessing: boolean;
|
||||
isAttachedToOSS: boolean;
|
||||
canProduceStructure: boolean;
|
||||
nothingSelected: boolean;
|
||||
canDeleteSelected: boolean;
|
||||
|
@ -153,6 +155,13 @@ export const RSEditState = ({
|
|||
() => !nothingSelected && selected.every(id => !model.schema?.cstByID.get(id)?.is_inherited),
|
||||
[selected, nothingSelected, model.schema]
|
||||
);
|
||||
const isAttachedToOSS = useMemo(
|
||||
() =>
|
||||
!!model.schema &&
|
||||
model.schema.oss.length > 0 &&
|
||||
(model.schema.stats.count_inherited > 0 || model.schema.items.length === 0),
|
||||
[model.schema]
|
||||
);
|
||||
|
||||
const [showUpload, setShowUpload] = useState(false);
|
||||
const [showClone, setShowClone] = useState(false);
|
||||
|
@ -618,6 +627,7 @@ export const RSEditState = ({
|
|||
isMutable,
|
||||
isContentEditable,
|
||||
isProcessing: model.processing,
|
||||
isAttachedToOSS,
|
||||
canProduceStructure,
|
||||
nothingSelected,
|
||||
canDeleteSelected,
|
||||
|
|
Loading…
Reference in New Issue
Block a user