diff --git a/rsconcept/backend/apps/rsform/serializers/__init__.py b/rsconcept/backend/apps/rsform/serializers/__init__.py index 966c8f86..bc6e198f 100644 --- a/rsconcept/backend/apps/rsform/serializers/__init__.py +++ b/rsconcept/backend/apps/rsform/serializers/__init__.py @@ -12,6 +12,7 @@ from .basics import ( WordFormSerializer ) from .data_access import ( + CrucialUpdateSerializer, CstCreateSerializer, CstInfoSerializer, CstListSerializer, diff --git a/rsconcept/backend/apps/rsform/serializers/data_access.py b/rsconcept/backend/apps/rsform/serializers/data_access.py index a93074a4..e8c04eeb 100644 --- a/rsconcept/backend/apps/rsform/serializers/data_access.py +++ b/rsconcept/backend/apps/rsform/serializers/data_access.py @@ -72,6 +72,24 @@ class CstUpdateSerializer(StrictSerializer): return attrs +class CrucialUpdateSerializer(StrictSerializer): + ''' Serializer: update crucial status. ''' + target = PKField( + many=True, + queryset=Constituenta.objects.all().only('crucial', 'schema_id') + ) + value = serializers.BooleanField() + + def validate(self, attrs): + schema = cast(LibraryItem, self.context['schema']) + for cst in attrs['target']: + if schema and cst.schema_id != schema.pk: + raise serializers.ValidationError({ + f'{cst.pk}': msg.constituentaNotInRSform(schema.title) + }) + return attrs + + class CstDetailsSerializer(StrictModelSerializer): ''' Serializer: Constituenta data including parse. ''' parse = CstParseSerializer() diff --git a/rsconcept/backend/apps/rsform/tests/s_views/t_rsforms.py b/rsconcept/backend/apps/rsform/tests/s_views/t_rsforms.py index bd1a983e..6c68f8aa 100644 --- a/rsconcept/backend/apps/rsform/tests/s_views/t_rsforms.py +++ b/rsconcept/backend/apps/rsform/tests/s_views/t_rsforms.py @@ -578,6 +578,19 @@ class TestConstituentaAPI(EndpointTester): self.assertEqual(self.cst3.definition_resolved, 'form1') self.assertEqual(self.cst3.term_forms, data['item_data']['term_forms']) + @decl_endpoint('/api/rsforms/{schema}/update-crucial', method='patch') + def test_update_crucial(self): + data = {'target': [self.cst1.pk], 'value': True} + self.executeForbidden(data=data, schema=self.unowned_id) + + self.logout() + self.executeForbidden(data=data, schema=self.owned_id) + + self.login() + self.executeOK(data=data, schema=self.owned_id) + self.cst1.refresh_from_db() + self.assertEqual(self.cst1.crucial, True) + class TestInlineSynthesis(EndpointTester): ''' Testing Operations endpoints. ''' diff --git a/rsconcept/backend/apps/rsform/views/rsforms.py b/rsconcept/backend/apps/rsform/views/rsforms.py index 8cf6b726..ef0592ef 100644 --- a/rsconcept/backend/apps/rsform/views/rsforms.py +++ b/rsconcept/backend/apps/rsform/views/rsforms.py @@ -42,6 +42,7 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr 'load_trs', 'create_cst', 'update_cst', + 'update_crucial', 'move_cst', 'delete_multiple_cst', 'substitute', @@ -137,6 +138,36 @@ class RSFormViewSet(viewsets.GenericViewSet, generics.ListAPIView, generics.Retr data=s.RSFormParseSerializer(schema.model).data ) + @extend_schema( + summary='update crucial attributes of a given list of constituents', + tags=['RSForm'], + request=s.CrucialUpdateSerializer, + responses={ + c.HTTP_200_OK: s.RSFormParseSerializer, + c.HTTP_400_BAD_REQUEST: None, + c.HTTP_403_FORBIDDEN: None, + c.HTTP_404_NOT_FOUND: None + } + ) + @action(detail=True, methods=['patch'], url_path='update-crucial') + def update_crucial(self, request: Request, pk) -> HttpResponse: + ''' Update crucial attributes of a given list of constituents. ''' + model = self._get_item() + serializer = s.CrucialUpdateSerializer(data=request.data, partial=True, context={'schema': model}) + serializer.is_valid(raise_exception=True) + value: bool = serializer.validated_data['value'] + + with transaction.atomic(): + for cst in serializer.validated_data['target']: + cst.crucial = value + cst.save(update_fields=['crucial']) + model.save(update_fields=['time_update']) + + return Response( + status=c.HTTP_200_OK, + data=s.RSFormParseSerializer(model).data + ) + @extend_schema( summary='produce the structure of a given constituenta', tags=['RSForm'], diff --git a/rsconcept/frontend/src/components/icons.tsx b/rsconcept/frontend/src/components/icons.tsx index f242cc80..a9300ff7 100644 --- a/rsconcept/frontend/src/components/icons.tsx +++ b/rsconcept/frontend/src/components/icons.tsx @@ -106,9 +106,9 @@ export { LuDatabase as IconDatabase } from 'react-icons/lu'; export { LuView as IconDBStructure } from 'react-icons/lu'; export { LuPlaneTakeoff as IconRESTapi } from 'react-icons/lu'; export { LuImage as IconImage } from 'react-icons/lu'; -export { PiFediverseLogo as IconGraphSelection } from 'react-icons/pi'; export { GoVersions as IconVersions } from 'react-icons/go'; export { LuAtSign as IconTerm } from 'react-icons/lu'; +export { MdTaskAlt as IconCrucial } from 'react-icons/md'; export { LuSubscript as IconAlias } from 'react-icons/lu'; export { TbMathFunction as IconFormula } from 'react-icons/tb'; export { BiFontFamily as IconText } from 'react-icons/bi'; @@ -150,9 +150,11 @@ export { GrConnect as IconConnect } from 'react-icons/gr'; export { BiPlayCircle as IconExecute } from 'react-icons/bi'; // ======== Graph UI ======= +export { PiFediverseLogo as IconContextSelection } from 'react-icons/pi'; +export { ImMakeGroup as IconGroupSelection } from 'react-icons/im'; export { BiCollapse as IconGraphCollapse } from 'react-icons/bi'; export { BiExpand as IconGraphExpand } from 'react-icons/bi'; -export { LuMaximize as IconGraphMaximize } from 'react-icons/lu'; +export { TiArrowMaximise as IconGraphMaximize } from 'react-icons/ti'; export { BiGitBranch as IconGraphInputs } from 'react-icons/bi'; export { TbEarScan as IconGraphInverse } from 'react-icons/tb'; export { BiGitMerge as IconGraphOutputs } from 'react-icons/bi'; diff --git a/rsconcept/frontend/src/features/ai/models/prompting-api.ts b/rsconcept/frontend/src/features/ai/models/prompting-api.ts index 792b4d26..3c2eb3be 100644 --- a/rsconcept/frontend/src/features/ai/models/prompting-api.ts +++ b/rsconcept/frontend/src/features/ai/models/prompting-api.ts @@ -40,12 +40,20 @@ export function generateSample(target: string): string { export function varSchema(schema: IRSForm): string { let result = `Название концептуальной схемы: ${schema.title}\n`; result += `[${schema.alias}] Описание: "${schema.description}"\n\n`; - result += 'Понятия:\n'; + result += 'Конституенты:\n'; schema.items.forEach(item => { result += `\n${item.alias} - "${labelCstTypification(item)}" - "${item.term_resolved}" - "${ item.definition_formal }" - "${item.definition_resolved}" - "${item.convention}"`; }); + if (schema.stats.count_crucial > 0) { + result += + '\nКлючевые конституенты: ' + + schema.items + .filter(cst => cst.crucial) + .map(cst => cst.alias) + .join(', '); + } return result; } diff --git a/rsconcept/frontend/src/features/help/items/help-thesaurus.tsx b/rsconcept/frontend/src/features/help/items/help-thesaurus.tsx index 85be08f2..45789313 100644 --- a/rsconcept/frontend/src/features/help/items/help-thesaurus.tsx +++ b/rsconcept/frontend/src/features/help/items/help-thesaurus.tsx @@ -1,6 +1,7 @@ import { IconChild, IconConsolidation, + IconCrucial, IconCstAxiom, IconCstBaseSet, IconCstConstSet, @@ -91,6 +92,11 @@ export function HelpThesaurus() { родоструктурной экспликации являются Термин, Конвенция, Типизация (Структура), Формальное определение, Текстовое определение, Комментарий.
+
+
diff --git a/rsconcept/frontend/src/features/rsform/components/pick-multi-constituenta.tsx b/rsconcept/frontend/src/features/rsform/components/pick-multi-constituenta.tsx
index a0cd840c..6056afef 100644
--- a/rsconcept/frontend/src/features/rsform/components/pick-multi-constituenta.tsx
+++ b/rsconcept/frontend/src/features/rsform/components/pick-multi-constituenta.tsx
@@ -116,7 +116,8 @@ export function PickMultiConstituenta({
const cst = schema.cstByID.get(cstID);
return !!cst && isBasicConcept(cst.cst_type);
}}
- isOwned={cstID => !schema.cstByID.get(cstID)?.is_inherited}
+ isCrucial={cstID => schema.cstByID.get(cstID)?.crucial ?? false}
+ isInherited={cstID => schema.cstByID.get(cstID)?.is_inherited ?? false}
value={value}
onChange={onChange}
className='w-fit'
diff --git a/rsconcept/frontend/src/features/rsform/components/rsform-stats.tsx b/rsconcept/frontend/src/features/rsform/components/rsform-stats.tsx
index f756a623..1b89d0ee 100644
--- a/rsconcept/frontend/src/features/rsform/components/rsform-stats.tsx
+++ b/rsconcept/frontend/src/features/rsform/components/rsform-stats.tsx
@@ -1,6 +1,7 @@
import {
IconChild,
IconConvention,
+ IconCrucial,
IconCstAxiom,
IconCstBaseSet,
IconCstConstSet,
@@ -113,6 +114,12 @@ export function RSFormStats({ className, stats }: RSFormStatsProps) {
value={stats.count_theorem}
/>
+