F: Implement substitutions propagation
Some checks failed
Backend CI / build (3.12) (push) Has been cancelled
Frontend CI / build (22.x) (push) Has been cancelled

This commit is contained in:
Ivan 2024-08-12 16:52:06 +03:00
parent 9170692f33
commit cb3fd32e78
14 changed files with 397 additions and 112 deletions

View File

@ -2,6 +2,7 @@
from typing import Optional, cast
from cctext import extract_entities
from rest_framework.serializers import ValidationError
from apps.library.models import LibraryItem
from apps.rsform.graph import Graph
@ -16,108 +17,20 @@ from apps.rsform.models import (
)
from .Inheritance import Inheritance
from .Operation import Operation
from .Operation import Operation, OperationType
from .OperationSchema import OperationSchema
from .Substitution import Substitution
CstMapping = dict[str, Constituenta]
CstSubstitution = list[tuple[Constituenta, Constituenta]]
class ChangeManager:
''' Change propagation wrapper for OSS. '''
class Cache:
''' Cache for RSForm constituents. '''
def __init__(self, oss: OperationSchema):
self._oss = oss
self._schemas: list[RSForm] = []
self._schema_by_id: dict[int, RSForm] = {}
self.operations = list(oss.operations().only('result_id'))
self.operation_by_id = {operation.pk: operation for operation in self.operations}
self.graph = Graph[int]()
for operation in self.operations:
self.graph.add_node(operation.pk)
for argument in self._oss.arguments().only('operation_id', 'argument_id'):
self.graph.add_edge(argument.argument_id, argument.operation_id)
self.is_loaded = False
self.substitutions: list[Substitution] = []
self.inheritance: dict[int, list[tuple[int, int]]] = {}
def insert(self, schema: RSForm) -> None:
''' Insert new schema. '''
if not self._schema_by_id.get(schema.model.pk):
self._insert_new(schema)
def get_schema(self, operation: Operation) -> Optional[RSForm]:
''' Get schema by Operation. '''
if operation.result_id is None:
return None
if operation.result_id in self._schema_by_id:
return self._schema_by_id[operation.result_id]
else:
schema = RSForm.from_id(operation.result_id)
schema.cache.ensure_loaded()
self._insert_new(schema)
return schema
def get_operation(self, schema: RSForm) -> Operation:
''' Get operation by schema. '''
for operation in self.operations:
if operation.result_id == schema.model.pk:
return operation
raise ValueError(f'Operation for schema {schema.model.pk} not found')
def ensure_loaded(self) -> None:
''' Ensure propagation of changes. '''
if self.is_loaded:
return
self.is_loaded = True
self.substitutions = list(self._oss.substitutions().only('operation_id', 'original_id', 'substitution_id'))
for operation in self.operations:
self.inheritance[operation.pk] = []
for item in self._oss.inheritance().only('operation_id', 'parent_id', 'child_id'):
self.inheritance[item.operation_id].append((item.parent_id, item.child_id))
def get_successor_for(
self,
parent_cst: int,
operation: int,
ignore_substitution: bool = False
) -> Optional[int]:
''' Get child for parent inside target RSFrom. '''
if not ignore_substitution:
for sub in self.substitutions:
if sub.operation_id == operation and sub.original_id == parent_cst:
return sub.substitution_id
for item in self.inheritance[operation]:
if item[0] == parent_cst:
return item[1]
return None
def insert_inheritance(self, inheritance: Inheritance) -> None:
''' Insert new inheritance. '''
self.inheritance[inheritance.operation_id].append((inheritance.parent_id, inheritance.child_id))
def remove_cst(self, target: list[int], operation: int) -> None:
''' Remove constituents from operation. '''
subs = [sub for sub in self.substitutions if sub.original_id in target or sub.substitution_id in target]
for sub in subs:
self.substitutions.remove(sub)
to_delete = [item for item in self.inheritance[operation] if item[1] in target]
for item in to_delete:
self.inheritance[operation].remove(item)
def _insert_new(self, schema: RSForm) -> None:
self._schemas.append(schema)
self._schema_by_id[schema.model.pk] = schema
def __init__(self, model: LibraryItem):
self.oss = OperationSchema(model)
self.cache = ChangeManager.Cache(self.oss)
self.cache = OssCache(self.oss)
def after_create_cst(self, cst_list: list[Constituenta], source: RSForm) -> None:
''' Trigger cascade resolutions when new constituent is created. '''
@ -159,6 +72,33 @@ class ChangeManager:
operation = self.cache.get_operation(source)
self._cascade_before_delete(target, operation)
def before_substitute(self, substitutions: CstSubstitution, source: RSForm) -> None:
''' Trigger cascade resolutions before constituents are substituted. '''
self.cache.insert(source)
operation = self.cache.get_operation(source)
self._cascade_before_substitute(substitutions, operation)
def _cascade_before_substitute(
self,
substitutions: CstSubstitution,
operation: Operation
) -> None:
children = self.cache.graph.outputs[operation.pk]
if len(children) == 0:
return
self.cache.ensure_loaded()
for child_id in children:
child_operation = self.cache.operation_by_id[child_id]
child_schema = self.cache.get_schema(child_operation)
if child_schema is None:
continue
child_schema.cache.ensure_loaded()
new_substitutions = self._transform_substitutions(substitutions, child_operation, child_schema)
if len(new_substitutions) == 0:
continue
self._cascade_before_substitute(new_substitutions, child_operation)
child_schema.substitute(new_substitutions)
def _cascade_create_cst(self, cst_list: list[Constituenta], operation: Operation, mapping: CstMapping) -> None:
children = self.cache.graph.outputs[operation.pk]
if len(children) == 0:
@ -195,7 +135,7 @@ class ChangeManager:
self.cache.ensure_loaded()
for child_id in children:
child_operation = self.cache.operation_by_id[child_id]
successor_id = self.cache.get_successor_for(cst_id, child_id, ignore_substitution=True)
successor_id = self.cache.get_inheritor(cst_id, child_id)
if successor_id is None:
continue
child_schema = self.cache.get_schema(child_operation)
@ -215,7 +155,7 @@ class ChangeManager:
self.cache.ensure_loaded()
for child_id in children:
child_operation = self.cache.operation_by_id[child_id]
successor_id = self.cache.get_successor_for(cst_id, child_id, ignore_substitution=True)
successor_id = self.cache.get_inheritor(cst_id, child_id)
if successor_id is None:
continue
child_schema = self.cache.get_schema(child_operation)
@ -251,7 +191,7 @@ class ChangeManager:
child_target_cst = []
child_target_ids = []
for cst in target:
successor_id = self.cache.get_successor_for(cst.pk, child_id, ignore_substitution=True)
successor_id = self.cache.get_inheritor(cst.pk, child_id)
if successor_id is not None:
child_target_ids.append(successor_id)
child_target_cst.append(child_schema.cache.by_id[successor_id])
@ -264,7 +204,7 @@ class ChangeManager:
return mapping
result: CstMapping = {}
for alias, cst in mapping.items():
successor_id = self.cache.get_successor_for(cst.pk, operation.pk)
successor_id = self.cache.get_successor(cst.pk, operation.pk)
if successor_id is None:
continue
successor = schema.cache.by_id.get(successor_id)
@ -283,8 +223,7 @@ class ChangeManager:
if prototype.order == 1:
return 1
prev_cst = source.cache.constituents[prototype.order - 2]
inherited_prev_id = self.cache.get_successor_for(
source.cache.constituents[prototype.order - 2].pk, operation.pk)
inherited_prev_id = self.cache.get_successor(prev_cst.pk, operation.pk)
if inherited_prev_id is None:
return INSERT_LAST
prev_cst = destination.cache.by_id[inherited_prev_id]
@ -320,3 +259,142 @@ class ChangeManager:
if replace_entities(old_data['definition_raw'], mapping) == cst.definition_raw:
new_data['definition_raw'] = replace_entities(data['definition_raw'], mapping)
return new_data
def _transform_substitutions(
self,
target: CstSubstitution,
operation: Operation,
schema: RSForm
) -> CstSubstitution:
result: CstSubstitution = []
for current_sub in target:
sub_replaced = False
new_substitution_id = self.cache.get_inheritor(current_sub[1].pk, operation.pk)
if new_substitution_id is None:
for sub in self.cache.substitutions[operation.pk]:
if sub.original_id == current_sub[1].pk:
sub_replaced = True
new_substitution_id = self.cache.get_inheritor(sub.original_id, operation.pk)
break
new_original_id = self.cache.get_inheritor(current_sub[0].pk, operation.pk)
original_replaced = False
if new_original_id is None:
for sub in self.cache.substitutions[operation.pk]:
if sub.original_id == current_sub[0].pk:
original_replaced = True
sub.original_id = current_sub[1].pk
sub.save()
new_original_id = new_substitution_id
new_substitution_id = self.cache.get_inheritor(sub.substitution_id, operation.pk)
break
if sub_replaced and original_replaced:
raise ValidationError({'propagation': 'Substitution breaks OSS substitutions.'})
for sub in self.cache.substitutions[operation.pk]:
if sub.substitution_id == current_sub[0].pk:
sub.substitution_id = current_sub[1].pk
sub.save()
if new_original_id is not None and new_substitution_id is not None:
result.append((schema.cache.by_id[new_original_id], schema.cache.by_id[new_substitution_id]))
return result
class OssCache:
''' Cache for OSS data. '''
def __init__(self, oss: OperationSchema):
self._oss = oss
self._schemas: list[RSForm] = []
self._schema_by_id: dict[int, RSForm] = {}
self.operations = list(oss.operations().only('result_id'))
self.operation_by_id = {operation.pk: operation for operation in self.operations}
self.graph = Graph[int]()
for operation in self.operations:
self.graph.add_node(operation.pk)
for argument in self._oss.arguments().only('operation_id', 'argument_id'):
self.graph.add_edge(argument.argument_id, argument.operation_id)
self.is_loaded = False
self.substitutions: dict[int, list[Substitution]] = {}
self.inheritance: dict[int, list[Inheritance]] = {}
def insert(self, schema: RSForm) -> None:
''' Insert new schema. '''
if not self._schema_by_id.get(schema.model.pk):
self._insert_new(schema)
def get_schema(self, operation: Operation) -> Optional[RSForm]:
''' Get schema by Operation. '''
if operation.result_id is None:
return None
if operation.result_id in self._schema_by_id:
return self._schema_by_id[operation.result_id]
else:
schema = RSForm.from_id(operation.result_id)
schema.cache.ensure_loaded()
self._insert_new(schema)
return schema
def get_operation(self, schema: RSForm) -> Operation:
''' Get operation by schema. '''
for operation in self.operations:
if operation.result_id == schema.model.pk:
return operation
raise ValueError(f'Operation for schema {schema.model.pk} not found')
def ensure_loaded(self) -> None:
''' Ensure propagation of changes. '''
if self.is_loaded:
return
self.is_loaded = True
for operation in self.operations:
if operation.operation_type != OperationType.INPUT:
self.inheritance[operation.pk] = []
self.substitutions[operation.pk] = []
for sub in self._oss.substitutions().only('operation_id', 'original_id', 'substitution_id'):
self.substitutions[sub.operation_id].append(sub)
for item in self._oss.inheritance().only('operation_id', 'parent_id', 'child_id'):
self.inheritance[item.operation_id].append(item)
def get_inheritor(self, parent_cst: int, operation: int) -> Optional[int]:
''' Get child for parent inside target RSFrom. '''
for item in self.inheritance[operation]:
if item.parent_id == parent_cst:
return item.child_id
return None
def get_successor(self, parent_cst: int, operation: int) -> Optional[int]:
''' Get child for parent inside target RSFrom including substitutions. '''
for sub in self.substitutions[operation]:
if sub.original_id == parent_cst:
return self.get_inheritor(sub.substitution_id, operation)
return self.get_inheritor(parent_cst, operation)
def insert_inheritance(self, inheritance: Inheritance) -> None:
''' Insert new inheritance. '''
self.inheritance[inheritance.operation_id].append(inheritance)
def insert_substitution(self, sub: Substitution) -> None:
''' Insert new inheritance. '''
self.substitutions[sub.operation_id].append(sub)
def remove_cst(self, target: list[int], operation: int) -> None:
''' Remove constituents from operation. '''
subs_to_delete = [
sub for sub in self.substitutions[operation]
if sub.original_id in target or sub.substitution_id in target
]
for sub in subs_to_delete:
self.substitutions[operation].remove(sub)
inherit_to_delete = [item for item in self.inheritance[operation] if item.child_id in target]
for item in inherit_to_delete:
self.inheritance[operation].remove(item)
def _insert_new(self, schema: RSForm) -> None:
self._schemas.append(schema)
self._schema_by_id[schema.model.pk] = schema

