Compare commits

...

5 Commits

Author SHA1 Message Date
Ivan
4c20d151d7 F: Rework user filter for LibraryPage
Some checks failed
Frontend CI / build (22.x) (push) Waiting to run
Backend CI / build (3.12) (push) Has been cancelled
2024-09-27 12:03:13 +03:00
Ivan
4383511a4a F: Add AST visualization for expression 2024-09-26 23:26:20 +03:00
Ivan
f3c11747d8 M: Inverse treeView 2024-09-26 22:40:00 +03:00
Ivan
aeaa92df3f B: Correctly process invalid manuals topic name 2024-09-26 11:48:22 +03:00
Ivan
e1604bb7f8 F: Implement rules from pyconcept0.1.10 2024-09-25 23:07:55 +03:00
27 changed files with 609 additions and 81 deletions

View File

@ -63,12 +63,12 @@ https://yandex.cloud/ru/docs/smartcaptcha
[Research]
Research and consider integration
- django-allauth - consider supporting popular auth providers
- drf-messages
- skeleton loading
https://react.dev/reference/react/Suspense
- backend error message unification
- drf-messages
https://drf-standardized-errors.readthedocs.io/en/latest/error_response.html
- semantic json diff

View File

@ -8,7 +8,7 @@ drf-spectacular-sidecar==2024.7.1
coreapi==2.3.3
django-rest-passwordreset==1.4.1
cctext==0.1.4
pyconcept==0.1.8
pyconcept==0.1.10
psycopg2-binary==2.9.9
gunicorn==23.0.0

View File

@ -8,7 +8,7 @@ drf-spectacular-sidecar==2024.7.1
coreapi==2.3.3
django-rest-passwordreset==1.4.1
cctext==0.1.4
pyconcept==0.1.8
pyconcept==0.1.10
psycopg2-binary==2.9.9
gunicorn==23.0.0

View File

