F: Add schemas coloring option for TermGraph
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-09-14 16:25:39 +03:00
parent d33f3e02b4
commit 0149f98c8b
13 changed files with 125 additions and 16 deletions

View File

@ -126,7 +126,7 @@ class InheritanceDataSerializer(serializers.Serializer):
''' Serializer: inheritance data. '''
child = serializers.IntegerField()
child_source = serializers.IntegerField()
parent = serializers.IntegerField()
parent = serializers.IntegerField() # type: ignore
parent_source = serializers.IntegerField()

View File

@ -4,8 +4,8 @@ import TextURL from '@/components/ui/TextURL';
import Tooltip, { PlacesType } from '@/components/ui/Tooltip';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { HelpTopic } from '@/models/miscellaneous';
import TopicPage from '@/pages/ManualsPage/TopicPage';
import TopicPage from '../../pages/ManualsPage/TopicPage';
import { IconHelp } from '../Icons';
import { CProps } from '../props';

View File

@ -60,10 +60,14 @@ export class RSFormLoader {
}
private inferCstAttributes() {
const parent_schemas = new Map<ConstituentaID, LibraryItemID>();
const schemaByCst = new Map<ConstituentaID, LibraryItemID>();
const parents: LibraryItemID[] = [];
this.schema.inheritance.forEach(item => {
if (item.child_source === this.schema.id) {
parent_schemas.set(item.child, item.parent_source);
schemaByCst.set(item.child, item.parent_source);
if (!parents.includes(item.parent_source)) {
parents.push(item.parent_source);
}
}
});
const inherit_children = new Set(this.schema.inheritance.map(item => item.child));
@ -75,7 +79,8 @@ export class RSFormLoader {
cst.cst_class = inferClass(cst.cst_type, cst.is_template);
cst.spawn = [];
cst.spawn_alias = [];
cst.parent_schema = parent_schemas.get(cst.id);
cst.parent_schema = schemaByCst.get(cst.id);
cst.parent_schema_index = cst.parent_schema ? parents.indexOf(cst.parent_schema) + 1 : 0;
cst.is_inherited = inherit_children.has(cst.id);
cst.has_inherited_children = inherit_parents.has(cst.id);
cst.is_simple_expression = this.inferSimpleExpression(cst);

View File

@ -48,7 +48,7 @@ export interface OssNodeInternal {
/**
* Represents graph node coloring scheme.
*/
export type GraphColoring = 'none' | 'status' | 'type';
export type GraphColoring = 'none' | 'status' | 'type' | 'schemas';
/**
* Represents graph node sizing scheme.

View File

@ -111,6 +111,10 @@ export interface IConstituenta extends IConstituentaData {
/** Indicates if this {@link IConstituenta} has a simple expression. */
is_simple_expression: boolean;
/** Index of {@link LibraryItemID} that contains this cst (or inheritance parent).
* 0 - not inherited, 1 - inherited by 1st schema, 2 - inherited by 2nd schema, etc.
*/
parent_schema_index: number;
/** {@link LibraryItemID} that contains parent of this inherited {@link IConstituenta}. */
parent_schema?: LibraryItemID;
/** Indicates if this {@link IConstituenta} is inherited. */

View File

@ -132,6 +132,7 @@ export function createMockConstituenta(id: ConstituentaID, alias: string, commen
definition_raw: '',
definition_resolved: '',
status: ExpressionStatus.INCORRECT,
parent_schema_index: 0,
is_template: false,
is_inherited: false,
has_inherited_children: false,

View File

@ -261,6 +261,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
const selectors = useMemo(
() => (
<GraphSelectors
schema={controller.schema}
coloring={coloring}
layout={layout}
sizing={sizing}
@ -269,7 +270,7 @@ function EditorTermGraph({ onOpenEdit }: EditorTermGraphProps) {
setSizing={setSizing}
/>
),
[coloring, layout, sizing, handleChangeLayout, setColoring, setSizing]
[coloring, controller.schema, layout, sizing, handleChangeLayout, setColoring, setSizing]
);
const viewHidden = useMemo(
() => (

View File

@ -3,10 +3,14 @@ import { GraphLayout } from '@/components/ui/GraphUI';
import Overlay from '@/components/ui/Overlay';
import SelectSingle from '@/components/ui/SelectSingle';
import { GraphColoring, GraphSizing, HelpTopic } from '@/models/miscellaneous';
import { IRSForm } from '@/models/rsform';
import { mapLabelColoring, mapLabelLayout, mapLabelSizing } from '@/utils/labels';
import { SelectorGraphColoring, SelectorGraphLayout, SelectorGraphSizing } from '@/utils/selectors';
import SchemasGuide from './SchemasGuide';
interface GraphSelectorsProps {
schema?: IRSForm;
coloring: GraphColoring;
layout: GraphLayout;
sizing: GraphSizing;
@ -16,7 +20,7 @@ interface GraphSelectorsProps {
setSizing: (newValue: GraphSizing) => void;
}
function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) {
function GraphSelectors({ schema, coloring, setColoring, layout, setLayout, sizing, setSizing }: GraphSelectorsProps) {
return (
<div className='border rounded-b-none select-none clr-input rounded-t-md'>
<SelectSingle
@ -30,6 +34,7 @@ function GraphSelectors({ coloring, setColoring, layout, setLayout, sizing, setS
<Overlay position='right-[2.5rem] top-[0.5rem]'>
{coloring === 'status' ? <BadgeHelp topic={HelpTopic.UI_CST_STATUS} className='min-w-[25rem]' /> : null}
{coloring === 'type' ? <BadgeHelp topic={HelpTopic.UI_CST_CLASS} className='min-w-[25rem]' /> : null}
{coloring === 'schemas' && !!schema ? <SchemasGuide schema={schema} /> : null}
</Overlay>
<SelectSingle
className='my-1'

View File

@ -0,0 +1,74 @@
import { useMemo } from 'react';
import { IconHelp } from '@/components/Icons';
import Tooltip from '@/components/ui/Tooltip';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useLibrary } from '@/context/LibraryContext';
import { LibraryItemID } from '@/models/library';
import { IRSForm } from '@/models/rsform';
import { colorBgSchemas } from '@/styling/color';
import { globals, prefixes } from '@/utils/constants';
interface SchemasGuideProps {
schema: IRSForm;
}
function SchemasGuide({ schema }: SchemasGuideProps) {
const { colors } = useConceptOptions();
const library = useLibrary();
const schemas = useMemo(() => {
const processed = new Set<LibraryItemID>();
const aliases: string[] = [];
const indexes: number[] = [];
schema.items.forEach(cst => {
if (cst.parent_schema && !processed.has(cst.parent_schema)) {
const item = library.items.find(item => item.id === cst.parent_schema);
if (item) {
aliases.push(item.alias);
} else {
aliases.push(`Схема ${cst.parent_schema_index}`);
}
processed.add(cst.parent_schema);
indexes.push(cst.parent_schema_index);
}
});
const result: string[] = [];
for (let i = 1; i <= aliases.length; i++) {
const trueIndex = indexes.findIndex(index => index === i);
result.push(aliases[trueIndex]);
}
return result;
}, [schema, library.items]);
return (
<div tabIndex={-1} id={globals.graph_schemas} className='p-1'>
<IconHelp size='1.25rem' className='icon-primary' />
<Tooltip
anchorSelect={`#${globals.graph_schemas}`}
layer='z-modalTooltip'
place='right'
className='max-w-[25rem] break-words text-base'
>
<div>
<span
className='min-w-[0.6rem] min-h-[0.6rem] border inline-block mr-1 rounded-full'
style={{ backgroundColor: colorBgSchemas(0, colors) }}
/>
Текущая схема
</div>
{schemas.map((alias, index) => (
<div key={`${prefixes.schemas_list}${index}`}>
<span
className='min-w-[0.6rem] min-h-[0.6rem] border inline-block mr-1 rounded-full'
style={{ backgroundColor: colorBgSchemas(index + 1, colors) }}
/>
{alias}
</div>
))}
</Tooltip>
</div>
);
}
export default SchemasGuide;

View File

@ -1,6 +1,6 @@
'use client';
import { RefObject, useCallback, useLayoutEffect, useMemo } from 'react';
import { RefObject, useCallback, useLayoutEffect } from 'react';
import GraphUI, {
CollapseProps,
@ -107,12 +107,8 @@ function TermGraph({
setSelections(newSelections);
}, [selectedIDs, setSelections, nodes]);
const canvasWidth = useMemo(() => {
return 'calc(100vw - 1rem)';
}, []);
return (
<div className='relative outline-none' style={{ width: canvasWidth, height: mainHeight }}>
<div className='relative outline-none w-[100dvw]' style={{ height: mainHeight }}>
<GraphUI
nodes={nodes}
edges={edges}

View File

@ -416,6 +416,23 @@ export function colorBgCstClass(cstClass: CstClass, colors: IColorTheme): string
}
}
/**
* Determines background color for {@link IConstituenta} depending on its parent schema index.
*/
export function colorBgSchemas(schema_index: number, colors: IColorTheme): string {
if (schema_index === 0) {
return colors.bgGreen;
}
// prettier-ignore
switch (schema_index % 4) {
case 1: return colors.bgPurple;
case 2: return colors.bgOrange;
case 3: return colors.bgTeal;
case 0: return colors.bgBlue;
}
return colors.bgBlue;
}
/**
* Determines background color for {@link GramData}.
*/
@ -462,5 +479,8 @@ export function colorBgGraphNode(cst: IConstituenta, coloringScheme: GraphColori
if (coloringScheme === 'status') {
return colorBgCstStatus(cst.status, colors);
}
if (coloringScheme === 'schemas') {
return colorBgSchemas(cst.parent_schema_index, colors);
}
return '';
}

View File

@ -143,7 +143,8 @@ export const globals = {
email_tooltip: 'email_tooltip',
main_scroll: 'main_scroll',
library_item_editor: 'library_item_editor',
constituenta_editor: 'constituenta_editor'
constituenta_editor: 'constituenta_editor',
graph_schemas: 'graph_schemas_tooltip'
};
/**
@ -165,6 +166,7 @@ export const prefixes = {
cst_source_list: 'cst_source_list_',
cst_delete_list: 'cst_delete_list_',
cst_dependant_list: 'cst_dependant_list_',
schemas_list: 'schemas_list_',
operation_list: 'operation_list_',
csttype_list: 'csttype_',
policy_list: 'policy_list_',

View File

@ -315,7 +315,8 @@ export const mapLabelLayout = new Map<GraphLayout, string>([
export const mapLabelColoring = new Map<GraphColoring, string>([
['none', 'Цвет: Моно'],
['status', 'Цвет: Статус'],
['type', 'Цвет: Класс']
['type', 'Цвет: Класс'],
['schemas', 'Цвет: Схемы']
]);
/**