View File

@ -40,3 +40,10 @@ class PropagationFacade:
hosts = _get_oss_hosts(source.model)
for host in hosts:
ChangeManager(host).before_delete(target, source)
@classmethod
def before_substitute(cls, substitutions: list[tuple[Constituenta, Constituenta]], source: RSForm) -> None:
''' Trigger cascade resolutions before constituents are substituted. '''
hosts = _get_oss_hosts(source.model)
for host in hosts:
ChangeManager(host).before_substitute(substitutions, source)

View File

@ -29,4 +29,4 @@ class Substitution(Model):
verbose_name_plural = 'Таблицы отождествлений'
def __str__(self) -> str:
return f'{self.original} -> {self.substitution}'
return f'{self.substitution} -> {self.original}'

View File

@ -1,3 +1,4 @@
''' Tests. '''
from .s_models import *
from .s_propagation import *
from .s_views import *

View File

@ -52,7 +52,7 @@ class TestSynthesisSubstitution(TestCase):
def test_str(self):
testStr = f'{self.ks1X1} -> {self.ks2X1}'
testStr = f'{self.ks2X1} -> {self.ks1X1}'
self.assertEqual(str(self.substitution), testStr)

View File

@ -0,0 +1,4 @@
''' Tests for REST API OSS propagation. '''
from .t_attributes import *
from .t_constituents import *
from .t_substitutions import *

