-
-
-
-
setQuery(data.target.value)}
+
+
+ Фильтр
+
+ {filtered} из {total}
+
+
+
);
}
export default SearchPanel;
-
-
-{/*
-
- setFilterText(event.target.value)}
- />
-
-
*/}
\ No newline at end of file
diff --git a/rsconcept/frontend/src/pages/LibraryPage/ViewLibrary.tsx b/rsconcept/frontend/src/pages/LibraryPage/ViewLibrary.tsx
index 3b74064e..c1fa705c 100644
--- a/rsconcept/frontend/src/pages/LibraryPage/ViewLibrary.tsx
+++ b/rsconcept/frontend/src/pages/LibraryPage/ViewLibrary.tsx
@@ -124,7 +124,7 @@ function ViewLibrary({ items, cleanQuery }: ViewLibraryProps) {
|
-
+
|
Очистить фильтр
diff --git a/rsconcept/frontend/src/pages/LibraryPage/index.tsx b/rsconcept/frontend/src/pages/LibraryPage/index.tsx
index 1c0f1974..0d050320 100644
--- a/rsconcept/frontend/src/pages/LibraryPage/index.tsx
+++ b/rsconcept/frontend/src/pages/LibraryPage/index.tsx
@@ -10,13 +10,13 @@ import ViewLibrary from './ViewLibrary';
function LibraryPage() {
const library = useLibrary();
- const [ filterParams, setFilterParams ] = useState({});
+ const [ filter, setFilter ] = useState({});
const [ items, setItems ] = useState([]);
- useLayoutEffect(() => {
- const filter = filterParams;
+ useLayoutEffect(
+ () => {
setItems(library.filter(filter));
- }, [library, filterParams]);
+ }, [library, filter, filter.query]);
return (
@@ -24,12 +24,13 @@ function LibraryPage() {
{ library.error &&
}
{ !library.loading && library.items &&
-
setFilterParams({})}
+ cleanQuery={() => setFilter({})}
items={items}
/>
diff --git a/rsconcept/frontend/src/pages/LoginPage.tsx b/rsconcept/frontend/src/pages/LoginPage.tsx
index dce900ab..303f62ad 100644
--- a/rsconcept/frontend/src/pages/LoginPage.tsx
+++ b/rsconcept/frontend/src/pages/LoginPage.tsx
@@ -34,28 +34,34 @@ function LoginPage() {
username: username,
password: password
};
- login(data, () => { navigate('/library?filter=personal'); });
+ login(data, () => navigate('/library'));
}
}
return (
-
{ user
+
+
{ user
?
{`Вы вошли в систему как ${user.username}`}
- :
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx
index 5edb0b4e..0e614216 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/DlgCloneRSForm.tsx
@@ -65,21 +65,21 @@ function DlgCloneRSForm({ hideWindow }: DlgCloneRSFormProps) {
{ setTitle(event.target.value); }}
+ onChange={event => setTitle(event.target.value)}
/>
{ setAlias(event.target.value); }}
+ onChange={event => setAlias(event.target.value)}
/>
diff --git a/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx b/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx
index fde06b3d..06d559a7 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/DlgRenameCst.tsx
@@ -31,11 +31,11 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
const handleSubmit = () => onRename(getData());
useLayoutEffect(
- () => {
- if (schema && initial && cstType !== initial.cst_type) {
- setAlias(createAliasFor(cstType, schema));
- }
- }, [initial, cstType, schema]);
+ () => {
+ if (schema && initial && cstType !== initial.cst_type) {
+ setAlias(createAliasFor(cstType, schema));
+ }
+ }, [initial, cstType, schema]);
useLayoutEffect(
() => {
@@ -66,13 +66,13 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
submitInvalidTooltip={'Введите имя, соответствующее типу и отсутствующее в схеме'}
submitText='Переименовать'
>
-
+
{ setCstType(data.length > 0 ? data[0].value : CstType.BASE); }}
+ onChange={data => setCstType(data.length > 0 ? data[0].value : CstType.BASE)}
/>
0) {
setFile(event.target.files[0]);
} else {
- setFile(undefined)
+ setFile(undefined);
}
}
@@ -53,7 +53,7 @@ function DlgUploadRSForm({ hideWindow }: DlgUploadRSFormProps) {
{ setLoadMetadata(event.target.checked); }}
+ onChange={event => setLoadMetadata(event.target.checked)}
/>
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx
index 52b8e43d..abb37287 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorConstituenta.tsx
@@ -45,7 +45,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
const isEnabled = useMemo(() => activeCst && isEditable, [activeCst, isEditable]);
- useLayoutEffect(() => {
+ useLayoutEffect(
+ () => {
if (!activeCst) {
setIsModified(false);
return;
@@ -60,7 +61,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
activeCst?.definition.text.raw, activeCst?.convention,
term, textDefinition, expression, convention]);
- useLayoutEffect(() => {
+ useLayoutEffect(
+ () => {
if (activeCst) {
setAlias(activeCst.alias);
setConvention(activeCst.convention ?? '');
@@ -73,8 +75,10 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
}
}, [activeCst, onOpenEdit, schema]);
- function handleSubmit(event: React.FormEvent) {
- event.preventDefault();
+ function handleSubmit(event?: React.FormEvent) {
+ if (event) {
+ event.preventDefault();
+ }
if (!activeID || processing) {
return;
}
@@ -86,7 +90,7 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
definition_raw: textDefinition,
term_raw: term
};
- cstUpdate(data, () => { toast.success('Изменения сохранены'); });
+ cstUpdate(data, () => toast.success('Изменения сохранены'));
}
function handleDelete() {
@@ -126,13 +130,14 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
return (
-
+
}
+ onClick={() => handleSubmit()}
>
@@ -208,8 +213,8 @@ function EditorConstituenta({ activeID, onShowAST, onCreateCst, onRenameCst, onO
resolved={activeCst?.definition.text.resolved ?? ''}
disabled={!isEnabled}
spellCheck
- onChange={event => { setTextDefinition(event.target.value); }}
- onFocus={() => { setEditMode(EditMode.TEXT); }}
+ onChange={event => setTextDefinition(event.target.value)}
+ onFocus={() => setEditMode(EditMode.TEXT)}
/>
{ setConvention(event.target.value); }}
- onFocus={() => { setEditMode(EditMode.TEXT); }}
+ onChange={event => setConvention(event.target.value)}
+ onFocus={() => setEditMode(EditMode.TEXT)}
/>
-
+
void
@@ -19,6 +20,7 @@ interface EditorItemsProps {
}
function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps) {
+ const { colors } = useConceptTheme();
const { schema, isEditable, cstMoveTo, resetAliases } = useRSForm();
const [selected, setSelected] = useState([]);
const nothingSelected = useMemo(() => selected.length === 0, [selected]);
@@ -51,7 +53,9 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
}, -1);
const target = Math.max(0, currentIndex - 1) + 1
const data = {
- items: selected.map(id => { return { id: id }; }),
+ items: selected.map(id => {
+ return { id: id };
+ }),
move_to: target
}
cstMoveTo(data);
@@ -76,7 +80,9 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
}, -1);
const target = Math.min(schema.items.length - 1, currentIndex - count + 2) + 1
const data: ICstMovetoData = {
- items: selected.map(id => { return { id: id }; }),
+ items: selected.map(id => {
+ return { id: id };
+ }),
move_to: target
}
cstMoveTo(data);
@@ -87,7 +93,6 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
resetAliases(() => toast.success('Переиндексация конституент успешна'));
}
- // Add new constituenta
function handleCreateCst(type?: CstType) {
if (!schema) {
return;
@@ -180,7 +185,8 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
return (<>
{cst.alias}
@@ -248,7 +254,7 @@ function EditorItems({ onOpenEdit, onCreateCst, onDeleteCst }: EditorItemsProps)
reorder: true,
hide: 1800
}
- ], []);
+ ], [colors]);
return (
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx
index 4b56bccc..a2682356 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorRSForm.tsx
@@ -27,7 +27,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
const { getUserLabel } = useUsers();
const {
schema, update, isForceAdmin,
- isEditable, isOwned, isClaimable, processing
+ isEditable, isClaimable, processing
} = useRSForm();
const { user } = useAuth();
@@ -79,7 +79,7 @@ function EditorRSForm({ onDestroy, onClaim, onShare, onDownload }: EditorRSFormP
};
return (
-
+
}
+ tooltip={isClaimable ? 'Стать владельцем' : 'Невозможно стать владельцем' }
+ icon={
}
disabled={!isClaimable || !user}
onClick={onClaim}
/>
diff --git a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx
index 31d9e6f0..faa5784c 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/EditorTermGraph.tsx
@@ -1,6 +1,6 @@
import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
-import { darkTheme, GraphCanvas, GraphCanvasRef, GraphEdge,
- GraphNode, LayoutTypes, lightTheme, Sphere, useSelection
+import { GraphCanvas, GraphCanvasRef, GraphEdge,
+ GraphNode, LayoutTypes, Sphere, useSelection
} from 'reagraph';
import Button from '../../components/Common/Button';
@@ -15,6 +15,7 @@ import { ArrowsRotateIcon, DumpBinIcon, FilterCogIcon, HelpIcon, SmallPlusIcon }
import { useRSForm } from '../../context/RSFormContext';
import { useConceptTheme } from '../../context/ThemeContext';
import useLocalStorage from '../../hooks/useLocalStorage';
+import { graphDarkT, graphLightT, IColorTheme } from '../../utils/color';
import { prefixes, resources } from '../../utils/constants';
import { Graph } from '../../utils/Graph';
import { CstType, IConstituenta, ICstCreateData } from '../../utils/models';
@@ -28,14 +29,14 @@ import ConstituentaTooltip from './elements/ConstituentaTooltip';
export type ColoringScheme = 'none' | 'status' | 'type';
const TREE_SIZE_MILESTONE = 50;
-function getCstNodeColor(cst: IConstituenta, coloringScheme: ColoringScheme, darkMode: boolean): string {
+function getCstNodeColor(cst: IConstituenta, coloringScheme: ColoringScheme, colors: IColorTheme): string {
if (coloringScheme === 'type') {
- return getCstClassColor(cst.cstClass, darkMode);
+ return getCstClassColor(cst.cstClass, colors);
}
if (coloringScheme === 'status') {
- return getCstStatusColor(cst.status, darkMode);
+ return getCstStatusColor(cst.status, colors);
}
- return (darkMode ? '#7a8c9e' :'#7ca0ab');
+ return '';
}
export interface GraphEditorParams {
@@ -62,7 +63,7 @@ interface EditorTermGraphProps {
function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGraphProps) {
const { schema, isEditable } = useRSForm();
- const { darkMode, noNavigation } = useConceptTheme();
+ const { darkMode, colors, noNavigation } = useConceptTheme();
const [ layout, setLayout ] = useLocalStorage
('graph_layout', 'treeTd2d');
const [ coloringScheme, setColoringScheme ] = useLocalStorage('graph_coloring', 'none');
@@ -171,13 +172,13 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
if (cst) {
result.push({
id: String(node.id),
- fill: getCstNodeColor(cst, coloringScheme, darkMode),
+ fill: getCstNodeColor(cst, coloringScheme, colors),
label: cst.term.resolved && !noTerms ? `${cst.alias}: ${cst.term.resolved}` : cst.alias
});
}
});
return result;
- }, [schema, coloringScheme, filtered.nodes, darkMode, noTerms]);
+ }, [schema, coloringScheme, filtered.nodes, noTerms, colors]);
const edges: GraphEdge[] = useMemo(
() => {
@@ -337,8 +338,8 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
const canvasHeight = useMemo(
() => {
return !noNavigation ?
- 'calc(100vh - 9.8rem)'
- : 'calc(100vh - 1.8rem)';
+ 'calc(100vh - 10.1rem)'
+ : 'calc(100vh - 2.1rem)';
}, [noNavigation]);
const dismissedStyle = useCallback(
@@ -354,7 +355,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
initial={getOptions()}
onConfirm={handleChangeOptions}
/>}
-
+
{hoverCst &&
setShowOptions(true)}
/>
{ setColoringScheme(data.length > 0 ? data[0].value : GraphColoringSelector[0].value); }}
+ onChange={data => setColoringScheme(data.length > 0 ? data[0].value : GraphColoringSelector[0].value)}
/>
@@ -409,7 +410,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
searchable={false}
placeholder='Способ расположения'
values={layout ? [{ value: layout, label: mapLayoutLabels.get(layout) }] : []}
- onChange={data => { setLayout(data.length > 0 ? data[0].value : GraphLayoutSelector[0].value); }}
+ onChange={data => setLayout(data.length > 0 ? data[0].value : GraphLayoutSelector[0].value)}
/>
toggleDismissed(cstID)}
onDoubleClick={() => onOpenEdit(cstID)}
>
@@ -458,7 +462,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
@@ -492,7 +496,7 @@ function EditorTermGraph({ onOpenEdit, onCreateCst, onDeleteCst }: EditorTermGra
: undefined
}
labelFontUrl={resources.graph_font}
- theme={darkMode ? darkTheme : lightTheme}
+ theme={darkMode ? graphDarkT : graphLightT}
renderNode={({ node, ...rest }) => (
)}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx
index 7be5de4b..ac2bb7b6 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/RSTabs.tsx
@@ -9,8 +9,9 @@ import ConceptTab from '../../components/Common/ConceptTab';
import { Loader } from '../../components/Common/Loader';
import { useLibrary } from '../../context/LibraryContext';
import { useRSForm } from '../../context/RSFormContext';
+import { useConceptTheme } from '../../context/ThemeContext';
import { prefixes, TIMEOUT_UI_REFRESH } from '../../utils/constants';
-import { ICstCreateData, ICstRenameData, SyntaxTree } from '../../utils/models';
+import { ICstCreateData, ICstRenameData, LibraryFilterStrategy, SyntaxTree } from '../../utils/models';
import { createAliasFor } from '../../utils/staticUI';
import DlgCloneRSForm from './DlgCloneRSForm';
import DlgCreateCst from './DlgCreateCst';
@@ -25,7 +26,7 @@ import EditorTermGraph from './EditorTermGraph';
import RSFormStats from './elements/RSFormStats';
import RSTabsMenu from './RSTabsMenu';
-export enum RSTabsList {
+export enum RSTabID {
CARD = 0,
CST_LIST = 1,
CST_EDIT = 2,
@@ -40,8 +41,9 @@ function RSTabs() {
cstCreate, cstDelete, cstRename, subscribe, unsubscribe
} = useRSForm();
const { destroySchema } = useLibrary();
+ const { setNoFooter } = useConceptTheme();
- const [activeTab, setActiveTab] = useState(RSTabsList.CARD);
+ const [activeTab, setActiveTab] = useState(RSTabID.CARD);
const [activeID, setActiveID] = useState(undefined);
const [showUpload, setShowUpload] = useState(false);
@@ -72,21 +74,23 @@ function RSTabs() {
}, [schema]);
useLayoutEffect(() => {
- const activeTab = Number(new URLSearchParams(search).get('tab')) ?? RSTabsList.CARD;
+ const activeTab = (Number(new URLSearchParams(search).get('tab')) ?? RSTabID.CARD) as RSTabID;
const cstQuery = new URLSearchParams(search).get('active');
setActiveTab(activeTab);
+ setNoFooter(activeTab === RSTabID.CST_EDIT || activeTab === RSTabID.CST_LIST);
setActiveID(Number(cstQuery) ?? ((schema && schema?.items.length > 0) ? schema.items[0].id : undefined));
- }, [search, setActiveTab, setActiveID, schema]);
+ return () => setNoFooter(false);
+ }, [search, setActiveTab, setActiveID, schema, setNoFooter]);
function onSelectTab(index: number) {
navigateTo(index, activeID);
}
const navigateTo = useCallback(
- (tab: RSTabsList, activeID?: number) => {
+ (tab: RSTabID, activeID?: number) => {
if (activeID) {
navigate(`/rsforms/${schema!.id}?tab=${tab}&active=${activeID}`, {
- replace: tab === activeTab && tab !== RSTabsList.CST_EDIT
+ replace: tab === activeTab && tab !== RSTabID.CST_EDIT
});
} else {
navigate(`/rsforms/${schema!.id}?tab=${tab}`);
@@ -102,7 +106,7 @@ function RSTabs() {
cstCreate(data, newCst => {
toast.success(`Конституента добавлена: ${newCst.alias}`);
navigateTo(activeTab, newCst.id);
- if (activeTab === RSTabsList.CST_EDIT || activeTab === RSTabsList.CST_LIST) {
+ if (activeTab === RSTabID.CST_EDIT || activeTab === RSTabID.CST_LIST) {
setTimeout(() => {
const element = document.getElementById(`${prefixes.cst_list}${newCst.alias}`);
if (element) {
@@ -144,14 +148,16 @@ function RSTabs() {
return;
}
const data = {
- items: deleted.map(id => { return { id: id }; })
+ items: deleted.map(id => {
+ return { id: id };
+ })
};
let activeIndex = schema.items.findIndex(cst => cst.id === activeID);
cstDelete(data, () => {
const deletedNames = deleted.map(id => schema.items.find(cst => cst.id === id)?.alias).join(', ');
toast.success(`Конституенты удалены: ${deletedNames}`);
if (deleted.length === schema.items.length) {
- navigateTo(RSTabsList.CST_LIST);
+ navigateTo(RSTabID.CST_LIST);
}
if (activeIndex) {
while (activeIndex < schema.items.length && deleted.find(id => id === schema.items[activeIndex].id)) {
@@ -182,7 +188,7 @@ function RSTabs() {
const onOpenCst = useCallback(
(cstID: number) => {
- navigateTo(RSTabsList.CST_EDIT, cstID)
+ navigateTo(RSTabID.CST_EDIT, cstID)
}, [navigateTo]);
const onDestroySchema = useCallback(
@@ -192,7 +198,7 @@ function RSTabs() {
}
destroySchema(schema.id, () => {
toast.success('Схема удалена');
- navigate('/library?filter=personal');
+ navigate(`/library?filter=${LibraryFilterStrategy.PERSONAL}`);
});
}, [schema, destroySchema, navigate]);
@@ -283,7 +289,7 @@ function RSTabs() {
defaultFocus={true}
selectedTabClassName='font-bold'
>
-
+
Граф термов
-
+
-
+
-
+
}
-
- // case DependencyMode.OUTPUTS: return 'потребители';
- // case DependencyMode.INPUTS: return 'поставщики';
- // case DependencyMode.EXPAND_INPUTS: return 'влияющие';
- // case DependencyMode.EXPAND_OUTPUTS: return 'зависимые';
- // }
- // }
-
);
}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/RSFormStats.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/RSFormStats.tsx
index dcef4ef4..f84cc53a 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/elements/RSFormStats.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/elements/RSFormStats.tsx
@@ -8,7 +8,7 @@ interface RSFormStatsProps {
function RSFormStats({ stats }: RSFormStatsProps) {
return (
-
+
}
-
+
-
+
+
+
{ stats.count_base > 0 &&
{ onInsert(TokenID.ID_LOCAL, text); }}
+ onClick={() => onInsert(TokenID.ID_LOCAL, text)}
title={tooltip}
tabIndex={-1}
className='w-[1.5rem] h-7 cursor-pointer border rounded-none clr-btn-clear'
diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx
index e9e797b9..bb468621 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/elements/RSTokenButton.tsx
@@ -14,7 +14,7 @@ function RSTokenButton({ id, disabled, onInsert }: RSTokenButtonProps) {
{ onInsert(id); }}
+ onClick={() => onInsert(id)}
title={data.tooltip}
tabIndex={-1}
className={`px-1 cursor-pointer border rounded-none h-7 ${width} clr-btn-clear`}
diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx
index f2b49c72..a80914a1 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/elements/StatusBar.tsx
@@ -1,7 +1,8 @@
import { useMemo } from 'react';
+import { useConceptTheme } from '../../../context/ThemeContext';
import { ExpressionStatus, type IConstituenta, IExpressionParse,inferStatus, ParsingStatus } from '../../../utils/models';
-import { mapStatusInfo } from '../../../utils/staticUI';
+import { getCstStatusColor, mapStatusInfo } from '../../../utils/staticUI';
interface StatusBarProps {
isModified?: boolean
@@ -10,6 +11,7 @@ interface StatusBarProps {
}
function StatusBar({ isModified, constituenta, parseData }: StatusBarProps) {
+ const { colors } = useConceptTheme();
const status = useMemo(() => {
if (isModified) {
return ExpressionStatus.UNKNOWN;
@@ -24,7 +26,9 @@ function StatusBar({ isModified, constituenta, parseData }: StatusBarProps) {
const data = mapStatusInfo.get(status)!;
return (
+ className='text-sm h-[1.6rem] w-[10rem] font-semibold inline-flex border items-center select-none justify-center align-middle'
+ style={{backgroundColor: getCstStatusColor(status, colors)}}
+ >
Статус: [ {data.text} ]
)
diff --git a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx
index 33bad802..372552ce 100644
--- a/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx
+++ b/rsconcept/frontend/src/pages/RSFormPage/elements/ViewSideConstituents.tsx
@@ -6,13 +6,13 @@ import { useConceptTheme } from '../../../context/ThemeContext';
import useLocalStorage from '../../../hooks/useLocalStorage';
import { prefixes } from '../../../utils/constants';
import { applyGraphFilter, CstMatchMode, CstType, DependencyMode, extractGlobals, IConstituenta, matchConstituenta } from '../../../utils/models';
-import { getCstDescription, getMockConstituenta, mapStatusInfo } from '../../../utils/staticUI';
+import { getCstDescription, getCstStatusColor, getMockConstituenta } from '../../../utils/staticUI';
import ConstituentaTooltip from './ConstituentaTooltip';
import DependencyModePicker from './DependencyModePicker';
import MatchModePicker from './MatchModePicker';
// Height that should be left to accomodate navigation panel + bottom margin
-const LOCAL_NAVIGATION_H = '2.6rem';
+const LOCAL_NAVIGATION_H = '2.1rem';
interface ViewSideConstituentsProps {
expression: string
@@ -26,7 +26,7 @@ function isMockCst(cst: IConstituenta) {
}
function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }: ViewSideConstituentsProps) {
- const { darkMode, noNavigation } = useConceptTheme();
+ const { noNavigation, colors } = useConceptTheme();
const { schema } = useRSForm();
const [filterMatch, setFilterMatch] = useLocalStorage('side-filter-match', CstMatchMode.ALL);
@@ -81,10 +81,10 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
{
when: (cst: IConstituenta) => cst.id === activeID,
style: {
- backgroundColor: darkMode ? '#0068b3' : '#def1ff',
+ backgroundColor: colors.selection,
},
}
- ], [activeID, darkMode]);
+ ], [activeID, colors]);
const columns = useMemo(
() => [
@@ -97,11 +97,11 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
name: 'ID',
id: 'alias',
cell: (cst: IConstituenta) => {
- const info = mapStatusInfo.get(cst.status)!;
return (<>
{cst.alias}
@@ -113,7 +113,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
conditionalCellStyles: [
{
when: (cst: IConstituenta) => isMockCst(cst),
- classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
+ style: {backgroundColor: colors.selectionError}
}
]
},
@@ -126,7 +126,7 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
conditionalCellStyles: [
{
when: (cst: IConstituenta) => isMockCst(cst),
- classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
+ style: {backgroundColor: colors.selectionError}
}
]
},
@@ -141,11 +141,11 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
conditionalCellStyles: [
{
when: (cst: IConstituenta) => isMockCst(cst),
- classNames: ['bg-[#ffc9c9]', 'dark:bg-[#592b2b]']
+ style: {backgroundColor: colors.selectionError}
}
]
}
- ], []);
+ ], [colors]);
const maxHeight = useMemo(
() => {
@@ -156,13 +156,13 @@ function ViewSideConstituents({ expression, baseHeight, activeID, onOpenEdit }:
}, [noNavigation, baseHeight]);
return (<>
-
+
setFilterText(event.target.value)}
diff --git a/rsconcept/frontend/src/pages/RegisterPage.tsx b/rsconcept/frontend/src/pages/RegisterPage.tsx
index 7362b39d..d5133fab 100644
--- a/rsconcept/frontend/src/pages/RegisterPage.tsx
+++ b/rsconcept/frontend/src/pages/RegisterPage.tsx
@@ -47,26 +47,30 @@ function RegisterPage() {
{ user &&
{`Вы вошли в систему как ${user.username}. Если хотите зарегистрировать нового пользователя, выйдите из системы (меню в правом верхнем углу экрана)`} }
{ !user &&
-
+
{ setUsername(event.target.value); }}
+ onChange={event => setUsername(event.target.value)}
/>
{ setPassword(event.target.value); }}
+ onChange={event => setPassword(event.target.value)}
/>
{ setPassword2(event.target.value); }}
+ onChange={event => setPassword2(event.target.value)}
/>
- используйте уникальный пароль
- портал функционирует в тестовом режиме
-
- безопасность информации пользователей не гарантируется
+
- безопасность информации не гарантируется
{/*
- минимум 8 символов
- большие, маленькие буквы, цифры
- минимум 1 спец. символ
*/}
@@ -74,18 +78,18 @@ function RegisterPage() {
{ setEmail(event.target.value); }}
+ onChange={event => setEmail(event.target.value)}
/>
{ setFirstName(event.target.value); }}
+ onChange={event => setFirstName(event.target.value)}
/>
{ setLastName(event.target.value); }}
+ onChange={event => setLastName(event.target.value)}
/>
-
+
{ error &&
}
diff --git a/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx b/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx
index 4e40a906..5e3cac26 100644
--- a/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx
+++ b/rsconcept/frontend/src/pages/UserProfilePage/EditorProfile.tsx
@@ -14,6 +14,20 @@ function EditorProfile() {
const [first_name, setFirstName] = useState('');
const [last_name, setLastName] = useState('');
+ const [isModified, setIsModified] = useState(true);
+
+ useLayoutEffect(() => {
+ if (!user) {
+ setIsModified(false);
+ return;
+ }
+ setIsModified(
+ user.email !== email ||
+ user.first_name !== first_name ||
+ user.last_name !== last_name
+ );
+ }, [user, user?.email, user?.first_name, user?.last_name, email, first_name, last_name]);
+
useLayoutEffect(() => {
if (user) {
setUsername(user.username);
@@ -57,6 +71,7 @@ function EditorProfile() {
diff --git a/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx b/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx
index a4a3f2e5..9a89bc98 100644
--- a/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx
+++ b/rsconcept/frontend/src/pages/UserProfilePage/UserTabs.tsx
@@ -16,7 +16,7 @@ function UserTabs() {
const { user: auth } = useAuth();
const { items } = useLibrary();
- const [showSubs, setShowSubs] = useState(true);
+ const [showSubs, setShowSubs] = useState(false);
const subscriptions = useMemo(
() => {
diff --git a/rsconcept/frontend/src/utils/color.ts b/rsconcept/frontend/src/utils/color.ts
new file mode 100644
index 00000000..9edc23cc
--- /dev/null
+++ b/rsconcept/frontend/src/utils/color.ts
@@ -0,0 +1,219 @@
+export interface IColorTheme {
+ red: string
+ green: string
+ blue: string
+ teal: string
+ orange: string
+
+ text: string
+
+ input: string
+ inputDisabled: string
+ selection: string
+ selectionError: string
+
+ // bg100: string
+ // bg70: string
+ // bg50: string
+
+ // fg100: string
+ // fg70: string
+ // fg50: string
+
+ // primary: string
+ // secondary: string
+}
+
+// =========== GENERAL THEMES =========
+export const lightT: IColorTheme = {
+ red: '#ffc9c9',
+ green: '#aaff80',
+ blue: '#b3bdff',
+ teal: '#a5e9fa',
+ orange: '#ffbb80',
+
+ text: '#000000',
+
+ input: '#ffffff',
+ inputDisabled: '#f0f2f7',
+ selection: '#def1ff',
+ selectionError: '#ffc9c9'
+};
+
+export const darkT: IColorTheme = {
+ red: '#bf0d00',
+ green: '#2b8000',
+ blue: '#394bbf',
+ teal: '#0099bf',
+ orange: '#964600',
+
+ text: '#e4e4e7',
+
+ input: '#070b12',
+ inputDisabled: '#374151', // bg-gray-700
+ selection: '#8c6000',
+ selectionError: '#592b2b'
+};
+
+
+// ========= DATA TABLE THEMES ========
+export const dataTableLightT = {
+ divider: {
+ default: '#d1d5db'
+ },
+ striped: {
+ default: '#f0f2f7'
+ },
+}
+
+export const dataTableDarkT = {
+ text: {
+ primary: 'rgba(228, 228, 231, 1)',
+ secondary: 'rgba(228, 228, 231, 0.87)',
+ disabled: 'rgba(228, 228, 231, 0.54)'
+ },
+ background: {
+ default: '#111827'
+ },
+ highlightOnHover: {
+ default: '#4d6080',
+ text: 'rgba(228, 228, 231, 1)'
+ },
+ divider: {
+ default: '#6b6b6b'
+ },
+ striped: {
+ default: '#374151',
+ text: 'rgba(228, 228, 231, 1)'
+ },
+ selected: {
+ default: '#4d6080',
+ text: 'rgba(228, 228, 231, 1)'
+ }
+};
+
+// ============ GRAPH THEMES ==========
+export const graphLightT = {
+ canvas: {
+ background: '#f9fafb',
+ },
+ node: {
+ fill: '#7ca0ab',
+ activeFill: '#1DE9AC',
+ opacity: 1,
+ selectedOpacity: 1,
+ inactiveOpacity: 0.2,
+ label: {
+ color: '#2A6475',
+ stroke: '#fff',
+ activeColor: '#1DE9AC'
+ }
+ },
+ lasso: {
+ border: '1px solid #55aaff',
+ background: 'rgba(75, 160, 255, 0.1)'
+ },
+ ring: {
+ fill: '#D8E6EA',
+ activeFill: '#1DE9AC'
+ },
+ edge: {
+ fill: '#D8E6EA',
+ activeFill: '#1DE9AC',
+ opacity: 1,
+ selectedOpacity: 1,
+ inactiveOpacity: 0.1,
+ label: {
+ stroke: '#fff',
+ color: '#2A6475',
+ activeColor: '#1DE9AC'
+ }
+ },
+ arrow: {
+ fill: '#D8E6EA',
+ activeFill: '#1DE9AC'
+ },
+ cluster: {
+ stroke: '#D8E6EA',
+ label: {
+ stroke: '#fff',
+ color: '#2A6475'
+ }
+ }
+}
+
+export const graphDarkT = {
+ canvas: {
+ background: '#1f2937'
+ },
+ node: {
+ fill: '#7a8c9e',
+ activeFill: '#1DE9AC',
+ opacity: 1,
+ selectedOpacity: 1,
+ inactiveOpacity: 0.2,
+ label: {
+ stroke: '#1E2026',
+ color: '#ACBAC7',
+ activeColor: '#1DE9AC'
+ }
+ },
+ lasso: {
+ border: '1px solid #55aaff',
+ background: 'rgba(75, 160, 255, 0.1)'
+ },
+ ring: {
+ fill: '#54616D',
+ activeFill: '#1DE9AC'
+ },
+ edge: {
+ fill: '#474B56',
+ activeFill: '#1DE9AC',
+ opacity: 1,
+ selectedOpacity: 1,
+ inactiveOpacity: 0.1,
+ label: {
+ stroke: '#1E2026',
+ color: '#ACBAC7',
+ activeColor: '#1DE9AC'
+ }
+ },
+ arrow: {
+ fill: '#474B56',
+ activeFill: '#1DE9AC'
+ },
+ cluster: {
+ stroke: '#474B56',
+ label: {
+ stroke: '#1E2026',
+ color: '#ACBAC7'
+ }
+ }
+}
+
+// ======== Bracket Matching Themes ===========
+export const bracketsLightT = {
+ '.cc-matchingBracket': {
+ fontWeight: 600,
+ },
+ '.cc-nonmatchingBracket': {
+ color: '#ef4444',
+ fontWeight: 700,
+ },
+ '&.cm-focused .cc-matchingBracket': {
+ backgroundColor: '#dae6f2',
+ },
+};
+
+export const bracketsDarkT = {
+ '.cc-matchingBracket': {
+ fontWeight: 600,
+ },
+ '.cc-nonmatchingBracket': {
+ color: '#ef4444',
+ fontWeight: 700,
+ },
+ '&.cm-focused .cc-matchingBracket': {
+ backgroundColor: '#734f00',
+ },
+};
diff --git a/rsconcept/frontend/src/utils/models.ts b/rsconcept/frontend/src/utils/models.ts
index 763d60f4..eabd3df4 100644
--- a/rsconcept/frontend/src/utils/models.ts
+++ b/rsconcept/frontend/src/utils/models.ts
@@ -247,6 +247,8 @@ export interface IRSFormStats {
count_incalc: number
count_termin: number
+ count_definition: number
+ count_convention: number
count_base: number
count_constant: number
@@ -281,10 +283,22 @@ export interface IRSFormUploadData {
}
// ========== Library =====
+export enum LibraryFilterStrategy {
+ MANUAL = 'manual',
+ PERSONAL = 'personal',
+ COMMON = 'common',
+ SUBSCRIBE = 'subscribe',
+ CANONICAL = 'canonical',
+ OWNED = 'owned'
+}
+
export interface ILibraryFilter {
- ownedBy?: number
+ query?: string
+ is_personal?: boolean
+ is_owned?: boolean
is_common?: boolean
- queryMeta?: string
+ is_canonical?: boolean
+ is_subscribed?: boolean
}
// ================ Misc types ================
@@ -392,6 +406,8 @@ export function LoadRSFormData(schema: IRSFormData): IRSForm {
count_incalc: 0,
count_termin: 0,
+ count_definition: 0,
+ count_convention: 0,
count_base: 0,
count_constant: 0,
@@ -416,6 +432,10 @@ export function LoadRSFormData(schema: IRSFormData): IRSForm {
count_termin: result.items.reduce(
(sum, cst) => (sum + (cst.term?.raw ? 1 : 0) || 0), 0),
+ count_definition: result.items.reduce(
+ (sum, cst) => (sum + (cst.definition?.text.raw ? 1 : 0) || 0), 0),
+ count_convention: result.items.reduce(
+ (sum, cst) => (sum + (cst.convention ? 1 : 0) || 0), 0),
count_base: result.items.reduce(
(sum, cst) => sum + (cst.cstType === CstType.BASE ? 1 : 0), 0),
diff --git a/rsconcept/frontend/src/utils/staticUI.ts b/rsconcept/frontend/src/utils/staticUI.ts
index ca78348b..9678e00b 100644
--- a/rsconcept/frontend/src/utils/staticUI.ts
+++ b/rsconcept/frontend/src/utils/staticUI.ts
@@ -1,6 +1,7 @@
import { LayoutTypes } from 'reagraph';
import { ColoringScheme } from '../pages/RSFormPage/EditorTermGraph';
+import { IColorTheme } from './color';
import { resolveErrorClass,RSErrorClass, RSErrorType, TokenID } from './enums';
import {
CstClass, CstMatchMode, CstType,
@@ -9,18 +10,7 @@ import {
ISyntaxTreeNode, ParsingStatus, ValueClass
} from './models';
-export interface IRSButtonData {
- text: string
- tooltip: string
-}
-
-export interface IFormatInfo {
- text: string
- color: string
- tooltip: string
-}
-
-export interface ITopicInfo {
+export interface IDescriptor {
text: string
tooltip: string
}
@@ -64,7 +54,7 @@ export function getCstExpressionPrefix(cst: IConstituenta): string {
return cst.alias + (cst.cstType === CstType.STRUCTURED ? '::=' : ':==');
}
-export function getRSButtonData(id: TokenID): IRSButtonData {
+export function getRSButtonData(id: TokenID): IDescriptor {
switch (id) {
case TokenID.BOOLEAN: return {
text: 'ℬ()',
@@ -323,51 +313,45 @@ export const GraphColoringSelector: {value: ColoringScheme, label: string}[] = [
{ value: 'type', label: 'Цвет: класс'},
];
-export function getCstStatusColor(status: ExpressionStatus, darkMode: boolean): string {
+export function getCstStatusColor(status: ExpressionStatus, colors: IColorTheme): string {
switch (status) {
- case ExpressionStatus.VERIFIED: return darkMode ? '#2b8000': '#aaff80';
- case ExpressionStatus.INCORRECT: return darkMode ? '#592b2b': '#ffc9c9';
- case ExpressionStatus.INCALCULABLE: return darkMode ? '#964600': '#ffbb80';
- case ExpressionStatus.PROPERTY: return darkMode ? '#36899e': '#a5e9fa';
- case ExpressionStatus.UNKNOWN: return darkMode ? '#1e00b3': '#b3bdff';
- case ExpressionStatus.UNDEFINED: return darkMode ? '#1e00b3': '#b3bdff';
+ case ExpressionStatus.VERIFIED: return colors.green;
+ case ExpressionStatus.INCORRECT: return colors.red;
+ case ExpressionStatus.INCALCULABLE: return colors.orange;
+ case ExpressionStatus.PROPERTY: return colors.teal;
+ case ExpressionStatus.UNKNOWN: return colors.blue;
+ case ExpressionStatus.UNDEFINED: return colors.blue;
}
}
-export const mapStatusInfo: Map = new Map([
+export const mapStatusInfo: Map = new Map([
[ ExpressionStatus.VERIFIED, {
text: 'ок',
- color: 'bg-[#aaff80] dark:bg-[#2b8000]',
tooltip: 'выражение корректно и вычислимо'
}],
[ ExpressionStatus.INCORRECT, {
text: 'ошибка',
- color: 'bg-[#ffc9c9] dark:bg-[#592b2b]',
tooltip: 'ошибка в выражении'
}],
[ ExpressionStatus.INCALCULABLE, {
text: 'невыч',
- color: 'bg-[#ffbb80] dark:bg-[#964600]',
tooltip: 'выражение не вычислимо'
}],
[ ExpressionStatus.PROPERTY, {
text: 'св-во',
- color: 'bg-[#a5e9fa] dark:bg-[#36899e]',
tooltip: 'можно проверить принадлежность, но нельзя получить значение'
}],
[ ExpressionStatus.UNKNOWN, {
text: 'неизв',
- color: 'bg-[#b3bdff] dark:bg-[#1e00b3]',
tooltip: 'требует проверки выражения'
}],
[ ExpressionStatus.UNDEFINED, {
text: 'N/A',
- color: 'bg-[#b3bdff] dark:bg-[#1e00b3]',
tooltip: 'произошла ошибка при проверке выражения'
}]
]);
-export const mapTopicInfo: Map = new Map([
+export const mapTopicInfo: Map = new Map([
[ HelpTopic.MAIN, {
text: 'Портал',
tooltip: 'Общая справка по порталу'
@@ -406,34 +390,30 @@ export const mapTopicInfo: Map = new Map([
}],
]);
-export function getCstClassColor(cstClass: CstClass, darkMode: boolean): string {
+export function getCstClassColor(cstClass: CstClass, colors: IColorTheme): string {
switch (cstClass) {
- case CstClass.TEMPLATE: return darkMode ? '#36899e': '#a5e9fa';
- case CstClass.BASIC: return darkMode ? '#2b8000': '#aaff80';
- case CstClass.DERIVED: return darkMode ? '#1e00b3': '#b3bdff';
- case CstClass.STATEMENT: return darkMode ? '#592b2b': '#ffc9c9';
+ case CstClass.BASIC: return colors.green;
+ case CstClass.DERIVED: return colors.blue;
+ case CstClass.STATEMENT: return colors.red;
+ case CstClass.TEMPLATE: return colors.teal;
}
}
-export const mapCstClassInfo: Map = new Map([
+export const mapCstClassInfo: Map = new Map([
[ CstClass.BASIC, {
text: 'базовый',
- color: 'bg-[#aaff80] dark:bg-[#2b8000]',
tooltip: 'неопределяемое понятие, требует конвенции'
}],
[ CstClass.DERIVED, {
text: 'производный',
- color: 'bg-[#b3bdff] dark:bg-[#1e00b3]',
tooltip: 'выводимое понятие, задаваемое определением'
}],
[ CstClass.STATEMENT, {
text: 'утверждение',
- color: 'bg-[#ffc9c9] dark:bg-[#592b2b]',
tooltip: 'неопределяемое понятие, требует конвенции'
}],
[ CstClass.TEMPLATE, {
text: 'шаблон',
- color: 'bg-[#a5e9fa] dark:bg-[#36899e]',
tooltip: 'параметризованный шаблон определения'
}],
]);
@@ -500,7 +480,7 @@ export function getTypificationLabel({isValid, resultType, args}: {
if (!isValid) {
return 'N/A';
}
- if (resultType === '') {
+ if (resultType === '' || resultType === 'LOGIC') {
resultType = 'Логический'
}
if (args.length === 0) {