From 318fadcc5fcee7b8afb91be976c10fc36dd9ed14 Mon Sep 17 00:00:00 2001 From: Ivan <8611739+IRBorisov@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:35:17 +0300 Subject: [PATCH] F: Add ordering to OSS arguments --- rsconcept/backend/apps/oss/admin.py | 2 +- .../oss/migrations/0007_argument_order.py | 18 + rsconcept/backend/apps/oss/models/Argument.py | 6 +- .../apps/oss/models/OperationSchema.py | 12 +- .../apps/oss/serializers/data_access.py | 2 +- .../apps/oss/tests/s_models/t_Argument.py | 10 + .../backend/apps/oss/tests/s_views/t_oss.py | 8 +- .../0002_alter_constituenta_order.py | 19 + .../apps/rsform/models/Constituenta.py | 2 +- .../rsform/tests/s_models/t_Constituenta.py | 5 - rsconcept/frontend/public/db_schema.svg | 1711 ++++++++--------- .../src/components/info/BadgeWordForm.tsx | 2 +- .../components/select/PickMultiOperation.tsx | 69 +- .../components/select/PickSubstitutions.tsx | 3 +- rsconcept/frontend/src/context/OssContext.tsx | 7 +- .../DlgConstituentaTemplate/TabArguments.tsx | 5 +- .../src/dialogs/DlgEditEditors/TableUsers.tsx | 4 +- .../dialogs/DlgEditVersions/TableVersions.tsx | 4 +- .../DlgEditWordForms/TableWordForms.tsx | 8 +- .../EditorRSFormCard/EditorLibraryItem.tsx | 2 +- 20 files changed, 983 insertions(+), 916 deletions(-) create mode 100644 rsconcept/backend/apps/oss/migrations/0007_argument_order.py create mode 100644 rsconcept/backend/apps/rsform/migrations/0002_alter_constituenta_order.py diff --git a/rsconcept/backend/apps/oss/admin.py b/rsconcept/backend/apps/oss/admin.py index 0dceed05..50c477fc 100644 --- a/rsconcept/backend/apps/oss/admin.py +++ b/rsconcept/backend/apps/oss/admin.py @@ -14,7 +14,7 @@ class OperationAdmin(admin.ModelAdmin): class ArgumentAdmin(admin.ModelAdmin): ''' Admin model: Operation arguments. ''' ordering = ['operation'] - list_display = ['id', 'operation', 'argument'] + list_display = ['id', 'order', 'operation', 'argument'] search_fields = ['id', 'operation', 'argument'] diff --git a/rsconcept/backend/apps/oss/migrations/0007_argument_order.py b/rsconcept/backend/apps/oss/migrations/0007_argument_order.py new file mode 100644 index 00000000..a7a0a399 --- /dev/null +++ b/rsconcept/backend/apps/oss/migrations/0007_argument_order.py @@ -0,0 +1,18 @@ +# Generated by Django 5.1 on 2024-09-04 09:54 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('oss', '0006_alter_operation_oss'), + ] + + operations = [ + migrations.AddField( + model_name='argument', + name='order', + field=models.PositiveIntegerField(default=0, verbose_name='Позиция'), + ), + ] diff --git a/rsconcept/backend/apps/oss/models/Argument.py b/rsconcept/backend/apps/oss/models/Argument.py index e8ac9094..14bd27b7 100644 --- a/rsconcept/backend/apps/oss/models/Argument.py +++ b/rsconcept/backend/apps/oss/models/Argument.py @@ -1,5 +1,5 @@ ''' Models: Operation Argument in OSS. ''' -from django.db.models import CASCADE, ForeignKey, Model +from django.db.models import CASCADE, ForeignKey, Model, PositiveIntegerField class Argument(Model): @@ -16,6 +16,10 @@ class Argument(Model): on_delete=CASCADE, related_name='descendants' ) + order: PositiveIntegerField = PositiveIntegerField( + verbose_name='Позиция', + default=0, + ) class Meta: ''' Model metadata. ''' diff --git a/rsconcept/backend/apps/oss/models/OperationSchema.py b/rsconcept/backend/apps/oss/models/OperationSchema.py index 4b69b324..53629eb5 100644 --- a/rsconcept/backend/apps/oss/models/OperationSchema.py +++ b/rsconcept/backend/apps/oss/models/OperationSchema.py @@ -137,23 +137,27 @@ class OperationSchema: self.cache.ensure_loaded() operation = self.cache.operation_by_id[target] processed: list[Operation] = [] + updated: list[Argument] = [] deleted: list[Argument] = [] for current in operation.getArguments(): if current.argument not in arguments: deleted.append(current) else: processed.append(current.argument) + current.order = arguments.index(current.argument) + updated.append(current) if len(deleted) > 0: self.before_delete_arguments(operation, [x.argument for x in deleted]) for deleted_arg in deleted: self.cache.remove_argument(deleted_arg) Argument.objects.filter(pk__in=[x.pk for x in deleted]).delete() + Argument.objects.bulk_update(updated, ['order']) added: list[Operation] = [] - for arg in arguments: + for order, arg in enumerate(arguments): if arg not in processed: processed.append(arg) - new_arg = Argument.objects.create(operation=operation, argument=arg) + new_arg = Argument.objects.create(operation=operation, argument=arg, order=order) self.cache.insert_argument(new_arg) added.append(arg) if len(added) > 0: @@ -219,7 +223,7 @@ class OperationSchema: def execute_operation(self, operation: Operation) -> bool: ''' Execute target operation. ''' - schemas: list[LibraryItem] = [arg.argument.result for arg in operation.getArguments().order_by('pk')] + schemas: list[LibraryItem] = [arg.argument.result for arg in operation.getArguments().order_by('order')] if None in schemas: return False substitutions = operation.getSubstitutions() @@ -693,7 +697,7 @@ class OssCache: 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'): + for argument in self._oss.arguments().only('operation_id', 'argument_id').order_by('order'): self.graph.add_edge(argument.argument_id, argument.operation_id) self.is_loaded = False diff --git a/rsconcept/backend/apps/oss/serializers/data_access.py b/rsconcept/backend/apps/oss/serializers/data_access.py index 0a02d18a..3ffed473 100644 --- a/rsconcept/backend/apps/oss/serializers/data_access.py +++ b/rsconcept/backend/apps/oss/serializers/data_access.py @@ -210,7 +210,7 @@ class OperationSchemaSerializer(serializers.ModelSerializer): for operation in oss.operations().order_by('pk'): result['items'].append(OperationSerializer(operation).data) result['arguments'] = [] - for argument in oss.arguments().order_by('pk'): + for argument in oss.arguments().order_by('order'): result['arguments'].append(ArgumentSerializer(argument).data) result['substitutions'] = [] for substitution in oss.substitutions().values( diff --git a/rsconcept/backend/apps/oss/tests/s_models/t_Argument.py b/rsconcept/backend/apps/oss/tests/s_models/t_Argument.py index 43b36c70..0b48dd91 100644 --- a/rsconcept/backend/apps/oss/tests/s_models/t_Argument.py +++ b/rsconcept/backend/apps/oss/tests/s_models/t_Argument.py @@ -1,4 +1,5 @@ ''' Testing models: Argument. ''' +from django.db.utils import IntegrityError from django.test import TestCase from apps.oss.models import Argument, Operation, OperationSchema, OperationType @@ -36,6 +37,15 @@ class TestArgument(TestCase): self.assertEqual(str(self.argument), testStr) + def test_order_positive_integer(self): + with self.assertRaises(IntegrityError): + Argument.objects.create( + operation=self.operation2, + argument=self.operation3, + order=-1 + ) + + def test_cascade_delete_operation(self): self.assertEqual(Argument.objects.count(), 1) self.operation2.delete() diff --git a/rsconcept/backend/apps/oss/tests/s_views/t_oss.py b/rsconcept/backend/apps/oss/tests/s_views/t_oss.py index ba52d035..e39dc221 100644 --- a/rsconcept/backend/apps/oss/tests/s_views/t_oss.py +++ b/rsconcept/backend/apps/oss/tests/s_views/t_oss.py @@ -387,7 +387,7 @@ class TestOssViewset(EndpointTester): 'comment': 'Comment mod' }, 'positions': [], - 'arguments': [self.operation1.pk, self.operation2.pk], + 'arguments': [self.operation2.pk, self.operation1.pk], 'substitutions': [ { 'original': self.ks1X1.pk, @@ -409,7 +409,11 @@ class TestOssViewset(EndpointTester): self.assertEqual(self.operation3.alias, data['item_data']['alias']) self.assertEqual(self.operation3.title, data['item_data']['title']) self.assertEqual(self.operation3.comment, data['item_data']['comment']) - self.assertEqual(set([argument.pk for argument in self.operation3.getArguments()]), set(data['arguments'])) + args = self.operation3.getArguments().order_by('order') + self.assertEqual(args[0].argument.pk, data['arguments'][0]) + self.assertEqual(args[0].order, 0) + self.assertEqual(args[1].argument.pk, data['arguments'][1]) + self.assertEqual(args[1].order, 1) sub = self.operation3.getSubstitutions()[0] self.assertEqual(sub.original.pk, data['substitutions'][0]['original']) self.assertEqual(sub.substitution.pk, data['substitutions'][0]['substitution']) diff --git a/rsconcept/backend/apps/rsform/migrations/0002_alter_constituenta_order.py b/rsconcept/backend/apps/rsform/migrations/0002_alter_constituenta_order.py new file mode 100644 index 00000000..0aefc446 --- /dev/null +++ b/rsconcept/backend/apps/rsform/migrations/0002_alter_constituenta_order.py @@ -0,0 +1,19 @@ +# Generated by Django 5.1 on 2024-09-04 09:56 + +import django.core.validators +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('rsform', '0001_initial'), + ] + + operations = [ + migrations.AlterField( + model_name='constituenta', + name='order', + field=models.PositiveIntegerField(default=1, validators=[django.core.validators.MinValueValidator(1)], verbose_name='Позиция'), + ), + ] diff --git a/rsconcept/backend/apps/rsform/models/Constituenta.py b/rsconcept/backend/apps/rsform/models/Constituenta.py index 6ea896f2..f84310b9 100644 --- a/rsconcept/backend/apps/rsform/models/Constituenta.py +++ b/rsconcept/backend/apps/rsform/models/Constituenta.py @@ -58,7 +58,7 @@ class Constituenta(Model): order: PositiveIntegerField = PositiveIntegerField( verbose_name='Позиция', validators=[MinValueValidator(1)], - default=-1, + default=1, ) alias: CharField = CharField( verbose_name='Имя', diff --git a/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py b/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py index 4f817542..d6d5687e 100644 --- a/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py +++ b/rsconcept/backend/apps/rsform/tests/s_models/t_Constituenta.py @@ -20,11 +20,6 @@ class TestConstituenta(TestCase): self.assertEqual(str(cst), testStr) - def test_order_not_null(self): - with self.assertRaises(IntegrityError): - Constituenta.objects.create(alias='X1', schema=self.schema1.model) - - def test_order_positive_integer(self): with self.assertRaises(IntegrityError): Constituenta.objects.create(alias='X1', schema=self.schema1.model, order=-1) diff --git a/rsconcept/frontend/public/db_schema.svg b/rsconcept/frontend/public/db_schema.svg index 4e8af053..ea053349 100644 --- a/rsconcept/frontend/public/db_schema.svg +++ b/rsconcept/frontend/public/db_schema.svg @@ -1,16 +1,16 @@ + --> model_graph - + cluster_django_contrib_auth - -           -           -django.contrib.auth -           -           + +           +           +django.contrib.auth +           +           cluster_django_contrib_admin @@ -23,57 +23,57 @@ cluster_django_contrib_contenttypes - -           -           -django.contrib.contenttypes -           -           + +           +           +django.contrib.contenttypes +           +           cluster_django_contrib_sessions - -           -           -django.contrib.sessions -           -           + +           +           +django.contrib.sessions +           +           cluster_django_rest_passwordreset - -           -           -django_rest_passwordreset -           -           + +           +           +django_rest_passwordreset +           +           cluster_apps_library - -           -           -apps.library -           -           + +           +           +apps.library +           +           cluster_apps_rsform - -           -           -apps.rsform -           -           + +           +           +apps.rsform +           +           cluster_apps_oss - -           -           -apps.oss -           -           + +           +           +apps.oss +           +           @@ -135,1001 +135,966 @@ django_contrib_auth_models_User - - -       -      User -< -AbstractUser ->       -       -id -       -       -AutoField -       -       -date_joined -       -       -DateTimeField -       -       -email -       -       -EmailField -       -       -first_name -       -       -CharField -       -       -is_active -       -       -BooleanField -       -       -is_staff -       -       -BooleanField -       -       -is_superuser -       -       -BooleanField -       -       -last_login -       -       -DateTimeField -       -       -last_name -       -       -CharField -       -       -password -       -       -CharField -       -       -username -       -       -CharField -       - + + +       +      User +< +AbstractUser +>       +       +id +       +       +AutoField +       +       +date_joined +       +       +DateTimeField +       +       +email +       +       +EmailField +       +       +first_name +       +       +CharField +       +       +is_active +       +       +BooleanField +       +       +is_staff +       +       +BooleanField +       +       +is_superuser +       +       +BooleanField +       +       +last_login +       +       +DateTimeField +       +       +last_name +       +       +CharField +       +       +password +       +       +CharField +       +       +username +       +       +CharField +       + django_contrib_admin_models_LogEntry->django_contrib_auth_models_User - - - user (logentry) + + + user (logentry) django_contrib_contenttypes_models_ContentType - - -       -      ContentType       -       -id -       -       -AutoField -       -       -app_label -       -       -CharField -       -       -model -       -       -CharField -       - + + +       +      ContentType       +       +id +       +       +AutoField +       +       +app_label +       +       +CharField +       +       +model +       +       +CharField +       + django_contrib_admin_models_LogEntry->django_contrib_contenttypes_models_ContentType - - - content_type (logentry) + + + content_type (logentry) django_contrib_auth_models_AbstractUser - - -       -      AbstractUser -< -AbstractBaseUser,PermissionsMixin ->       -       -date_joined -       -       -DateTimeField -       -       -email -       -       -EmailField -       -       -first_name -       -       -CharField -       -       -is_active -       -       -BooleanField -       -       -is_staff -       -       -BooleanField -       -       -is_superuser -       -       -BooleanField -       -       -last_login -       -       -DateTimeField -       -       -last_name -       -       -CharField -       -       -password -       -       -CharField -       -       -username -       -       -CharField -       - + + +       +      AbstractUser +< +AbstractBaseUser,PermissionsMixin +>       +       +date_joined +       +       +DateTimeField +       +       +email +       +       +EmailField +       +       +first_name +       +       +CharField +       +       +is_active +       +       +BooleanField +       +       +is_staff +       +       +BooleanField +       +       +is_superuser +       +       +BooleanField +       +       +last_login +       +       +DateTimeField +       +       +last_name +       +       +CharField +       +       +password +       +       +CharField +       +       +username +       +       +CharField +       + - + django_contrib_auth_base_user_AbstractBaseUser - - -   -AbstractBaseUser -   + + +   +AbstractBaseUser +   django_contrib_auth_models_AbstractUser->django_contrib_auth_base_user_AbstractBaseUser - - - abstract -inheritance + + + abstract +inheritance - + django_contrib_auth_models_PermissionsMixin - - -   -PermissionsMixin -   + + +   +PermissionsMixin +   django_contrib_auth_models_AbstractUser->django_contrib_auth_models_PermissionsMixin - - - abstract -inheritance + + + abstract +inheritance django_contrib_auth_models_Permission - - -       -      Permission       -       -id -       -       -AutoField -       -       -content_type -       -       -ForeignKey (id) -       -       -codename -       -       -CharField -       -       -name -       -       -CharField -       - + + +       +      Permission       +       +id +       +       +AutoField +       +       +content_type +       +       +ForeignKey (id) +       +       +codename +       +       +CharField +       +       +name +       +       +CharField +       + django_contrib_auth_models_Permission->django_contrib_contenttypes_models_ContentType - - - content_type (permission) + + + content_type (permission) django_contrib_auth_models_Group - - -       -      Group       -       -id -       -       -AutoField -       -       -name -       -       -CharField -       - + + +       +      Group       +       +id +       +       +AutoField +       +       +name +       +       +CharField +       + django_contrib_auth_models_Group->django_contrib_auth_models_Permission - - - - permissions (group) + + + + permissions (group) django_contrib_auth_models_User->django_contrib_auth_models_AbstractUser - - - abstract -inheritance + + + abstract +inheritance django_contrib_auth_models_User->django_contrib_auth_models_Permission - - - - user_permissions (user) + + + + user_permissions (user) django_contrib_auth_models_User->django_contrib_auth_models_Group - - - - groups (user) + + + + groups (user) django_contrib_sessions_base_session_AbstractBaseSession - - -       -      AbstractBaseSession       -       -expire_date -       -       -DateTimeField -       -       -session_data -       -       -TextField -       - + + +       +      AbstractBaseSession       +       +expire_date +       +       +DateTimeField +       +       +session_data +       +       +TextField +       + django_contrib_sessions_models_Session - - -       -      Session -< -AbstractBaseSession ->       -       -session_key -       -       -CharField -       -       -expire_date -       -       -DateTimeField -       -       -session_data -       -       -TextField -       - + + +       +      Session +< +AbstractBaseSession +>       +       +session_key +       +       +CharField +       +       +expire_date +       +       +DateTimeField +       +       +session_data +       +       +TextField +       + django_contrib_sessions_models_Session->django_contrib_sessions_base_session_AbstractBaseSession - - - abstract -inheritance + + + abstract +inheritance django_rest_passwordreset_models_ResetPasswordToken - - -       -      ResetPasswordToken       -       -id -       -       -AutoField -       -       -user -       -       -ForeignKey (id) -       -       -created_at -       -       -DateTimeField -       -       -ip_address -       -       -GenericIPAddressField -       -       -key -       -       -CharField -       -       -user_agent -       -       -CharField -       - + + +       +      ResetPasswordToken       +       +id +       +       +AutoField +       +       +user +       +       +ForeignKey (id) +       +       +created_at +       +       +DateTimeField +       +       +ip_address +       +       +GenericIPAddressField +       +       +key +       +       +CharField +       +       +user_agent +       +       +CharField +       + django_rest_passwordreset_models_ResetPasswordToken->django_contrib_auth_models_User - - - user (password_reset_tokens) + + + user (password_reset_tokens) apps_library_models_Editor_Editor - - -       -      Editor       -       -id -       -       -BigAutoField -       -       -editor -       -       -ForeignKey (id) -       -       -item -       -       -ForeignKey (id) -       -       -time_create -       -       -DateTimeField -       - + + +       +      Editor       +       +id +       +       +BigAutoField +       +       +editor +       +       +ForeignKey (id) +       +       +item +       +       +ForeignKey (id) +       +       +time_create +       +       +DateTimeField +       + apps_library_models_Editor_Editor->django_contrib_auth_models_User - - - editor (editor) + + + editor (editor) - + apps_library_models_LibraryItem_LibraryItem - - -       -      LibraryItem       + + +       +      LibraryItem       +       +id +             -id -       -       -BigAutoField -       -       -owner -       -       -ForeignKey (id) -       -       -access_policy -       -       -CharField -       +BigAutoField +       +       +owner +       +       +ForeignKey (id) +       +       +access_policy +       +       +CharField +       +       +alias +             -alias -       -       -CharField -       +CharField +       +       +comment +             -comment -       -       -TextField -       +TextField +       +       +item_type +             -item_type -       -       -CharField -       +CharField +       +       +location +             -location -       -       -TextField -       +TextField +       +       +read_only +             -read_only -       -       -BooleanField -       +BooleanField +       +       +time_create +             -time_create -       -       -DateTimeField -       +DateTimeField +       +       +time_update +             -time_update -       -       -DateTimeField -       +DateTimeField +       +       +title +             -title -       -       -TextField -       +TextField +       +       +visible +             -visible -       -       -BooleanField -       - +BooleanField +       + apps_library_models_Editor_Editor->apps_library_models_LibraryItem_LibraryItem - - - item (editor) - - - -apps_library_models_Subscription_Subscription - - -       -      Subscription       -       -id -       -       -BigAutoField -       -       -item -       -       -ForeignKey (id) -       -       -user -       -       -ForeignKey (id) -       - - - - -apps_library_models_Subscription_Subscription->django_contrib_auth_models_User - - - user (subscription) - - - -apps_library_models_Subscription_Subscription->apps_library_models_LibraryItem_LibraryItem - - - item (subscription) + + + item (editor) - + apps_library_models_Version_Version - - -       -      Version       -       -id -       -       -BigAutoField -       -       -item -       -       -ForeignKey (id) -       -       -data -       -       -JSONField -       -       -description -       -       -TextField -       -       -time_create -       -       -DateTimeField -       -       -version -       -       -CharField -       - + + +       +      Version       +       +id +       +       +BigAutoField +       +       +item +       +       +ForeignKey (id) +       +       +data +       +       +JSONField +       +       +description +       +       +TextField +       +       +time_create +       +       +DateTimeField +       +       +version +       +       +CharField +       + - + apps_library_models_Version_Version->apps_library_models_LibraryItem_LibraryItem - - - item (version) + + + item (version) - + apps_library_models_LibraryItem_LibraryItem->django_contrib_auth_models_User - - - owner (libraryitem) + + + owner (libraryitem) - + apps_library_models_LibraryTemplate_LibraryTemplate - - -       -      LibraryTemplate       -       -id -       -       -BigAutoField -       -       -lib_source -       -       -ForeignKey (id) -       - + + +       +      LibraryTemplate       +       +id +       +       +BigAutoField +       +       +lib_source +       +       +ForeignKey (id) +       + - + apps_library_models_LibraryTemplate_LibraryTemplate->apps_library_models_LibraryItem_LibraryItem - - - lib_source (librarytemplate) + + + lib_source (librarytemplate) - + apps_rsform_models_Constituenta_Constituenta - - -       -      Constituenta       -       -id -       -       -BigAutoField -       -       -schema -       -       -ForeignKey (id) -       -       -alias -       -       -CharField -       -       -convention -       -       -TextField -       -       -cst_type -       -       -CharField -       -       -definition_formal -       -       -TextField -       -       -definition_raw -       -       -TextField -       -       -definition_resolved -       -       -TextField -       -       -order -       -       -PositiveIntegerField -       -       -term_forms -       -       -JSONField -       -       -term_raw -       -       -TextField -       -       -term_resolved -       -       -TextField -       - + + +       +      Constituenta       +       +id +       +       +BigAutoField +       +       +schema +       +       +ForeignKey (id) +       +       +alias +       +       +CharField +       +       +convention +       +       +TextField +       +       +cst_type +       +       +CharField +       +       +definition_formal +       +       +TextField +       +       +definition_raw +       +       +TextField +       +       +definition_resolved +       +       +TextField +       +       +order +       +       +PositiveIntegerField +       +       +term_forms +       +       +JSONField +       +       +term_raw +       +       +TextField +       +       +term_resolved +       +       +TextField +       + - + apps_rsform_models_Constituenta_Constituenta->apps_library_models_LibraryItem_LibraryItem - - - schema (constituenta) + + + schema (constituenta) - + apps_oss_models_Argument_Argument - - -       -      Argument       -       -id -       -       -BigAutoField -       -       -argument -       -       -ForeignKey (id) -       -       -operation -       -       -ForeignKey (id) -       - + + +       +      Argument       +       +id +       +       +BigAutoField +       +       +argument +       +       +ForeignKey (id) +       +       +operation +       +       +ForeignKey (id) +       +       +order +       +       +PositiveIntegerField +       + - + apps_oss_models_Operation_Operation - - -       -      Operation       -       -id -       -       -BigAutoField -       -       -oss -       -       -ForeignKey (id) -       -       -result -       -       -ForeignKey (id) -       -       -alias -       -       -CharField -       -       -comment -       -       -TextField -       -       -operation_type -       -       -CharField -       -       -position_x -       -       -FloatField -       -       -position_y -       -       -FloatField -       -       -title -       -       -TextField -       - + + +       +      Operation       +       +id +       +       +BigAutoField +       +       +oss +       +       +ForeignKey (id) +       +       +result +       +       +ForeignKey (id) +       +       +alias +       +       +CharField +       +       +comment +       +       +TextField +       +       +operation_type +       +       +CharField +       +       +position_x +       +       +FloatField +       +       +position_y +       +       +FloatField +       +       +title +       +       +TextField +       + - + apps_oss_models_Argument_Argument->apps_oss_models_Operation_Operation - - - operation (arguments) + + + operation (arguments) - + apps_oss_models_Argument_Argument->apps_oss_models_Operation_Operation - - - argument (descendants) + + + argument (descendants) - + apps_oss_models_Inheritance_Inheritance - - -       -      Inheritance       -       -id -       -       -BigAutoField -       -       -child -       -       -ForeignKey (id) -       -       -operation -       -       -ForeignKey (id) -       -       -parent -       -       -ForeignKey (id) -       - + + +       +      Inheritance       +       +id +       +       +BigAutoField +       +       +child +       +       +ForeignKey (id) +       +       +operation +       +       +ForeignKey (id) +       +       +parent +       +       +ForeignKey (id) +       + - + apps_oss_models_Inheritance_Inheritance->apps_rsform_models_Constituenta_Constituenta - - - parent (as_parent) + + + parent (as_parent) - + apps_oss_models_Inheritance_Inheritance->apps_rsform_models_Constituenta_Constituenta - - - child (as_child) + + + child (as_child) - + apps_oss_models_Inheritance_Inheritance->apps_oss_models_Operation_Operation - - - operation (inheritances) + + + operation (inheritances) - + apps_oss_models_Substitution_Substitution - - -       -      Substitution       -       -id -       -       -BigAutoField -       -       -operation -       -       -ForeignKey (id) -       -       -original -       -       -ForeignKey (id) -       -       -substitution -       -       -ForeignKey (id) -       - + + +       +      Substitution       +       +id +       +       +BigAutoField +       +       +operation +       +       +ForeignKey (id) +       +       +original +       +       +ForeignKey (id) +       +       +substitution +       +       +ForeignKey (id) +       + - + apps_oss_models_Substitution_Substitution->apps_rsform_models_Constituenta_Constituenta - - - original (as_original) + + + original (as_original) - + apps_oss_models_Substitution_Substitution->apps_rsform_models_Constituenta_Constituenta - - - substitution (as_substitute) + + + substitution (as_substitute) - + apps_oss_models_Substitution_Substitution->apps_oss_models_Operation_Operation - - - operation (substitution) + + + operation (substitution) - + apps_oss_models_Operation_Operation->apps_library_models_LibraryItem_LibraryItem - - - oss (items) + + + oss (operations) - + apps_oss_models_Operation_Operation->apps_library_models_LibraryItem_LibraryItem - - - result (producer) + + + result (producer) \ No newline at end of file diff --git a/rsconcept/frontend/src/components/info/BadgeWordForm.tsx b/rsconcept/frontend/src/components/info/BadgeWordForm.tsx index 546eeb06..efe36fb7 100644 --- a/rsconcept/frontend/src/components/info/BadgeWordForm.tsx +++ b/rsconcept/frontend/src/components/info/BadgeWordForm.tsx @@ -9,7 +9,7 @@ interface BadgeWordFormProps { function BadgeWordForm({ keyPrefix, form }: BadgeWordFormProps) { return ( -
+
{form.grams.map(gram => ( ))} diff --git a/rsconcept/frontend/src/components/select/PickMultiOperation.tsx b/rsconcept/frontend/src/components/select/PickMultiOperation.tsx index 75365a48..6461726f 100644 --- a/rsconcept/frontend/src/components/select/PickMultiOperation.tsx +++ b/rsconcept/frontend/src/components/select/PickMultiOperation.tsx @@ -2,7 +2,7 @@ import { useCallback, useMemo, useState } from 'react'; -import { IconRemove } from '@/components/Icons'; +import { IconMoveDown, IconMoveUp, IconRemove } from '@/components/Icons'; import SelectOperation from '@/components/select/SelectOperation'; import DataTable, { createColumnHelper } from '@/components/ui/DataTable'; import MiniButton from '@/components/ui/MiniButton'; @@ -20,7 +20,10 @@ interface PickMultiOperationProps { const columnHelper = createColumnHelper(); function PickMultiOperation({ rows, items, selected, setSelected }: PickMultiOperationProps) { - const selectedItems = useMemo(() => items.filter(item => selected.includes(item.id)), [items, selected]); + const selectedItems = useMemo( + () => selected.map(itemID => items.find(item => item.id === itemID)!), + [items, selected] + ); const nonSelectedItems = useMemo(() => items.filter(item => !selected.includes(item.id)), [items, selected]); const [lastSelected, setLastSelected] = useState(undefined); @@ -40,6 +43,36 @@ function PickMultiOperation({ rows, items, selected, setSelected }: PickMultiOpe [setSelected] ); + const handleMoveUp = useCallback( + (operation: OperationID) => { + const index = selected.indexOf(operation); + if (index > 0) { + setSelected(prev => { + const newSelected = [...prev]; + newSelected[index] = newSelected[index - 1]; + newSelected[index - 1] = operation; + return newSelected; + }); + } + }, + [setSelected, selected] + ); + + const handleMoveDown = useCallback( + (operation: OperationID) => { + const index = selected.indexOf(operation); + if (index < selected.length - 1) { + setSelected(prev => { + const newSelected = [...prev]; + newSelected[index] = newSelected[index + 1]; + newSelected[index + 1] = operation; + return newSelected; + }); + } + }, + [setSelected, selected] + ); + const columns = useMemo( () => [ columnHelper.accessor('alias', { @@ -59,17 +92,35 @@ function PickMultiOperation({ rows, items, selected, setSelected }: PickMultiOpe }), columnHelper.display({ id: 'actions', + size: 0, cell: props => ( - } - onClick={() => handleDelete(props.row.original.id)} - /> +
+ } + onClick={() => handleDelete(props.row.original.id)} + /> + } + onClick={() => handleMoveUp(props.row.original.id)} + /> + } + onClick={() => handleMoveDown(props.row.original.id)} + /> +
) }) ], - [handleDelete] + [handleDelete, handleMoveUp, handleMoveDown] ); return ( diff --git a/rsconcept/frontend/src/components/select/PickSubstitutions.tsx b/rsconcept/frontend/src/components/select/PickSubstitutions.tsx index 627e81aa..8039896b 100644 --- a/rsconcept/frontend/src/components/select/PickSubstitutions.tsx +++ b/rsconcept/frontend/src/components/select/PickSubstitutions.tsx @@ -187,7 +187,7 @@ function PickSubstitutions({ }), columnHelper.display({ id: 'status', - size: 40, + size: 0, cell: () => }), columnHelper.accessor(item => item.original.alias, { @@ -204,6 +204,7 @@ function PickSubstitutions({ }), columnHelper.display({ id: 'actions', + size: 0, cell: props => props.row.original.is_suggestion ? (
diff --git a/rsconcept/frontend/src/context/OssContext.tsx b/rsconcept/frontend/src/context/OssContext.tsx index f5a6c3b6..0c4d7584 100644 --- a/rsconcept/frontend/src/context/OssContext.tsx +++ b/rsconcept/frontend/src/context/OssContext.tsx @@ -260,12 +260,13 @@ export const OssState = ({ itemID, children }: OssStateProps) => { onError: setProcessingError, onSuccess: newData => { oss.setData(newData); - library.localUpdateTimestamp(newData.id); - if (callback) callback(); + library.reloadItems(() => { + if (callback) callback(); + }); } }); }, - [itemID, library.localUpdateTimestamp, oss.setData] + [itemID, library.reloadItems, oss.setData] ); const createInput = useCallback( diff --git a/rsconcept/frontend/src/dialogs/DlgConstituentaTemplate/TabArguments.tsx b/rsconcept/frontend/src/dialogs/DlgConstituentaTemplate/TabArguments.tsx index 582af1d2..6a10cdcb 100644 --- a/rsconcept/frontend/src/dialogs/DlgConstituentaTemplate/TabArguments.tsx +++ b/rsconcept/frontend/src/dialogs/DlgConstituentaTemplate/TabArguments.tsx @@ -117,6 +117,7 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) { }), argumentsHelper.display({ id: 'actions', + size: 0, cell: props => (
{props.row.original.value ? ( @@ -190,7 +191,7 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) { title='Подставить значение аргумента' noHover className='py-0' - icon={} + icon={} disabled={!argumentValue || !selectedArgument} onClick={() => handleAssignArgument(selectedArgument!, argumentValue)} /> @@ -200,7 +201,7 @@ function TabArguments({ state, schema, partialUpdate }: TabArgumentsProps) { className='py-0' disabled={!isModified} onClick={handleReset} - icon={} + icon={} />
diff --git a/rsconcept/frontend/src/dialogs/DlgEditEditors/TableUsers.tsx b/rsconcept/frontend/src/dialogs/DlgEditEditors/TableUsers.tsx index 338db89b..e3d9fb7d 100644 --- a/rsconcept/frontend/src/dialogs/DlgEditEditors/TableUsers.tsx +++ b/rsconcept/frontend/src/dialogs/DlgEditEditors/TableUsers.tsx @@ -29,9 +29,7 @@ function TableUsers({ items, onDelete }: TableUsersProps) { }), columnHelper.display({ id: 'actions', - size: 50, - minSize: 50, - maxSize: 50, + size: 0, cell: props => (
(
{props.getValue()}
+ cell: props =>
{props.getValue()}
}), columnHelper.accessor('grams', { id: 'grams', - maxSize: 150, + size: 0, cell: props => }), columnHelper.display({ id: 'actions', - size: 50, - minSize: 50, - maxSize: 50, + size: 0, cell: props => (