View File

@ -117,3 +117,18 @@ class TestChangeConstituents(EndpointTester):
self.assertEqual(self.ks3.constituents().count(), 3)
self.assertEqual(self.ks2D1.definition_formal, r'DEL\DEL')
self.assertEqual(inherited_cst.definition_formal, r'DEL\DEL')
@decl_endpoint('/api/rsforms/{schema}/substitute', method='patch')
def test_substitute(self):
d2 = self.ks3.insert_new('D2', cst_type=CstType.TERM, definition_formal=r'X1\X2\X3')
data = {'substitutions': [{
'original': self.ks1X1.pk,
'substitution': self.ks1X2.pk
}]}
self.executeOK(data=data, schema=self.ks1.model.pk)
self.ks1X2.refresh_from_db()
d2.refresh_from_db()
self.assertEqual(self.ks1.constituents().count(), 1)
self.assertEqual(self.ks3.constituents().count(), 4)
self.assertEqual(self.ks1X2.order, 1)
self.assertEqual(d2.definition_formal, r'X2\X2\X3')

View File

@ -0,0 +1,160 @@
''' Testing API: Change substitutions in OSS. '''
from apps.oss.models import OperationSchema, OperationType
from apps.rsform.models import Constituenta, CstType, RSForm
from shared.EndpointTester import EndpointTester, decl_endpoint
class TestChangeSubstitutions(EndpointTester):
''' Testing Substitutions change propagation in OSS. '''
def setUp(self):
super().setUp()
self.owned = OperationSchema.create(
title='Test',
alias='T1',
owner=self.user
)
self.owned_id = self.owned.model.pk
self.ks1 = RSForm.create(
alias='KS1',
title='Test1',
owner=self.user
)
self.ks1X1 = self.ks1.insert_new('X1', convention='KS1X1')
self.ks1X2 = self.ks1.insert_new('X2', convention='KS1X2')
self.ks1D1 = self.ks1.insert_new('D1', definition_formal='X1 X2', convention='KS1D1')
self.ks2 = RSForm.create(
alias='KS2',
title='Test2',
owner=self.user
)
self.ks2X1 = self.ks2.insert_new('X1', convention='KS2X1')
self.ks2X2 = self.ks2.insert_new('X2', convention='KS2X2')
self.ks2S1 = self.ks2.insert_new(
alias='S1',
definition_formal=r'X1',
convention='KS2S1'
)
self.ks3 = RSForm.create(
alias='KS3',
title='Test3',
owner=self.user
)
self.ks3X1 = self.ks3.insert_new('X1', convention='KS3X1')
self.ks3D1 = self.ks3.insert_new(
alias='D1',
definition_formal='X1 X1',
convention='KS3D1'
)
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.INPUT,
result=self.ks3.model
)
self.operation4 = self.owned.create_operation(
alias='4',
operation_type=OperationType.SYNTHESIS
)
self.owned.set_arguments(self.operation4, [self.operation1, self.operation2])
self.owned.set_substitutions(self.operation4, [{
'original': self.ks1X1,
'substitution': self.ks2S1
}])
self.owned.execute_operation(self.operation4)
self.operation4.refresh_from_db()
self.ks4 = RSForm(self.operation4.result)
self.ks4X1 = Constituenta.objects.get(as_child__parent_id=self.ks1X2.pk)
self.ks4S1 = Constituenta.objects.get(as_child__parent_id=self.ks2S1.pk)
self.ks4D1 = Constituenta.objects.get(as_child__parent_id=self.ks1D1.pk)
self.ks4D2 = self.ks4.insert_new(
alias='D2',
definition_formal=r'X1 X2 X3 S1 D1',
convention='KS4D2'
)
self.operation5 = self.owned.create_operation(
alias='5',
operation_type=OperationType.SYNTHESIS
)
self.owned.set_arguments(self.operation5, [self.operation4, self.operation3])
self.owned.set_substitutions(self.operation5, [{
'original': self.ks4X1,
'substitution': self.ks3X1
}])
self.owned.execute_operation(self.operation5)
self.operation5.refresh_from_db()
self.ks5 = RSForm(self.operation5.result)
self.ks5D4 = self.ks5.insert_new(
alias='D4',
definition_formal=r'X1 X2 X3 S1 D1 D2 D3',
convention='KS5D4'
)
def test_oss_setup(self):
self.assertEqual(self.ks1.constituents().count(), 3)
self.assertEqual(self.ks2.constituents().count(), 3)
self.assertEqual(self.ks3.constituents().count(), 2)
self.assertEqual(self.ks4.constituents().count(), 6)
self.assertEqual(self.ks5.constituents().count(), 8)
self.assertEqual(self.ks4D1.definition_formal, 'S1 X1')
@decl_endpoint('/api/rsforms/{schema}/substitute', method='patch')
def test_substitute_original(self):
data = {'substitutions': [{
'original': self.ks1X1.pk,
'substitution': self.ks1X2.pk
}]}
self.executeOK(data=data, schema=self.ks1.model.pk)
self.ks4D1.refresh_from_db()
self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions()
self.assertEqual(subs1_2.count(), 1)
self.assertEqual(subs1_2.first().original, self.ks1X2)
self.assertEqual(subs1_2.first().substitution, self.ks2S1)
subs3_4 = self.operation5.getSubstitutions()
self.assertEqual(subs3_4.count(), 1)
self.assertEqual(subs3_4.first().original, self.ks4S1)
self.assertEqual(subs3_4.first().substitution, self.ks3X1)
self.assertEqual(self.ks4D1.definition_formal, r'S1 S1')
self.assertEqual(self.ks4D2.definition_formal, r'S1 X2 X3 S1 D1')
self.assertEqual(self.ks5D4.definition_formal, r'X1 X2 X3 X1 D1 D2 D3')
@decl_endpoint('/api/rsforms/{schema}/substitute', method='patch')
def test_substitute_substitution(self):
data = {'substitutions': [{
'original': self.ks2S1.pk,
'substitution': self.ks2X1.pk
}]}
self.executeOK(data=data, schema=self.ks2.model.pk)
self.ks4D1.refresh_from_db()
self.ks4D2.refresh_from_db()
self.ks5D4.refresh_from_db()
subs1_2 = self.operation4.getSubstitutions()
self.assertEqual(subs1_2.count(), 1)
self.assertEqual(subs1_2.first().original, self.ks1X1)
self.assertEqual(subs1_2.first().substitution, self.ks2X1)
subs3_4 = self.operation5.getSubstitutions()
self.assertEqual(subs3_4.count(), 1)
self.assertEqual(subs3_4.first().original, self.ks4X1)
self.assertEqual(subs3_4.first().substitution, self.ks3X1)
self.assertEqual(self.ks4D1.definition_formal, r'X2 X1')
self.assertEqual(self.ks4D2.definition_formal, r'X1 X2 X3 X2 D1')
self.assertEqual(self.ks5D4.definition_formal, r'X1 X2 X3 X2 D1 D2 D3')