@ -4,7 +4,7 @@
"version": "1.0.0",
"type": "module",
"scripts": {
"generate": "lezer-generator src/components/RSInput/rslang/rslangFull.grammar -o src/components/RSInput/rslang/parser.ts && lezer-generator src/components/RefsInput/parse/refsText.grammar -o src/components/RefsInput/parse/parser.ts",
"generate": "lezer-generator src/components/RSInput/rslang/rslangFast.grammar -o src/components/RSInput/rslang/parser.ts && lezer-generator src/components/RSInput/rslang/rslangAST.grammar -o src/components/RSInput/rslang/parserAST.ts && lezer-generator src/components/RefsInput/parse/refsText.grammar -o src/components/RefsInput/parse/parser.ts",
"test": "jest",
"dev": "vite --host",
"build": "tsc && vite build",

View File

@ -28,6 +28,10 @@ export const Router = createBrowserRouter([
path: '',
element: <HomePage />
},
{
path: `${routes.not_found}`,
element: <NotFoundPage />
},
{
path: routes.login,
element: <LoginPage />

View File

@ -8,6 +8,7 @@ import { buildConstants } from '@/utils/buildConstants';
* Routes.
*/
export const routes = {
not_found: 'not-found',
login: 'login',
signup: 'signup',
profile: 'profile',
@ -39,6 +40,7 @@ interface OssProps {
* Internal navigation URLs.
*/
export const urls = {
page404: '/not-found',
admin: `${buildConstants.backend}/admin`,
rest_api: `${buildConstants.backend}/`,
home: '/',

View File

@ -75,7 +75,7 @@ export function SubfoldersIcon({ value, size = '1.25rem', className }: DomIconPr
if (value) {
return <IconSubfolders size={size} className={className ?? 'clr-text-green'} />;
} else {
return <IconSubfolders size={size} className={className ?? 'clr-text-controls'} />;
return <IconSubfolders size={size} className={className ?? 'clr-text-primary'} />;
}
}

View File

@ -34,6 +34,7 @@ export { LuMoon as IconDarkTheme } from 'react-icons/lu';
export { LuSun as IconLightTheme } from 'react-icons/lu';
export { LuFolderTree as IconFolderTree } from 'react-icons/lu';
export { LuFolder as IconFolder } from 'react-icons/lu';
export { LuFolderSearch as IconFolderSearch } from 'react-icons/lu';
export { LuFolders as IconSubfolders } from 'react-icons/lu';
export { LuFolderEdit as IconFolderEdit } from 'react-icons/lu';
export { LuFolderOpen as IconFolderOpened } from 'react-icons/lu';
@ -57,6 +58,7 @@ export { PiFileCsv as IconCSV } from 'react-icons/pi';
export { LuUserCircle2 as IconUser } from 'react-icons/lu';
export { FaCircleUser as IconUser2 } from 'react-icons/fa6';
export { TbUserEdit as IconEditor } from 'react-icons/tb';
export { TbUserSearch as IconUserSearch } from 'react-icons/tb';
export { LuCrown as IconOwner } from 'react-icons/lu';
export { TbMeteor as IconAdmin } from 'react-icons/tb';
export { TbMeteorOff as IconAdminOff } from 'react-icons/tb';

View File

@ -0,0 +1,46 @@
// This file was generated by lezer-generator. You probably shouldn't edit it.
export const
Expression = 1,
Logic = 2,
Logic_predicates = 3,
Variable = 4,
Local = 5,
Tuple = 8,
Setexpr_enum_min2 = 9,
Setexpr_enum = 10,
Setexpr = 11,
Literal = 12,
Integer = 13,
EmptySet = 14,
IntegerSet = 15,
Global = 16,
Radical = 17,
Setexpr_binary = 18,
Setexpr_generators = 27,
Enumeration = 30,
Boolean = 31,
Filter_expression = 33,
Filter = 34,
Declarative = 37,
PrefixD = 40,
PrefixI = 41,
Imperative = 42,
Imp_blocks = 43,
PrefixR = 45,
Recursion = 46,
Function = 48,
TextFunction = 49,
BigPr = 50,
SmallPr = 51,
Card = 52,
Bool = 53,
Debool = 54,
Red = 55,
Logic_unary = 68,
Predicate = 71,
Logic_quantor = 72,
Variable_pack = 74,
Logic_binary = 76,
Function_decl = 81,
Arguments = 82,
Declaration = 83

View File

@ -0,0 +1,20 @@
// This file was generated by lezer-generator. You probably shouldn't edit it.
import {LRParser} from "@lezer/lr"
export const parser = LRParser.deserialize({
version: 14,
states: "2xO!sQPOOOOQO'#Ch'#ChO#lQPO'#EWOOQO'#EW'#EWO%yQPO'#EVOVQPO'#CnO'_QPO'#CzO'fQPO'#C{O'nQPO'#C}O'sQPO'#DRO'xQPO'#DWO'}QPO'#D[OOQO'#Cw'#CwO(SQPO'#CwOOQO'#D_'#D_OOQO'#Cg'#CgO)pQPO'#CgO)uQPO'#CgO)zQPO'#C_OVQPO'#DsO*SQPO'#DvOOQO'#Dr'#DrO*[QPO'#DrO*aQPO'#EVOOQO'#C^'#C^O*rQPO'#EPQOQPOOO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,59YO*wQPO,58yO+OQPO'#CfO+VQPO,59YO,jQPO,59OO,rQPO'#CeO,wQPO,58xO-YQPO,59mO-{QPO'#CfO*wQPO'#CnO.YQPO,59fOOQO'#Cf'#CfO*wQPO,59gOOQO,59g,59gO*wQPO,59iO*SQPO,59mO*wQPO,59rO*SQPO,59vO*wQPO,59RO*wQPO,59RO$lQPO'#C_OOQO,5:_,5:_O*wQPO'#CdOOQO'#C`'#C`OOQO'#Dx'#DxO.bQPO,5:bO*wQPO,5:^OVQPO,5:fOVQPO,5:fOVQPO,5:fOVQPO,5:fO.jQPO'#EROOQO'#EQ'#EQO.oQPO,5:kOOQO1G.t1G.tO2`QPO1G.tO2gQPO1G.tO6VQPO1G.tO9uQPO1G.tO9|QPO1G.tO:TQPO1G.tO:[QPO1G.tO=vQPO1G.eOOQO1G.j1G.jO*wQPO,59POOQO1G.d1G.dO*wQPO1G/XOOQO1G/Q1G/QO>gQPO1G/RO>nQPO1G/TO>vQPO1G/XO>{QPO1G/^O?SQPO1G/bO?XQPO1G.mO?aQPO1G.mO*SQPO,5:dO*wQPO1G/|O?hQPO1G/xOOQO1G0Q1G0QO@[QPO1G0QO@cQPO1G0QO@jQPO1G0QO*wQPO,5:mO*rQPO,5:lOVQPO1G0VOAXQPO1G.kOAiQPO7+$sOOQO7+$m7+$mOApQPO7+$oO*wQPO7+$sOVQPO7+$xO*wQPO7+$|OOQO7+$X7+$XOOQO1G0O1G0OOAuQPO7+%hOOQO7+%d7+%dOBcQPO1G0XOOQO1G0W1G0WOOQO7+%q7+%qOVQPO<<H_O*wQPO<<HZOBmQPO<<H_OBtQPO'#DXOCYQPO<<HdOCbQPO<<HhOCiQPO<<ISODWQPOAN=yODiQPOAN=uOVQPOAN=yOVQPO,59sOOQOAN>OAN>OOVQPOAN>SOOQOG23eG23eOOQOG23aG23aODpQPOG23eOERQPO1G/_OEgQPOG23nOEnQPOG23nOOQOLD)PLD)POOQOLD)YLD)YO*wQPOLD)YOFPQPO!$'LtOOQO!)9B`!)9B`",
stateData: "Fi~O!xOS~OTQOVTO]PO^PO_PO`ROaROmUOpVOrWOxXOyYO}ZO!Q`O!S^O!T^O!U^O!V^O!W^O!X^O!hcO!ifO!kdO!mdO~OsiO~PVOc!zXd!zXe!zXf!zXg!zXh!zXi!zXj!zX!Y!zXl!zX~Ov!zX!PSX!ZSX![!zX!]!zX!^!zX!_!zX!`!zX!a!zX!b!zX!c!zX!d!zX!e!zX!v!zX~P!zOckOdlOemOfnOgoOhpOiqOjrOvsO![sO!]sO!^sO!_sO!`sO!asO!bsO!csO!dsO!esO~O!v!yX~P$lOV{O]PO^PO_PO`ROaROmUOpVOrWOxXOyYO}ZO!Q`O!S^O!T^O!U^O!V^O!W^O!X^O~OTyO~P&QOV!OOpVO~Os!QO~Om!RO~Om!SO~Om!TO~OckXdkXekXfkXgkXhkXikXjkXvkX!PSX!ZSX![kX!]kX!^kX!_kX!`kX!akX!bkX!ckX!dkX!ekX!vkX!YkXlkX~Os!UO~OV!VO~O!PsO!ZsO~OT!ZOV!YO~Os!^O~O!o!_O!p!`O!q!aO!r!bO!v!yX~OT!cO~OTRO~P&QO!YYX~P$lOU!fOcZXdZXeZXfZXgZXhZXiZXjZXvZX!YZX![ZX!]ZX!^ZX!_ZX!`ZX!aZX!bZX!cZX!dZX!eZX~OU!oO!YYX~O!Y!pO~OU!qO!o!_O!p!`O!q!aO!r!bO~Ov!rO~P!zOckOdlOemOfnOgoOhpOiqOjrO~OlYX!YYXtYX~P-aOl!sO!Y!pO~Ov!|O!Y!{O~Ov#SO~Ot#UO!Y#TO~OckOebifbigbihbiibijbivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~Odbi~P.wOdlO~P.wOckOdlOemOjrOgbihbiibivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~Ofbi~P2nOckOdlOemOfnOiqOjrOhbivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~Ogbi~P6^OgoO~P6^OfnO~P2nOckOdlOemOfbigbihbiibijbivbi![bi!]bi!^bi!_bi!`bi!abi!bbi!cbi!dbi!ebi!vbiUbi!Ybilbi!obi!pbi!qbi!rbitbiwbiTbiVbi]bi^bi_bi`biabimbipbirbixbiybi}bi!Qbi!Sbi!Tbi!Ubi!Vbi!Wbi!Xbi!hbi!ibi!kbi!mbi|bi~O!oRi!pRi!qRi!rRi!vRiURilRi|RiwRi~P-aOU#XO~P-aOt#YO!Y!pO~Ov#ZO~Ow#[O~P-aO!P#]O~Ot#^O!Y!pO~OU#^O~P-aOt#aO!Y!pO~O!o!_O!q!ni!r!ni!v!niU!nil!ni|!niw!ni~O!p!ni~P?pO!p!`O~P?pO!o!_O!p!`O!q!aO!r!ni!v!niU!nil!ni|!niw!ni~OUXi!YXilXitXi~P-aOw#eO~P-aOV#fO~OckOdlOemOfnOgoOhpOiqOjrO~PVOt!ui!Y!ui~P-aOw#nO~P-aO!o!_O!p!`O!q!aO!r!bOl{X|{X~Ol#pO|#oO~Ow#qO~P-aO!o!_O!p!`O!q!aO!r!bO!v!jyU!jyl!jy|!jyw!jy~Ol#rO!o!_O!p!`O!q!aO!r!bO~OU#sO~P-aOl#xO!o!_O!p!`O!q!aO!r!bO~O!o!_O!p!`O!q!aO!r!bOl{i|{i~Ol#yO~P$lOw#zO!o!_O!p!`O!q!aO!r!bO~Ol#|O~P-aOr!S!i!Q`a!U!V!W!X!TT}yxy~",
goto: "-}!{PP!|#v$WPPP$t%x&T&f(dPPPPP)`PPPPPPPP(dPP*^+YP*^PPP*^PPPP*^,XPP*^PP,[PPPPPPPPPPPPPPPPPP#v-WPP-WP-hP#vPPPP-k-n-qPPP-w(dSgO#UQxTQ!XcQ#O!_Q#P!`Q#Q!aQ#R!bQ#h#[Q#k#`Q#l#eQ#t#nQ#u#oR#w#qmhOTc!_!`!a!b#U#[#`#e#n#o#qlbOTc!_!`!a!b#U#[#`#e#n#o#qQ![dQ!v!RQ!x!TR#_!{!U[Uklmnopqrs{!O!Q!S!U!V!Y!^!p!r!|#S#Z#]#f#zl]OTc!_!`!a!b#U#[#`#e#n#o#qX!Zd!R!T!{UvT{!YX}U!Q!U!^UwT{!YQ|UQ!u!QQ!y!UR!}!^SSO#UQtT[zU{!Q!U!Y!^d!Wc!_!`!a!b#[#`#e#n#oQ!fkQ!glQ!hmQ!inQ!joQ!kpQ!lqQ!mrQ!nsQ!t!OQ!w!SQ!z!VQ#V!pQ#W!rQ#`!|Q#b#SQ#g#ZQ#j#]Q#m#fQ#v#qR#{#z!s_OTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#z!n_OUcklmnopqrs!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#zTuT{!s[OTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#z!r[OTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#zR!PVR#i#[!saOTUcklmnopqrs{!O!Q!S!U!V!Y!^!_!`!a!b!p!r!|#S#U#Z#[#]#`#e#f#n#o#q#zmeOTc!_!`!a!b#U#[#`#e#n#o#qR!]dRjOR!eiQ!diR#c#TQjOR#d#U",
nodeNames: "⚠ Expression Logic Logic_predicates Variable Local ) ( Tuple Setexpr_enum_min2 Setexpr_enum Setexpr Literal Integer EmptySet IntegerSet Global Radical Setexpr_binary + - * \\ ∆ ∩ × Setexpr_generators } { Enumeration Boolean Filter_expression Filter [ ] Declarative ∈ | PrefixD PrefixI Imperative Imp_blocks ; PrefixR Recursion := Function TextFunction BigPr SmallPr Card Bool Debool Red , :∈ ∉ ⊆ ⊄ ⊂ > ≥ < ≤ ≠ = Logic_unary Negation ¬ Predicate Logic_quantor ∀ Variable_pack ∃ Logic_binary ⇔ ⇒ & Function_decl Arguments Declaration",
maxTerm: 88,
nodeProps: [
["openedBy", 6,"(",28,"{"],
["closedBy", 7,")",29,"}"]
],
skippedNodes: [0],
repeatNodeCount: 0,
tokenData: "6g~R!iX^%ppq%pvw&exy&jyz&oz{&t{|&y|}'O}!O'T!Q!['Y![!]'b!]!^'u!^!_'z!_!`(P!`!a(U!c!d(Z!e!f(Z!f!g(i!h!i(q!k!l)e!r!s)j!t!u*^!u!v(Z!v!w(Z!z!{(Z!|!}*n!}#O*s#O#P*x#P#Q*}#R#S+S#T#U+S#U#V+j#V#W-Y#W#X.u#X#d+S#d#e1_#e#f+S#f#g2t#g#o+S#o#p4O#p#q4T#q#r4Y#y#z%p$f$g%p$r$s4_%o%p4d5i6S+S#BY#BZ%p$IS$I_%p$I|$JO%p$JT$JU%p$KV$KW%p% l% m4i%%Y%%Z4n%%[%%]4s%&Y%&Z4x%&]%&^4}%&_%&`5S%&`%&a5X%&b%&c5^%&c%&d5c%'S%'T5h%'T%'U5m%'U%'V5r%(^%(_5w%(b%(c5|%(c%(d6R%)Q%)R6W%)S%)T6]%)U%)V6b&FU&FV%p~%uY!x~X^%ppq%p#y#z%p$f$g%p#BY#BZ%p$IS$I_%p$I|$JO%p$JT$JU%p$KV$KW%p&FU&FV%p~&jO!r~~&oOV~~&tOU~~&yOe~~'OOc~~'TO!Y~~'YOd~~'_P]~!Q!['Y~'eQ!_!`'k%&b%&c'p~'pO!P~~'uO!Z~~'zO|~~(PO!b~~(UO!e~~(ZO!`~~(^P!Q![(a~(fP`~!Q![(a~(nPx~!Q![(a~(tQ!Q![(z#]#^)S~)PP!Q~!Q![(z~)VP!R![)Y~)_Qr~|})S!Q![)Y~)jOy~~)mQ!Q![)s#f#g){~)xP!i~!Q![)s~*OP!R![*R~*WQ!S~|}){!Q![*R~*cP}~!Q![*f~*kPa~!Q![*f~*sO_~~*xOs~~*}Og~~+SOt~~+XRT~!Q![+b#T#o+S5i6S+S~+gPT~!Q![+b~+oTT~!Q![+b#T#c+S#c#d,O#d#o+S5i6S+S~,TTT~!Q![+b#T#c+S#c#d,d#d#o+S5i6S+S~,iTT~!Q![+b#T#`+S#`#a,x#a#o+S5i6S+S~-PR!V~T~!Q![+b#T#o+S5i6S+S~-_ST~!Q![+b#T#U-k#U#o+S5i6S+S~-pTT~!Q![+b#T#f+S#f#g.P#g#o+S5i6S+S~.UTT~!Q![+b#T#W+S#W#X.e#X#o+S5i6S+S~.lR!U~T~!Q![+b#T#o+S5i6S+S~.zTT~!Q![+b#T#X+S#X#Y/Z#Y#o+S5i6S+S~/`TT~!Q![+b#T#U+S#U#V/o#V#o+S5i6S+S~/tTT~!Q![+b#T#c+S#c#d0T#d#o+S5i6S+S~0YTT~!Q![+b#T#c+S#c#d0i#d#o+S5i6S+S~0nTT~!Q![+b#T#`+S#`#a0}#a#o+S5i6S+S~1UR!W~T~!Q![+b#T#o+S5i6S+S~1dTT~!Q![+b#T#f+S#f#g1s#g#o+S5i6S+S~1xST~!Q!R+b!R![2U#T#o+S5i6S+S~2]Q!T~T~|}2c!Q![2U~2fP!R![2i~2nQ!T~|}2c!Q![2i~2yTT~!Q![+b#T#X+S#X#Y3Y#Y#o+S5i6S+S~3_TT~!Q![+b#T#W+S#W#X3n#X#o+S5i6S+S~3uR!X~T~!Q![+b#T#o+S5i6S+S~4TOm~~4YOw~~4_Ol~~4dO!h~~4iOj~~4nOp~~4sO!p~~4xO!o~~4}O!k~~5SO!m~~5XO^~~5^Oh~~5cOv~~5hO![~~5mO!q~~5rOi~~5wOf~~5|O!d~~6RO!c~~6WO!a~~6]O!_~~6bO!^~~6gO!]~",
tokenizers: [0],
topRules: {"Expression":[0,1]},
tokenPrec: 1710
})

View File

@ -0,0 +1,247 @@
///////////////////////////////////////////////////////////
// ------------- Generator Definitions --------------------
///////////////////////////////////////////////////////////
@detectDelim
///////////////////////////////////////////////////////////
// ------------- Precedence Definitions --------------------
///////////////////////////////////////////////////////////
@precedence {
plus @left minus @left,
times @left,
not @right,
log_equiv @left,
log_impl @left,
log_or @left,
log_and @left,
set_decart @left set_union @left set_intersect @left set_minus @left set_symminus @left,
set_bool @right,
quant @right
}
///////////////////////////////////////////////////////////
// ------------- Terminal Tokens --------------------------
///////////////////////////////////////////////////////////
@tokens {
space { @whitespace+ }
Integer { $[0-9]+ }
EmptySet { "∅" }
IntegerSet { "Z" }
BigPr { "Pr"$[1-9]$[0-9]*(","$[1-9]$[0-9]*)* }
SmallPr { "pr"$[1-9]$[0-9]*(","$[1-9]$[0-9]*)* }
Filter { "Fi"$[1-9]$[0-9]*(","$[1-9]$[0-9]*)* }
Card { "card" }
Bool { "bool" }
Debool { "debool" }
Red { "red" }
Global { $[XCSDAT]$[0-9]+ }
Function { "F"$[0-9]+ }
Predicate { "P"$[0-9]+ }
Radical { "R"$[0-9]+ }
Local { $[_a-zα-ω]($[a-zα-ω])*$[0-9]* }
PrefixR { "R" }
PrefixI { "I" }
PrefixD { "D" }
"¬"
"∀" "∃" "⇔" "⇒" "" "&"
""
"+" "-" "*" "" "\\" "∆" "∩" "×"
"∈" "∉" "⊆" "⊄" "⊂" ">" "≥" "≤" "<" "≠" "="
":∈" ":="
"," ";" "|"
"[" "]"
"{" "}"
"(" ")"
@precedence {
Filter
BigPr
Predicate
Function
Global
Radical
PrefixR
PrefixI
PrefixD
}
@precedence {
Card
Bool
Debool
Red
SmallPr
Local
}
}
@skip { space }
///////////////////////////////////////////////////////////////////////////////
// ------------------------- Grammar Rules ------------------------------------
///////////////////////////////////////////////////////////////////////////////
// ------------------------- Language Expression ------------------------------
@top Expression {
logic_or_setexpr |
Function_decl
}
logic_or_setexpr {
Logic |
Setexpr
}
Function_decl {
"[" Arguments "]" logic_or_setexpr
}
// ------------------------- Variables and arguments -------------------------
Arguments {
Declaration |
Arguments "," Declaration
}
Declaration {
Local "∈" Setexpr
}
Variable {
Local |
Tuple
}
Variable_pack {
Variable |
Variable_pack "," Variable
}
// ------------------------- Logic Expressions --------------------------------
Logic {
Logic_predicates |
Logic_unary |
Logic_binary |
"(" Logic ")"
}
Logic_predicates {
Variable ":∈" Setexpr |
Variable ":=" Setexpr |
Setexpr "∈" Setexpr |
Setexpr "∉" Setexpr |
Setexpr "⊆" Setexpr |
Setexpr "⊄" Setexpr |
Setexpr "⊂" Setexpr |
Setexpr ">" Setexpr |
Setexpr "≥" Setexpr |
Setexpr "<" Setexpr |
Setexpr "≤" Setexpr |
Setexpr "≠" Setexpr |
Setexpr "=" Setexpr
}
Logic_unary {
Negation { !not "¬" Logic } |
Predicate "[" Setexpr_enum "]" |
Logic_quantor
}
Logic_quantor {
"∀" Variable_pack "∈" Setexpr !quant Logic |
"∃" Variable_pack "∈" Setexpr !quant Logic
}
Logic_binary {
Logic !log_equiv "⇔" Logic |
Logic !log_impl "⇒" Logic |
Logic !log_or "" Logic |
Logic !log_and "&" Logic
}
// ------------------------- Set Expressions ----------------------------------
Setexpr {
Literal |
identifier |
Setexpr_binary |
Setexpr_generators |
Function "[" Setexpr_enum "]" |
TextFunction "(" Setexpr ")"
}
TextFunction {
BigPr |
SmallPr |
Card |
Bool |
Debool |
Red
}
Setexpr_enum {
Setexpr |
Setexpr_enum_min2
}
Setexpr_enum_min2 {
Setexpr_enum "," Setexpr
}
Literal {
Integer |
EmptySet |
IntegerSet
}
identifier {
Local |
Global |
Radical
}
Setexpr_binary {
Setexpr !plus "+" Setexpr |
Setexpr !minus "-" Setexpr |
Setexpr !times "*" Setexpr |
Setexpr !set_union "" Setexpr |
Setexpr !set_minus "\\" Setexpr |
Setexpr !set_symminus "∆" Setexpr |
Setexpr !set_intersect "∩" Setexpr |
Setexpr !set_decart "×" Setexpr |
"(" Setexpr_binary ")"
}
Setexpr_generators {
Enumeration |
Tuple |
Boolean |
Filter_expression |
Declarative |
Imperative |
Recursion
}
Enumeration {
"{" Setexpr_enum "}"
}
Tuple {
"(" Setexpr_enum_min2 ")"
}
Boolean {
!set_bool "" "(" Setexpr ")" |
!set_bool "" Boolean
}
Filter_expression {
Filter "[" Setexpr_enum "]" "(" Setexpr ")"
}
Declarative {
"{" Local "∈" Setexpr "|" Logic "}" |
PrefixD "{" Variable "∈" Setexpr "|" Logic "}"
}
Recursion {
PrefixR "{" Variable ":=" Setexpr ("|" Logic)? "|" Setexpr "}"
}
Imperative {
PrefixI "{" Setexpr "|" Imp_blocks "}"
}
Imp_blocks {
Logic |
Imp_blocks ";" Logic
}

View File

@ -27,7 +27,7 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
const nodes: GraphNode[] = useMemo(
() =>
syntaxTree.map(node => ({
id: String(node.uid),
id: String(syntaxTree.length - node.uid), // invert order of IDs to force correct ordering in graph layout
label: labelSyntaxTree(node),
fill: colorBgSyntaxTree(node, colors)
})),
@ -40,15 +40,15 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
if (node.parent !== node.uid) {
result.push({
id: String(node.uid),
source: String(node.parent),
target: String(node.uid)
source: String(syntaxTree.length - node.parent),
target: String(syntaxTree.length - node.uid)
});
}
});
return result;
}, [syntaxTree]);
const handleHoverIn = useCallback((node: GraphNode) => setHoverID(Number(node.id)), []);
const handleHoverIn = useCallback((node: GraphNode) => setHoverID(syntaxTree.length - Number(node.id)), [syntaxTree]);
const handleHoverOut = useCallback(() => setHoverID(undefined), []);

View File

@ -6,6 +6,7 @@ import { Node } from 'reactflow';
import { LibraryItemType, LocationHead } from './library';
import { IOperation } from './oss';
import { UserID } from './user';
/**
* Represents graph dependency mode.
@ -182,6 +183,7 @@ export interface ILibraryFilter {
isVisible?: boolean;
isOwned?: boolean;
isEditor?: boolean;
filterUser?: UserID;
}
/**

View File

@ -232,6 +232,7 @@ export enum RSErrorType {
invalidBinding = 34836,
localOutOfScope = 34837,
invalidElementPredicate = 34838,
invalidEmptySetUsage = 34839,
invalidArgsArity = 34840,
invalidArgumentType = 34841,
globalStructure = 34844,

View File

@ -16,6 +16,7 @@ import DlgChangeLocation from '@/dialogs/DlgChangeLocation';
import useLocalStorage from '@/hooks/useLocalStorage';
import { ILibraryItem, IRenameLocationData, LocationHead } from '@/models/library';
import { ILibraryFilter } from '@/models/miscellaneous';
import { UserID } from '@/models/user';
import { storage } from '@/utils/constants';
import { information } from '@/utils/labels';
import { convertToCSV, toggleTristateFlag } from '@/utils/utils';
@ -36,8 +37,9 @@ function LibraryPage() {
const [head, setHead] = useLocalStorage<LocationHead | undefined>(storage.librarySearchHead, undefined);
const [subfolders, setSubfolders] = useLocalStorage<boolean>(storage.librarySearchSubfolders, false);
const [isVisible, setIsVisible] = useLocalStorage<boolean | undefined>(storage.librarySearchVisible, true);
const [isOwned, setIsOwned] = useLocalStorage<boolean | undefined>(storage.librarySearchEditor, undefined);
const [isOwned, setIsOwned] = useLocalStorage<boolean | undefined>(storage.librarySearchOwned, undefined);
const [isEditor, setIsEditor] = useLocalStorage<boolean | undefined>(storage.librarySearchEditor, undefined);
const [filterUser, setFilterUser] = useLocalStorage<UserID | undefined>(storage.librarySearchUser, undefined);
const [showRenameLocation, setShowRenameLocation] = useState(false);
const filter: ILibraryFilter = useMemo(
@ -50,9 +52,22 @@ function LibraryPage() {
isVisible: user ? isVisible : true,
folderMode: options.folderMode,
subfolders: subfolders,
location: options.location
location: options.location,
filterUser: filterUser
}),
[head, path, query, isEditor, isOwned, isVisible, user, options.folderMode, options.location, subfolders]
[
head,
path,
query,
isEditor,
isOwned,
isVisible,
user,
options.folderMode,
options.location,
subfolders,
filterUser
]
);
const hasCustomFilter = useMemo(
@ -63,6 +78,7 @@ function LibraryPage() {
filter.isEditor !== undefined ||
filter.isOwned !== undefined ||
filter.isVisible !== true ||
filter.filterUser !== undefined ||
!!filter.location,
[filter]
);
@ -84,8 +100,9 @@ function LibraryPage() {
setIsVisible(true);
setIsOwned(undefined);
setIsEditor(undefined);
setFilterUser(undefined);
options.setLocation('');
}, [setHead, setIsVisible, setIsOwned, setIsEditor, options.setLocation]);
}, [setHead, setIsVisible, setIsOwned, setIsEditor, setFilterUser, options.setLocation]);
const promptRenameLocation = useCallback(() => {
setShowRenameLocation(true);
@ -186,6 +203,8 @@ function LibraryPage() {
toggleVisible={toggleVisible}
isEditor={isEditor}
toggleEditor={toggleEditor}
filterUser={filterUser}
setFilterUser={setFilterUser}
resetFilter={resetFilter}
folderMode={options.folderMode}
toggleFolderMode={toggleFolderMode}

View File

@ -1,19 +1,31 @@
'use client';
import clsx from 'clsx';
import { useCallback } from 'react';
import { motion } from 'framer-motion';
import { useCallback, useMemo } from 'react';
import { LocationIcon, VisibilityIcon } from '@/components/DomainIcons';
import { IconEditor, IconFilterReset, IconFolder, IconFolderTree, IconOwner } from '@/components/Icons';
import {
IconEditor,
IconFilterReset,
IconFolder,
IconFolderSearch,
IconFolderTree,
IconOwner,
IconUserSearch
} from '@/components/Icons';
import { CProps } from '@/components/props';
import SelectUser from '@/components/select/SelectUser';
import Dropdown from '@/components/ui/Dropdown';
import DropdownButton from '@/components/ui/DropdownButton';
import MiniButton from '@/components/ui/MiniButton';
import SearchBar from '@/components/ui/SearchBar';
import SelectorButton from '@/components/ui/SelectorButton';
import { useAuth } from '@/context/AuthContext';
import { useUsers } from '@/context/UsersContext';
import useDropdown from '@/hooks/useDropdown';
import { LocationHead } from '@/models/library';
import { UserID } from '@/models/user';
import { animateDropdownItem } from '@/styling/animations';
import { prefixes } from '@/utils/constants';
import { describeLocationHead, labelLocationHead } from '@/utils/labels';
import { tripleToggleColor } from '@/utils/utils';
@ -39,6 +51,9 @@ interface ToolbarSearchProps {
toggleOwned: () => void;
isEditor: boolean | undefined;
toggleEditor: () => void;
filterUser: UserID | undefined;
setFilterUser: React.Dispatch<React.SetStateAction<UserID | undefined>>;
resetFilter: () => void;
}
@ -63,10 +78,19 @@ function ToolbarSearch({
toggleOwned,
isEditor,
toggleEditor,
filterUser,
setFilterUser,
resetFilter
}: ToolbarSearchProps) {
const { user } = useAuth();
const headMenu = useDropdown();
const userMenu = useDropdown();
const { users } = useUsers();
const userActive = useMemo(
() => isOwned !== undefined || isEditor !== undefined || filterUser !== undefined,
[isOwned, isEditor, filterUser]
);
const handleChange = useCallback(
(newValue: LocationHead | undefined) => {
@ -106,7 +130,7 @@ function ToolbarSearch({
<div
className={clsx(
'ml-3 pt-1 self-center',
'min-w-[4.5rem] sm:min-w-[5.5rem]',
'min-w-[4.5rem] sm:min-w-[7.4rem]',
'select-none',
'whitespace-nowrap'
)}
@ -114,41 +138,58 @@ function ToolbarSearch({
{filtered} из {total}
</div>
{user ? (
<div className='cc-icons'>
<MiniButton
title='Видимость'
icon={<VisibilityIcon value={true} className={tripleToggleColor(isVisible)} />}
onClick={toggleVisible}
/>
<div className='cc-icons'>
<MiniButton
title='Видимость'
icon={<VisibilityIcon value={true} className={tripleToggleColor(isVisible)} />}
onClick={toggleVisible}
/>
<div ref={userMenu.ref} className='flex'>
<MiniButton
title='Я - Владелец'
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
onClick={toggleOwned}
/>
<MiniButton
title='Я - Редактор'
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
onClick={toggleEditor}
/>
<MiniButton
title='Сбросить фильтры'
icon={<IconFilterReset size='1.25rem' className='icon-primary' />}
onClick={resetFilter}
disabled={!hasCustomFilter}
title='Поиск пользователя'
hideTitle={userMenu.isOpen}
icon={<IconUserSearch size='1.25rem' className={userActive ? 'icon-green' : 'icon-primary'} />}
onClick={userMenu.toggle}
/>
<Dropdown isOpen={userMenu.isOpen}>
<DropdownButton
text='Я - Владелец'
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
onClick={toggleOwned}
/>
<DropdownButton
text='Я - Редактор'
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
onClick={toggleEditor}
/>
<motion.div className='px-1 pb-1' variants={animateDropdownItem}>
<SelectUser
noBorder
placeholder='Выберите автора'
className='min-w-[15rem] text-sm'
items={users}
value={filterUser}
onSelectValue={setFilterUser}
/>
</motion.div>
</Dropdown>
</div>
) : null}
<div className='flex h-full'>
<MiniButton
title='Сбросить фильтры'
icon={<IconFilterReset size='1.25rem' className='icon-primary' />}
onClick={resetFilter}
disabled={!hasCustomFilter}
/>
</div>
<div className='flex h-full flex-grow pr-4'>
<SearchBar
id='library_search'
placeholder='Поиск'
noBorder
className='min-w-[7rem] sm:min-w-[10rem]'
className={clsx('min-w-[7rem] sm:min-w-[10rem] max-w-[20rem]', folderMode && 'flex-grow')}
value={query}
onChange={setQuery}
/>
@ -163,7 +204,7 @@ function ToolbarSearch({
head ? (
<LocationIcon value={head} size='1.25rem' />
) : (
<IconFolder size='1.25rem' className='clr-text-controls' />
<IconFolderSearch size='1.25rem' className='clr-text-controls' />
)
}
onClick={handleFolderClick}
@ -171,7 +212,7 @@ function ToolbarSearch({
/>
<Dropdown isOpen={headMenu.isOpen} stretchLeft className='z-modalTooltip'>
<DropdownButton className='w-[10rem]' title='Переключение в режим Проводник' onClick={handleToggleFolder}>
<DropdownButton title='Переключение в режим Проводник' onClick={handleToggleFolder}>
<div className='inline-flex items-center gap-3'>
<IconFolderTree size='1rem' className='clr-text-controls' />
<span>проводник...</span>
@ -207,7 +248,7 @@ function ToolbarSearch({
placeholder='Путь'
noIcon
noBorder
className='min-w-[4.5rem] sm:min-w-[5rem]'
className='w-[4.5rem] sm:w-[5rem] flex-grow'
value={path}
onChange={setPath}
/>

View File

@ -89,13 +89,18 @@ function ViewSideLocation({
place='right-start'
/>
<div className='cc-icons'>
{canRename ? (
<MiniButton
icon={<IconFolderEdit size='1.25rem' className='icon-primary' />}
titleHtml='<b>Редактирование пути</b><br/>Перемещаются только Ваши схемы<br/>в указанной папке (и подпапках)'
onClick={onRenameLocation}
/>
) : null}
<MiniButton
icon={<IconFolderEdit size='1.25rem' className='icon-primary' />}
titleHtml='<b>Редактирование пути</b><br/>Перемещаются только Ваши схемы<br/>в указанной папке (и подпапках)'
onClick={onRenameLocation}
disabled={!canRename}
title='Вложенные папки' // prettier: split-lines
icon={<SubfoldersIcon value={subfolders} />}
onClick={toggleSubfolders}
/>
<MiniButton title='Вложенные папки' icon={<SubfoldersIcon value={subfolders} />} onClick={toggleSubfolders} />
<MiniButton
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
title='Переключение в режим Поиск'

View File

@ -7,6 +7,7 @@ import { useConceptOptions } from '@/context/ConceptOptionsContext';
import { useConceptNavigation } from '@/context/NavigationContext';
import useQueryStrings from '@/hooks/useQueryStrings';
import { HelpTopic } from '@/models/miscellaneous';
import { PARAMETER } from '@/utils/constants';
import TopicsList from './TopicsList';
import ViewTopic from './ViewTopic';
@ -18,6 +19,14 @@ function ManualsPage() {
const { mainHeight } = useConceptOptions();
if (!Object.values(HelpTopic).includes(activeTopic)) {
setTimeout(() => {
router.push(urls.page404);
}, PARAMETER.refreshTimeout);
console.log(1);
return null;
}
const onSelectTopic = useCallback(
(newTopic: HelpTopic) => {
router.push(urls.help_topic(newTopic));

View File

@ -5,6 +5,7 @@ import {
IconFolderEdit,
IconFolderEmpty,
IconFolderOpened,
IconFolderSearch,
IconFolderTree,
IconOSS,
IconRSForm,
@ -12,7 +13,8 @@ import {
IconShow,
IconSortAsc,
IconSortDesc,
IconSubfolders
IconSubfolders,
IconUserSearch
} from '@/components/Icons';
import LinkTopic from '@/components/ui/LinkTopic';
import { useConceptOptions } from '@/context/ConceptOptionsContext';
@ -43,11 +45,14 @@ function HelpLibrary() {
<IconSortAsc size='1rem' className='inline-icon' />
<IconSortDesc size='1rem' className='inline-icon' /> сортировка по клику на заголовок таблицы
</li>
<li>
<IconUserSearch size='1rem' className='inline-icon' /> фильтр по пользователю
</li>
<li>
<IconSearch size='1rem' className='inline-icon' /> фильтр по названию и шифру
</li>
<li>
<IconFolder size='1rem' className='inline-icon' /> фильтр по расположению
<IconFolderSearch size='1rem' className='inline-icon' /> фильтр по расположению
</li>
<li>
<IconFilterReset size='1rem' className='inline-icon' /> сбросить фильтры

View File

@ -6,7 +6,9 @@ import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
import { toast } from 'react-toastify';
import BadgeHelp from '@/components/info/BadgeHelp';
import { CProps } from '@/components/props';
import RSInput from '@/components/RSInput';
import { parser as rslangParser } from '@/components/RSInput/rslang/parserAST';
import { RSTextWrapper } from '@/components/RSInput/textEditing';
import Overlay from '@/components/ui/Overlay';
import { useRSForm } from '@/context/RSFormContext';
@ -18,6 +20,7 @@ import { ConstituentaID, IConstituenta } from '@/models/rsform';
import { getDefinitionPrefix } from '@/models/rsformAPI';
import { IExpressionParse, IRSErrorDescription, SyntaxTree } from '@/models/rslang';
import { TokenID } from '@/models/rslang';
import { transformAST } from '@/utils/codemirror';
import { storage } from '@/utils/constants';
import { errors, labelTypification } from '@/utils/labels';
@ -124,17 +127,25 @@ function EditorRSExpression({
setIsModified(true);
}, []);
function handleShowAST() {
handleCheckExpression(parse => {
if (!parse.astText) {
toast.error(errors.astFailed);
} else {
setSyntaxTree(parse.ast);
// TODO: return prefix from parser API instead of prefixLength
setExpression(getDefinitionPrefix(activeCst) + value);
setShowAST(true);
}
});
function handleShowAST(event: CProps.EventMouse) {
if (event.ctrlKey) {
const tree = rslangParser.parse(value);
const ast = transformAST(tree);
setSyntaxTree(ast);
setExpression(value);
setShowAST(true);
} else {
handleCheckExpression(parse => {
if (!parse.astText) {
toast.error(errors.astFailed);
} else {
setSyntaxTree(parse.ast);
// TODO: return prefix from parser API instead of prefixLength
setExpression(getDefinitionPrefix(activeCst) + value);
setShowAST(true);
}
});
}
}
const controls = useMemo(

View File

@ -1,4 +1,5 @@
import { IconControls, IconTree } from '@/components/Icons';
import { CProps } from '@/components/props';
import MiniButton from '@/components/ui/MiniButton';
import Overlay from '@/components/ui/Overlay';
import { useRSForm } from '@/context/RSFormContext';
@ -8,7 +9,7 @@ interface ToolbarRSExpressionProps {
showControls: boolean;
toggleControls: () => void;
showAST: () => void;
showAST: (event: CProps.EventMouse) => void;
}
function ToolbarRSExpression({ disabled, showControls, toggleControls, showAST }: ToolbarRSExpressionProps) {

View File

@ -6,6 +6,7 @@ import { GramData, Grammeme, NounGrams, PartOfSpeech, VerbGrams } from '@/models
import { GraphColoring } from '@/models/miscellaneous';
import { CstClass, ExpressionStatus, IConstituenta } from '@/models/rsform';
import { ISyntaxTreeNode, TokenID } from '@/models/rslang';
import { PARAMETER } from '@/utils/constants';
/**
* Represents application color theme configuration.
@ -375,8 +376,65 @@ export function colorBgSyntaxTree(node: ISyntaxTreeNode, colors: IColorTheme): s
case TokenID.ITERATE:
return colors.bgRed;
}
switch (node.data.value) {
case 'Expression':
case 'Local':
return colors.bgGreen;
case 'Global':
case 'Radical':
case 'Function':
case 'Predicate':
case 'Literal':
case 'Integer':
case 'EmptySet':
case 'IntegerSet':
return colors.bgTeal;
case 'Logic':
case 'Logic_predicates':
case 'Variable':
case 'Tuple':
case 'Setexpr_enum_min2':
case 'Setexpr_enum':
case 'Setexpr':
case 'Setexpr_binary':
case 'Setexpr_generators':
case 'Enumeration':
case 'Boolean':
case 'Filter_expression':
case 'Filter':
case 'Declarative':
case 'Imperative':
case 'Imp_blocks':
case 'Recursion':
case 'TextFunction':
case 'Logic_unary':
case 'Logic_quantor':
case 'Variable_pack':
case 'Logic_binary':
case 'Function_decl':
case 'Arguments':
case 'Declaration':
return colors.bgBlue;
case 'BigPr':
case 'SmallPr':
case 'Card':
case 'Bool':
case 'Debool':
case 'Red':
case 'PrefixD':
case 'PrefixI':
case 'PrefixR':
return colors.bgPurple;
case PARAMETER.errorNodeLabel:
return colors.bgRed;
}
// node
return colors.bgRed;
return colors.bgPurple;
}
/**

View File

@ -13,8 +13,10 @@ import { IEntityReference, ISyntacticReference } from '@/models/language';
import { parseEntityReference, parseGrammemes, parseSyntacticReference } from '@/models/languageAPI';
import { IConstituenta } from '@/models/rsform';
import { isBasicConcept } from '@/models/rsformAPI';
import { SyntaxTree } from '@/models/rslang';
import { colorFgGrammeme, IColorTheme } from '../styling/color';
import { PARAMETER } from './constants';
import { describeConstituentaTerm, labelCstTypification, labelGrammeme } from './labels';
/**
@ -91,6 +93,56 @@ export function printTree(tree: Tree): string {
return state.output;
}
/**
* Transform Tree to {@link SyntaxTree}.
*/
export function transformAST(tree: Tree): SyntaxTree {
const result: SyntaxTree = [];
const parents: number[] = [];
const cursor = tree.cursor();
let finished = false;
let leave = true;
while (!finished) {
let node = cursorNode(cursor);
node.isLeaf = !cursor.firstChild();
leave = true;
result.push({
uid: result.length,
parent: parents.length > 0 ? parents[parents.length - 1] : result.length,
typeID: node.type.id,
start: node.from,
finish: node.to,
data: {
dataType: 'string',
value: node.type.name == '⚠' ? PARAMETER.errorNodeLabel : node.type.name
}
});
parents.push(result.length - 1);
if (!node.isLeaf) continue;
for (;;) {
node = cursorNode(cursor, node.isLeaf);
if (leave) {
parents.pop();
}
leave = cursor.type.isAnonymous;
node.isLeaf = false;
if (cursor.nextSibling()) {
break;
}
if (!cursor.parent()) {
finished = true;
break;
}
leave = true;
}
}
return result;
}
/**
* Retrieves a list of all nodes, containing given range and corresponding to a filter.
*/

View File

@ -34,6 +34,7 @@ export const PARAMETER = {
statSmallThreshold: 3, // characters - threshold for small labels - small font
logicLabel: 'LOGIC',
errorNodeLabel: '[ERROR]',
exteorVersion: '4.9.5',
TOOLTIP_WIDTH: 'max-w-[29rem]'
@ -116,6 +117,7 @@ export const storage = {
librarySearchVisible: 'library.search.visible',
librarySearchOwned: 'library.search.owned',
librarySearchEditor: 'library.search.editor',
librarySearchUser: 'library.search.user',
libraryPagination: 'library.pagination',
rsgraphFilter: 'rsgraph.filter2',

View File

@ -362,11 +362,11 @@ export function describeExpressionStatus(status: ExpressionStatus): string {
export function labelHelpTopic(topic: HelpTopic): string {
// prettier-ignore
switch (topic) {
case HelpTopic.MAIN: return 'Портал';
case HelpTopic.MAIN: return '🏠 Портал';
case HelpTopic.THESAURUS: return 'Тезаурус';
case HelpTopic.THESAURUS: return '📖 Тезаурус';
case HelpTopic.INTERFACE: return 'Интерфейс';
case HelpTopic.INTERFACE: return '🦄 Интерфейс';
case HelpTopic.UI_LIBRARY: return 'Библиотека';
case HelpTopic.UI_RS_MENU: return 'Меню схемы';
case HelpTopic.UI_RS_CARD: return 'Карточка схемы';
@ -378,7 +378,7 @@ export function labelHelpTopic(topic: HelpTopic): string {
case HelpTopic.UI_CST_CLASS: return 'Класс конституенты';
case HelpTopic.UI_OSS_GRAPH: return 'Граф синтеза';
case HelpTopic.CONCEPTUAL: return 'Концептуализация';
case HelpTopic.CONCEPTUAL: return '♨️ Концептуализация';
case HelpTopic.CC_SYSTEM: return 'Система определений';
case HelpTopic.CC_CONSTITUENTA: return 'Конституента';
case HelpTopic.CC_RELATIONS: return 'Связи понятий';
@ -386,24 +386,24 @@ export function labelHelpTopic(topic: HelpTopic): string {
case HelpTopic.CC_OSS: return 'Операционная схема';
case HelpTopic.CC_PROPAGATION: return 'Сквозные изменения';
case HelpTopic.RSLANG: return 'Экспликация';
case HelpTopic.RSLANG: return '🚀 Экспликация';
case HelpTopic.RSL_TYPES: return 'Типизация';
case HelpTopic.RSL_CORRECT: return 'Переносимость';
case HelpTopic.RSL_INTERPRET: return 'Интерпретируемость';
case HelpTopic.RSL_OPERATIONS: return 'Операции';
case HelpTopic.RSL_TEMPLATES: return 'Банк выражений';
case HelpTopic.TERM_CONTROL: return 'Терминологизация';
case HelpTopic.ACCESS: return 'Доступы';
case HelpTopic.VERSIONS: return 'Версионирование';
case HelpTopic.TERM_CONTROL: return '🪸 Терминологизация';
case HelpTopic.ACCESS: return '👀 Доступы';
case HelpTopic.VERSIONS: return '🏺 Версионирование';
case HelpTopic.INFO: return 'Информация';
case HelpTopic.INFO: return '📰 Информация';
case HelpTopic.INFO_RULES: return 'Правила';
case HelpTopic.INFO_CONTRIB: return 'Разработчики';
case HelpTopic.INFO_PRIVACY: return 'Обработка данных';
case HelpTopic.INFO_API: return 'REST API';
case HelpTopic.EXTEOR: return 'Экстеор';
case HelpTopic.EXTEOR: return '🖥️ Экстеор';
}
}
@ -622,6 +622,9 @@ export function labelSyntaxTree(node: ISyntaxTreeNode): string {
return labelToken(node.typeID);
}
// node
if (node.data.value) {
return node.data.value as string;
}
return 'UNKNOWN ' + String(node.typeID);
}
@ -760,6 +763,8 @@ export function describeRSError(error: IRSErrorDescription): string {
return `Использование имени переменной вне области действия: ${error.params[0]}`;
case RSErrorType.invalidElementPredicate:
return `Несоответствие типизаций операндов для оператора: ${error.params[0]}${error.params[1]}${error.params[2]}`;
case RSErrorType.invalidEmptySetUsage:
return 'Бессмысленное использование пустого множества';
case RSErrorType.invalidArgsArity:
return `Неверное число аргументов терм-функции: ${error.params[0]} != ${error.params[1]}`;
case RSErrorType.invalidArgumentType:

View File

@ -3,10 +3,6 @@
$container= Read-Host -Prompt "Enter backend container name: "
function PopulateDevData() {
ImportInitialData
}
function ImportInitialData() {
docker exec `
-it $container `
python3.12 manage.py loaddata ./fixtures/InitialData.json