View File

@ -1,4 +1,2 @@
''' Tests for REST API. '''
from .t_change_attributes import *
from .t_change_constituents import *
from .t_oss import *

View File

@ -236,7 +236,7 @@ class RSForm:
**kwargs
)
self.cache.insert(result)
self.save()
self.save(update_fields=['time_update'])
return result
def insert_copy(self, items: list[Constituenta], position: int = INSERT_LAST,
@ -271,7 +271,7 @@ class RSForm:
new_cst = Constituenta.objects.bulk_create(result)
self.cache.insert_multi(new_cst)
self.save()
self.save(update_fields=['time_update'])
return result
# pylint: disable=too-many-branches
@ -319,7 +319,7 @@ class RSForm:
cst.save()
if term_changed:
self.on_term_change([cst.pk])
self.save()
self.save(update_fields=['time_update'])
return old_data
def move_cst(self, target: list[Constituenta], destination: int) -> None:
@ -345,7 +345,7 @@ class RSForm:
cst.order = destination + size + count_bot
count_bot += 1
Constituenta.objects.bulk_update(cst_list, ['order'])
self.save()
self.save(update_fields=['time_update'])
def delete_cst(self, target: Iterable[Constituenta]) -> None:
''' Delete multiple constituents. Do not check if listCst are from this schema. '''
@ -355,7 +355,7 @@ class RSForm:
self.apply_mapping(mapping)
Constituenta.objects.filter(pk__in=[cst.pk for cst in target]).delete()
self._reset_order()
self.save()
self.save(update_fields=['time_update'])
def substitute(self, substitutions: list[tuple[Constituenta, Constituenta]]) -> None:
''' Execute constituenta substitution. '''
@ -363,12 +363,12 @@ class RSForm:
deleted: list[Constituenta] = []
replacements: list[Constituenta] = []
for original, substitution in substitutions:
assert original.pk != substitution.pk
mapping[original.alias] = substitution.alias
deleted.append(original)
replacements.append(substitution)
self.cache.remove_multi(deleted)
Constituenta.objects.filter(pk__in=[cst.pk for cst in deleted]).delete()
self._reset_order()
self.apply_mapping(mapping)
self.on_term_change([substitution.pk for substitution in replacements])
@ -417,7 +417,7 @@ class RSForm:
if cst.apply_mapping(mapping, change_aliases):
update_list.append(cst)
Constituenta.objects.bulk_update(update_list, ['alias', 'definition_formal', 'term_raw', 'definition_raw'])
self.save()
self.save(update_fields=['time_update'])
def resolve_all_text(self) -> None:
''' Trigger reference resolution for all texts. '''
@ -479,7 +479,7 @@ class RSForm:
position = position + 1
self.cache.insert_multi(result)
self.save()
self.save(update_fields=['time_update'])
return result
def _shift_positions(self, start: int, shift: int) -> None:

View File

@ -194,6 +194,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
cst.cst_type = serializer.validated_data['cst_type']
cst.save()
schema.apply_mapping(mapping=mapping, change_aliases=False)
schema.save()
cst.refresh_from_db()
if changed_type:
PropagationFacade.after_change_cst_type(cst, schema)
@ -232,6 +233,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
original = cast(m.Constituenta, substitution['original'])
replacement = cast(m.Constituenta, substitution['substitution'])
substitutions.append((original, replacement))
PropagationFacade.before_substitute(substitutions, schema)
schema.substitute(substitutions)
return Response(
status=c.HTTP_200_OK,
@ -312,7 +314,8 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr
def reset_aliases(self, request: Request, pk) -> HttpResponse:
''' Endpoint: Recreate all aliases based on order. '''
model = self._get_item()
m.RSForm(model).reset_aliases()
schema = m.RSForm(model)
schema.reset_aliases()
return Response(
status=c.HTTP_200_OK,
data=s.RSFormParseSerializer(model).data

View File

@ -24,6 +24,7 @@ function TextArea({
return (
<div
className={clsx(
'w-full',
{
'flex flex-col gap-2': !dense,
'flex flex-grow items-center gap-3': dense

View File

@ -345,6 +345,8 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
setSchema(newData);
library.localUpdateTimestamp(newData.id);
if (callback) callback();
// TODO: deal with OSS cache invalidation
}
});
},
@ -414,6 +416,8 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
if (callback) callback(newData.new_cst);
// TODO: deal with OSS cache invalidation
}
});
},
@ -432,6 +436,8 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
setSchema(newData);
library.localUpdateTimestamp(newData.id);
if (callback) callback();
// TODO: deal with OSS cache invalidation
}
});
},
@ -450,6 +456,8 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
reload(setProcessing, () => {
library.localUpdateTimestamp(Number(itemID));
if (callback) callback(newData);
// TODO: deal with OSS cache invalidation
})
});
},
@ -467,7 +475,11 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
onSuccess: newData => {
setSchema(newData.schema);
library.localUpdateTimestamp(newData.schema.id);
if (library.globalOSS?.schemas.includes(newData.schema.id)) {
library.reloadOSS(() => {
if (callback) callback(newData.new_cst);
});
} else if (callback) callback(newData.new_cst);
}
});
},
@ -485,7 +497,11 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
onSuccess: newData => {
setSchema(newData);
library.localUpdateTimestamp(newData.id);
if (library.globalOSS?.schemas.includes(newData.id)) {
library.reloadOSS(() => {
if (callback) callback();
});
} else if (callback) callback();
}
});
},
@ -611,6 +627,8 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
setSchema(newData);
library.localUpdateTimestamp(Number(itemID));
if (callback) callback(newData);
// TODO: deal with OSS cache invalidation
}
});
},