mirror of
https://github.com/IRBorisov/ConceptPortal.git
synced 2025-06-26 13:00:39 +03:00
Merge branch 'main' into synthesis
This commit is contained in:
commit
91865e54f0
31
.vscode/settings.json
vendored
31
.vscode/settings.json
vendored
|
@ -84,6 +84,7 @@
|
||||||
"Grammeme",
|
"Grammeme",
|
||||||
"Grammemes",
|
"Grammemes",
|
||||||
"GRND",
|
"GRND",
|
||||||
|
"IDEF",
|
||||||
"impr",
|
"impr",
|
||||||
"inan",
|
"inan",
|
||||||
"incapsulation",
|
"incapsulation",
|
||||||
|
@ -150,39 +151,67 @@
|
||||||
"viewsets",
|
"viewsets",
|
||||||
"wordform",
|
"wordform",
|
||||||
"Wordforms",
|
"Wordforms",
|
||||||
|
"Айзенштат",
|
||||||
|
"Акименков",
|
||||||
|
"Астрина",
|
||||||
|
"Ашихмин",
|
||||||
"Биективная",
|
"Биективная",
|
||||||
"биективной",
|
"биективной",
|
||||||
"Булеан",
|
"Булеан",
|
||||||
"Бурбаки",
|
"Бурбаки",
|
||||||
|
"Бурбакизатор",
|
||||||
"Версионирование",
|
"Версионирование",
|
||||||
|
"Владельцом",
|
||||||
|
"Демешко",
|
||||||
"Десинглетон",
|
"Десинглетон",
|
||||||
|
"доксинг",
|
||||||
|
"Закс",
|
||||||
"интерпретируемости",
|
"интерпретируемости",
|
||||||
"интерпретируемость",
|
"интерпретируемость",
|
||||||
|
"Инттеор",
|
||||||
|
"Климишин",
|
||||||
"компаратив",
|
"компаратив",
|
||||||
|
"Кононенко",
|
||||||
"конституент",
|
"конституент",
|
||||||
"Конституента",
|
"Конституента",
|
||||||
"конституентами",
|
"конституентами",
|
||||||
"конституенте",
|
"конституенте",
|
||||||
"конституенту",
|
"конституенту",
|
||||||
"конституенты",
|
"конституенты",
|
||||||
|
"Крайнев",
|
||||||
"Кучкаров",
|
"Кучкаров",
|
||||||
"Кучкарова",
|
"Кучкарова",
|
||||||
"неинтерпретируемый",
|
"неинтерпретируемый",
|
||||||
"неитерируемого",
|
"неитерируемого",
|
||||||
|
"Никанорова",
|
||||||
|
"операционализации",
|
||||||
|
"операционализированных",
|
||||||
|
"Оргтеор",
|
||||||
|
"Пакулина",
|
||||||
"пересинтез",
|
"пересинтез",
|
||||||
|
"Персиц",
|
||||||
|
"Присакарь",
|
||||||
|
"ПРОКСИМА",
|
||||||
"Родоструктурная",
|
"Родоструктурная",
|
||||||
"родоструктурного",
|
"родоструктурного",
|
||||||
"Родоструктурное",
|
"Родоструктурное",
|
||||||
"родоструктурной",
|
"родоструктурной",
|
||||||
"родоструктурном",
|
"родоструктурном",
|
||||||
|
"родоструктурных",
|
||||||
|
"Савелов",
|
||||||
"Синглетон",
|
"Синглетон",
|
||||||
"твор",
|
"твор",
|
||||||
"Терминологизация",
|
"Терминологизация",
|
||||||
|
"троллинг",
|
||||||
|
"Тулисов",
|
||||||
"Цермелло",
|
"Цермелло",
|
||||||
"ЦИВТ",
|
"ЦИВТ",
|
||||||
|
"Чувашов",
|
||||||
|
"Шульпекин",
|
||||||
"Экстеор",
|
"Экстеор",
|
||||||
"Экстеора",
|
"Экстеора",
|
||||||
"Экстеоре"
|
"Экстеоре",
|
||||||
|
"Юдкин"
|
||||||
],
|
],
|
||||||
"cSpell.language": "en,ru",
|
"cSpell.language": "en,ru",
|
||||||
"cSpell.ignorePaths": ["node_modules/**", "*.json"]
|
"cSpell.ignorePaths": ["node_modules/**", "*.json"]
|
||||||
|
|
15
TODO.txt
15
TODO.txt
|
@ -2,25 +2,24 @@
|
||||||
For more specific TODOs see comments in code
|
For more specific TODOs see comments in code
|
||||||
|
|
||||||
[Functionality - PROGRESS]
|
[Functionality - PROGRESS]
|
||||||
- Landing page
|
|
||||||
- Home page (user specific)
|
|
||||||
|
|
||||||
- Operational synthesis schema as LibraryItem ?
|
- Operational synthesis schema as LibraryItem ?
|
||||||
|
|
||||||
- Draggable rows in constituents table
|
|
||||||
- Clickable IDs in RSEditor tooltips
|
|
||||||
|
|
||||||
- Library organization, search and exploration. Consider new user experience
|
- Library organization, search and exploration. Consider new user experience
|
||||||
- Private projects and permissions. Consider cooperative editing
|
- Private projects and permissions. Consider cooperative editing
|
||||||
- Rework access setup: project-based, user-based, enable sharing. Prevent enumerating access to private schemas by default
|
|
||||||
|
|
||||||
|
|
||||||
[Functionality - PENDING]
|
[Functionality - PENDING]
|
||||||
|
- Search functionality for manuals
|
||||||
- User notifications on edit - consider spam prevention and change aggregation
|
- User notifications on edit - consider spam prevention and change aggregation
|
||||||
- Static analyzer for RSForm
|
- Static analyzer for RSForm
|
||||||
- Content based search in Library
|
- Content based search in Library
|
||||||
- User profile: Settings + settings persistency
|
- User profile: Settings + settings persistency
|
||||||
|
|
||||||
|
- Landing page
|
||||||
|
- Home page (user specific)
|
||||||
|
|
||||||
|
- Draggable rows in constituents table
|
||||||
|
|
||||||
- Export PDF (Items list, Graph)
|
- Export PDF (Items list, Graph)
|
||||||
- ARIA (accessibility considerations) - for now machine reading not supported
|
- ARIA (accessibility considerations) - for now machine reading not supported
|
||||||
- Internationalization - at least english version. Consider react.intl
|
- Internationalization - at least english version. Consider react.intl
|
||||||
|
@ -42,6 +41,8 @@ For more specific TODOs see comments in code
|
||||||
[Security]
|
[Security]
|
||||||
- password-reset leaks info of email being used
|
- password-reset leaks info of email being used
|
||||||
- improve nginx config. Consider DDOS and other types of attacks on infrastructure
|
- improve nginx config. Consider DDOS and other types of attacks on infrastructure
|
||||||
|
- recaptcha for create user and rest password
|
||||||
|
https://yandex.cloud/ru/docs/smartcaptcha
|
||||||
|
|
||||||
|
|
||||||
[Research]
|
[Research]
|
||||||
|
|
|
@ -4,11 +4,11 @@ djangorestframework==3.15.1
|
||||||
django-cors-headers==4.3.1
|
django-cors-headers==4.3.1
|
||||||
django-filter==24.2
|
django-filter==24.2
|
||||||
drf-spectacular==0.27.2
|
drf-spectacular==0.27.2
|
||||||
drf-spectacular-sidecar==2024.5.1
|
drf-spectacular-sidecar==2024.6.1
|
||||||
coreapi==2.3.3
|
coreapi==2.3.3
|
||||||
django-rest-passwordreset==1.4.1
|
django-rest-passwordreset==1.4.1
|
||||||
cctext==0.1.3
|
cctext==0.1.3
|
||||||
pyconcept==0.1.5
|
pyconcept==0.1.6
|
||||||
|
|
||||||
psycopg2-binary==2.9.9
|
psycopg2-binary==2.9.9
|
||||||
gunicorn==22.0.0
|
gunicorn==22.0.0
|
|
@ -16,7 +16,7 @@ Styling conventions
|
||||||
- border: borer-2 outline-none shadow-md
|
- border: borer-2 outline-none shadow-md
|
||||||
- colors: clr-controls
|
- colors: clr-controls
|
||||||
- text: text-start text-sm font-semibold whitespace-nowrap
|
- text: text-start text-sm font-semibold whitespace-nowrap
|
||||||
- behavior modifiers: select-none disabled:cursor-not-allowed
|
- behavior modifiers: select-none disabled:cursor-auto
|
||||||
- transitions:
|
- transitions:
|
||||||
</pre>
|
</pre>
|
||||||
</details>
|
</details>
|
||||||
|
|
|
@ -22,11 +22,14 @@
|
||||||
<title>Концепт Портал</title>
|
<title>Концепт Портал</title>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
if (
|
let isDark = false;
|
||||||
localStorage.getItem('darkMode') === 'true' ||
|
if ('portal.theme.dark' in localStorage) {
|
||||||
localStorage.getItem('color-theme') === 'dark' ||
|
isDark = localStorage.getItem('portal.theme.dark') === 'true';
|
||||||
(!('color-theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)
|
} else if (window.matchMedia) {
|
||||||
) {
|
isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;
|
||||||
|
localStorage.setItem('portal.theme.dark', isDark ? 'true' : 'false');
|
||||||
|
}
|
||||||
|
if (isDark) {
|
||||||
document.documentElement.classList.add('dark');
|
document.documentElement.classList.add('dark');
|
||||||
} else {
|
} else {
|
||||||
document.documentElement.classList.remove('dark');
|
document.documentElement.classList.remove('dark');
|
||||||
|
|
496
rsconcept/frontend/package-lock.json
generated
496
rsconcept/frontend/package-lock.json
generated
|
@ -11,8 +11,8 @@
|
||||||
"@lezer/lr": "^1.4.1",
|
"@lezer/lr": "^1.4.1",
|
||||||
"@reactflow/core": "^11.8.3",
|
"@reactflow/core": "^11.8.3",
|
||||||
"@tanstack/react-table": "^8.17.3",
|
"@tanstack/react-table": "^8.17.3",
|
||||||
"@uiw/codemirror-themes": "^4.22.1",
|
"@uiw/codemirror-themes": "^4.22.2",
|
||||||
"@uiw/react-codemirror": "^4.22.1",
|
"@uiw/react-codemirror": "^4.22.2",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"framer-motion": "^10.18.0",
|
"framer-motion": "^10.18.0",
|
||||||
|
@ -23,24 +23,24 @@
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-intl": "^6.6.8",
|
"react-intl": "^6.6.8",
|
||||||
"react-loader-spinner": "^5.4.5",
|
"react-loader-spinner": "^5.4.5",
|
||||||
"react-pdf": "^7.7.3",
|
"react-pdf": "^9.0.0",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-select": "^5.8.0",
|
"react-select": "^5.8.0",
|
||||||
"react-tabs": "^6.0.2",
|
"react-tabs": "^6.0.2",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"react-tooltip": "^5.26.4",
|
"react-tooltip": "^5.27.0",
|
||||||
"reagraph": "^4.19.0",
|
"reagraph": "^4.19.1",
|
||||||
"use-debounce": "^10.0.1"
|
"use-debounce": "^10.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lezer/generator": "^1.7.0",
|
"@lezer/generator": "^1.7.0",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^20.14.0",
|
"@types/node": "^20.14.5",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
|
@ -49,8 +49,8 @@
|
||||||
"eslint-plugin-tsdoc": "^0.2.17",
|
"eslint-plugin-tsdoc": "^0.2.17",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.4",
|
||||||
"ts-jest": "^29.1.4",
|
"ts-jest": "^29.1.5",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"vite": "^4.5.3"
|
"vite": "^4.5.3"
|
||||||
}
|
}
|
||||||
|
@ -82,12 +82,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/code-frame": {
|
"node_modules/@babel/code-frame": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
|
||||||
"integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==",
|
"integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/highlight": "^7.24.6",
|
"@babel/highlight": "^7.24.7",
|
||||||
"picocolors": "^1.0.0"
|
"picocolors": "^1.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -95,30 +95,30 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/compat-data": {
|
"node_modules/@babel/compat-data": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz",
|
||||||
"integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==",
|
"integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/core": {
|
"node_modules/@babel/core": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz",
|
||||||
"integrity": "sha512-qAHSfAdVyFmIvl0VHELib8xar7ONuSHrE2hLnsaWkYNTI68dmi1x8GYDhJjMI/e7XWal9QBlZkwbOnkcw7Z8gQ==",
|
"integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.2.0",
|
"@ampproject/remapping": "^2.2.0",
|
||||||
"@babel/code-frame": "^7.24.6",
|
"@babel/code-frame": "^7.24.7",
|
||||||
"@babel/generator": "^7.24.6",
|
"@babel/generator": "^7.24.7",
|
||||||
"@babel/helper-compilation-targets": "^7.24.6",
|
"@babel/helper-compilation-targets": "^7.24.7",
|
||||||
"@babel/helper-module-transforms": "^7.24.6",
|
"@babel/helper-module-transforms": "^7.24.7",
|
||||||
"@babel/helpers": "^7.24.6",
|
"@babel/helpers": "^7.24.7",
|
||||||
"@babel/parser": "^7.24.6",
|
"@babel/parser": "^7.24.7",
|
||||||
"@babel/template": "^7.24.6",
|
"@babel/template": "^7.24.7",
|
||||||
"@babel/traverse": "^7.24.6",
|
"@babel/traverse": "^7.24.7",
|
||||||
"@babel/types": "^7.24.6",
|
"@babel/types": "^7.24.7",
|
||||||
"convert-source-map": "^2.0.0",
|
"convert-source-map": "^2.0.0",
|
||||||
"debug": "^4.1.0",
|
"debug": "^4.1.0",
|
||||||
"gensync": "^1.0.0-beta.2",
|
"gensync": "^1.0.0-beta.2",
|
||||||
|
@ -143,12 +143,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/generator": {
|
"node_modules/@babel/generator": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
|
||||||
"integrity": "sha512-S7m4eNa6YAPJRHmKsLHIDJhNAGNKoWNiWefz1MBbpnt8g9lvMDl1hir4P9bo/57bQEmuwEhnRU/AMWsD0G/Fbg==",
|
"integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.24.6",
|
"@babel/types": "^7.24.7",
|
||||||
"@jridgewell/gen-mapping": "^0.3.5",
|
"@jridgewell/gen-mapping": "^0.3.5",
|
||||||
"@jridgewell/trace-mapping": "^0.3.25",
|
"@jridgewell/trace-mapping": "^0.3.25",
|
||||||
"jsesc": "^2.5.1"
|
"jsesc": "^2.5.1"
|
||||||
|
@ -158,25 +158,25 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-annotate-as-pure": {
|
"node_modules/@babel/helper-annotate-as-pure": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
|
||||||
"integrity": "sha512-DitEzDfOMnd13kZnDqns1ccmftwJTS9DMkyn9pYTxulS7bZxUxpMly3Nf23QQ6NwA4UB8lAqjbqWtyvElEMAkg==",
|
"integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-compilation-targets": {
|
"node_modules/@babel/helper-compilation-targets": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz",
|
||||||
"integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==",
|
"integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/compat-data": "^7.24.6",
|
"@babel/compat-data": "^7.24.7",
|
||||||
"@babel/helper-validator-option": "^7.24.6",
|
"@babel/helper-validator-option": "^7.24.7",
|
||||||
"browserslist": "^4.22.2",
|
"browserslist": "^4.22.2",
|
||||||
"lru-cache": "^5.1.1",
|
"lru-cache": "^5.1.1",
|
||||||
"semver": "^6.3.1"
|
"semver": "^6.3.1"
|
||||||
|
@ -195,62 +195,66 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-environment-visitor": {
|
"node_modules/@babel/helper-environment-visitor": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
|
||||||
"integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==",
|
"integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/types": "^7.24.7"
|
||||||
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-function-name": {
|
"node_modules/@babel/helper-function-name": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
|
||||||
"integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==",
|
"integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.24.6",
|
"@babel/template": "^7.24.7",
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-hoist-variables": {
|
"node_modules/@babel/helper-hoist-variables": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
|
||||||
"integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==",
|
"integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-imports": {
|
"node_modules/@babel/helper-module-imports": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
|
||||||
"integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==",
|
"integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/traverse": "^7.24.7",
|
||||||
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-module-transforms": {
|
"node_modules/@babel/helper-module-transforms": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz",
|
||||||
"integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==",
|
"integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-environment-visitor": "^7.24.6",
|
"@babel/helper-environment-visitor": "^7.24.7",
|
||||||
"@babel/helper-module-imports": "^7.24.6",
|
"@babel/helper-module-imports": "^7.24.7",
|
||||||
"@babel/helper-simple-access": "^7.24.6",
|
"@babel/helper-simple-access": "^7.24.7",
|
||||||
"@babel/helper-split-export-declaration": "^7.24.6",
|
"@babel/helper-split-export-declaration": "^7.24.7",
|
||||||
"@babel/helper-validator-identifier": "^7.24.6"
|
"@babel/helper-validator-identifier": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
@ -260,85 +264,86 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-plugin-utils": {
|
"node_modules/@babel/helper-plugin-utils": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz",
|
||||||
"integrity": "sha512-MZG/JcWfxybKwsA9N9PmtF2lOSFSEMVCpIRrbxccZFLJPrJciJdG/UhSh5W96GEteJI2ARqm5UAHxISwRDLSNg==",
|
"integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-simple-access": {
|
"node_modules/@babel/helper-simple-access": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
|
||||||
"integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==",
|
"integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/traverse": "^7.24.7",
|
||||||
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-split-export-declaration": {
|
"node_modules/@babel/helper-split-export-declaration": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
|
||||||
"integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==",
|
"integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-string-parser": {
|
"node_modules/@babel/helper-string-parser": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
|
||||||
"integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==",
|
"integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-identifier": {
|
"node_modules/@babel/helper-validator-identifier": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
|
||||||
"integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==",
|
"integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helper-validator-option": {
|
"node_modules/@babel/helper-validator-option": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz",
|
||||||
"integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==",
|
"integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/helpers": {
|
"node_modules/@babel/helpers": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz",
|
||||||
"integrity": "sha512-V2PI+NqnyFu1i0GyTd/O/cTpxzQCYioSkUIRmgo7gFEHKKCg5w46+r/A6WeUR1+P3TeQ49dspGPNd/E3n9AnnA==",
|
"integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/template": "^7.24.6",
|
"@babel/template": "^7.24.7",
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/highlight": {
|
"node_modules/@babel/highlight": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
|
||||||
"integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==",
|
"integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-validator-identifier": "^7.24.6",
|
"@babel/helper-validator-identifier": "^7.24.7",
|
||||||
"chalk": "^2.4.2",
|
"chalk": "^2.4.2",
|
||||||
"js-tokens": "^4.0.0",
|
"js-tokens": "^4.0.0",
|
||||||
"picocolors": "^1.0.0"
|
"picocolors": "^1.0.0"
|
||||||
|
@ -348,9 +353,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/parser": {
|
"node_modules/@babel/parser": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
|
||||||
"integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==",
|
"integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"parser": "bin/babel-parser.js"
|
"parser": "bin/babel-parser.js"
|
||||||
|
@ -425,12 +430,12 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-jsx": {
|
"node_modules/@babel/plugin-syntax-jsx": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.24.7.tgz",
|
||||||
"integrity": "sha512-lWfvAIFNWMlCsU0DRUun2GpFwZdGTukLaHJqRh1JRb80NdAP5Sb1HDHB5X9P9OtgZHQl089UzQkpYlBq2VTPRw==",
|
"integrity": "sha512-6ddciUPe/mpMnOKv/U+RSd2vvVy+Yw/JfBB0ZHYjEZt9NLHmCUylNYlsbqCCS1Bffjlb0fCwC9Vqz+sBz6PsiQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.24.6"
|
"@babel/helper-plugin-utils": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
@ -534,13 +539,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-syntax-typescript": {
|
"node_modules/@babel/plugin-syntax-typescript": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.24.7.tgz",
|
||||||
"integrity": "sha512-TzCtxGgVTEJWWwcYwQhCIQ6WaKlo80/B+Onsk4RRCcYqpYGFcG9etPW94VToGte5AAcxRrhjPUFvUS3Y2qKi4A==",
|
"integrity": "sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.24.6"
|
"@babel/helper-plugin-utils": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
@ -550,13 +555,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz",
|
||||||
"integrity": "sha512-FfZfHXtQ5jYPQsCRyLpOv2GeLIIJhs8aydpNh39vRDjhD411XcfWDni5i7OjP/Rs8GAtTn7sWFFELJSHqkIxYg==",
|
"integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.24.6"
|
"@babel/helper-plugin-utils": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
@ -566,13 +571,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/plugin-transform-react-jsx-source": {
|
"node_modules/@babel/plugin-transform-react-jsx-source": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz",
|
||||||
"integrity": "sha512-BQTBCXmFRreU3oTUXcGKuPOfXAGb1liNY4AvvFKsOBAJ89RKcTsIrSsnMYkj59fNa66OFKnSa4AJZfy5Y4B9WA==",
|
"integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-plugin-utils": "^7.24.6"
|
"@babel/helper-plugin-utils": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
|
@ -582,9 +587,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/runtime": {
|
"node_modules/@babel/runtime": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz",
|
||||||
"integrity": "sha512-Ja18XcETdEl5mzzACGd+DKgaGJzPTCow7EglgwTmHdwokzDFYh/MHua6lU6DV/hjF2IaOJ4oX2nqnjG7RElKOw==",
|
"integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.14.0"
|
"regenerator-runtime": "^0.14.0"
|
||||||
|
@ -594,33 +599,33 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/template": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
|
||||||
"integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==",
|
"integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.24.6",
|
"@babel/code-frame": "^7.24.7",
|
||||||
"@babel/parser": "^7.24.6",
|
"@babel/parser": "^7.24.7",
|
||||||
"@babel/types": "^7.24.6"
|
"@babel/types": "^7.24.7"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6.9.0"
|
"node": ">=6.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/traverse": {
|
"node_modules/@babel/traverse": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
|
||||||
"integrity": "sha512-OsNjaJwT9Zn8ozxcfoBc+RaHdj3gFmCmYoQLUII1o6ZrUwku0BMg80FoOTPx+Gi6XhcQxAYE4xyjPTo4SxEQqw==",
|
"integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/code-frame": "^7.24.6",
|
"@babel/code-frame": "^7.24.7",
|
||||||
"@babel/generator": "^7.24.6",
|
"@babel/generator": "^7.24.7",
|
||||||
"@babel/helper-environment-visitor": "^7.24.6",
|
"@babel/helper-environment-visitor": "^7.24.7",
|
||||||
"@babel/helper-function-name": "^7.24.6",
|
"@babel/helper-function-name": "^7.24.7",
|
||||||
"@babel/helper-hoist-variables": "^7.24.6",
|
"@babel/helper-hoist-variables": "^7.24.7",
|
||||||
"@babel/helper-split-export-declaration": "^7.24.6",
|
"@babel/helper-split-export-declaration": "^7.24.7",
|
||||||
"@babel/parser": "^7.24.6",
|
"@babel/parser": "^7.24.7",
|
||||||
"@babel/types": "^7.24.6",
|
"@babel/types": "^7.24.7",
|
||||||
"debug": "^4.3.1",
|
"debug": "^4.3.1",
|
||||||
"globals": "^11.1.0"
|
"globals": "^11.1.0"
|
||||||
},
|
},
|
||||||
|
@ -629,13 +634,13 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@babel/types": {
|
"node_modules/@babel/types": {
|
||||||
"version": "7.24.6",
|
"version": "7.24.7",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
|
||||||
"integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==",
|
"integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/helper-string-parser": "^7.24.6",
|
"@babel/helper-string-parser": "^7.24.7",
|
||||||
"@babel/helper-validator-identifier": "^7.24.6",
|
"@babel/helper-validator-identifier": "^7.24.7",
|
||||||
"to-fast-properties": "^2.0.0"
|
"to-fast-properties": "^2.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -668,21 +673,21 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/commands": {
|
"node_modules/@codemirror/commands": {
|
||||||
"version": "6.5.0",
|
"version": "6.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/commands/-/commands-6.6.0.tgz",
|
||||||
"integrity": "sha512-rK+sj4fCAN/QfcY9BEzYMgp4wwL/q5aj/VfNSoH1RWPF9XS/dUwBkvlL3hpWgEjOqlpdN1uLC9UkjJ4tmyjJYg==",
|
"integrity": "sha512-qnY+b7j1UNcTS31Eenuc/5YJB6gQOzkUoNmJQc0rznwqSRpeaWWpjkWy2C/MPTcePpsKJEM26hXrOXl1+nceXg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
"@codemirror/view": "^6.0.0",
|
"@codemirror/view": "^6.27.0",
|
||||||
"@lezer/common": "^1.1.0"
|
"@lezer/common": "^1.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/language": {
|
"node_modules/@codemirror/language": {
|
||||||
"version": "6.10.1",
|
"version": "6.10.2",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.1.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.10.2.tgz",
|
||||||
"integrity": "sha512-5GrXzrhq6k+gL5fjkAwt90nYDmjlzTIJV8THnxNFtNKWotMIlzzN+CpqxqwXOECnUdOndmSeWntVrVcv5axWRQ==",
|
"integrity": "sha512-kgbTYTo0Au6dCSc/TFy7fK3fpJmgHDv1sG1KNQKJXVi+xBTEeBPY/M30YXiU6mMXeH+YIDLsbrT4ZwNRdtF+SA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.0.0",
|
"@codemirror/state": "^6.0.0",
|
||||||
|
@ -734,9 +739,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@codemirror/view": {
|
"node_modules/@codemirror/view": {
|
||||||
"version": "6.26.3",
|
"version": "6.28.1",
|
||||||
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.26.3.tgz",
|
"resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.28.1.tgz",
|
||||||
"integrity": "sha512-gmqxkPALZjkgSxIeeweY/wGQXBfwTUaLs8h7OKtSwfbj9Ct3L11lD+u1sS7XHppxFQoMDiMDp07P9f3I2jWOHw==",
|
"integrity": "sha512-BUWr+zCJpMkA/u69HlJmR+YkV4yPpM81HeMkOMZuwFa8iM5uJdEPKAs1icIRZKkKmy0Ub1x9/G3PQLTXdpBxrQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/state": "^6.4.0",
|
"@codemirror/state": "^6.4.0",
|
||||||
|
@ -1311,9 +1316,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint-community/regexpp": {
|
"node_modules/@eslint-community/regexpp": {
|
||||||
"version": "4.10.0",
|
"version": "4.10.1",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.1.tgz",
|
||||||
"integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==",
|
"integrity": "sha512-Zm2NGpWELsQAD1xsJzGQpYfvICSsFkEpU0jxBjfdC6uNEWXcHnfs9hScFWtXVDVl+rBQJGrl4g1vcKIejpH9dA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1530,6 +1535,7 @@
|
||||||
"version": "0.11.14",
|
"version": "0.11.14",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz",
|
||||||
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
"integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==",
|
||||||
|
"deprecated": "Use @eslint/config-array instead",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -1583,6 +1589,7 @@
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz",
|
||||||
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
"integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==",
|
||||||
|
"deprecated": "Use @eslint/object-schema instead",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BSD-3-Clause"
|
"license": "BSD-3-Clause"
|
||||||
},
|
},
|
||||||
|
@ -3294,9 +3301,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.14.0",
|
"version": "20.14.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.5.tgz",
|
||||||
"integrity": "sha512-5cHBxFGJx6L4s56Bubp4fglrEpmyJypsqI6RgzMfBHWUJQGWAAi8cWcgetEbZXHYXo9C2Fa4EEds/uSyS4cxmA==",
|
"integrity": "sha512-aoRR+fJkZT2l0aGOJhuA8frnCSoNX6W7U2mpNq63+BxBIj5BQFt8rHy627kijCmm63ijdSdwvGgpUsU6MBsZZA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -3394,9 +3401,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@types/webxr": {
|
"node_modules/@types/webxr": {
|
||||||
"version": "0.5.16",
|
"version": "0.5.17",
|
||||||
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.16.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.17.tgz",
|
||||||
"integrity": "sha512-0E0Cl84FECtzrB4qG19TNTqpunw0F1YF0QZZnFMF6pDw1kNKJtrlTKlVB34stGIsHbZsYQ7H0tNjPfZftkHHoA==",
|
"integrity": "sha512-JYcclaQIlisHRXM9dMF7SeVvQ54kcYc7QK1eKCExCTLKWnZDxP4cp/rXH4Uoa1j5+5oQJ0Cc2sZC/PWiiG4q2g==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/@types/yargs": {
|
"node_modules/@types/yargs": {
|
||||||
|
@ -3615,9 +3622,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@uiw/codemirror-extensions-basic-setup": {
|
"node_modules/@uiw/codemirror-extensions-basic-setup": {
|
||||||
"version": "4.22.1",
|
"version": "4.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/@uiw/codemirror-extensions-basic-setup/-/codemirror-extensions-basic-setup-4.22.2.tgz",
|
||||||
"integrity": "sha512-Iz8eFaZBNrwjaAADszOxOv2byDMn4rqob/luuSPAzJjTrSn5KawRXcoNLoWGPGNO6Mils6bIly/g2LaU34otNw==",
|
"integrity": "sha512-zcHGkldLFN3cGoI5XdOGAkeW24yaAgrDEYoyPyWHODmPiNwybQQoZGnH3qUdzZwUaXtAcLWoAeOPzfNRW2yGww==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/autocomplete": "^6.0.0",
|
"@codemirror/autocomplete": "^6.0.0",
|
||||||
|
@ -3642,9 +3649,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@uiw/codemirror-themes": {
|
"node_modules/@uiw/codemirror-themes": {
|
||||||
"version": "4.22.1",
|
"version": "4.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/@uiw/codemirror-themes/-/codemirror-themes-4.22.2.tgz",
|
||||||
"integrity": "sha512-5TeB8wCc0aNd3YEhzOvgekpAFQfEm4fCTUcGmEIQqaRNgKAM83HYNpE1JF2j7x2oDFugdiO0yJynS6bo1zVOuw==",
|
"integrity": "sha512-gsLHn6SUuV5iboBvGrM7YimzLFHQmsNlkGIYs3UaVUJTo/A/ZrKoSJNyPziShLRjBXA2UwKdBTIU6VhHyyaChw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@codemirror/language": "^6.0.0",
|
"@codemirror/language": "^6.0.0",
|
||||||
|
@ -3661,16 +3668,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@uiw/react-codemirror": {
|
"node_modules/@uiw/react-codemirror": {
|
||||||
"version": "4.22.1",
|
"version": "4.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.22.1.tgz",
|
"resolved": "https://registry.npmjs.org/@uiw/react-codemirror/-/react-codemirror-4.22.2.tgz",
|
||||||
"integrity": "sha512-yrq9FdGZ6E4Rh+7W0xyirSEeESGyG/k54/DfFqSk40fqel/3x/3fqjIImEZUYPxxgFPmZ3RtP+O0Em46nwRvgg==",
|
"integrity": "sha512-okCSl+WJG63gRx8Fdz7v0C6RakBQnbb3pHhuzIgDB+fwhipgFodSnu2n9oOsQesJ5YQ7mSOcKMgX0JEsu4nnfQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/runtime": "^7.18.6",
|
"@babel/runtime": "^7.18.6",
|
||||||
"@codemirror/commands": "^6.1.0",
|
"@codemirror/commands": "^6.1.0",
|
||||||
"@codemirror/state": "^6.1.1",
|
"@codemirror/state": "^6.1.1",
|
||||||
"@codemirror/theme-one-dark": "^6.0.0",
|
"@codemirror/theme-one-dark": "^6.0.0",
|
||||||
"@uiw/codemirror-extensions-basic-setup": "4.22.1",
|
"@uiw/codemirror-extensions-basic-setup": "4.22.2",
|
||||||
"codemirror": "^6.0.0"
|
"codemirror": "^6.0.0"
|
||||||
},
|
},
|
||||||
"funding": {
|
"funding": {
|
||||||
|
@ -3712,9 +3719,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@vitejs/plugin-react": {
|
"node_modules/@vitejs/plugin-react": {
|
||||||
"version": "4.3.0",
|
"version": "4.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz",
|
||||||
"integrity": "sha512-KcEbMsn4Dpk+LIbHMj7gDPRKaTMStxxWRkRmxsg/jVdFdJCZWt1SchZcf0M4t8lIKdwwMsEyzhrcOXRrDPtOBw==",
|
"integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -3745,9 +3752,9 @@
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.11.3",
|
"version": "8.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.0.tgz",
|
||||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
"integrity": "sha512-RTvkC4w+KNXrM39/lWCUaG0IbRkWdCv7W/IOW9oU6SawyxulvkQy5HQPVTKxEjczcUvapcrw3cFx/60VN/NRNw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -4240,9 +4247,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/browserslist": {
|
"node_modules/browserslist": {
|
||||||
"version": "4.23.0",
|
"version": "4.23.1",
|
||||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
|
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.1.tgz",
|
||||||
"integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
|
"integrity": "sha512-TUfofFo/KsK/bWZ9TWQ5O26tsWW4Uhmt8IYklbnUa70udB6P2wA7w7o4PY4muaEPBQaAX+CEnmmIA41NVHtPVw==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
@ -4259,10 +4266,10 @@
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001587",
|
"caniuse-lite": "^1.0.30001629",
|
||||||
"electron-to-chromium": "^1.4.668",
|
"electron-to-chromium": "^1.4.796",
|
||||||
"node-releases": "^2.0.14",
|
"node-releases": "^2.0.14",
|
||||||
"update-browserslist-db": "^1.0.13"
|
"update-browserslist-db": "^1.0.16"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
"browserslist": "cli.js"
|
"browserslist": "cli.js"
|
||||||
|
@ -4340,18 +4347,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/camera-controls": {
|
"node_modules/camera-controls": {
|
||||||
"version": "2.8.4",
|
"version": "2.8.5",
|
||||||
"resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.8.4.tgz",
|
"resolved": "https://registry.npmjs.org/camera-controls/-/camera-controls-2.8.5.tgz",
|
||||||
"integrity": "sha512-pzVKpeZCRXIx2VOMB+E4OPjOhErHqhxrHYxcRLofOVgBeCeKSb8QAC2toc1onMllrxldRWXR8bl4K50hkrtwsg==",
|
"integrity": "sha512-7VTwRk7Nu1nRKsY7bEt9HVBfKt8DETvzyYhLN4OW26OByBayMDB5fUaNcPI+z++vG23RH5yqn6ZRhZcgLQy2rA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"three": ">=0.126.1"
|
"three": ">=0.126.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/caniuse-lite": {
|
"node_modules/caniuse-lite": {
|
||||||
"version": "1.0.30001626",
|
"version": "1.0.30001636",
|
||||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001626.tgz",
|
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001636.tgz",
|
||||||
"integrity": "sha512-JRW7kAH8PFJzoPCJhLSHgDgKg5348hsQ68aqb+slnzuB5QFERv846oA/mRChmlLAOdEDeOkRn3ynb1gSFnjt3w==",
|
"integrity": "sha512-bMg2vmr8XBsbL6Lr0UHXy/21m84FTxDLWn2FSqMd5PrlbMxwJlQnC2YWYxVgp66PZE+BBNF2jYQUBKCo1FDeZg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "opencollective",
|
"type": "opencollective",
|
||||||
|
@ -5217,9 +5224,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/electron-to-chromium": {
|
"node_modules/electron-to-chromium": {
|
||||||
"version": "1.4.788",
|
"version": "1.4.805",
|
||||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.788.tgz",
|
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.805.tgz",
|
||||||
"integrity": "sha512-ubp5+Ev/VV8KuRoWnfP2QF2Bg+O2ZFdb49DiiNbz2VmgkIqrnyYaqIOqj8A6K/3p1xV0QcU5hBQ1+BmB6ot1OA==",
|
"integrity": "sha512-8W4UJwX/w9T0QSzINJckTKG6CYpAUTqsaWcWIsdud3I1FYJcMgW9QqT1/4CBff/pP/TihWh13OmiyY8neto6vw==",
|
||||||
"license": "ISC"
|
"license": "ISC"
|
||||||
},
|
},
|
||||||
"node_modules/ellipsize": {
|
"node_modules/ellipsize": {
|
||||||
|
@ -5891,9 +5898,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/foreground-child": {
|
"node_modules/foreground-child": {
|
||||||
"version": "3.1.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz",
|
||||||
"integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==",
|
"integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -6331,9 +6338,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/graphology-metrics": {
|
"node_modules/graphology-metrics": {
|
||||||
"version": "2.2.0",
|
"version": "2.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/graphology-metrics/-/graphology-metrics-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/graphology-metrics/-/graphology-metrics-2.3.0.tgz",
|
||||||
"integrity": "sha512-eZZFRLGGyyI+iD+XwQvc+lLM3EKCoqUvVjvF/14Htgy4grB2m95OytToYq3saWuHfuf22VVnj9GBHv/pTzKuTw==",
|
"integrity": "sha512-ayDWSnSlq2wIL1QIrRQ3cIUsS7V/kRdBzciLPkGsI8Vl/MDQkxiU9WDt9cUAMzAE6Q1n1pWT5SXPkKeZdKCjzA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"graphology-shortest-path": "^2.0.0",
|
"graphology-shortest-path": "^2.0.0",
|
||||||
|
@ -6780,9 +6787,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jackspeak": {
|
"node_modules/jackspeak": {
|
||||||
"version": "3.1.2",
|
"version": "3.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz",
|
||||||
"integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==",
|
"integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "BlueOak-1.0.0",
|
"license": "BlueOak-1.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -8474,9 +8481,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/jiti": {
|
"node_modules/jiti": {
|
||||||
"version": "1.21.0",
|
"version": "1.21.6",
|
||||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz",
|
||||||
"integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==",
|
"integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -8785,9 +8792,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/meshline": {
|
"node_modules/meshline": {
|
||||||
"version": "3.2.1",
|
"version": "3.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/meshline/-/meshline-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/meshline/-/meshline-3.3.1.tgz",
|
||||||
"integrity": "sha512-/Zrhq1sbQCtqSsrud0hN/U8wOdKKOcxCWefEowZRHsosIcy1p87+2PlWSNO4s9zOoT/zjrQR8YikXYao8XCqVQ==",
|
"integrity": "sha512-/TQj+JdZkeSUOl5Mk2J7eLcYTLiQm2IDzmlSvYm7ov15anEcDJ92GHqqazxTSreeNgfnYu24kiEvvv0WlbCdFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"three": ">=0.137"
|
"three": ">=0.137"
|
||||||
|
@ -8958,9 +8965,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/nan": {
|
"node_modules/nan": {
|
||||||
"version": "2.19.0",
|
"version": "2.20.0",
|
||||||
"resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/nan/-/nan-2.20.0.tgz",
|
||||||
"integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==",
|
"integrity": "sha512-bk3gXBZDGILuuo/6sKtr0DQmSThYHLtNCdSdXk9YkxD/jK6X2vmCyyXBBxyqZ4XcnzTyYEAThfX3DCEnLf6igw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
@ -9308,27 +9315,27 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path2d-polyfill": {
|
"node_modules/path2d": {
|
||||||
"version": "2.0.1",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path2d/-/path2d-0.2.0.tgz",
|
||||||
"integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==",
|
"integrity": "sha512-KdPAykQX6kmLSOO6Jpu2KNcCED7CKjmaBNGGNuctOsG0hgYO1OdYQaan6cYXJiG0WmXOwZZPILPBimu5QAIw3A==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"optional": true,
|
"optional": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/pdfjs-dist": {
|
"node_modules/pdfjs-dist": {
|
||||||
"version": "3.11.174",
|
"version": "4.3.136",
|
||||||
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz",
|
"resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-4.3.136.tgz",
|
||||||
"integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==",
|
"integrity": "sha512-gzfnt1qc4yA+U46golPGYtU4WM2ssqP2MvFjKga8GEKOrEnzRPrA/9jogLLPYHiA3sGBPJ+p7BdAq+ytmw3jEg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"canvas": "^2.11.2",
|
"canvas": "^2.11.2",
|
||||||
"path2d-polyfill": "^2.0.1"
|
"path2d": "^0.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/picocolors": {
|
"node_modules/picocolors": {
|
||||||
|
@ -9542,9 +9549,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-load-config/node_modules/lilconfig": {
|
"node_modules/postcss-load-config/node_modules/lilconfig": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz",
|
||||||
"integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==",
|
"integrity": "sha512-eop+wDAvpItUys0FWkHIKeC9ybYrTGbU41U5K7+bttZZeohvnY7M9dZ5kB21GNWiFT2q1OoPTvncPCgSOVO5ow==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -9555,9 +9562,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/postcss-load-config/node_modules/yaml": {
|
"node_modules/postcss-load-config/node_modules/yaml": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.5",
|
||||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz",
|
||||||
"integrity": "sha512-sntgmxj8o7DE7g/Qi60cqpLBA3HG3STcDA0kO+WfB05jEKhZMbY7umNm2rBpQvsmZ16/lPXCJGW2672dgOUkrg==",
|
"integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -9853,18 +9860,17 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-pdf": {
|
"node_modules/react-pdf": {
|
||||||
"version": "7.7.3",
|
"version": "9.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-7.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/react-pdf/-/react-pdf-9.0.0.tgz",
|
||||||
"integrity": "sha512-a2VfDl8hiGjugpqezBTUzJHYLNB7IS7a2t7GD52xMI9xHg8LdVaTMsnM9ZlNmKadnStT/tvX5IfV0yLn+JvYmw==",
|
"integrity": "sha512-J+pza8R2p9oNEOJOHIQJI4o5rFK7ji7bBl2IvsHvz1OOyphvuzVDo5tOJwWAFAbxYauCH3Kt8jOvcMJUOpxYZQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"dequal": "^2.0.3",
|
"dequal": "^2.0.3",
|
||||||
"make-cancellable-promise": "^1.3.1",
|
"make-cancellable-promise": "^1.3.1",
|
||||||
"make-event-props": "^1.6.0",
|
"make-event-props": "^1.6.0",
|
||||||
"merge-refs": "^1.2.1",
|
"merge-refs": "^1.3.0",
|
||||||
"pdfjs-dist": "3.11.174",
|
"pdfjs-dist": "4.3.136",
|
||||||
"prop-types": "^15.6.2",
|
|
||||||
"tiny-invariant": "^1.0.0",
|
"tiny-invariant": "^1.0.0",
|
||||||
"warning": "^4.0.0"
|
"warning": "^4.0.0"
|
||||||
},
|
},
|
||||||
|
@ -9872,9 +9878,9 @@
|
||||||
"url": "https://github.com/wojtekmaj/react-pdf?sponsor=1"
|
"url": "https://github.com/wojtekmaj/react-pdf?sponsor=1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"@types/react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
"react": "^16.8.0 || ^17.0.0 || ^18.0.0",
|
"react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0",
|
||||||
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0"
|
"react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0"
|
||||||
},
|
},
|
||||||
"peerDependenciesMeta": {
|
"peerDependenciesMeta": {
|
||||||
"@types/react": {
|
"@types/react": {
|
||||||
|
@ -10006,9 +10012,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-tooltip": {
|
"node_modules/react-tooltip": {
|
||||||
"version": "5.26.4",
|
"version": "5.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.26.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-tooltip/-/react-tooltip-5.27.0.tgz",
|
||||||
"integrity": "sha512-5WyDrsfw1+6qNVSr3IjqElqJ+cCwE8+44b+HpJ8qRLv7v0a3mcKf8wvv+NfgALFS6QpksGFqTLV2JQ60c+okZQ==",
|
"integrity": "sha512-JXROcdfCEbCqkAkh8LyTSP3guQ0dG53iY2E2o4fw3D8clKzziMpE6QG6CclDaHELEKTzpMSeAOsdtg0ahoQosw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@floating-ui/dom": "^1.6.1",
|
"@floating-ui/dom": "^1.6.1",
|
||||||
|
@ -10097,9 +10103,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/reagraph": {
|
"node_modules/reagraph": {
|
||||||
"version": "4.19.0",
|
"version": "4.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/reagraph/-/reagraph-4.19.0.tgz",
|
"resolved": "https://registry.npmjs.org/reagraph/-/reagraph-4.19.1.tgz",
|
||||||
"integrity": "sha512-hQZjA8coxFS6UjDhlP5Ho/woc36sM1dqsliwvTtThN/1ZoGbAuxt5QntVka4jesh0HhNB3ZafYgCIqXoo2sq8Q==",
|
"integrity": "sha512-BMSfZ2CoLSWsxe+vowHbCZSqeJJlH2UcbQA6hM1JHI0PmZ/3UHIXCQUHXrsROtYIIH5AnFEj9pUAZh2FGnfGhw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@react-spring/three": "9.6.1",
|
"@react-spring/three": "9.6.1",
|
||||||
|
@ -10806,9 +10812,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.3",
|
"version": "3.4.4",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.4.tgz",
|
||||||
"integrity": "sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==",
|
"integrity": "sha512-ZoyXOdJjISB7/BcLTR6SEsLgKtDStYyYZVLsUtWChO4Ps20CBad7lfJKVDiejocV4ME1hLmyY0WJE3hSDcmQ2A==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -11086,9 +11092,9 @@
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/ts-jest": {
|
"node_modules/ts-jest": {
|
||||||
"version": "29.1.4",
|
"version": "29.1.5",
|
||||||
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.5.tgz",
|
||||||
"integrity": "sha512-YiHwDhSvCiItoAgsKtoLFCuakDzDsJ1DLDnSouTaTmdOcOwIkSzbLXduaQ6M5DRVhuZC/NYaaZ/mtHbWMv/S6Q==",
|
"integrity": "sha512-UuClSYxM7byvvYfyWdFI+/2UxMmwNyJb0NPkZPQE2hew3RurV7l7zURgOHAd/1I1ZdPpe3GUsXNXAcN8TFKSIg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -11134,9 +11140,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.6.2",
|
"version": "2.6.3",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.3.tgz",
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
"integrity": "sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ==",
|
||||||
"license": "0BSD"
|
"license": "0BSD"
|
||||||
},
|
},
|
||||||
"node_modules/tunnel-rat": {
|
"node_modules/tunnel-rat": {
|
||||||
|
|
|
@ -14,8 +14,8 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@lezer/lr": "^1.4.1",
|
"@lezer/lr": "^1.4.1",
|
||||||
"@tanstack/react-table": "^8.17.3",
|
"@tanstack/react-table": "^8.17.3",
|
||||||
"@uiw/codemirror-themes": "^4.22.1",
|
"@uiw/codemirror-themes": "^4.22.2",
|
||||||
"@uiw/react-codemirror": "^4.22.1",
|
"@uiw/react-codemirror": "^4.22.2",
|
||||||
"axios": "^1.7.2",
|
"axios": "^1.7.2",
|
||||||
"@reactflow/core": "^11.8.3",
|
"@reactflow/core": "^11.8.3",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
|
@ -27,24 +27,24 @@
|
||||||
"react-icons": "^4.12.0",
|
"react-icons": "^4.12.0",
|
||||||
"react-intl": "^6.6.8",
|
"react-intl": "^6.6.8",
|
||||||
"react-loader-spinner": "^5.4.5",
|
"react-loader-spinner": "^5.4.5",
|
||||||
"react-pdf": "^7.7.3",
|
"react-pdf": "^9.0.0",
|
||||||
"react-router-dom": "^6.23.1",
|
"react-router-dom": "^6.23.1",
|
||||||
"react-select": "^5.8.0",
|
"react-select": "^5.8.0",
|
||||||
"react-tabs": "^6.0.2",
|
"react-tabs": "^6.0.2",
|
||||||
"react-toastify": "^9.1.3",
|
"react-toastify": "^9.1.3",
|
||||||
"react-tooltip": "^5.26.4",
|
"react-tooltip": "^5.27.0",
|
||||||
"reagraph": "^4.19.0",
|
"reagraph": "^4.19.1",
|
||||||
"use-debounce": "^10.0.1"
|
"use-debounce": "^10.0.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@lezer/generator": "^1.7.0",
|
"@lezer/generator": "^1.7.0",
|
||||||
"@types/jest": "^29.5.12",
|
"@types/jest": "^29.5.12",
|
||||||
"@types/node": "^20.14.0",
|
"@types/node": "^20.14.5",
|
||||||
"@types/react": "^18.3.3",
|
"@types/react": "^18.3.3",
|
||||||
"@types/react-dom": "^18.3.0",
|
"@types/react-dom": "^18.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
||||||
"@typescript-eslint/parser": "^6.21.0",
|
"@typescript-eslint/parser": "^6.21.0",
|
||||||
"@vitejs/plugin-react": "^4.3.0",
|
"@vitejs/plugin-react": "^4.3.1",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-plugin-react-hooks": "^4.6.2",
|
"eslint-plugin-react-hooks": "^4.6.2",
|
||||||
|
@ -53,8 +53,8 @@
|
||||||
"eslint-plugin-tsdoc": "^0.2.17",
|
"eslint-plugin-tsdoc": "^0.2.17",
|
||||||
"jest": "^29.7.0",
|
"jest": "^29.7.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.4",
|
||||||
"ts-jest": "^29.1.4",
|
"ts-jest": "^29.1.5",
|
||||||
"typescript": "^5.4.5",
|
"typescript": "^5.4.5",
|
||||||
"vite": "^4.5.3"
|
"vite": "^4.5.3"
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,3 +1,2 @@
|
||||||
User-agent: *
|
User-agent: *
|
||||||
Allow: /
|
|
||||||
Disallow: /library
|
Disallow: /library
|
|
@ -15,7 +15,7 @@ function Footer() {
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'z-navigation',
|
'z-navigation',
|
||||||
'mx-auto',
|
'mx-auto',
|
||||||
'sm:px-4 sm:py-2 flex flex-col items-center gap-1',
|
'px-3 py-2 flex flex-col items-center gap-1',
|
||||||
'text-xs sm:text-sm select-none whitespace-nowrap'
|
'text-xs sm:text-sm select-none whitespace-nowrap'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { UsersState } from '@/context/UsersContext';
|
||||||
|
|
||||||
import ErrorFallback from './ErrorFallback';
|
import ErrorFallback from './ErrorFallback';
|
||||||
|
|
||||||
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.js', import.meta.url).toString();
|
pdfjs.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString();
|
||||||
|
|
||||||
const resetState = () => {
|
const resetState = () => {
|
||||||
console.log('Resetting state after error fallback');
|
console.log('Resetting state after error fallback');
|
||||||
|
|
|
@ -47,7 +47,7 @@ function Navigation() {
|
||||||
<div tabIndex={-1} className='flex items-center mr-auto cursor-pointer' onClick={navigateHome}>
|
<div tabIndex={-1} className='flex items-center mr-auto cursor-pointer' onClick={navigateHome}>
|
||||||
<Logo />
|
<Logo />
|
||||||
</div>
|
</div>
|
||||||
<div className='flex'>
|
<div className='flex gap-1 py-[0.3rem]'>
|
||||||
<NavigationButton
|
<NavigationButton
|
||||||
text='Новая схема'
|
text='Новая схема'
|
||||||
title='Создать новую схему'
|
title='Создать новую схему'
|
||||||
|
|
|
@ -23,6 +23,8 @@ function NavigationButton({ icon, title, titleHtml, hideTitle, onClick, text }:
|
||||||
'mr-1 h-full', // prettier: split lines
|
'mr-1 h-full', // prettier: split lines
|
||||||
'flex items-center gap-1',
|
'flex items-center gap-1',
|
||||||
'clr-btn-nav',
|
'clr-btn-nav',
|
||||||
|
'rounded-xl',
|
||||||
|
'transition duration-500',
|
||||||
'font-controls whitespace-nowrap',
|
'font-controls whitespace-nowrap',
|
||||||
{
|
{
|
||||||
'px-2': text,
|
'px-2': text,
|
||||||
|
|
|
@ -14,8 +14,9 @@ function ToggleNavigationButton() {
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'absolute top-0 right-0 z-navigation flex items-center justify-center',
|
'absolute top-0 right-0 z-navigation flex items-center justify-center',
|
||||||
'clr-btn-nav',
|
'clr-hover',
|
||||||
'select-none disabled:cursor-not-allowed'
|
'select-none',
|
||||||
|
'min-h-[2rem]'
|
||||||
)}
|
)}
|
||||||
onClick={toggleNoNavigation}
|
onClick={toggleNoNavigation}
|
||||||
initial={false}
|
initial={false}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||||
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
import { CstMatchMode, DependencyMode } from '@/models/miscellaneous';
|
||||||
|
import { ExpressionStatus } from '@/models/rsform';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
IconAlias,
|
IconAlias,
|
||||||
|
@ -21,6 +22,10 @@ import {
|
||||||
IconRSForm,
|
IconRSForm,
|
||||||
IconSettings,
|
IconSettings,
|
||||||
IconShow,
|
IconShow,
|
||||||
|
IconStatusError,
|
||||||
|
IconStatusIncalculable,
|
||||||
|
IconStatusOK,
|
||||||
|
IconStatusUnknown,
|
||||||
IconTemplates,
|
IconTemplates,
|
||||||
IconTerm,
|
IconTerm,
|
||||||
IconText,
|
IconText,
|
||||||
|
@ -80,34 +85,51 @@ export function LocationIcon({ value, size = '1.25rem', className }: DomIconProp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DependencyIcon(mode: DependencyMode, size: string, color?: string) {
|
export function DependencyIcon({ value, size = '1.25rem', className }: DomIconProps<DependencyMode>) {
|
||||||
switch (mode) {
|
switch (value) {
|
||||||
case DependencyMode.ALL:
|
case DependencyMode.ALL:
|
||||||
return <IconSettings size={size} className={color} />;
|
return <IconSettings size={size} className={className} />;
|
||||||
case DependencyMode.EXPRESSION:
|
case DependencyMode.EXPRESSION:
|
||||||
return <IconText size={size} className={color} />;
|
return <IconText size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case DependencyMode.OUTPUTS:
|
case DependencyMode.OUTPUTS:
|
||||||
return <IconGraphOutputs size={size} className={color} />;
|
return <IconGraphOutputs size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case DependencyMode.INPUTS:
|
case DependencyMode.INPUTS:
|
||||||
return <IconGraphInputs size={size} className={color} />;
|
return <IconGraphInputs size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case DependencyMode.EXPAND_OUTPUTS:
|
case DependencyMode.EXPAND_OUTPUTS:
|
||||||
return <IconGraphExpand size={size} className={color} />;
|
return <IconGraphExpand size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case DependencyMode.EXPAND_INPUTS:
|
case DependencyMode.EXPAND_INPUTS:
|
||||||
return <IconGraphCollapse size={size} className={color} />;
|
return <IconGraphCollapse size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MatchModeIcon(mode: CstMatchMode, size: string, color?: string) {
|
export function MatchModeIcon({ value, size = '1.25rem', className }: DomIconProps<CstMatchMode>) {
|
||||||
switch (mode) {
|
switch (value) {
|
||||||
case CstMatchMode.ALL:
|
case CstMatchMode.ALL:
|
||||||
return <IconFilter size={size} className={color} />;
|
return <IconFilter size={size} className={className} />;
|
||||||
case CstMatchMode.TEXT:
|
case CstMatchMode.TEXT:
|
||||||
return <IconText size={size} className={color} />;
|
return <IconText size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case CstMatchMode.EXPR:
|
case CstMatchMode.EXPR:
|
||||||
return <IconFormula size={size} className={color} />;
|
return <IconFormula size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case CstMatchMode.TERM:
|
case CstMatchMode.TERM:
|
||||||
return <IconTerm size={size} className={color} />;
|
return <IconTerm size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
case CstMatchMode.NAME:
|
case CstMatchMode.NAME:
|
||||||
return <IconAlias size={size} className={color} />;
|
return <IconAlias size={size} className={className ?? 'clr-text-primary'} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StatusIcon({ value, size = '1.25rem', className }: DomIconProps<ExpressionStatus>) {
|
||||||
|
switch (value) {
|
||||||
|
case ExpressionStatus.VERIFIED:
|
||||||
|
case ExpressionStatus.PROPERTY:
|
||||||
|
return <IconStatusOK size={size} className={className} />;
|
||||||
|
|
||||||
|
case ExpressionStatus.UNKNOWN:
|
||||||
|
return <IconStatusUnknown size={size} className={className} />;
|
||||||
|
case ExpressionStatus.INCALCULABLE:
|
||||||
|
return <IconStatusIncalculable size={size} className={className} />;
|
||||||
|
|
||||||
|
case ExpressionStatus.INCORRECT:
|
||||||
|
case ExpressionStatus.UNDEFINED:
|
||||||
|
return <IconStatusError size={size} className={className} />;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,8 @@ export { BiCog as IconSettings } from 'react-icons/bi';
|
||||||
export { TbEye as IconShow } from 'react-icons/tb';
|
export { TbEye as IconShow } from 'react-icons/tb';
|
||||||
export { TbEyeX as IconHide } from 'react-icons/tb';
|
export { TbEyeX as IconHide } from 'react-icons/tb';
|
||||||
export { BiShareAlt as IconShare } from 'react-icons/bi';
|
export { BiShareAlt as IconShare } from 'react-icons/bi';
|
||||||
export { BiFilterAlt as IconFilter } from 'react-icons/bi';
|
export { LuFilter as IconFilter } from 'react-icons/lu';
|
||||||
|
export { LuFilterX as IconFilterReset } from 'react-icons/lu';
|
||||||
export {BiDownArrowCircle as IconOpenList } from 'react-icons/bi';
|
export {BiDownArrowCircle as IconOpenList } from 'react-icons/bi';
|
||||||
export { LuAlertTriangle as IconAlert } from 'react-icons/lu';
|
export { LuAlertTriangle as IconAlert } from 'react-icons/lu';
|
||||||
|
|
||||||
|
@ -30,7 +31,11 @@ export { RiMenuFoldFill as IconMenuFold } from 'react-icons/ri';
|
||||||
export { RiMenuUnfoldFill as IconMenuUnfold } from 'react-icons/ri';
|
export { RiMenuUnfoldFill as IconMenuUnfold } from 'react-icons/ri';
|
||||||
export { LuMoon as IconDarkTheme } from 'react-icons/lu';
|
export { LuMoon as IconDarkTheme } from 'react-icons/lu';
|
||||||
export { LuSun as IconLightTheme } from 'react-icons/lu';
|
export { LuSun as IconLightTheme } from 'react-icons/lu';
|
||||||
export { FaRegFolder as IconFolder } from 'react-icons/fa';
|
export { LuFolderTree as IconFolderTree } from 'react-icons/lu';
|
||||||
|
export { LuFolder as IconFolder } from 'react-icons/lu';
|
||||||
|
export { LuFolderOpen as IconFolderOpened } from 'react-icons/lu';
|
||||||
|
export { LuFolderClosed as IconFolderClosed } from 'react-icons/lu';
|
||||||
|
export { LuFolderDot as IconFolderEmpty } from 'react-icons/lu';
|
||||||
export { LuLightbulb as IconHelp } from 'react-icons/lu';
|
export { LuLightbulb as IconHelp } from 'react-icons/lu';
|
||||||
export { LuLightbulbOff as IconHelpOff } from 'react-icons/lu';
|
export { LuLightbulbOff as IconHelpOff } from 'react-icons/lu';
|
||||||
export { RiPushpinFill as IconPin } from 'react-icons/ri';
|
export { RiPushpinFill as IconPin } from 'react-icons/ri';
|
||||||
|
|
|
@ -10,12 +10,13 @@ import { forwardRef, useCallback, useMemo, useRef } from 'react';
|
||||||
|
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { useRSForm } from '@/context/RSFormContext';
|
|
||||||
import { getFontClassName } from '@/models/miscellaneousAPI';
|
import { getFontClassName } from '@/models/miscellaneousAPI';
|
||||||
|
import { ConstituentaID, IRSForm } from '@/models/rsform';
|
||||||
import { generateAlias, getCstTypePrefix, guessCstType } from '@/models/rsformAPI';
|
import { generateAlias, getCstTypePrefix, guessCstType } from '@/models/rsformAPI';
|
||||||
import { extractGlobals } from '@/models/rslangAPI';
|
import { extractGlobals } from '@/models/rslangAPI';
|
||||||
|
|
||||||
import { ccBracketMatching } from './bracketMatching';
|
import { ccBracketMatching } from './bracketMatching';
|
||||||
|
import { rsNavigation } from './clickNavigation';
|
||||||
import { RSLanguage } from './rslang';
|
import { RSLanguage } from './rslang';
|
||||||
import { getSymbolSubstitute, RSTextWrapper } from './textEditing';
|
import { getSymbolSubstitute, RSTextWrapper } from './textEditing';
|
||||||
import { rsHoverTooltip } from './tooltip';
|
import { rsHoverTooltip } from './tooltip';
|
||||||
|
@ -39,6 +40,8 @@ interface RSInputProps
|
||||||
noTooltip?: boolean;
|
noTooltip?: boolean;
|
||||||
onChange?: (newValue: string) => void;
|
onChange?: (newValue: string) => void;
|
||||||
onAnalyze?: () => void;
|
onAnalyze?: () => void;
|
||||||
|
schema?: IRSForm;
|
||||||
|
onOpenEdit?: (cstID: ConstituentaID) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
|
@ -49,6 +52,9 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
disabled,
|
disabled,
|
||||||
noTooltip,
|
noTooltip,
|
||||||
|
|
||||||
|
schema,
|
||||||
|
onOpenEdit,
|
||||||
|
|
||||||
className,
|
className,
|
||||||
style,
|
style,
|
||||||
|
|
||||||
|
@ -59,7 +65,6 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
const { darkMode, colors, mathFont } = useConceptOptions();
|
const { darkMode, colors, mathFont } = useConceptOptions();
|
||||||
const { schema } = useRSForm();
|
|
||||||
|
|
||||||
const internalRef = useRef<ReactCodeMirrorRef>(null);
|
const internalRef = useRef<ReactCodeMirrorRef>(null);
|
||||||
const thisRef = useMemo(() => (!ref || typeof ref === 'function' ? internalRef : ref), [internalRef, ref]);
|
const thisRef = useMemo(() => (!ref || typeof ref === 'function' ? internalRef : ref), [internalRef, ref]);
|
||||||
|
@ -77,7 +82,7 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
caret: colors.fgDefault
|
caret: colors.fgDefault
|
||||||
},
|
},
|
||||||
styles: [
|
styles: [
|
||||||
{ tag: tags.name, color: colors.fgPurple, cursor: 'default' }, // GlobalID
|
{ tag: tags.name, color: colors.fgPurple, cursor: schema ? 'default' : cursor }, // GlobalID
|
||||||
{ tag: tags.variableName, color: colors.fgGreen }, // LocalID
|
{ tag: tags.variableName, color: colors.fgGreen }, // LocalID
|
||||||
{ tag: tags.propertyName, color: colors.fgTeal }, // Radical
|
{ tag: tags.propertyName, color: colors.fgTeal }, // Radical
|
||||||
{ tag: tags.keyword, color: colors.fgBlue }, // keywords
|
{ tag: tags.keyword, color: colors.fgBlue }, // keywords
|
||||||
|
@ -87,7 +92,7 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
{ tag: tags.brace, color: colors.fgPurple, fontWeight: '600' } // braces (curly brackets)
|
{ tag: tags.brace, color: colors.fgPurple, fontWeight: '600' } // braces (curly brackets)
|
||||||
]
|
]
|
||||||
}),
|
}),
|
||||||
[disabled, colors, darkMode]
|
[disabled, colors, darkMode, schema, cursor]
|
||||||
);
|
);
|
||||||
|
|
||||||
const editorExtensions = useMemo(
|
const editorExtensions = useMemo(
|
||||||
|
@ -95,9 +100,10 @@ const RSInput = forwardRef<ReactCodeMirrorRef, RSInputProps>(
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
RSLanguage,
|
RSLanguage,
|
||||||
ccBracketMatching(darkMode),
|
ccBracketMatching(darkMode),
|
||||||
...(noTooltip || !schema ? [] : [rsHoverTooltip(schema)])
|
...(!schema || !onOpenEdit ? [] : [rsNavigation(schema, onOpenEdit)]),
|
||||||
|
...(noTooltip || !schema ? [] : [rsHoverTooltip(schema, onOpenEdit !== undefined)])
|
||||||
],
|
],
|
||||||
[darkMode, schema, noTooltip]
|
[darkMode, schema, noTooltip, onOpenEdit]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleInput = useCallback(
|
const handleInput = useCallback(
|
||||||
|
|
38
rsconcept/frontend/src/components/RSInput/clickNavigation.ts
Normal file
38
rsconcept/frontend/src/components/RSInput/clickNavigation.ts
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
import { Extension } from '@codemirror/state';
|
||||||
|
import { EditorView } from '@uiw/react-codemirror';
|
||||||
|
|
||||||
|
import { ConstituentaID, IRSForm } from '@/models/rsform';
|
||||||
|
import { findAliasAt } from '@/utils/codemirror';
|
||||||
|
|
||||||
|
const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => {
|
||||||
|
return EditorView.domEventHandlers({
|
||||||
|
click: (event: MouseEvent, view: EditorView) => {
|
||||||
|
if (!event.ctrlKey && !event.metaKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
||||||
|
if (!pos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { alias } = findAliasAt(pos, view.state);
|
||||||
|
if (!alias) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cst = schema.cstByAlias.get(alias);
|
||||||
|
if (!cst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
onOpenEdit(cst.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export function rsNavigation(schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void): Extension {
|
||||||
|
return [navigationProducer(schema, onOpenEdit)];
|
||||||
|
}
|
|
@ -1,31 +1,11 @@
|
||||||
import { syntaxTree } from '@codemirror/language';
|
|
||||||
import { Extension } from '@codemirror/state';
|
import { Extension } from '@codemirror/state';
|
||||||
import { hoverTooltip } from '@codemirror/view';
|
import { hoverTooltip } from '@codemirror/view';
|
||||||
import { EditorState } from '@uiw/react-codemirror';
|
|
||||||
|
|
||||||
import { IRSForm } from '@/models/rsform';
|
import { IRSForm } from '@/models/rsform';
|
||||||
import { findEnvelopingNodes } from '@/utils/codemirror';
|
import { findAliasAt } from '@/utils/codemirror';
|
||||||
import { domTooltipConstituenta } from '@/utils/codemirror';
|
import { domTooltipConstituenta } from '@/utils/codemirror';
|
||||||
|
|
||||||
import { GlobalTokens } from './rslang';
|
const tooltipProducer = (schema: IRSForm, canClick?: boolean) => {
|
||||||
|
|
||||||
function findAliasAt(pos: number, state: EditorState) {
|
|
||||||
const { from: lineStart, to: lineEnd, text } = state.doc.lineAt(pos);
|
|
||||||
const nodes = findEnvelopingNodes(pos, pos, syntaxTree(state), GlobalTokens);
|
|
||||||
let alias = '';
|
|
||||||
let start = 0;
|
|
||||||
let end = 0;
|
|
||||||
nodes.forEach(node => {
|
|
||||||
if (node.to <= lineEnd && node.from >= lineStart) {
|
|
||||||
alias = text.slice(node.from - lineStart, node.to - lineStart);
|
|
||||||
start = node.from;
|
|
||||||
end = node.to;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return { alias, start, end };
|
|
||||||
}
|
|
||||||
|
|
||||||
const globalsHoverTooltip = (schema: IRSForm) => {
|
|
||||||
return hoverTooltip((view, pos) => {
|
return hoverTooltip((view, pos) => {
|
||||||
const { alias, start, end } = findAliasAt(pos, view.state);
|
const { alias, start, end } = findAliasAt(pos, view.state);
|
||||||
if (!alias) {
|
if (!alias) {
|
||||||
|
@ -36,11 +16,11 @@ const globalsHoverTooltip = (schema: IRSForm) => {
|
||||||
pos: start,
|
pos: start,
|
||||||
end: end,
|
end: end,
|
||||||
above: false,
|
above: false,
|
||||||
create: () => domTooltipConstituenta(cst)
|
create: () => domTooltipConstituenta(cst, canClick)
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function rsHoverTooltip(schema: IRSForm): Extension {
|
export function rsHoverTooltip(schema: IRSForm, canClick?: boolean): Extension {
|
||||||
return [globalsHoverTooltip(schema)];
|
return [tooltipProducer(schema, canClick)];
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,10 +13,11 @@ import Label from '@/components/ui/Label';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import DlgEditReference from '@/dialogs/DlgEditReference';
|
import DlgEditReference from '@/dialogs/DlgEditReference';
|
||||||
import { ReferenceType } from '@/models/language';
|
import { ReferenceType } from '@/models/language';
|
||||||
import { IRSForm } from '@/models/rsform';
|
import { ConstituentaID, IRSForm } from '@/models/rsform';
|
||||||
import { CodeMirrorWrapper } from '@/utils/codemirror';
|
import { CodeMirrorWrapper } from '@/utils/codemirror';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
|
import { refsNavigation } from './clickNavigation';
|
||||||
import { NaturalLanguage, ReferenceTokens } from './parse';
|
import { NaturalLanguage, ReferenceTokens } from './parse';
|
||||||
import { RefEntity } from './parse/parser.terms';
|
import { RefEntity } from './parse/parser.terms';
|
||||||
import { refsHoverTooltip } from './tooltip';
|
import { refsHoverTooltip } from './tooltip';
|
||||||
|
@ -65,6 +66,7 @@ interface RefsInputInputProps
|
||||||
label?: string;
|
label?: string;
|
||||||
onChange?: (newValue: string) => void;
|
onChange?: (newValue: string) => void;
|
||||||
schema?: IRSForm;
|
schema?: IRSForm;
|
||||||
|
onOpenEdit?: (cstID: ConstituentaID) => void;
|
||||||
disabled?: boolean;
|
disabled?: boolean;
|
||||||
|
|
||||||
initialValue?: string;
|
initialValue?: string;
|
||||||
|
@ -73,7 +75,23 @@ interface RefsInputInputProps
|
||||||
}
|
}
|
||||||
|
|
||||||
const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
({ id, label, disabled, schema, initialValue, value, resolved, onFocus, onBlur, onChange, ...restProps }, ref) => {
|
(
|
||||||
|
{
|
||||||
|
id, // prettier: split-lines
|
||||||
|
label,
|
||||||
|
disabled,
|
||||||
|
schema,
|
||||||
|
onOpenEdit,
|
||||||
|
initialValue,
|
||||||
|
value,
|
||||||
|
resolved,
|
||||||
|
onFocus,
|
||||||
|
onBlur,
|
||||||
|
onChange,
|
||||||
|
...restProps
|
||||||
|
},
|
||||||
|
ref
|
||||||
|
) => {
|
||||||
const { darkMode, colors } = useConceptOptions();
|
const { darkMode, colors } = useConceptOptions();
|
||||||
|
|
||||||
const [isFocused, setIsFocused] = useState(false);
|
const [isFocused, setIsFocused] = useState(false);
|
||||||
|
@ -114,9 +132,10 @@ const RefsInput = forwardRef<ReactCodeMirrorRef, RefsInputInputProps>(
|
||||||
EditorView.lineWrapping,
|
EditorView.lineWrapping,
|
||||||
EditorView.contentAttributes.of({ spellcheck: 'true' }),
|
EditorView.contentAttributes.of({ spellcheck: 'true' }),
|
||||||
NaturalLanguage,
|
NaturalLanguage,
|
||||||
...(schema ? [refsHoverTooltip(schema, colors)] : [])
|
...(!schema || !onOpenEdit ? [] : [refsNavigation(schema, onOpenEdit)]),
|
||||||
|
...(schema ? [refsHoverTooltip(schema, colors, onOpenEdit !== undefined)] : [])
|
||||||
],
|
],
|
||||||
[schema, colors]
|
[schema, colors, onOpenEdit]
|
||||||
);
|
);
|
||||||
|
|
||||||
function handleChange(newValue: string) {
|
function handleChange(newValue: string) {
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Extension } from '@codemirror/state';
|
||||||
|
import { EditorView } from '@uiw/react-codemirror';
|
||||||
|
|
||||||
|
import { ConstituentaID, IRSForm } from '@/models/rsform';
|
||||||
|
import { findReferenceAt } from '@/utils/codemirror';
|
||||||
|
|
||||||
|
const navigationProducer = (schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void) => {
|
||||||
|
return EditorView.domEventHandlers({
|
||||||
|
click: (event: MouseEvent, view: EditorView) => {
|
||||||
|
if (!event.ctrlKey && !event.metaKey) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pos = view.posAtCoords({ x: event.clientX, y: event.clientY });
|
||||||
|
if (!pos) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parse = findReferenceAt(pos, view.state);
|
||||||
|
if (!parse || !('entity' in parse.ref)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const cst = schema.cstByAlias.get(parse.ref.entity);
|
||||||
|
if (!cst) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
onOpenEdit(cst.id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
export function refsNavigation(schema: IRSForm, onOpenEdit: (cstID: ConstituentaID) => void): Extension {
|
||||||
|
return [navigationProducer(schema, onOpenEdit)];
|
||||||
|
}
|
|
@ -2,65 +2,58 @@ import { syntaxTree } from '@codemirror/language';
|
||||||
import { Extension } from '@codemirror/state';
|
import { Extension } from '@codemirror/state';
|
||||||
import { hoverTooltip } from '@codemirror/view';
|
import { hoverTooltip } from '@codemirror/view';
|
||||||
|
|
||||||
import { parseEntityReference, parseSyntacticReference } from '@/models/languageAPI';
|
import { IEntityReference, ISyntacticReference } from '@/models/language';
|
||||||
import { IRSForm } from '@/models/rsform';
|
import { IRSForm } from '@/models/rsform';
|
||||||
import { IColorTheme } from '@/styling/color';
|
import { IColorTheme } from '@/styling/color';
|
||||||
import {
|
import {
|
||||||
domTooltipEntityReference,
|
domTooltipEntityReference,
|
||||||
domTooltipSyntacticReference,
|
domTooltipSyntacticReference,
|
||||||
findContainedNodes,
|
findContainedNodes,
|
||||||
findEnvelopingNodes
|
findReferenceAt
|
||||||
} from '@/utils/codemirror';
|
} from '@/utils/codemirror';
|
||||||
|
|
||||||
import { ReferenceTokens } from './parse';
|
import { RefEntity } from './parse/parser.terms';
|
||||||
import { RefEntity, RefSyntactic } from './parse/parser.terms';
|
|
||||||
|
|
||||||
export const globalsHoverTooltip = (schema: IRSForm, colors: IColorTheme) => {
|
export const tooltipProducer = (schema: IRSForm, colors: IColorTheme, canClick?: boolean) => {
|
||||||
return hoverTooltip((view, pos) => {
|
return hoverTooltip((view, pos) => {
|
||||||
const nodes = findEnvelopingNodes(pos, pos, syntaxTree(view.state), ReferenceTokens);
|
const parse = findReferenceAt(pos, view.state);
|
||||||
if (nodes.length !== 1) {
|
if (!parse) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
const start = nodes[0].from;
|
|
||||||
const end = nodes[0].to;
|
if ('entity' in parse.ref) {
|
||||||
const text = view.state.doc.sliceString(start, end);
|
const cst = schema.cstByAlias.get(parse.ref.entity);
|
||||||
if (nodes[0].type.id === RefEntity) {
|
|
||||||
const ref = parseEntityReference(text);
|
|
||||||
const cst = schema.cstByAlias.get(ref.entity);
|
|
||||||
return {
|
return {
|
||||||
pos: start,
|
pos: parse.start,
|
||||||
end: end,
|
end: parse.end,
|
||||||
above: false,
|
above: false,
|
||||||
create: () => domTooltipEntityReference(ref, cst, colors)
|
create: () => domTooltipEntityReference(parse.ref as IEntityReference, cst, colors, canClick)
|
||||||
};
|
};
|
||||||
} else if (nodes[0].type.id === RefSyntactic) {
|
} else {
|
||||||
const ref = parseSyntacticReference(text);
|
|
||||||
let masterText: string | undefined = undefined;
|
let masterText: string | undefined = undefined;
|
||||||
if (ref.offset > 0) {
|
if (parse.ref.offset > 0) {
|
||||||
const entities = findContainedNodes(end, view.state.doc.length, syntaxTree(view.state), [RefEntity]);
|
const entities = findContainedNodes(parse.end, view.state.doc.length, syntaxTree(view.state), [RefEntity]);
|
||||||
if (ref.offset <= entities.length) {
|
if (parse.ref.offset <= entities.length) {
|
||||||
const master = entities[ref.offset - 1];
|
const master = entities[parse.ref.offset - 1];
|
||||||
masterText = view.state.doc.sliceString(master.from, master.to);
|
masterText = view.state.doc.sliceString(master.from, master.to);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const entities = findContainedNodes(0, start, syntaxTree(view.state), [RefEntity]);
|
const entities = findContainedNodes(0, parse.start, syntaxTree(view.state), [RefEntity]);
|
||||||
if (-ref.offset <= entities.length) {
|
if (-parse.ref.offset <= entities.length) {
|
||||||
const master = entities[-ref.offset - 1];
|
const master = entities[-parse.ref.offset - 1];
|
||||||
masterText = view.state.doc.sliceString(master.from, master.to);
|
masterText = view.state.doc.sliceString(master.from, master.to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
pos: start,
|
pos: parse.start,
|
||||||
end: end,
|
end: parse.end,
|
||||||
above: false,
|
above: false,
|
||||||
create: () => domTooltipSyntacticReference(ref, masterText)
|
create: () => domTooltipSyntacticReference(parse.ref as ISyntacticReference, masterText, canClick)
|
||||||
};
|
};
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export function refsHoverTooltip(schema: IRSForm, colors: IColorTheme): Extension {
|
export function refsHoverTooltip(schema: IRSForm, colors: IColorTheme, canClick?: boolean): Extension {
|
||||||
return [globalsHoverTooltip(schema, colors)];
|
return [tooltipProducer(schema, colors, canClick)];
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,7 +50,7 @@ function GraphSelectionToolbar({
|
||||||
disabled={emptySelection}
|
disabled={emptySelection}
|
||||||
/>
|
/>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
titleHtml='<b>Максимизация</b> - дополнение выделения конституентами, зависимыми только от выделенных'
|
titleHtml='<b>Максимизация</b> <br/>дополнение выделения конституентами, <br/>зависимыми только от выделенных'
|
||||||
icon={<IconGraphMaximize size='1.25rem' className='icon-primary' />}
|
icon={<IconGraphMaximize size='1.25rem' className='icon-primary' />}
|
||||||
onClick={() => setSelected(prev => graph.maximizePart(prev))}
|
onClick={() => setSelected(prev => graph.maximizePart(prev))}
|
||||||
disabled={emptySelection}
|
disabled={emptySelection}
|
||||||
|
|
|
@ -12,7 +12,7 @@ import { prefixes } from '@/utils/constants';
|
||||||
import { describeConstituenta } from '@/utils/labels';
|
import { describeConstituenta } from '@/utils/labels';
|
||||||
|
|
||||||
import BadgeConstituenta from '../info/BadgeConstituenta';
|
import BadgeConstituenta from '../info/BadgeConstituenta';
|
||||||
import FlexColumn from '../ui/FlexColumn';
|
import NoData from '../ui/NoData';
|
||||||
|
|
||||||
interface PickConstituentaProps {
|
interface PickConstituentaProps {
|
||||||
id?: string;
|
id?: string;
|
||||||
|
@ -106,10 +106,10 @@ function PickConstituenta({
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<NoData className='min-h-[6rem]'>
|
||||||
<p>Список конституент пуст</p>
|
<p>Список конституент пуст</p>
|
||||||
<p>Измените параметры фильтра</p>
|
<p>Измените параметры фильтра</p>
|
||||||
</FlexColumn>
|
</NoData>
|
||||||
}
|
}
|
||||||
onRowClicked={onSelectValue}
|
onRowClicked={onSelectValue}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -10,7 +10,7 @@ import { isBasicConcept } from '@/models/rsformAPI';
|
||||||
import { describeConstituenta } from '@/utils/labels';
|
import { describeConstituenta } from '@/utils/labels';
|
||||||
|
|
||||||
import BadgeConstituenta from '../info/BadgeConstituenta';
|
import BadgeConstituenta from '../info/BadgeConstituenta';
|
||||||
import FlexColumn from '../ui/FlexColumn';
|
import NoData from '../ui/NoData';
|
||||||
import GraphSelectionToolbar from './GraphSelectionToolbar';
|
import GraphSelectionToolbar from './GraphSelectionToolbar';
|
||||||
|
|
||||||
interface PickMultiConstituentaProps {
|
interface PickMultiConstituentaProps {
|
||||||
|
@ -103,9 +103,9 @@ function PickMultiConstituenta({ id, schema, prefixID, rows, selected, setSelect
|
||||||
rowSelection={rowSelection}
|
rowSelection={rowSelection}
|
||||||
onRowSelectionChange={handleRowSelection}
|
onRowSelectionChange={handleRowSelection}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='items-center p-3'>
|
<NoData>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
</FlexColumn>
|
</NoData>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import DataTable, { createColumnHelper, IConditionalStyle } from '@/components/u
|
||||||
import SearchBar from '@/components/ui/SearchBar';
|
import SearchBar from '@/components/ui/SearchBar';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
import { ILibraryItem, LibraryItemID, LibraryItemType } from '@/models/library';
|
||||||
import { ILibraryFilter } from '@/models/miscellaneous';
|
import { ILibraryFilter } from '@/models/miscellaneous';
|
||||||
|
|
||||||
import FlexColumn from '../ui/FlexColumn';
|
import FlexColumn from '../ui/FlexColumn';
|
||||||
|
@ -32,7 +32,8 @@ function PickSchema({ id, initialFilter = '', rows = 4, value, onSelectValue }:
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
setFilter({
|
setFilter({
|
||||||
query: filterText
|
query: filterText,
|
||||||
|
type: LibraryItemType.RSFORM
|
||||||
});
|
});
|
||||||
}, [filterText]);
|
}, [filterText]);
|
||||||
|
|
||||||
|
@ -103,7 +104,7 @@ function PickSchema({ id, initialFilter = '', rows = 4, value, onSelectValue }:
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<FlexColumn className='dense p-3 items-center min-h-[6rem]'>
|
||||||
<p>Список схем пуст</p>
|
<p>Список схем пуст</p>
|
||||||
<p>Измените параметры фильтра</p>
|
<p>Измените параметры фильтра</p>
|
||||||
</FlexColumn>
|
</FlexColumn>
|
||||||
|
|
|
@ -23,6 +23,7 @@ import {
|
||||||
IconRemove,
|
IconRemove,
|
||||||
IconReplace
|
IconReplace
|
||||||
} from '../Icons';
|
} from '../Icons';
|
||||||
|
import NoData from '../ui/NoData';
|
||||||
|
|
||||||
interface PickSubstitutionsProps {
|
interface PickSubstitutionsProps {
|
||||||
prefixID: string;
|
prefixID: string;
|
||||||
|
@ -259,10 +260,10 @@ function PickSubstitutions({
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<span className='p-2 text-center min-h-[2rem]'>
|
<NoData className='min-h-[2rem]'>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
<p>Добавьте отождествление</p>
|
<p>Добавьте отождествление</p>
|
||||||
</span>
|
</NoData>
|
||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -37,7 +37,7 @@ function SelectAccessPolicy({ value, disabled, stretchLeft, onChange }: SelectAc
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title={`Доступ: ${labelAccessPolicy(value)}`}
|
title={`Доступ: ${labelAccessPolicy(value)}`}
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full disabled:cursor-auto'
|
className='h-full'
|
||||||
icon={<PolicyIcon value={value} size='1.25rem' />}
|
icon={<PolicyIcon value={value} size='1.25rem' />}
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
disabled={disabled}
|
disabled={disabled}
|
||||||
|
|
|
@ -36,10 +36,10 @@ function SelectGraphFilter({ value, dense, onChange }: SelectGraphFilterProps) {
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
transparent
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
title='Настройка фильтрации по графу термов'
|
titleHtml='Настройка фильтрации <br/>по графу термов'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
icon={DependencyIcon(value, '1rem', value !== DependencyMode.ALL ? 'icon-primary' : '')}
|
icon={<DependencyIcon value={value} size='1rem' />}
|
||||||
text={dense || size.isSmall ? undefined : labelCstSource(value)}
|
text={dense || size.isSmall ? undefined : labelCstSource(value)}
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
/>
|
/>
|
||||||
|
@ -55,7 +55,7 @@ function SelectGraphFilter({ value, dense, onChange }: SelectGraphFilterProps) {
|
||||||
onClick={() => handleChange(source)}
|
onClick={() => handleChange(source)}
|
||||||
>
|
>
|
||||||
<div className='inline-flex items-center gap-1'>
|
<div className='inline-flex items-center gap-1'>
|
||||||
{DependencyIcon(source, '1rem')}
|
{<DependencyIcon value={source} size='1rem' />}
|
||||||
{!dense ? (
|
{!dense ? (
|
||||||
<span>
|
<span>
|
||||||
<b>{labelCstSource(source)}:</b> {describeCstSource(source)}
|
<b>{labelCstSource(source)}:</b> {describeCstSource(source)}
|
||||||
|
|
|
@ -38,7 +38,7 @@ function SelectItemType({ value, disabled, stretchLeft, onChange }: SelectItemTy
|
||||||
transparent
|
transparent
|
||||||
title={describeLibraryItemType(value)}
|
title={describeLibraryItemType(value)}
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full py-1 px-2 disabled:cursor-auto rounded-lg'
|
className='h-full px-2 py-1 rounded-lg'
|
||||||
icon={<ItemTypeIcon value={value} size='1.25rem' />}
|
icon={<ItemTypeIcon value={value} size='1.25rem' />}
|
||||||
text={labelLibraryItemType(value)}
|
text={labelLibraryItemType(value)}
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
|
|
42
rsconcept/frontend/src/components/select/SelectLocation.tsx
Normal file
42
rsconcept/frontend/src/components/select/SelectLocation.tsx
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
|
import { FolderTree } from '@/models/FolderTree';
|
||||||
|
|
||||||
|
import { IconFolderTree } from '../Icons';
|
||||||
|
import MiniButton from '../ui/MiniButton';
|
||||||
|
|
||||||
|
interface SelectLocationProps {
|
||||||
|
value: string;
|
||||||
|
onChange: (newValue: string) => void;
|
||||||
|
|
||||||
|
folderTree: FolderTree;
|
||||||
|
}
|
||||||
|
|
||||||
|
function SelectLocation({ value, onChange, folderTree }: SelectLocationProps) {
|
||||||
|
const menu = useDropdown();
|
||||||
|
|
||||||
|
const handleChange = useCallback(
|
||||||
|
(newValue: string) => {
|
||||||
|
console.log(folderTree.roots.size);
|
||||||
|
console.log(value);
|
||||||
|
menu.hide();
|
||||||
|
onChange(newValue);
|
||||||
|
},
|
||||||
|
[menu, onChange, value, folderTree]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div ref={menu.ref} className='h-full text-right'>
|
||||||
|
<MiniButton
|
||||||
|
title='Проводник...'
|
||||||
|
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||||
|
onClick={() => handleChange('/U/test')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SelectLocation;
|
|
@ -14,7 +14,7 @@ import DropdownButton from '../ui/DropdownButton';
|
||||||
|
|
||||||
interface SelectLocationHeadProps {
|
interface SelectLocationHeadProps {
|
||||||
value: LocationHead;
|
value: LocationHead;
|
||||||
onChange: (value: LocationHead) => void;
|
onChange: (newValue: LocationHead) => void;
|
||||||
excluded?: LocationHead[];
|
excluded?: LocationHead[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,10 +35,10 @@ function SelectMatchMode({ value, dense, onChange }: SelectMatchModeProps) {
|
||||||
<div ref={menu.ref}>
|
<div ref={menu.ref}>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
transparent
|
||||||
title='Настройка фильтрации по проверяемым атрибутам'
|
titleHtml='Настройка фильтрации <br/>по проверяемым атрибутам'
|
||||||
hideTitle={menu.isOpen}
|
hideTitle={menu.isOpen}
|
||||||
className='h-full pr-2'
|
className='h-full pr-2'
|
||||||
icon={MatchModeIcon(value, '1rem', value !== CstMatchMode.ALL ? 'icon-primary' : '')}
|
icon={<MatchModeIcon value={value} size='1rem' />}
|
||||||
text={dense || size.isSmall ? undefined : labelCstMatchMode(value)}
|
text={dense || size.isSmall ? undefined : labelCstMatchMode(value)}
|
||||||
onClick={menu.toggle}
|
onClick={menu.toggle}
|
||||||
/>
|
/>
|
||||||
|
@ -54,7 +54,7 @@ function SelectMatchMode({ value, dense, onChange }: SelectMatchModeProps) {
|
||||||
onClick={() => handleChange(matchMode)}
|
onClick={() => handleChange(matchMode)}
|
||||||
>
|
>
|
||||||
<div className='inline-flex items-center gap-1'>
|
<div className='inline-flex items-center gap-1'>
|
||||||
{MatchModeIcon(matchMode, '1rem')}
|
{<MatchModeIcon value={matchMode} size='1rem' />}
|
||||||
{!dense ? (
|
{!dense ? (
|
||||||
<span>
|
<span>
|
||||||
<b>{labelCstMatchMode(matchMode)}:</b> {describeCstMatchMode(matchMode)}
|
<b>{labelCstMatchMode(matchMode)}:</b> {describeCstMatchMode(matchMode)}
|
||||||
|
|
|
@ -33,7 +33,7 @@ function Button({
|
||||||
disabled={disabled ?? loading}
|
disabled={disabled ?? loading}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'inline-flex gap-2 items-center justify-center',
|
'inline-flex gap-2 items-center justify-center',
|
||||||
'select-none disabled:cursor-not-allowed',
|
'select-none disabled:cursor-auto',
|
||||||
{
|
{
|
||||||
'border rounded': !noBorder,
|
'border rounded': !noBorder,
|
||||||
'px-1': dense,
|
'px-1': dense,
|
||||||
|
|
|
@ -27,7 +27,7 @@ function Checkbox({
|
||||||
}: CheckboxProps) {
|
}: CheckboxProps) {
|
||||||
const cursor = useMemo(() => {
|
const cursor = useMemo(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return 'cursor-not-allowed';
|
return 'cursor-auto';
|
||||||
} else if (setValue) {
|
} else if (setValue) {
|
||||||
return 'cursor-pointer';
|
return 'cursor-pointer';
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -25,7 +25,7 @@ function CheckboxTristate({
|
||||||
}: CheckboxTristateProps) {
|
}: CheckboxTristateProps) {
|
||||||
const cursor = useMemo(() => {
|
const cursor = useMemo(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
return 'cursor-not-allowed';
|
return 'cursor-auto';
|
||||||
} else if (setValue) {
|
} else if (setValue) {
|
||||||
return 'cursor-pointer';
|
return 'cursor-pointer';
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -35,7 +35,7 @@ function DropdownButton({
|
||||||
'disabled:clr-text-controls',
|
'disabled:clr-text-controls',
|
||||||
{
|
{
|
||||||
'clr-hover': onClick,
|
'clr-hover': onClick,
|
||||||
'cursor-pointer disabled:cursor-not-allowed': onClick,
|
'cursor-pointer disabled:cursor-auto': onClick,
|
||||||
'cursor-default': !onClick
|
'cursor-default': !onClick
|
||||||
},
|
},
|
||||||
className
|
className
|
||||||
|
|
|
@ -2,9 +2,7 @@ import clsx from 'clsx';
|
||||||
|
|
||||||
import { CProps } from '../props';
|
import { CProps } from '../props';
|
||||||
|
|
||||||
export interface FlexColumnProps extends CProps.Div {}
|
function FlexColumn({ className, children, ...restProps }: CProps.Div) {
|
||||||
|
|
||||||
function FlexColumn({ className, children, ...restProps }: FlexColumnProps) {
|
|
||||||
return (
|
return (
|
||||||
<div className={clsx('cc-column', className)} {...restProps}>
|
<div className={clsx('cc-column', className)} {...restProps}>
|
||||||
{children}
|
{children}
|
||||||
|
|
|
@ -28,7 +28,7 @@ function MiniButton({
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'rounded-lg',
|
'rounded-lg',
|
||||||
'clr-btn-clear',
|
'clr-btn-clear',
|
||||||
'cursor-pointer disabled:cursor-not-allowed',
|
'cursor-pointer disabled:cursor-auto',
|
||||||
{
|
{
|
||||||
'px-1 py-1': !noPadding,
|
'px-1 py-1': !noPadding,
|
||||||
'outline-none': noHover,
|
'outline-none': noHover,
|
||||||
|
|
13
rsconcept/frontend/src/components/ui/NoData.tsx
Normal file
13
rsconcept/frontend/src/components/ui/NoData.tsx
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import { CProps } from '../props';
|
||||||
|
|
||||||
|
function NoData({ className, children, ...restProps }: CProps.Div) {
|
||||||
|
return (
|
||||||
|
<div className={clsx('p-3 flex flex-col items-center text-center select-none w-full', className)} {...restProps}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default NoData;
|
|
@ -11,21 +11,23 @@ import Overlay from '../Overlay';
|
||||||
import PageControls from './PageControls';
|
import PageControls from './PageControls';
|
||||||
|
|
||||||
const MAXIMUM_WIDTH = 1000;
|
const MAXIMUM_WIDTH = 1000;
|
||||||
const MINIMUM_WIDTH = 320;
|
const MINIMUM_WIDTH = 300;
|
||||||
|
|
||||||
interface PDFViewerProps {
|
interface PDFViewerProps {
|
||||||
file?: string | ArrayBuffer | Blob;
|
file?: string | ArrayBuffer | Blob;
|
||||||
|
offsetXpx?: number;
|
||||||
|
minWidth?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
function PDFViewer({ file }: PDFViewerProps) {
|
function PDFViewer({ file, offsetXpx, minWidth = MINIMUM_WIDTH }: PDFViewerProps) {
|
||||||
const windowSize = useWindowSize();
|
const windowSize = useWindowSize();
|
||||||
|
|
||||||
const [pageCount, setPageCount] = useState(0);
|
const [pageCount, setPageCount] = useState(0);
|
||||||
const [pageNumber, setPageNumber] = useState(1);
|
const [pageNumber, setPageNumber] = useState(1);
|
||||||
|
|
||||||
const pageWidth = useMemo(() => {
|
const pageWidth = useMemo(() => {
|
||||||
return Math.max(MINIMUM_WIDTH, Math.min((windowSize?.width ?? 0) - 10, MAXIMUM_WIDTH));
|
return Math.max(minWidth, Math.min((windowSize?.width ?? 0) - (offsetXpx ?? 0) - 10, MAXIMUM_WIDTH));
|
||||||
}, [windowSize]);
|
}, [windowSize, offsetXpx, minWidth]);
|
||||||
|
|
||||||
function onDocumentLoadSuccess({ numPages }: PDFDocumentProxy) {
|
function onDocumentLoadSuccess({ numPages }: PDFDocumentProxy) {
|
||||||
setPageCount(numPages);
|
setPageCount(numPages);
|
||||||
|
@ -42,14 +44,14 @@ function PDFViewer({ file }: PDFViewerProps) {
|
||||||
<PageControls pageCount={pageCount} pageNumber={pageNumber} setPageNumber={setPageNumber} />
|
<PageControls pageCount={pageCount} pageNumber={pageNumber} setPageNumber={setPageNumber} />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
<Page
|
<Page
|
||||||
className='pointer-events-none select-none sm:translate-x-0'
|
className='overflow-hidden pointer-events-none select-none'
|
||||||
renderTextLayer={false}
|
renderTextLayer={false}
|
||||||
renderAnnotationLayer={false}
|
renderAnnotationLayer={false}
|
||||||
pageNumber={pageNumber}
|
pageNumber={pageNumber}
|
||||||
width={pageWidth}
|
width={pageWidth}
|
||||||
canvasBackground={graphLightT.canvas.background}
|
canvasBackground={graphLightT.canvas.background}
|
||||||
/>
|
/>
|
||||||
<Overlay position='bottom-6 left-1/2 -translate-x-1/2' className='flex select-none'>
|
<Overlay position='bottom-3 left-1/2 -translate-x-1/2' className='flex select-none'>
|
||||||
<PageControls pageCount={pageCount} pageNumber={pageNumber} setPageNumber={setPageNumber} />
|
<PageControls pageCount={pageCount} pageNumber={pageNumber} setPageNumber={setPageNumber} />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
</Document>
|
</Document>
|
||||||
|
|
|
@ -8,7 +8,7 @@ interface PageControlsProps {
|
||||||
|
|
||||||
function PageControls({ pageNumber, pageCount, setPageNumber }: PageControlsProps) {
|
function PageControls({ pageNumber, pageCount, setPageNumber }: PageControlsProps) {
|
||||||
return (
|
return (
|
||||||
<>
|
<div className='flex items-center'>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className='clr-hover clr-text-controls'
|
className='clr-hover clr-text-controls'
|
||||||
|
@ -25,9 +25,9 @@ function PageControls({ pageNumber, pageCount, setPageNumber }: PageControlsProp
|
||||||
>
|
>
|
||||||
<IconPageLeft size='1.5rem' />
|
<IconPageLeft size='1.5rem' />
|
||||||
</button>
|
</button>
|
||||||
<p className='px-3 text-black text-nowrap'>
|
<div className='px-3 text-nowrap'>
|
||||||
Страница {pageNumber} из {pageCount}
|
Страница {pageNumber} из {pageCount}
|
||||||
</p>
|
</div>
|
||||||
<button
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className='clr-hover clr-text-controls'
|
className='clr-hover clr-text-controls'
|
||||||
|
@ -44,7 +44,7 @@ function PageControls({ pageNumber, pageCount, setPageNumber }: PageControlsProp
|
||||||
>
|
>
|
||||||
<IconPageLast size='1.5rem' />
|
<IconPageLast size='1.5rem' />
|
||||||
</button>
|
</button>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ function SelectTree<ItemType>({
|
||||||
value === item && 'clr-selected'
|
value === item && 'clr-selected'
|
||||||
)}
|
)}
|
||||||
data-tooltip-id={globals.tooltip}
|
data-tooltip-id={globals.tooltip}
|
||||||
data-tooltip-content={getDescription(item)}
|
data-tooltip-html={getDescription(item)}
|
||||||
onClick={event => handleSetValue(event, item)}
|
onClick={event => handleSetValue(event, item)}
|
||||||
initial={{ ...animateSideAppear.initial }}
|
initial={{ ...animateSideAppear.initial }}
|
||||||
animate={{ ...animateSideAppear.animate }}
|
animate={{ ...animateSideAppear.animate }}
|
||||||
|
|
|
@ -31,7 +31,7 @@ function SelectorButton({
|
||||||
'px-1 flex flex-start items-center gap-1',
|
'px-1 flex flex-start items-center gap-1',
|
||||||
'text-sm font-controls select-none',
|
'text-sm font-controls select-none',
|
||||||
'text-btn clr-text-controls',
|
'text-btn clr-text-controls',
|
||||||
'disabled:cursor-not-allowed cursor-pointer',
|
'disabled:cursor-auto cursor-pointer',
|
||||||
{
|
{
|
||||||
'clr-hover': transparent,
|
'clr-hover': transparent,
|
||||||
'border': !transparent
|
'border': !transparent
|
||||||
|
|
|
@ -17,7 +17,7 @@ function SubmitButton({ text = 'ОК', icon, disabled, loading, className, ...re
|
||||||
'border',
|
'border',
|
||||||
'font-medium',
|
'font-medium',
|
||||||
'clr-btn-primary',
|
'clr-btn-primary',
|
||||||
'select-none disabled:cursor-not-allowed',
|
'select-none disabled:cursor-auto',
|
||||||
loading && 'cursor-progress',
|
loading && 'cursor-progress',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -18,9 +18,9 @@ function TextURL({ text, href, title, color = 'clr-text-url', onClick }: TextURL
|
||||||
);
|
);
|
||||||
} else if (onClick) {
|
} else if (onClick) {
|
||||||
return (
|
return (
|
||||||
<span tabIndex={-1} className={design} onClick={onClick}>
|
<button type='button' tabIndex={-1} className={design} onClick={onClick}>
|
||||||
{text}
|
{text}
|
||||||
</span>
|
</button>
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -33,7 +33,8 @@ function Tooltip({
|
||||||
delayHide={100}
|
delayHide={100}
|
||||||
opacity={0.97}
|
opacity={0.97}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'overflow-auto sm:overflow-hidden overscroll-contain',
|
'max-h-[calc(100svh-6rem)]',
|
||||||
|
'overflow-y-auto overflow-x-hidden sm:overflow-hidden overscroll-contain',
|
||||||
'border shadow-md',
|
'border shadow-md',
|
||||||
'text-balance',
|
'text-balance',
|
||||||
layer,
|
layer,
|
||||||
|
|
|
@ -1,27 +1,34 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { AnimatePresence } from 'framer-motion';
|
||||||
|
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
|
|
||||||
|
import Loader from '../ui/Loader';
|
||||||
import TextURL from '../ui/TextURL';
|
import TextURL from '../ui/TextURL';
|
||||||
|
import AnimateFade from './AnimateFade';
|
||||||
|
|
||||||
interface RequireAuthProps {
|
interface RequireAuthProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function RequireAuth({ children }: RequireAuthProps) {
|
function RequireAuth({ children }: RequireAuthProps) {
|
||||||
const { user } = useAuth();
|
const { user, loading } = useAuth();
|
||||||
if (user) {
|
|
||||||
return children;
|
|
||||||
} else {
|
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col items-center gap-1 mt-2'>
|
<AnimatePresence mode='wait'>
|
||||||
|
{loading ? <Loader key='auth-loader' /> : null}
|
||||||
|
{!loading && user ? <AnimateFade key='auth-data'>{children}</AnimateFade> : null}
|
||||||
|
{!loading && !user ? (
|
||||||
|
<AnimateFade key='auth-no-user' className='flex flex-col items-center gap-1 mt-2'>
|
||||||
<p className='mb-2'>Пожалуйста войдите в систему</p>
|
<p className='mb-2'>Пожалуйста войдите в систему</p>
|
||||||
<TextURL text='Войти в Портал' href='/login' />
|
<TextURL text='Войти в Портал' href='/login' />
|
||||||
<TextURL text='Зарегистрироваться' href='/signup' />
|
<TextURL text='Зарегистрироваться' href='/signup' />
|
||||||
<TextURL text='Начальная страница' href='/' />
|
<TextURL text='Начальная страница' href='/' />
|
||||||
</div>
|
</AnimateFade>
|
||||||
|
) : null}
|
||||||
|
</AnimatePresence>
|
||||||
);
|
);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default RequireAuth;
|
export default RequireAuth;
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
import { createContext, useContext, useState } from 'react';
|
import { createContext, useContext, useState } from 'react';
|
||||||
|
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserLevel } from '@/models/user';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
interface IAccessModeContext {
|
interface IAccessModeContext {
|
||||||
accessLevel: UserLevel;
|
accessLevel: UserLevel;
|
||||||
|
@ -13,7 +14,7 @@ const AccessContext = createContext<IAccessModeContext | null>(null);
|
||||||
export const useAccessMode = () => {
|
export const useAccessMode = () => {
|
||||||
const context = useContext(AccessContext);
|
const context = useContext(AccessContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useAccessMode has to be used within <AccessModeState.Provider>');
|
throw new Error(contextOutsideScope('useAccessMode', 'AccessModeState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,6 +25,7 @@ import {
|
||||||
IUserSignupData,
|
IUserSignupData,
|
||||||
IUserUpdatePassword
|
IUserUpdatePassword
|
||||||
} from '@/models/user';
|
} from '@/models/user';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
import { useUsers } from './UsersContext';
|
import { useUsers } from './UsersContext';
|
||||||
|
|
||||||
|
@ -46,7 +47,7 @@ const AuthContext = createContext<IAuthContext | null>(null);
|
||||||
export const useAuth = () => {
|
export const useAuth = () => {
|
||||||
const context = useContext(AuthContext);
|
const context = useContext(AuthContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useAuth has to be used within <AuthState.Provider>');
|
throw new Error(contextOutsideScope('useAuth', 'AuthState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { createContext, useCallback, useContext, useEffect, useState } from 'react';
|
import { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
DataCallback,
|
DataCallback,
|
||||||
|
@ -14,12 +14,14 @@ import {
|
||||||
postRSFormFromFile
|
postRSFormFromFile
|
||||||
} from '@/app/backendAPI';
|
} from '@/app/backendAPI';
|
||||||
import { ErrorData } from '@/components/info/InfoError';
|
import { ErrorData } from '@/components/info/InfoError';
|
||||||
import { ILibraryItem, LibraryItemID } from '@/models/library';
|
import { FolderTree } from '@/models/FolderTree';
|
||||||
|
import { ILibraryItem, LibraryItemID, LocationHead } from '@/models/library';
|
||||||
import { ILibraryCreateData } from '@/models/library';
|
import { ILibraryCreateData } from '@/models/library';
|
||||||
import { matchLibraryItem, matchLibraryItemLocation } from '@/models/libraryAPI';
|
import { matchLibraryItem, matchLibraryItemLocation } from '@/models/libraryAPI';
|
||||||
import { ILibraryFilter } from '@/models/miscellaneous';
|
import { ILibraryFilter } from '@/models/miscellaneous';
|
||||||
import { IRSForm, IRSFormCloneData, IRSFormData } from '@/models/rsform';
|
import { IRSForm, IRSFormCloneData, IRSFormData } from '@/models/rsform';
|
||||||
import { RSFormLoader } from '@/models/RSFormLoader';
|
import { RSFormLoader } from '@/models/RSFormLoader';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
import { useAuth } from './AuthContext';
|
import { useAuth } from './AuthContext';
|
||||||
import { useConceptOptions } from './OptionsContext';
|
import { useConceptOptions } from './OptionsContext';
|
||||||
|
@ -27,10 +29,17 @@ import { useConceptOptions } from './OptionsContext';
|
||||||
interface ILibraryContext {
|
interface ILibraryContext {
|
||||||
items: ILibraryItem[];
|
items: ILibraryItem[];
|
||||||
templates: ILibraryItem[];
|
templates: ILibraryItem[];
|
||||||
|
folders: FolderTree;
|
||||||
|
|
||||||
loading: boolean;
|
loading: boolean;
|
||||||
|
loadingError: ErrorData;
|
||||||
|
setLoadingError: (error: ErrorData) => void;
|
||||||
|
|
||||||
processing: boolean;
|
processing: boolean;
|
||||||
error: ErrorData;
|
processingError: ErrorData;
|
||||||
setError: (error: ErrorData) => void;
|
setProcessingError: (error: ErrorData) => void;
|
||||||
|
|
||||||
|
reloadItems: (callback?: () => void) => void;
|
||||||
|
|
||||||
applyFilter: (params: ILibraryFilter) => ILibraryItem[];
|
applyFilter: (params: ILibraryFilter) => ILibraryItem[];
|
||||||
retrieveTemplate: (templateID: LibraryItemID, callback: (schema: IRSForm) => void) => void;
|
retrieveTemplate: (templateID: LibraryItemID, callback: (schema: IRSForm) => void) => void;
|
||||||
|
@ -46,7 +55,7 @@ const LibraryContext = createContext<ILibraryContext | null>(null);
|
||||||
export const useLibrary = (): ILibraryContext => {
|
export const useLibrary = (): ILibraryContext => {
|
||||||
const context = useContext(LibraryContext);
|
const context = useContext(LibraryContext);
|
||||||
if (context === null) {
|
if (context === null) {
|
||||||
throw new Error('useLibrary has to be used within <LibraryState.Provider>');
|
throw new Error(contextOutsideScope('useLibrary', 'LibraryState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
@ -63,15 +72,32 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
const [templates, setTemplates] = useState<ILibraryItem[]>([]);
|
const [templates, setTemplates] = useState<ILibraryItem[]>([]);
|
||||||
const [loading, setLoading] = useState(false);
|
const [loading, setLoading] = useState(false);
|
||||||
const [processing, setProcessing] = useState(false);
|
const [processing, setProcessing] = useState(false);
|
||||||
const [error, setError] = useState<ErrorData>(undefined);
|
const [loadingError, setLoadingError] = useState<ErrorData>(undefined);
|
||||||
|
const [processingError, setProcessingError] = useState<ErrorData>(undefined);
|
||||||
const [cachedTemplates, setCachedTemplates] = useState<IRSForm[]>([]);
|
const [cachedTemplates, setCachedTemplates] = useState<IRSForm[]>([]);
|
||||||
|
|
||||||
|
const folders = useMemo(() => {
|
||||||
|
const result = new FolderTree();
|
||||||
|
result.addPath(LocationHead.USER, 0);
|
||||||
|
result.addPath(LocationHead.COMMON, 0);
|
||||||
|
result.addPath(LocationHead.LIBRARY, 0);
|
||||||
|
result.addPath(LocationHead.PROJECTS, 0);
|
||||||
|
items.forEach(item => result.addPath(item.location));
|
||||||
|
return result;
|
||||||
|
}, [items]);
|
||||||
|
|
||||||
const applyFilter = useCallback(
|
const applyFilter = useCallback(
|
||||||
(filter: ILibraryFilter) => {
|
(filter: ILibraryFilter) => {
|
||||||
let result = items;
|
let result = items;
|
||||||
if (filter.head) {
|
if (!filter.folderMode && filter.head) {
|
||||||
result = result.filter(item => item.location.startsWith(filter.head!));
|
result = result.filter(item => item.location.startsWith(filter.head!));
|
||||||
}
|
}
|
||||||
|
if (filter.folderMode && filter.folder) {
|
||||||
|
result = result.filter(item => item.location == filter.folder);
|
||||||
|
}
|
||||||
|
if (filter.type) {
|
||||||
|
result = result.filter(item => item.item_type === filter.type);
|
||||||
|
}
|
||||||
if (filter.isVisible !== undefined) {
|
if (filter.isVisible !== undefined) {
|
||||||
result = result.filter(item => filter.isVisible === item.visible);
|
result = result.filter(item => filter.isVisible === item.visible);
|
||||||
}
|
}
|
||||||
|
@ -84,12 +110,12 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
if (filter.isEditor !== undefined) {
|
if (filter.isEditor !== undefined) {
|
||||||
result = result.filter(item => filter.isEditor == user?.editor.includes(item.id));
|
result = result.filter(item => filter.isEditor == user?.editor.includes(item.id));
|
||||||
}
|
}
|
||||||
|
if (!filter.folderMode && filter.path) {
|
||||||
|
result = result.filter(item => matchLibraryItemLocation(item, filter.path!));
|
||||||
|
}
|
||||||
if (filter.query) {
|
if (filter.query) {
|
||||||
result = result.filter(item => matchLibraryItem(item, filter.query!));
|
result = result.filter(item => matchLibraryItem(item, filter.query!));
|
||||||
}
|
}
|
||||||
if (filter.path) {
|
|
||||||
result = result.filter(item => matchLibraryItemLocation(item, filter.path!));
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
[items, user]
|
[items, user]
|
||||||
|
@ -102,11 +128,11 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
callback(cached);
|
callback(cached);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setError(undefined);
|
setProcessingError(undefined);
|
||||||
getRSFormDetails(String(templateID), '', {
|
getRSFormDetails(String(templateID), '', {
|
||||||
showError: true,
|
showError: true,
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setError,
|
onError: setProcessingError,
|
||||||
onSuccess: data => {
|
onSuccess: data => {
|
||||||
const schema = new RSFormLoader(data).produceRSForm();
|
const schema = new RSFormLoader(data).produceRSForm();
|
||||||
setCachedTemplates(prev => [...prev, schema]);
|
setCachedTemplates(prev => [...prev, schema]);
|
||||||
|
@ -120,12 +146,12 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
const reloadItems = useCallback(
|
const reloadItems = useCallback(
|
||||||
(callback?: () => void) => {
|
(callback?: () => void) => {
|
||||||
setItems([]);
|
setItems([]);
|
||||||
setError(undefined);
|
setLoadingError(undefined);
|
||||||
if (user?.is_staff && adminMode) {
|
if (user?.is_staff && adminMode) {
|
||||||
getAdminLibrary({
|
getAdminLibrary({
|
||||||
setLoading: setLoading,
|
setLoading: setLoading,
|
||||||
showError: true,
|
showError: true,
|
||||||
onError: setError,
|
onError: setLoadingError,
|
||||||
onSuccess: newData => {
|
onSuccess: newData => {
|
||||||
setItems(newData);
|
setItems(newData);
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
|
@ -135,7 +161,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
getLibrary({
|
getLibrary({
|
||||||
setLoading: setLoading,
|
setLoading: setLoading,
|
||||||
showError: true,
|
showError: true,
|
||||||
onError: setError,
|
onError: setLoadingError,
|
||||||
onSuccess: newData => {
|
onSuccess: newData => {
|
||||||
setItems(newData);
|
setItems(newData);
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
|
@ -149,6 +175,8 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
const reloadTemplates = useCallback(() => {
|
const reloadTemplates = useCallback(() => {
|
||||||
setTemplates([]);
|
setTemplates([]);
|
||||||
getTemplates({
|
getTemplates({
|
||||||
|
setLoading: setLoading,
|
||||||
|
onError: setLoadingError,
|
||||||
showError: true,
|
showError: true,
|
||||||
onSuccess: newData => setTemplates(newData)
|
onSuccess: newData => setTemplates(newData)
|
||||||
});
|
});
|
||||||
|
@ -189,13 +217,13 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
}
|
}
|
||||||
if (callback) callback(newSchema);
|
if (callback) callback(newSchema);
|
||||||
});
|
});
|
||||||
setError(undefined);
|
setProcessingError(undefined);
|
||||||
if (data.file) {
|
if (data.file) {
|
||||||
postRSFormFromFile({
|
postRSFormFromFile({
|
||||||
data: data,
|
data: data,
|
||||||
showError: true,
|
showError: true,
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setError,
|
onError: setProcessingError,
|
||||||
onSuccess: onSuccess
|
onSuccess: onSuccess
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -203,7 +231,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
data: data,
|
data: data,
|
||||||
showError: true,
|
showError: true,
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setError,
|
onError: setProcessingError,
|
||||||
onSuccess: onSuccess
|
onSuccess: onSuccess
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -213,11 +241,11 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
|
|
||||||
const destroyItem = useCallback(
|
const destroyItem = useCallback(
|
||||||
(target: LibraryItemID, callback?: () => void) => {
|
(target: LibraryItemID, callback?: () => void) => {
|
||||||
setError(undefined);
|
setProcessingError(undefined);
|
||||||
deleteLibraryItem(String(target), {
|
deleteLibraryItem(String(target), {
|
||||||
showError: true,
|
showError: true,
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setError,
|
onError: setProcessingError,
|
||||||
onSuccess: () =>
|
onSuccess: () =>
|
||||||
reloadItems(() => {
|
reloadItems(() => {
|
||||||
if (user && user.subscriptions.includes(target)) {
|
if (user && user.subscriptions.includes(target)) {
|
||||||
|
@ -230,7 +258,7 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[setError, reloadItems, user]
|
[reloadItems, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
const cloneItem = useCallback(
|
const cloneItem = useCallback(
|
||||||
|
@ -238,12 +266,12 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setError(undefined);
|
setProcessingError(undefined);
|
||||||
postCloneLibraryItem(String(target), {
|
postCloneLibraryItem(String(target), {
|
||||||
data: data,
|
data: data,
|
||||||
showError: true,
|
showError: true,
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setError,
|
onError: setProcessingError,
|
||||||
onSuccess: newSchema =>
|
onSuccess: newSchema =>
|
||||||
reloadItems(() => {
|
reloadItems(() => {
|
||||||
if (user && !user.subscriptions.includes(newSchema.id)) {
|
if (user && !user.subscriptions.includes(newSchema.id)) {
|
||||||
|
@ -253,18 +281,26 @@ export const LibraryState = ({ children }: LibraryStateProps) => {
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[reloadItems, setError, user]
|
[reloadItems, user]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<LibraryContext.Provider
|
<LibraryContext.Provider
|
||||||
value={{
|
value={{
|
||||||
items,
|
items,
|
||||||
|
folders,
|
||||||
templates,
|
templates,
|
||||||
|
|
||||||
loading,
|
loading,
|
||||||
|
loadingError,
|
||||||
|
setLoadingError,
|
||||||
|
|
||||||
processing,
|
processing,
|
||||||
error,
|
processingError,
|
||||||
setError,
|
setProcessingError,
|
||||||
|
|
||||||
|
reloadItems,
|
||||||
|
|
||||||
applyFilter,
|
applyFilter,
|
||||||
createItem,
|
createItem,
|
||||||
cloneItem,
|
cloneItem,
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'rea
|
||||||
import { useLocation, useNavigate } from 'react-router-dom';
|
import { useLocation, useNavigate } from 'react-router-dom';
|
||||||
|
|
||||||
import { globals } from '@/utils/constants';
|
import { globals } from '@/utils/constants';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
interface INavigationContext {
|
interface INavigationContext {
|
||||||
push: (path: string, newTab?: boolean) => void;
|
push: (path: string, newTab?: boolean) => void;
|
||||||
|
@ -21,7 +22,7 @@ const NavigationContext = createContext<INavigationContext | null>(null);
|
||||||
export const useConceptNavigation = () => {
|
export const useConceptNavigation = () => {
|
||||||
const context = useContext(NavigationContext);
|
const context = useContext(NavigationContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useConceptNavigation has to be used within <NavigationState.Provider>');
|
throw new Error(contextOutsideScope('useConceptNavigation', 'NavigationState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -9,6 +9,7 @@ import { FontStyle } from '@/models/miscellaneous';
|
||||||
import { animationDuration } from '@/styling/animations';
|
import { animationDuration } from '@/styling/animations';
|
||||||
import { darkT, IColorTheme, lightT } from '@/styling/color';
|
import { darkT, IColorTheme, lightT } from '@/styling/color';
|
||||||
import { globals, storage } from '@/utils/constants';
|
import { globals, storage } from '@/utils/constants';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
interface IOptionsContext {
|
interface IOptionsContext {
|
||||||
viewportHeight: string;
|
viewportHeight: string;
|
||||||
|
@ -45,7 +46,7 @@ const OptionsContext = createContext<IOptionsContext | null>(null);
|
||||||
export const useConceptOptions = () => {
|
export const useConceptOptions = () => {
|
||||||
const context = useContext(OptionsContext);
|
const context = useContext(OptionsContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useConceptTheme has to be used within <ThemeState.Provider>');
|
throw new Error(contextOutsideScope('useConceptTheme', 'ThemeState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,7 @@ import { AccessPolicy, ILibraryItem } from '@/models/library';
|
||||||
import { ILibraryUpdateData } from '@/models/library';
|
import { ILibraryUpdateData } from '@/models/library';
|
||||||
import { IOperationSchema } from '@/models/oss';
|
import { IOperationSchema } from '@/models/oss';
|
||||||
import { UserID } from '@/models/user';
|
import { UserID } from '@/models/user';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
import { useAuth } from './AuthContext';
|
import { useAuth } from './AuthContext';
|
||||||
import { useLibrary } from './LibraryContext';
|
import { useLibrary } from './LibraryContext';
|
||||||
|
@ -48,7 +49,7 @@ const OssContext = createContext<IOssContext | null>(null);
|
||||||
export const useOSS = () => {
|
export const useOSS = () => {
|
||||||
const context = useContext(OssContext);
|
const context = useContext(OssContext);
|
||||||
if (context === null) {
|
if (context === null) {
|
||||||
throw new Error('useOSS has to be used within <OssState.Provider>');
|
throw new Error(contextOutsideScope('useOSS', 'OssState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -48,6 +48,7 @@ import {
|
||||||
ITargetCst
|
ITargetCst
|
||||||
} from '@/models/rsform';
|
} from '@/models/rsform';
|
||||||
import { UserID } from '@/models/user';
|
import { UserID } from '@/models/user';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
import { useAuth } from './AuthContext';
|
import { useAuth } from './AuthContext';
|
||||||
import { useLibrary } from './LibraryContext';
|
import { useLibrary } from './LibraryContext';
|
||||||
|
@ -99,7 +100,7 @@ const RSFormContext = createContext<IRSFormContext | null>(null);
|
||||||
export const useRSForm = () => {
|
export const useRSForm = () => {
|
||||||
const context = useContext(RSFormContext);
|
const context = useContext(RSFormContext);
|
||||||
if (context === null) {
|
if (context === null) {
|
||||||
throw new Error('useRSForm has to be used within <RSFormState.Provider>');
|
throw new Error(contextOutsideScope('useRSForm', 'RSFormState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
@ -295,8 +296,7 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
|
||||||
onError: setProcessingError,
|
onError: setProcessingError,
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
schema.location = newLocation;
|
schema.location = newLocation;
|
||||||
library.localUpdateItem(schema);
|
library.reloadItems(callback);
|
||||||
if (callback) callback();
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
@ -336,7 +336,7 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setProcessingError,
|
onError: setProcessingError,
|
||||||
onSuccess: newData => {
|
onSuccess: newData => {
|
||||||
setSchema(Object.assign(schema, newData));
|
setSchema(newData);
|
||||||
library.localUpdateTimestamp(newData.id);
|
library.localUpdateTimestamp(newData.id);
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
|
@ -356,7 +356,7 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setProcessingError,
|
onError: setProcessingError,
|
||||||
onSuccess: newData => {
|
onSuccess: newData => {
|
||||||
setSchema(Object.assign(schema, newData));
|
setSchema(newData);
|
||||||
library.localUpdateTimestamp(newData.id);
|
library.localUpdateTimestamp(newData.id);
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
|
@ -572,14 +572,14 @@ export const RSFormState = ({ itemID, versionID, children }: RSFormStateProps) =
|
||||||
showError: true,
|
showError: true,
|
||||||
setLoading: setProcessing,
|
setLoading: setProcessing,
|
||||||
onError: setProcessingError,
|
onError: setProcessingError,
|
||||||
onSuccess: () => {
|
onSuccess: newData => {
|
||||||
setSchema(schema);
|
setSchema(newData);
|
||||||
library.localUpdateItem(schema!);
|
library.localUpdateItem(newData);
|
||||||
if (callback) callback();
|
if (callback) callback();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[schema, setSchema, library]
|
[setSchema, library]
|
||||||
);
|
);
|
||||||
|
|
||||||
const inlineSynthesis = useCallback(
|
const inlineSynthesis = useCallback(
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'rea
|
||||||
import { DataCallback, getProfile, patchProfile } from '@/app/backendAPI';
|
import { DataCallback, getProfile, patchProfile } from '@/app/backendAPI';
|
||||||
import { ErrorData } from '@/components/info/InfoError';
|
import { ErrorData } from '@/components/info/InfoError';
|
||||||
import { IUserProfile, IUserUpdateData } from '@/models/user';
|
import { IUserProfile, IUserUpdateData } from '@/models/user';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
import { useUsers } from './UsersContext';
|
import { useUsers } from './UsersContext';
|
||||||
|
|
||||||
|
@ -23,7 +24,7 @@ const ProfileContext = createContext<IUserProfileContext | null>(null);
|
||||||
export const useUserProfile = () => {
|
export const useUserProfile = () => {
|
||||||
const context = useContext(ProfileContext);
|
const context = useContext(ProfileContext);
|
||||||
if (!context) {
|
if (!context) {
|
||||||
throw new Error('useUserProfile has to be used within <UserProfileState.Provider>');
|
throw new Error(contextOutsideScope('useUserProfile', 'UserProfileState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,6 +4,7 @@ import { createContext, useCallback, useContext, useEffect, useState } from 'rea
|
||||||
|
|
||||||
import { getActiveUsers } from '@/app/backendAPI';
|
import { getActiveUsers } from '@/app/backendAPI';
|
||||||
import { IUserInfo } from '@/models/user';
|
import { IUserInfo } from '@/models/user';
|
||||||
|
import { contextOutsideScope } from '@/utils/labels';
|
||||||
|
|
||||||
interface IUsersContext {
|
interface IUsersContext {
|
||||||
users: IUserInfo[];
|
users: IUserInfo[];
|
||||||
|
@ -15,7 +16,7 @@ const UsersContext = createContext<IUsersContext | null>(null);
|
||||||
export const useUsers = (): IUsersContext => {
|
export const useUsers = (): IUsersContext => {
|
||||||
const context = useContext(UsersContext);
|
const context = useContext(UsersContext);
|
||||||
if (context === null) {
|
if (context === null) {
|
||||||
throw new Error('useUsers has to be used within <UsersState.Provider>');
|
throw new Error(contextOutsideScope('useUsers', 'UsersState'));
|
||||||
}
|
}
|
||||||
return context;
|
return context;
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,6 +20,7 @@ import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { AccessPolicy, ILibraryItem, LocationHead } from '@/models/library';
|
import { AccessPolicy, ILibraryItem, LocationHead } from '@/models/library';
|
||||||
import { cloneTitle, combineLocation, validateLocation } from '@/models/libraryAPI';
|
import { cloneTitle, combineLocation, validateLocation } from '@/models/libraryAPI';
|
||||||
import { ConstituentaID, IRSFormCloneData } from '@/models/rsform';
|
import { ConstituentaID, IRSFormCloneData } from '@/models/rsform';
|
||||||
|
import { information } from '@/utils/labels';
|
||||||
|
|
||||||
interface DlgCloneLibraryItemProps extends Pick<ModalProps, 'hideWindow'> {
|
interface DlgCloneLibraryItemProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
base: ILibraryItem;
|
base: ILibraryItem;
|
||||||
|
@ -62,7 +63,7 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
|
||||||
data.items = selected;
|
data.items = selected;
|
||||||
}
|
}
|
||||||
cloneItem(base.id, data, newSchema => {
|
cloneItem(base.id, data, newSchema => {
|
||||||
toast.success(`Копия создана: ${newSchema.alias}`);
|
toast.success(information.cloneComplete(newSchema.alias));
|
||||||
router.push(urls.schema(newSchema.id));
|
router.push(urls.schema(newSchema.id));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -100,7 +101,6 @@ function DlgCloneLibraryItem({ hideWindow, base, initialLocation, selected, tota
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||||
icon={<VisibilityIcon value={visible} />}
|
icon={<VisibilityIcon value={visible} />}
|
||||||
onClick={() => setVisible(prev => !prev)}
|
onClick={() => setVisible(prev => !prev)}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import RSInput from '@/components/RSInput';
|
||||||
import PickConstituenta from '@/components/select/PickConstituenta';
|
import PickConstituenta from '@/components/select/PickConstituenta';
|
||||||
import DataTable, { IConditionalStyle } from '@/components/ui/DataTable';
|
import DataTable, { IConditionalStyle } from '@/components/ui/DataTable';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
import NoData from '@/components/ui/NoData';
|
||||||
import AnimateFade from '@/components/wrap/AnimateFade';
|
import AnimateFade from '@/components/wrap/AnimateFade';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
import { IConstituenta, IRSForm } from '@/models/rsform';
|
import { IConstituenta, IRSForm } from '@/models/rsform';
|
||||||
|
@ -160,7 +161,7 @@ function ArgumentsTab({ state, schema, partialUpdate }: ArgumentsTabProps) {
|
||||||
data={state.arguments}
|
data={state.arguments}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
conditionalRowStyles={conditionalRowStyles}
|
conditionalRowStyles={conditionalRowStyles}
|
||||||
noDataComponent={<p className={clsx('min-h-[3.6rem]', 'p-2', 'text-center')}>Аргументы отсутствуют</p>}
|
noDataComponent={<NoData className='min-h-[3.6rem]'>Аргументы отсутствуют</NoData>}
|
||||||
onRowClicked={handleSelectArgument}
|
onRowClicked={handleSelectArgument}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
|
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
|
||||||
import { generateAlias, validateNewAlias } from '@/models/rsformAPI';
|
import { generateAlias, validateNewAlias } from '@/models/rsformAPI';
|
||||||
import { inferTemplatedType, substituteTemplateArgs } from '@/models/rslangAPI';
|
import { inferTemplatedType, substituteTemplateArgs } from '@/models/rslangAPI';
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
import FormCreateCst from '../DlgCreateCst/FormCreateCst';
|
import FormCreateCst from '../DlgCreateCst/FormCreateCst';
|
||||||
import ArgumentsTab, { IArgumentsState } from './ArgumentsTab';
|
import ArgumentsTab, { IArgumentsState } from './ArgumentsTab';
|
||||||
|
@ -144,7 +145,11 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
>
|
>
|
||||||
<Overlay position='top-0 right-[6rem]'>
|
<Overlay position='top-0 right-[6rem]'>
|
||||||
<BadgeHelp topic={HelpTopic.RSL_TEMPLATES} className='max-w-[40rem]' offset={12} />
|
<BadgeHelp
|
||||||
|
topic={HelpTopic.RSL_TEMPLATES}
|
||||||
|
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')}
|
||||||
|
offset={12}
|
||||||
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
<Tabs
|
<Tabs
|
||||||
selectedTabClassName='clr-selected'
|
selectedTabClassName='clr-selected'
|
||||||
|
@ -155,7 +160,7 @@ function DlgConstituentaTemplate({ hideWindow, schema, onCreate, insertAfter }:
|
||||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
||||||
<TabLabel label='Шаблон' title='Выбор шаблона выражения' className='w-[8rem]' />
|
<TabLabel label='Шаблон' title='Выбор шаблона выражения' className='w-[8rem]' />
|
||||||
<TabLabel label='Аргументы' title='Подстановка аргументов шаблона' className='w-[8rem]' />
|
<TabLabel label='Аргументы' title='Подстановка аргументов шаблона' className='w-[8rem]' />
|
||||||
<TabLabel label='Конституента' title='Редактирование атрибутов конституенты' className='w-[8rem]' />
|
<TabLabel label='Конституента' title='Редактирование конституенты' className='w-[8rem]' />
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
{templatePanel}
|
{templatePanel}
|
||||||
|
|
|
@ -24,7 +24,7 @@ interface TemplateTabProps {
|
||||||
|
|
||||||
function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
||||||
const { templates, retrieveTemplate } = useLibrary();
|
const { templates, retrieveTemplate } = useLibrary();
|
||||||
const [category, setCategory] = useState<IRSForm | undefined>(undefined);
|
const [templateSchema, setTemplateSchema] = useState<IRSForm | undefined>(undefined);
|
||||||
|
|
||||||
const [filteredData, setFilteredData] = useState<IConstituenta[]>([]);
|
const [filteredData, setFilteredData] = useState<IConstituenta[]>([]);
|
||||||
|
|
||||||
|
@ -48,16 +48,16 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
const categorySelector = useMemo((): { value: number; label: string }[] => {
|
const categorySelector = useMemo((): { value: number; label: string }[] => {
|
||||||
if (!category) {
|
if (!templateSchema) {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
return category.items
|
return templateSchema.items
|
||||||
.filter(cst => cst.cst_type === CATEGORY_CST_TYPE)
|
.filter(cst => cst.cst_type === CATEGORY_CST_TYPE)
|
||||||
.map(cst => ({
|
.map(cst => ({
|
||||||
value: cst.id,
|
value: cst.id,
|
||||||
label: cst.term_raw
|
label: cst.term_raw
|
||||||
}));
|
}));
|
||||||
}, [category]);
|
}, [templateSchema]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (templates.length > 0 && !state.templateID) {
|
if (templates.length > 0 && !state.templateID) {
|
||||||
|
@ -67,22 +67,22 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!state.templateID) {
|
if (!state.templateID) {
|
||||||
setCategory(undefined);
|
setTemplateSchema(undefined);
|
||||||
} else {
|
} else {
|
||||||
retrieveTemplate(state.templateID, setCategory);
|
retrieveTemplate(state.templateID, setTemplateSchema);
|
||||||
}
|
}
|
||||||
}, [state.templateID, retrieveTemplate]);
|
}, [state.templateID, retrieveTemplate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!category) {
|
if (!templateSchema) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let data = category.items;
|
let data = templateSchema.items;
|
||||||
if (state.filterCategory) {
|
if (state.filterCategory) {
|
||||||
data = applyFilterCategory(state.filterCategory, category);
|
data = applyFilterCategory(state.filterCategory, templateSchema);
|
||||||
}
|
}
|
||||||
setFilteredData(data);
|
setFilteredData(data);
|
||||||
}, [state.filterCategory, category]);
|
}, [state.filterCategory, templateSchema]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AnimateFade>
|
<AnimateFade>
|
||||||
|
@ -93,14 +93,16 @@ function TemplateTab({ state, partialUpdate }: TemplateTabProps) {
|
||||||
className='flex-grow border-none'
|
className='flex-grow border-none'
|
||||||
options={categorySelector}
|
options={categorySelector}
|
||||||
value={
|
value={
|
||||||
state.filterCategory && category
|
state.filterCategory && templateSchema
|
||||||
? {
|
? {
|
||||||
value: state.filterCategory.id,
|
value: state.filterCategory.id,
|
||||||
label: state.filterCategory.term_raw
|
label: state.filterCategory.term_raw
|
||||||
}
|
}
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
onChange={data => partialUpdate({ filterCategory: data ? category?.cstByID.get(data?.value) : undefined })}
|
onChange={data =>
|
||||||
|
partialUpdate({ filterCategory: data ? templateSchema?.cstByID.get(data?.value) : undefined })
|
||||||
|
}
|
||||||
isClearable
|
isClearable
|
||||||
/>
|
/>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
import { AnimatePresence } from 'framer-motion';
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
import { useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ import AnimateFade from '@/components/wrap/AnimateFade';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
|
import { CstType, ICstCreateData, IRSForm } from '@/models/rsform';
|
||||||
import { generateAlias, isBaseSet, isBasicConcept, isFunctional, validateNewAlias } from '@/models/rsformAPI';
|
import { generateAlias, isBaseSet, isBasicConcept, isFunctional, validateNewAlias } from '@/models/rsformAPI';
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { labelCstType } from '@/utils/labels';
|
import { labelCstType } from '@/utils/labels';
|
||||||
import { SelectorCstType } from '@/utils/selectors';
|
import { SelectorCstType } from '@/utils/selectors';
|
||||||
|
|
||||||
|
@ -52,7 +54,11 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
value={{ value: state.cst_type, label: labelCstType(state.cst_type) }}
|
value={{ value: state.cst_type, label: labelCstType(state.cst_type) }}
|
||||||
onChange={data => partialUpdate({ cst_type: data?.value ?? CstType.BASE })}
|
onChange={data => partialUpdate({ cst_type: data?.value ?? CstType.BASE })}
|
||||||
/>
|
/>
|
||||||
<BadgeHelp topic={HelpTopic.CC_CONSTITUENTA} offset={16} className='max-w-[40rem] max-h-[calc(100svh-2rem)]' />
|
<BadgeHelp
|
||||||
|
topic={HelpTopic.CC_CONSTITUENTA}
|
||||||
|
offset={16}
|
||||||
|
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')}
|
||||||
|
/>
|
||||||
<TextInput
|
<TextInput
|
||||||
id='dlg_cst_alias'
|
id='dlg_cst_alias'
|
||||||
dense
|
dense
|
||||||
|
@ -89,6 +95,7 @@ function FormCreateCst({ schema, state, partialUpdate, setValidated }: FormCreat
|
||||||
}
|
}
|
||||||
value={state.definition_formal}
|
value={state.definition_formal}
|
||||||
onChange={value => partialUpdate({ definition_formal: value })}
|
onChange={value => partialUpdate({ definition_formal: value })}
|
||||||
|
schema={schema}
|
||||||
/>
|
/>
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
<AnimateFade key='dlg_cst_definition' hideContent={!state.definition_raw && isElementary}>
|
<AnimateFade key='dlg_cst_definition' hideContent={!state.definition_raw && isElementary}>
|
||||||
|
|
|
@ -48,7 +48,12 @@ function DlgDeleteCst({ hideWindow, selected, schema, onDelete }: DlgDeleteCstPr
|
||||||
schema={schema}
|
schema={schema}
|
||||||
prefix={prefixes.cst_dependant_list}
|
prefix={prefixes.cst_dependant_list}
|
||||||
/>
|
/>
|
||||||
<Checkbox label='Удалить зависимые конституенты' value={expandOut} setValue={value => setExpandOut(value)} />
|
<Checkbox
|
||||||
|
label='Удалить зависимые конституенты'
|
||||||
|
className='my-2'
|
||||||
|
value={expandOut}
|
||||||
|
setValue={value => setExpandOut(value)}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import TabLabel from '@/components/ui/TabLabel';
|
||||||
import { ReferenceType } from '@/models/language';
|
import { ReferenceType } from '@/models/language';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { IRSForm } from '@/models/rsform';
|
import { IRSForm } from '@/models/rsform';
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { labelReferenceType } from '@/utils/labels';
|
import { labelReferenceType } from '@/utils/labels';
|
||||||
|
|
||||||
import EntityTab from './EntityTab';
|
import EntityTab from './EntityTab';
|
||||||
|
@ -69,10 +70,14 @@ function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditRefere
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={isValid}
|
canSubmit={isValid}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className='w-[40rem] px-6 min-h-[34rem]'
|
className='w-[40rem] px-6 min-h-[35rem]'
|
||||||
>
|
>
|
||||||
<Overlay position='top-0 right-[4rem]'>
|
<Overlay position='top-0 right-0'>
|
||||||
<BadgeHelp topic={HelpTopic.TERM_CONTROL} className='max-w-[35rem]' offset={14} />
|
<BadgeHelp
|
||||||
|
topic={HelpTopic.TERM_CONTROL}
|
||||||
|
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')}
|
||||||
|
offset={14}
|
||||||
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<Tabs
|
<Tabs
|
||||||
|
@ -82,15 +87,10 @@ function DlgEditReference({ hideWindow, schema, initial, onSave }: DlgEditRefere
|
||||||
onSelect={setActiveTab}
|
onSelect={setActiveTab}
|
||||||
>
|
>
|
||||||
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
<TabList className={clsx('mb-3 self-center', 'flex', 'border divide-x rounded-none')}>
|
||||||
<TabLabel
|
<TabLabel title='Отсылка на термин в заданной словоформе' label={labelReferenceType(ReferenceType.ENTITY)} />
|
||||||
title='Отсылка на термин в заданной словоформе'
|
|
||||||
label={labelReferenceType(ReferenceType.ENTITY)}
|
|
||||||
className='w-[12rem]'
|
|
||||||
/>
|
|
||||||
<TabLabel
|
<TabLabel
|
||||||
title='Установление синтаксической связи с отсылкой на термин'
|
title='Установление синтаксической связи с отсылкой на термин'
|
||||||
label={labelReferenceType(ReferenceType.SYNTACTIC)}
|
label={labelReferenceType(ReferenceType.SYNTACTIC)}
|
||||||
className='w-[12rem]'
|
|
||||||
/>
|
/>
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
|
|
|
@ -22,7 +22,7 @@ function SelectWordForm({ selected, setSelected }: SelectWordFormProps) {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='text-sm'>
|
<div className='text-xs sm:text-sm'>
|
||||||
{DefaultWordForms.slice(0, 12).map((data, index) => (
|
{DefaultWordForms.slice(0, 12).map((data, index) => (
|
||||||
<WordformButton
|
<WordformButton
|
||||||
key={`${prefixes.wordform_list}${index}`}
|
key={`${prefixes.wordform_list}${index}`}
|
||||||
|
|
|
@ -17,7 +17,7 @@ function WordformButton({ text, example, grams, onSelectGrams, isSelected, ...re
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
onClick={() => onSelectGrams(grams)}
|
onClick={() => onSelectGrams(grams)}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
'min-w-[6.15rem]',
|
'min-w-[4.15rem] sm:min-w-[6.15rem]',
|
||||||
'p-1',
|
'p-1',
|
||||||
'border rounded-none',
|
'border rounded-none',
|
||||||
'cursor-pointer',
|
'cursor-pointer',
|
||||||
|
|
|
@ -16,6 +16,8 @@ import { Grammeme, ITextRequest, IWordForm, IWordFormPlain } from '@/models/lang
|
||||||
import { parseGrammemes, wordFormEquals } from '@/models/languageAPI';
|
import { parseGrammemes, wordFormEquals } from '@/models/languageAPI';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { IConstituenta, TermForm } from '@/models/rsform';
|
import { IConstituenta, TermForm } from '@/models/rsform';
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
import { prompts } from '@/utils/labels';
|
||||||
import { IGrammemeOption, SelectorGrammemes, SelectorGrammemesList } from '@/utils/selectors';
|
import { IGrammemeOption, SelectorGrammemes, SelectorGrammemesList } from '@/utils/selectors';
|
||||||
|
|
||||||
import WordFormsTable from './WordFormsTable';
|
import WordFormsTable from './WordFormsTable';
|
||||||
|
@ -92,7 +94,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
|
|
||||||
function handleGenerateLexeme() {
|
function handleGenerateLexeme() {
|
||||||
if (forms.length > 0) {
|
if (forms.length > 0) {
|
||||||
if (!window.confirm('Данное действие приведет к перезаписи словоформ при совпадении граммем. Продолжить?')) {
|
if (!window.confirm(prompts.generateWordforms)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +132,11 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
className='flex flex-col w-[40rem] px-6'
|
className='flex flex-col w-[40rem] px-6'
|
||||||
>
|
>
|
||||||
<Overlay position='top-[-0.2rem] left-[8rem]'>
|
<Overlay position='top-[-0.2rem] left-[8rem]'>
|
||||||
<BadgeHelp topic={HelpTopic.TERM_CONTROL} className='max-w-[38rem]' offset={3} />
|
<BadgeHelp
|
||||||
|
topic={HelpTopic.TERM_CONTROL}
|
||||||
|
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')}
|
||||||
|
offset={3}
|
||||||
|
/>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
|
||||||
<TextArea
|
<TextArea
|
||||||
|
@ -178,7 +184,8 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Overlay position='top-2 left-0'>
|
<div className='flex justify-between'>
|
||||||
|
<div className='cc-icons'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
noHover
|
noHover
|
||||||
title='Внести словоформу'
|
title='Внести словоформу'
|
||||||
|
@ -193,10 +200,11 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
disabled={textProcessor.loading || !inputText}
|
disabled={textProcessor.loading || !inputText}
|
||||||
onClick={handleGenerateLexeme}
|
onClick={handleGenerateLexeme}
|
||||||
/>
|
/>
|
||||||
</Overlay>
|
</div>
|
||||||
|
<div
|
||||||
<div className={clsx('mt-3 mb-2', 'flex self-center items-center', 'text-sm text-center font-semibold')}>
|
className={clsx('mt-3 mb-2', 'w-full flex justify-center items-center', 'text-sm text-center font-semibold')}
|
||||||
<span>Заданные вручную словоформы [{forms.length}]</span>
|
>
|
||||||
|
<div>Заданные вручную словоформы [{forms.length}]</div>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
noHover
|
noHover
|
||||||
title='Сбросить все словоформы'
|
title='Сбросить все словоформы'
|
||||||
|
@ -206,6 +214,7 @@ function DlgEditWordForms({ hideWindow, target, onSave }: DlgEditWordFormsProps)
|
||||||
onClick={handleResetAll}
|
onClick={handleResetAll}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<WordFormsTable forms={forms} setForms={setForms} onFormSelect={handleSelectForm} />
|
<WordFormsTable forms={forms} setForms={setForms} onFormSelect={handleSelectForm} />
|
||||||
</Modal>
|
</Modal>
|
||||||
|
|
|
@ -7,6 +7,7 @@ import { IconRemove } from '@/components/Icons';
|
||||||
import BadgeWordForm from '@/components/info/BadgeWordForm';
|
import BadgeWordForm from '@/components/info/BadgeWordForm';
|
||||||
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper } from '@/components/ui/DataTable';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
import NoData from '@/components/ui/NoData';
|
||||||
import { IWordForm } from '@/models/language';
|
import { IWordForm } from '@/models/language';
|
||||||
|
|
||||||
interface WordFormsTableProps {
|
interface WordFormsTableProps {
|
||||||
|
@ -78,10 +79,10 @@ function WordFormsTable({ forms, setForms, onFormSelect }: WordFormsTableProps)
|
||||||
columns={columns}
|
columns={columns}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<span className='p-2 text-center min-h-[2rem]'>
|
<NoData className='min-h-[2rem]'>
|
||||||
<p>Список пуст</p>
|
<p>Список пуст</p>
|
||||||
<p>Добавьте словоформу</p>
|
<p>Добавьте словоформу</p>
|
||||||
</span>
|
</NoData>
|
||||||
}
|
}
|
||||||
onRowClicked={onFormSelect}
|
onRowClicked={onFormSelect}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -27,7 +27,7 @@ function DlgGraphParams({ hideWindow, initial, onConfirm }: DlgGraphParamsProps)
|
||||||
header='Настройки графа термов'
|
header='Настройки графа термов'
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
submitText='Применить'
|
submitText='Применить'
|
||||||
className='flex gap-6 px-6 py-2 w-[35rem]'
|
className='flex gap-6 justify-between px-6 pb-3 w-[30rem]'
|
||||||
>
|
>
|
||||||
<div className='flex flex-col gap-1'>
|
<div className='flex flex-col gap-1'>
|
||||||
<h1 className='mb-2'>Преобразования</h1>
|
<h1 className='mb-2'>Преобразования</h1>
|
||||||
|
@ -45,13 +45,13 @@ function DlgGraphParams({ hideWindow, initial, onConfirm }: DlgGraphParamsProps)
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Скрыть шаблоны'
|
label='Скрыть шаблоны'
|
||||||
title='Терм-функции и предикат-функции с параметризованными аргументами'
|
titleHtml='Терм-функции и предикат-функции <br/>с параметризованными аргументами'
|
||||||
value={params.noTemplates}
|
value={params.noTemplates}
|
||||||
setValue={value => updateParams({ noTemplates: value })}
|
setValue={value => updateParams({ noTemplates: value })}
|
||||||
/>
|
/>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
label='Транзитивная редукция'
|
label='Транзитивная редукция'
|
||||||
title='Удалить связи, образующие транзитивные пути в графе'
|
titleHtml='Удалить связи, образующие <br/>транзитивные пути в графе'
|
||||||
value={params.noTransitive}
|
value={params.noTransitive}
|
||||||
setValue={value => updateParams({ noTransitive: value })}
|
setValue={value => updateParams({ noTransitive: value })}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import usePartialUpdate from '@/hooks/usePartialUpdate';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { CstType, ICstRenameData } from '@/models/rsform';
|
import { CstType, ICstRenameData } from '@/models/rsform';
|
||||||
import { generateAlias, validateNewAlias } from '@/models/rsformAPI';
|
import { generateAlias, validateNewAlias } from '@/models/rsformAPI';
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { labelCstType } from '@/utils/labels';
|
import { labelCstType } from '@/utils/labels';
|
||||||
import { SelectorCstType } from '@/utils/selectors';
|
import { SelectorCstType } from '@/utils/selectors';
|
||||||
|
|
||||||
|
@ -47,7 +48,7 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
hideWindow={hideWindow}
|
hideWindow={hideWindow}
|
||||||
canSubmit={validated}
|
canSubmit={validated}
|
||||||
onSubmit={handleSubmit}
|
onSubmit={handleSubmit}
|
||||||
className={clsx('w-[30rem]', 'py-6 px-6 flex gap-3 justify-center items-center')}
|
className={clsx('w-[30rem]', 'py-6 pr-3 pl-6 flex justify-center items-center')}
|
||||||
>
|
>
|
||||||
<SelectSingle
|
<SelectSingle
|
||||||
id='dlg_cst_type'
|
id='dlg_cst_type'
|
||||||
|
@ -60,15 +61,20 @@ function DlgRenameCst({ hideWindow, initial, onRename }: DlgRenameCstProps) {
|
||||||
}}
|
}}
|
||||||
onChange={data => updateData({ cst_type: data?.value ?? CstType.BASE })}
|
onChange={data => updateData({ cst_type: data?.value ?? CstType.BASE })}
|
||||||
/>
|
/>
|
||||||
<BadgeHelp topic={HelpTopic.CC_CONSTITUENTA} offset={16} className='max-w-[40rem] max-h-[calc(100svh-2rem)]' />
|
|
||||||
<TextInput
|
<TextInput
|
||||||
id='dlg_cst_alias'
|
id='dlg_cst_alias'
|
||||||
dense
|
dense
|
||||||
label='Имя'
|
label='Имя'
|
||||||
className='w-[7rem]'
|
className='w-[7rem] ml-3'
|
||||||
value={cstData.alias}
|
value={cstData.alias}
|
||||||
onChange={event => updateData({ alias: event.target.value })}
|
onChange={event => updateData({ alias: event.target.value })}
|
||||||
/>
|
/>
|
||||||
|
<BadgeHelp
|
||||||
|
topic={HelpTopic.CC_CONSTITUENTA}
|
||||||
|
offset={16}
|
||||||
|
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'sm:max-w-[40rem]')}
|
||||||
|
/>
|
||||||
</Modal>
|
</Modal>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { SyntaxTree } from '@/models/rslang';
|
import { SyntaxTree } from '@/models/rslang';
|
||||||
import { graphDarkT, graphLightT } from '@/styling/color';
|
import { graphDarkT, graphLightT } from '@/styling/color';
|
||||||
import { colorBgSyntaxTree } from '@/styling/color';
|
import { colorBgSyntaxTree } from '@/styling/color';
|
||||||
import { resources } from '@/utils/constants';
|
import { PARAMETER, resources } from '@/utils/constants';
|
||||||
import { labelSyntaxTree } from '@/utils/labels';
|
import { labelSyntaxTree } from '@/utils/labels';
|
||||||
|
|
||||||
interface DlgShowASTProps extends Pick<ModalProps, 'hideWindow'> {
|
interface DlgShowASTProps extends Pick<ModalProps, 'hideWindow'> {
|
||||||
|
@ -55,7 +55,7 @@ function DlgShowAST({ hideWindow, syntaxTree, expression }: DlgShowASTProps) {
|
||||||
return (
|
return (
|
||||||
<Modal readonly hideWindow={hideWindow} className='px-6'>
|
<Modal readonly hideWindow={hideWindow} className='px-6'>
|
||||||
<Overlay position='left-[-1rem] top-[0.25rem]'>
|
<Overlay position='left-[-1rem] top-[0.25rem]'>
|
||||||
<BadgeHelp topic={HelpTopic.UI_FORMULA_TREE} className='max-w-[32rem]' />
|
<BadgeHelp topic={HelpTopic.UI_FORMULA_TREE} className={PARAMETER.TOOLTIP_WIDTH} />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
<div className='my-2 text-lg text-center'>
|
<div className='my-2 text-lg text-center'>
|
||||||
{!hoverNode ? expression : null}
|
{!hoverNode ? expression : null}
|
||||||
|
|
47
rsconcept/frontend/src/models/FolderTree.test.ts
Normal file
47
rsconcept/frontend/src/models/FolderTree.test.ts
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
import { FolderTree } from './FolderTree';
|
||||||
|
|
||||||
|
// TODO: test FolderNode and FolderTree exhaustively
|
||||||
|
|
||||||
|
describe('Testing Tree construction', () => {
|
||||||
|
test('empty Tree should be empty', () => {
|
||||||
|
const tree = new FolderTree();
|
||||||
|
expect(tree.roots.size).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('constructing from paths', () => {
|
||||||
|
const tree = new FolderTree(['/S', '/S/project1/123', '/U']);
|
||||||
|
expect(tree.roots.size).toBe(2);
|
||||||
|
expect(tree.roots.get('S')?.children.size).toBe(1);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Testing Tree editing', () => {
|
||||||
|
test('add invalid path', () => {
|
||||||
|
const tree = new FolderTree();
|
||||||
|
expect(() => tree.addPath('invalid')).toThrow(Error);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('add valid path', () => {
|
||||||
|
const tree = new FolderTree();
|
||||||
|
const node = tree.addPath('/S/test');
|
||||||
|
expect(node.getPath()).toBe('/S/test');
|
||||||
|
expect(node.filesInside).toBe(1);
|
||||||
|
expect(node.filesTotal).toBe(1);
|
||||||
|
|
||||||
|
expect(node.parent?.getPath()).toBe('/S');
|
||||||
|
expect(node.parent?.filesInside).toBe(0);
|
||||||
|
expect(node.parent?.filesTotal).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
test('incrementing counter', () => {
|
||||||
|
const tree = new FolderTree();
|
||||||
|
const node1 = tree.addPath('/S/test', 0);
|
||||||
|
expect(node1.filesInside).toBe(0);
|
||||||
|
expect(node1.filesTotal).toBe(0);
|
||||||
|
|
||||||
|
const node2 = tree.addPath('/S/test', 2);
|
||||||
|
expect(node1).toBe(node2);
|
||||||
|
expect(node2.filesInside).toBe(2);
|
||||||
|
expect(node2.filesTotal).toBe(2);
|
||||||
|
});
|
||||||
|
});
|
159
rsconcept/frontend/src/models/FolderTree.ts
Normal file
159
rsconcept/frontend/src/models/FolderTree.ts
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
/**
|
||||||
|
* Module: Folder tree data structure. Does not support deletions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents single node of a {@link FolderTree}.
|
||||||
|
*/
|
||||||
|
export class FolderNode {
|
||||||
|
rank: number = 0;
|
||||||
|
text: string;
|
||||||
|
children: Map<string, FolderNode>;
|
||||||
|
parent: FolderNode | undefined;
|
||||||
|
|
||||||
|
filesInside: number = 0;
|
||||||
|
filesTotal: number = 0;
|
||||||
|
|
||||||
|
constructor(text: string, parent?: FolderNode) {
|
||||||
|
this.text = text;
|
||||||
|
this.parent = parent;
|
||||||
|
this.children = new Map();
|
||||||
|
if (parent) {
|
||||||
|
this.rank = parent.rank + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
addChild(text: string): FolderNode {
|
||||||
|
const node = new FolderNode(text, this);
|
||||||
|
this.children.set(text, node);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
hasPredecessor(target: FolderNode): boolean {
|
||||||
|
if (this.parent === target) {
|
||||||
|
return true;
|
||||||
|
} else if (!this.parent) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let node = this.parent;
|
||||||
|
while (node.parent) {
|
||||||
|
if (node.parent === target) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
node = node.parent;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
incrementFiles(count: number = 1): void {
|
||||||
|
this.filesInside = this.filesInside + count;
|
||||||
|
this.incrementTotal(count);
|
||||||
|
}
|
||||||
|
|
||||||
|
incrementTotal(count: number = 1): void {
|
||||||
|
this.filesTotal = this.filesTotal + count;
|
||||||
|
if (this.parent) {
|
||||||
|
this.parent.incrementTotal(count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getPath(): string {
|
||||||
|
const suffix = this.text ? `/${this.text}` : '';
|
||||||
|
if (!this.parent) {
|
||||||
|
return suffix;
|
||||||
|
} else {
|
||||||
|
return this.parent.getPath() + suffix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a FolderTree.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
export class FolderTree {
|
||||||
|
roots: Map<string, FolderNode> = new Map();
|
||||||
|
|
||||||
|
constructor(arr?: string[]) {
|
||||||
|
arr?.forEach(path => this.addPath(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
at(path: string): FolderNode | undefined {
|
||||||
|
let parse = ChopPathHead(path);
|
||||||
|
if (!this.roots.has(parse.head)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
let node = this.roots.get(parse.head)!;
|
||||||
|
while (parse.tail !== '') {
|
||||||
|
parse = ChopPathHead(parse.tail);
|
||||||
|
if (!node.children.has(parse.head)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
node = node.children.get(parse.head)!;
|
||||||
|
}
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
getTree(): FolderNode[] {
|
||||||
|
const result: FolderNode[] = [];
|
||||||
|
this.roots.forEach(root => this.visitNode(root, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private visitNode(target: FolderNode, result: FolderNode[]) {
|
||||||
|
result.push(target);
|
||||||
|
[...target.children.keys()]
|
||||||
|
.sort((a, b) => a.localeCompare(b))
|
||||||
|
.forEach(key => this.visitNode(target.children.get(key)!, result));
|
||||||
|
}
|
||||||
|
|
||||||
|
addPath(path: string, filesCount: number = 1): FolderNode {
|
||||||
|
let parse = ChopPathHead(path);
|
||||||
|
if (!parse.head) {
|
||||||
|
throw Error(`Invalid path ${path}`);
|
||||||
|
}
|
||||||
|
let node = this.roots.has(parse.head) ? this.roots.get(parse.head)! : this.addNode(parse.head);
|
||||||
|
while (parse.tail !== '') {
|
||||||
|
parse = ChopPathHead(parse.tail);
|
||||||
|
if (node.children.has(parse.head)) {
|
||||||
|
node = node.children.get(parse.head)!;
|
||||||
|
} else {
|
||||||
|
node = this.addNode(parse.head, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node.incrementFiles(filesCount);
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
private addNode(text: string, parent?: FolderNode): FolderNode {
|
||||||
|
if (parent === undefined) {
|
||||||
|
const newNode = new FolderNode(text);
|
||||||
|
this.roots.set(text, newNode);
|
||||||
|
return newNode;
|
||||||
|
} else {
|
||||||
|
return parent.addChild(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ========= Internals =======
|
||||||
|
function ChopPathHead(path: string) {
|
||||||
|
if (!path || path.at(0) !== '/') {
|
||||||
|
return {
|
||||||
|
head: '',
|
||||||
|
tail: ''
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const slash = path.indexOf('/', 1);
|
||||||
|
if (slash === -1) {
|
||||||
|
return {
|
||||||
|
head: path.substring(1),
|
||||||
|
tail: ''
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
head: path.substring(1, slash),
|
||||||
|
tail: path.substring(slash)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -26,9 +26,9 @@ export enum AccessPolicy {
|
||||||
*/
|
*/
|
||||||
export enum LocationHead {
|
export enum LocationHead {
|
||||||
USER = '/U',
|
USER = '/U',
|
||||||
LIBRARY = '/L',
|
|
||||||
COMMON = '/S',
|
COMMON = '/S',
|
||||||
PROJECTS = '/P'
|
PROJECTS = '/P',
|
||||||
|
LIBRARY = '/L'
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Module: Miscellaneous frontend model types. Future targets for refactoring aimed at extracting modules.
|
* Module: Miscellaneous frontend model types. Future targets for refactoring aimed at extracting modules.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { LocationHead } from './library';
|
import { LibraryItemType, LocationHead } from './library';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents graph dependency mode.
|
* Represents graph dependency mode.
|
||||||
|
@ -37,11 +37,6 @@ export type FontStyle = 'controls' | 'main' | 'math' | 'math2';
|
||||||
export enum HelpTopic {
|
export enum HelpTopic {
|
||||||
MAIN = 'main',
|
MAIN = 'main',
|
||||||
|
|
||||||
DOCS = 'documentation',
|
|
||||||
RULES = 'rules',
|
|
||||||
PRIVACY = 'privacy',
|
|
||||||
API = 'api',
|
|
||||||
|
|
||||||
INTERFACE = 'user-interface',
|
INTERFACE = 'user-interface',
|
||||||
UI_LIBRARY = 'ui-library',
|
UI_LIBRARY = 'ui-library',
|
||||||
UI_RS_MENU = 'ui-rsform-menu',
|
UI_RS_MENU = 'ui-rsform-menu',
|
||||||
|
@ -52,12 +47,14 @@ export enum HelpTopic {
|
||||||
UI_FORMULA_TREE = 'ui-formula-tree',
|
UI_FORMULA_TREE = 'ui-formula-tree',
|
||||||
UI_CST_STATUS = 'ui-rsform-cst-status',
|
UI_CST_STATUS = 'ui-rsform-cst-status',
|
||||||
UI_CST_CLASS = 'ui-rsform-cst-class',
|
UI_CST_CLASS = 'ui-rsform-cst-class',
|
||||||
|
UI_OSS_GRAPH = 'ui-oss-graph',
|
||||||
|
|
||||||
CONCEPTUAL = 'concept',
|
CONCEPTUAL = 'concept',
|
||||||
CC_SYSTEM = 'rslang-rsform',
|
CC_SYSTEM = 'concept-rsform',
|
||||||
CC_CONSTITUENTA = 'rslang-cst',
|
CC_CONSTITUENTA = 'concept-constituenta',
|
||||||
CC_RELATIONS = 'rslang-relations',
|
CC_RELATIONS = 'concept-relations',
|
||||||
CC_SYNTHESIS = 'rslang-synthesis',
|
CC_SYNTHESIS = 'concept-synthesis',
|
||||||
|
CC_OSS = 'concept-operations-schema',
|
||||||
|
|
||||||
RSLANG = 'rslang',
|
RSLANG = 'rslang',
|
||||||
RSL_TYPES = 'rslang-types',
|
RSL_TYPES = 'rslang-types',
|
||||||
|
@ -69,6 +66,13 @@ export enum HelpTopic {
|
||||||
TERM_CONTROL = 'terminology-control',
|
TERM_CONTROL = 'terminology-control',
|
||||||
ACCESS = 'access',
|
ACCESS = 'access',
|
||||||
VERSIONS = 'versions',
|
VERSIONS = 'versions',
|
||||||
|
|
||||||
|
INFO = 'documentation',
|
||||||
|
INFO_RULES = 'rules',
|
||||||
|
INFO_CONTRIB = 'contributors',
|
||||||
|
INFO_PRIVACY = 'privacy',
|
||||||
|
INFO_API = 'api',
|
||||||
|
|
||||||
EXTEOR = 'exteor'
|
EXTEOR = 'exteor'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,11 +82,6 @@ export enum HelpTopic {
|
||||||
export const topicParent: Map<HelpTopic, HelpTopic> = new Map([
|
export const topicParent: Map<HelpTopic, HelpTopic> = new Map([
|
||||||
[HelpTopic.MAIN, HelpTopic.MAIN],
|
[HelpTopic.MAIN, HelpTopic.MAIN],
|
||||||
|
|
||||||
[HelpTopic.DOCS, HelpTopic.DOCS],
|
|
||||||
[HelpTopic.RULES, HelpTopic.DOCS],
|
|
||||||
[HelpTopic.API, HelpTopic.DOCS],
|
|
||||||
[HelpTopic.PRIVACY, HelpTopic.DOCS],
|
|
||||||
|
|
||||||
[HelpTopic.INTERFACE, HelpTopic.INTERFACE],
|
[HelpTopic.INTERFACE, HelpTopic.INTERFACE],
|
||||||
[HelpTopic.UI_LIBRARY, HelpTopic.INTERFACE],
|
[HelpTopic.UI_LIBRARY, HelpTopic.INTERFACE],
|
||||||
[HelpTopic.UI_RS_MENU, HelpTopic.INTERFACE],
|
[HelpTopic.UI_RS_MENU, HelpTopic.INTERFACE],
|
||||||
|
@ -93,12 +92,14 @@ export const topicParent: Map<HelpTopic, HelpTopic> = new Map([
|
||||||
[HelpTopic.UI_FORMULA_TREE, HelpTopic.INTERFACE],
|
[HelpTopic.UI_FORMULA_TREE, HelpTopic.INTERFACE],
|
||||||
[HelpTopic.UI_CST_STATUS, HelpTopic.INTERFACE],
|
[HelpTopic.UI_CST_STATUS, HelpTopic.INTERFACE],
|
||||||
[HelpTopic.UI_CST_CLASS, HelpTopic.INTERFACE],
|
[HelpTopic.UI_CST_CLASS, HelpTopic.INTERFACE],
|
||||||
|
[HelpTopic.UI_OSS_GRAPH, HelpTopic.INTERFACE],
|
||||||
|
|
||||||
[HelpTopic.CONCEPTUAL, HelpTopic.CONCEPTUAL],
|
[HelpTopic.CONCEPTUAL, HelpTopic.CONCEPTUAL],
|
||||||
[HelpTopic.CC_SYSTEM, HelpTopic.CONCEPTUAL],
|
[HelpTopic.CC_SYSTEM, HelpTopic.CONCEPTUAL],
|
||||||
[HelpTopic.CC_CONSTITUENTA, HelpTopic.CONCEPTUAL],
|
[HelpTopic.CC_CONSTITUENTA, HelpTopic.CONCEPTUAL],
|
||||||
[HelpTopic.CC_RELATIONS, HelpTopic.CONCEPTUAL],
|
[HelpTopic.CC_RELATIONS, HelpTopic.CONCEPTUAL],
|
||||||
[HelpTopic.CC_SYNTHESIS, HelpTopic.CONCEPTUAL],
|
[HelpTopic.CC_SYNTHESIS, HelpTopic.CONCEPTUAL],
|
||||||
|
[HelpTopic.CC_OSS, HelpTopic.CONCEPTUAL],
|
||||||
|
|
||||||
[HelpTopic.RSLANG, HelpTopic.RSLANG],
|
[HelpTopic.RSLANG, HelpTopic.RSLANG],
|
||||||
[HelpTopic.RSL_TYPES, HelpTopic.RSLANG],
|
[HelpTopic.RSL_TYPES, HelpTopic.RSLANG],
|
||||||
|
@ -110,13 +111,20 @@ export const topicParent: Map<HelpTopic, HelpTopic> = new Map([
|
||||||
[HelpTopic.TERM_CONTROL, HelpTopic.TERM_CONTROL],
|
[HelpTopic.TERM_CONTROL, HelpTopic.TERM_CONTROL],
|
||||||
[HelpTopic.ACCESS, HelpTopic.ACCESS],
|
[HelpTopic.ACCESS, HelpTopic.ACCESS],
|
||||||
[HelpTopic.VERSIONS, HelpTopic.VERSIONS],
|
[HelpTopic.VERSIONS, HelpTopic.VERSIONS],
|
||||||
|
|
||||||
|
[HelpTopic.INFO, HelpTopic.INFO],
|
||||||
|
[HelpTopic.INFO_RULES, HelpTopic.INFO],
|
||||||
|
[HelpTopic.INFO_CONTRIB, HelpTopic.INFO],
|
||||||
|
[HelpTopic.INFO_PRIVACY, HelpTopic.INFO],
|
||||||
|
[HelpTopic.INFO_API, HelpTopic.INFO],
|
||||||
|
|
||||||
[HelpTopic.EXTEOR, HelpTopic.EXTEOR]
|
[HelpTopic.EXTEOR, HelpTopic.EXTEOR]
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Topics that can be folded.
|
* Topics that can be folded.
|
||||||
*/
|
*/
|
||||||
export const foldableTopics = [HelpTopic.INTERFACE, HelpTopic.RSLANG, HelpTopic.CONCEPTUAL, HelpTopic.DOCS];
|
export const foldableTopics = [HelpTopic.INTERFACE, HelpTopic.RSLANG, HelpTopic.CONCEPTUAL, HelpTopic.INFO];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents {@link IConstituenta} matching mode.
|
* Represents {@link IConstituenta} matching mode.
|
||||||
|
@ -133,10 +141,15 @@ export enum CstMatchMode {
|
||||||
* Represents Library filter parameters.
|
* Represents Library filter parameters.
|
||||||
*/
|
*/
|
||||||
export interface ILibraryFilter {
|
export interface ILibraryFilter {
|
||||||
|
type?: LibraryItemType;
|
||||||
query?: string;
|
query?: string;
|
||||||
|
|
||||||
path?: string;
|
path?: string;
|
||||||
head?: LocationHead;
|
head?: LocationHead;
|
||||||
|
|
||||||
|
folderMode?: boolean;
|
||||||
|
folder?: string;
|
||||||
|
|
||||||
isVisible?: boolean;
|
isVisible?: boolean;
|
||||||
isOwned?: boolean;
|
isOwned?: boolean;
|
||||||
isSubscribed?: boolean;
|
isSubscribed?: boolean;
|
||||||
|
|
|
@ -65,6 +65,3 @@ export interface IRunSynthesisResponse {
|
||||||
export interface IOperationSchema extends IOperationSchemaData {
|
export interface IOperationSchema extends IOperationSchemaData {
|
||||||
subscribers: UserID[];
|
subscribers: UserID[];
|
||||||
editors: UserID[];
|
editors: UserID[];
|
||||||
|
|
||||||
//producedData: number[]; // TODO: modify this to store calculated state on load
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
import { useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
import { toast } from 'react-toastify';
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
@ -10,6 +10,7 @@ import { IconDownload } from '@/components/Icons';
|
||||||
import InfoError from '@/components/info/InfoError';
|
import InfoError from '@/components/info/InfoError';
|
||||||
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
import SelectAccessPolicy from '@/components/select/SelectAccessPolicy';
|
||||||
import SelectItemType from '@/components/select/SelectItemType';
|
import SelectItemType from '@/components/select/SelectItemType';
|
||||||
|
import SelectLocation from '@/components/select/SelectLocation';
|
||||||
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
import SelectLocationHead from '@/components/select/SelectLocationHead';
|
||||||
import Button from '@/components/ui/Button';
|
import Button from '@/components/ui/Button';
|
||||||
import Label from '@/components/ui/Label';
|
import Label from '@/components/ui/Label';
|
||||||
|
@ -25,11 +26,12 @@ import { AccessPolicy, LibraryItemType, LocationHead } from '@/models/library';
|
||||||
import { ILibraryCreateData } from '@/models/library';
|
import { ILibraryCreateData } from '@/models/library';
|
||||||
import { combineLocation, validateLocation } from '@/models/libraryAPI';
|
import { combineLocation, validateLocation } from '@/models/libraryAPI';
|
||||||
import { EXTEOR_TRS_FILE, limits, patterns } from '@/utils/constants';
|
import { EXTEOR_TRS_FILE, limits, patterns } from '@/utils/constants';
|
||||||
|
import { information } from '@/utils/labels';
|
||||||
|
|
||||||
function FormCreateItem() {
|
function FormCreateItem() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user } = useAuth();
|
||||||
const { createItem, error, setError, processing } = useLibrary();
|
const { createItem, processingError, setProcessingError, processing, folders } = useLibrary();
|
||||||
|
|
||||||
const [itemType, setItemType] = useState(LibraryItemType.RSFORM);
|
const [itemType, setItemType] = useState(LibraryItemType.RSFORM);
|
||||||
const [title, setTitle] = useState('');
|
const [title, setTitle] = useState('');
|
||||||
|
@ -49,8 +51,8 @@ function FormCreateItem() {
|
||||||
const inputRef = useRef<HTMLInputElement | null>(null);
|
const inputRef = useRef<HTMLInputElement | null>(null);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setError(undefined);
|
setProcessingError(undefined);
|
||||||
}, [title, alias, setError]);
|
}, [title, alias, setProcessingError]);
|
||||||
|
|
||||||
function handleCancel() {
|
function handleCancel() {
|
||||||
if (router.canBack()) {
|
if (router.canBack()) {
|
||||||
|
@ -78,7 +80,7 @@ function FormCreateItem() {
|
||||||
fileName: file?.name
|
fileName: file?.name
|
||||||
};
|
};
|
||||||
createItem(data, newItem => {
|
createItem(data, newItem => {
|
||||||
toast.success('Схема успешно создана');
|
toast.success(information.newLibraryItem);
|
||||||
if (itemType == LibraryItemType.RSFORM) {
|
if (itemType == LibraryItemType.RSFORM) {
|
||||||
router.push(urls.schema(newItem.id));
|
router.push(urls.schema(newItem.id));
|
||||||
} else {
|
} else {
|
||||||
|
@ -97,6 +99,11 @@ function FormCreateItem() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const handleSelectLocation = useCallback((newValue: string) => {
|
||||||
|
setHead(newValue.substring(0, 2) as LocationHead);
|
||||||
|
setBody(newValue.length > 3 ? newValue.substring(3) : '');
|
||||||
|
}, []);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')} onSubmit={handleSubmit}>
|
<form className={clsx('cc-column', 'min-w-[30rem] max-w-[30rem] mx-auto', 'px-6 py-3')} onSubmit={handleSubmit}>
|
||||||
<h1>
|
<h1>
|
||||||
|
@ -153,7 +160,6 @@ function FormCreateItem() {
|
||||||
<div className='ml-auto cc-icons'>
|
<div className='ml-auto cc-icons'>
|
||||||
<SelectAccessPolicy value={policy} onChange={setPolicy} />
|
<SelectAccessPolicy value={policy} onChange={setPolicy} />
|
||||||
<MiniButton
|
<MiniButton
|
||||||
className='disabled:cursor-auto'
|
|
||||||
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
title={visible ? 'Библиотека: отображать' : 'Библиотека: скрывать'}
|
||||||
icon={<VisibilityIcon value={visible} />}
|
icon={<VisibilityIcon value={visible} />}
|
||||||
onClick={() => setVisible(prev => !prev)}
|
onClick={() => setVisible(prev => !prev)}
|
||||||
|
@ -179,6 +185,11 @@ function FormCreateItem() {
|
||||||
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
excluded={!user?.is_staff ? [LocationHead.LIBRARY] : []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
{user?.is_staff ? (
|
||||||
|
<div className='self-start mt-[-0.25rem] ml-[-1.5rem]'>
|
||||||
|
<SelectLocation folderTree={folders} value={location} onChange={handleSelectLocation} />
|
||||||
|
</div>
|
||||||
|
) : null}
|
||||||
<TextArea
|
<TextArea
|
||||||
id='dlg_cst_body'
|
id='dlg_cst_body'
|
||||||
label='Путь'
|
label='Путь'
|
||||||
|
@ -193,7 +204,7 @@ function FormCreateItem() {
|
||||||
<SubmitButton text='Создать схему' loading={processing} className='min-w-[10rem]' disabled={!isValid} />
|
<SubmitButton text='Создать схему' loading={processing} className='min-w-[10rem]' disabled={!isValid} />
|
||||||
<Button text='Отмена' className='min-w-[10rem]' onClick={() => handleCancel()} />
|
<Button text='Отмена' className='min-w-[10rem]' onClick={() => handleCancel()} />
|
||||||
</div>
|
</div>
|
||||||
{error ? <InfoError error={error} /> : null}
|
{processingError ? <InfoError error={processingError} /> : null}
|
||||||
</form>
|
</form>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
import { useLayoutEffect } from 'react';
|
import { useLayoutEffect } from 'react';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
|
import Loader from '@/components/ui/Loader';
|
||||||
import { useAuth } from '@/context/AuthContext';
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { PARAMETER } from '@/utils/constants';
|
import { PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
function HomePage() {
|
function HomePage() {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const { user } = useAuth();
|
const { user, loading } = useAuth();
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
if (!loading) {
|
||||||
if (!user) {
|
if (!user) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
router.push(urls.manuals);
|
router.push(urls.manuals);
|
||||||
|
@ -19,9 +21,10 @@ function HomePage() {
|
||||||
router.push(urls.library);
|
router.push(urls.library);
|
||||||
}, PARAMETER.refreshTimeout);
|
}, PARAMETER.refreshTimeout);
|
||||||
}
|
}
|
||||||
}, [router, user]);
|
}
|
||||||
|
}, [router, user, loading]);
|
||||||
|
|
||||||
return <div />;
|
return <Loader />;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default HomePage;
|
export default HomePage;
|
||||||
|
|
156
rsconcept/frontend/src/pages/LibraryPage/LibraryFolders.tsx
Normal file
156
rsconcept/frontend/src/pages/LibraryPage/LibraryFolders.tsx
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
|
import clsx from 'clsx';
|
||||||
|
import { motion } from 'framer-motion';
|
||||||
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
import { toast } from 'react-toastify';
|
||||||
|
|
||||||
|
import { IconFolder, IconFolderClosed, IconFolderEmpty, IconFolderOpened, IconFolderTree } from '@/components/Icons';
|
||||||
|
import BadgeHelp from '@/components/info/BadgeHelp';
|
||||||
|
import { CProps } from '@/components/props';
|
||||||
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
|
import { FolderNode, FolderTree } from '@/models/FolderTree';
|
||||||
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
import { animateSideView } from '@/styling/animations';
|
||||||
|
import { PARAMETER, prefixes } from '@/utils/constants';
|
||||||
|
import { information, labelFolderNode } from '@/utils/labels';
|
||||||
|
|
||||||
|
interface LibraryTableProps {
|
||||||
|
folders: FolderTree;
|
||||||
|
currentFolder: string;
|
||||||
|
setFolder: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
toggleFolderMode: () => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
function LibraryFolders({ folders, currentFolder, setFolder, toggleFolderMode }: LibraryTableProps) {
|
||||||
|
const activeNode = useMemo(() => folders.at(currentFolder), [folders, currentFolder]);
|
||||||
|
|
||||||
|
const items = useMemo(() => folders.getTree(), [folders]);
|
||||||
|
const [folded, setFolded] = useState<FolderNode[]>(items);
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
setFolded(items.filter(item => item !== activeNode && (!activeNode || !activeNode.hasPredecessor(item))));
|
||||||
|
}, [items, activeNode]);
|
||||||
|
|
||||||
|
const onFoldItem = useCallback(
|
||||||
|
(target: FolderNode, showChildren: boolean) => {
|
||||||
|
setFolded(prev =>
|
||||||
|
items.filter(item => {
|
||||||
|
if (item === target) {
|
||||||
|
return !showChildren;
|
||||||
|
}
|
||||||
|
if (!showChildren && item.hasPredecessor(target)) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return prev.includes(item);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
},
|
||||||
|
[items]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClickFolder = useCallback(
|
||||||
|
(event: CProps.EventMouse, target: FolderNode) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
navigator.clipboard
|
||||||
|
.writeText(target.getPath())
|
||||||
|
.then(() => toast.success(information.pathReady))
|
||||||
|
.catch(console.error);
|
||||||
|
} else {
|
||||||
|
setFolder(target.getPath());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[setFolder]
|
||||||
|
);
|
||||||
|
|
||||||
|
const handleClickFold = useCallback(
|
||||||
|
(event: CProps.EventMouse, target: FolderNode, showChildren: boolean) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
onFoldItem(target, showChildren);
|
||||||
|
},
|
||||||
|
[onFoldItem]
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<motion.div
|
||||||
|
className='flex flex-col select-none text:xs sm:text-sm'
|
||||||
|
initial={{ ...animateSideView.initial }}
|
||||||
|
animate={{ ...animateSideView.animate }}
|
||||||
|
exit={{ ...animateSideView.exit }}
|
||||||
|
>
|
||||||
|
<div className='h-[2.08rem] flex justify-between items-center pr-1'>
|
||||||
|
<BadgeHelp
|
||||||
|
topic={HelpTopic.UI_LIBRARY}
|
||||||
|
className={clsx(PARAMETER.TOOLTIP_WIDTH, 'text-sm')}
|
||||||
|
offset={5}
|
||||||
|
place='right-start'
|
||||||
|
/>
|
||||||
|
<MiniButton
|
||||||
|
icon={<IconFolderTree size='1.25rem' className='icon-green' />}
|
||||||
|
title='Переключение в режим Поиск'
|
||||||
|
onClick={toggleFolderMode}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className={clsx(
|
||||||
|
'max-w-[10rem] sm:max-w-[15rem] min-w-[10rem] sm:min-w-[15rem]',
|
||||||
|
'flex flex-col',
|
||||||
|
'cc-scroll-y'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{items.map((item, index) =>
|
||||||
|
!item.parent || !folded.includes(item.parent) ? (
|
||||||
|
<div
|
||||||
|
tabIndex={-1}
|
||||||
|
key={`${prefixes.folders_list}${index}`}
|
||||||
|
className={clsx(
|
||||||
|
'min-h-[2.0825rem] sm:min-h-[2.3125rem]',
|
||||||
|
'pr-3 flex items-center gap-2',
|
||||||
|
'cc-scroll-row',
|
||||||
|
'clr-hover',
|
||||||
|
'cursor-pointer',
|
||||||
|
activeNode === item && 'clr-selected'
|
||||||
|
)}
|
||||||
|
style={{ paddingLeft: `${(item.rank > 5 ? 5 : item.rank) * 0.5 + 0.5}rem` }}
|
||||||
|
onClick={event => handleClickFolder(event, item)}
|
||||||
|
>
|
||||||
|
{item.children.size > 0 ? (
|
||||||
|
<MiniButton
|
||||||
|
noPadding
|
||||||
|
noHover
|
||||||
|
icon={
|
||||||
|
folded.includes(item) ? (
|
||||||
|
item.filesInside ? (
|
||||||
|
<IconFolderClosed size='1rem' className='icon-primary' />
|
||||||
|
) : (
|
||||||
|
<IconFolderEmpty size='1rem' className='icon-primary' />
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<IconFolderOpened size='1rem' className='icon-green' />
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClick={event => handleClickFold(event, item, folded.includes(item))}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<div>
|
||||||
|
{item.filesInside ? (
|
||||||
|
<IconFolder size='1rem' className='clr-text-default' />
|
||||||
|
) : (
|
||||||
|
<IconFolderEmpty size='1rem' className='clr-text-controls' />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
<div className='self-center'>{labelFolderNode(item)}</div>
|
||||||
|
</div>
|
||||||
|
) : null
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</motion.div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default LibraryFolders;
|
|
@ -1,8 +1,10 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
|
import { AnimatePresence } from 'framer-motion';
|
||||||
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
|
|
||||||
import DataLoader from '@/components/wrap/DataLoader';
|
import DataLoader from '@/components/wrap/DataLoader';
|
||||||
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import { useLibrary } from '@/context/LibraryContext';
|
import { useLibrary } from '@/context/LibraryContext';
|
||||||
import useLocalStorage from '@/hooks/useLocalStorage';
|
import useLocalStorage from '@/hooks/useLocalStorage';
|
||||||
import { ILibraryItem, LocationHead } from '@/models/library';
|
import { ILibraryItem, LocationHead } from '@/models/library';
|
||||||
|
@ -10,17 +12,21 @@ import { ILibraryFilter } from '@/models/miscellaneous';
|
||||||
import { storage } from '@/utils/constants';
|
import { storage } from '@/utils/constants';
|
||||||
import { toggleTristateFlag } from '@/utils/utils';
|
import { toggleTristateFlag } from '@/utils/utils';
|
||||||
|
|
||||||
|
import LibraryFolders from './LibraryFolders';
|
||||||
import LibraryTable from './LibraryTable';
|
import LibraryTable from './LibraryTable';
|
||||||
import SearchPanel from './SearchPanel';
|
import SearchPanel from './SearchPanel';
|
||||||
|
|
||||||
function LibraryPage() {
|
function LibraryPage() {
|
||||||
const library = useLibrary();
|
const library = useLibrary();
|
||||||
|
const { user } = useAuth();
|
||||||
const [items, setItems] = useState<ILibraryItem[]>([]);
|
const [items, setItems] = useState<ILibraryItem[]>([]);
|
||||||
|
|
||||||
const [query, setQuery] = useState('');
|
const [query, setQuery] = useState('');
|
||||||
const [path, setPath] = useState('');
|
const [path, setPath] = useState('');
|
||||||
|
|
||||||
const [head, setHead] = useLocalStorage<LocationHead | undefined>(storage.librarySearchHead, undefined);
|
const [head, setHead] = useLocalStorage<LocationHead | undefined>(storage.librarySearchHead, undefined);
|
||||||
|
const [folderMode, setFolderMode] = useLocalStorage<boolean>(storage.librarySearchFolderMode, true);
|
||||||
|
const [folder, setFolder] = useLocalStorage<string>(storage.librarySearchFolder, '');
|
||||||
const [isVisible, setIsVisible] = useLocalStorage<boolean | undefined>(storage.librarySearchVisible, true);
|
const [isVisible, setIsVisible] = useLocalStorage<boolean | undefined>(storage.librarySearchVisible, true);
|
||||||
const [isSubscribed, setIsSubscribed] = useLocalStorage<boolean | undefined>(
|
const [isSubscribed, setIsSubscribed] = useLocalStorage<boolean | undefined>(
|
||||||
storage.librarySearchSubscribed,
|
storage.librarySearchSubscribed,
|
||||||
|
@ -34,12 +40,27 @@ function LibraryPage() {
|
||||||
head: head,
|
head: head,
|
||||||
path: path,
|
path: path,
|
||||||
query: query,
|
query: query,
|
||||||
isEditor: isEditor,
|
isEditor: user ? isEditor : undefined,
|
||||||
isOwned: isOwned,
|
isOwned: user ? isOwned : undefined,
|
||||||
isSubscribed: isSubscribed,
|
isSubscribed: user ? isSubscribed : undefined,
|
||||||
isVisible: isVisible
|
isVisible: user ? isVisible : true,
|
||||||
|
folderMode: folderMode,
|
||||||
|
folder: folder
|
||||||
}),
|
}),
|
||||||
[head, path, query, isEditor, isOwned, isSubscribed, isVisible]
|
[head, path, query, isEditor, isOwned, isSubscribed, isVisible, user, folderMode, folder]
|
||||||
|
);
|
||||||
|
|
||||||
|
const hasCustomFilter = useMemo(
|
||||||
|
() =>
|
||||||
|
!!filter.path ||
|
||||||
|
!!filter.query ||
|
||||||
|
filter.head !== undefined ||
|
||||||
|
filter.isEditor !== undefined ||
|
||||||
|
filter.isOwned !== undefined ||
|
||||||
|
filter.isSubscribed !== undefined ||
|
||||||
|
filter.isVisible !== true ||
|
||||||
|
!!filter.folder,
|
||||||
|
[filter]
|
||||||
);
|
);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
|
@ -50,6 +71,7 @@ function LibraryPage() {
|
||||||
const toggleOwned = useCallback(() => setIsOwned(prev => toggleTristateFlag(prev)), [setIsOwned]);
|
const toggleOwned = useCallback(() => setIsOwned(prev => toggleTristateFlag(prev)), [setIsOwned]);
|
||||||
const toggleSubscribed = useCallback(() => setIsSubscribed(prev => toggleTristateFlag(prev)), [setIsSubscribed]);
|
const toggleSubscribed = useCallback(() => setIsSubscribed(prev => toggleTristateFlag(prev)), [setIsSubscribed]);
|
||||||
const toggleEditor = useCallback(() => setIsEditor(prev => toggleTristateFlag(prev)), [setIsEditor]);
|
const toggleEditor = useCallback(() => setIsEditor(prev => toggleTristateFlag(prev)), [setIsEditor]);
|
||||||
|
const toggleFolderMode = useCallback(() => setFolderMode(prev => !prev), [setFolderMode]);
|
||||||
|
|
||||||
const resetFilter = useCallback(() => {
|
const resetFilter = useCallback(() => {
|
||||||
setQuery('');
|
setQuery('');
|
||||||
|
@ -59,34 +81,38 @@ function LibraryPage() {
|
||||||
setIsSubscribed(undefined);
|
setIsSubscribed(undefined);
|
||||||
setIsOwned(undefined);
|
setIsOwned(undefined);
|
||||||
setIsEditor(undefined);
|
setIsEditor(undefined);
|
||||||
}, [setHead, setIsVisible, setIsSubscribed, setIsOwned, setIsEditor]);
|
setFolder('');
|
||||||
|
}, [setHead, setIsVisible, setIsSubscribed, setIsOwned, setIsEditor, setFolder]);
|
||||||
|
|
||||||
const view = useMemo(
|
const view = useMemo(
|
||||||
() => (
|
() => (
|
||||||
<LibraryTable
|
<LibraryTable
|
||||||
resetQuery={resetFilter} // prettier: split lines
|
resetQuery={resetFilter} // prettier: split lines
|
||||||
items={items}
|
items={items}
|
||||||
|
folderMode={folderMode}
|
||||||
|
toggleFolderMode={toggleFolderMode}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
[resetFilter, items]
|
[resetFilter, items, folderMode, toggleFolderMode]
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataLoader
|
<DataLoader
|
||||||
id='library-page' // prettier: split lines
|
id='library-page' // prettier: split lines
|
||||||
isLoading={library.loading}
|
isLoading={library.loading}
|
||||||
error={library.error}
|
error={library.loadingError}
|
||||||
hasNoData={library.items.length === 0}
|
hasNoData={library.items.length === 0}
|
||||||
>
|
>
|
||||||
<SearchPanel
|
<SearchPanel
|
||||||
|
total={library.items.length ?? 0}
|
||||||
|
filtered={items.length}
|
||||||
|
hasCustomFilter={hasCustomFilter}
|
||||||
query={query}
|
query={query}
|
||||||
setQuery={setQuery}
|
setQuery={setQuery}
|
||||||
path={path}
|
path={path}
|
||||||
setPath={setPath}
|
setPath={setPath}
|
||||||
head={head}
|
head={head}
|
||||||
setHead={setHead}
|
setHead={setHead}
|
||||||
total={library.items.length ?? 0}
|
|
||||||
filtered={items.length}
|
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
isOwned={isOwned}
|
isOwned={isOwned}
|
||||||
toggleOwned={toggleOwned}
|
toggleOwned={toggleOwned}
|
||||||
|
@ -95,8 +121,24 @@ function LibraryPage() {
|
||||||
toggleSubscribed={toggleSubscribed}
|
toggleSubscribed={toggleSubscribed}
|
||||||
isEditor={isEditor}
|
isEditor={isEditor}
|
||||||
toggleEditor={toggleEditor}
|
toggleEditor={toggleEditor}
|
||||||
|
resetFilter={resetFilter}
|
||||||
|
folderMode={folderMode}
|
||||||
|
toggleFolderMode={toggleFolderMode}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<div className='flex'>
|
||||||
|
<AnimatePresence initial={false}>
|
||||||
|
{folderMode ? (
|
||||||
|
<LibraryFolders
|
||||||
|
currentFolder={folder} // prettier: split-lines
|
||||||
|
setFolder={setFolder}
|
||||||
|
folders={library.folders}
|
||||||
|
toggleFolderMode={toggleFolderMode}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</AnimatePresence>
|
||||||
{view}
|
{view}
|
||||||
|
</div>
|
||||||
</DataLoader>
|
</DataLoader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useLayoutEffect, useMemo, useState } from 'react';
|
import clsx from 'clsx';
|
||||||
|
import { useCallback, useLayoutEffect, useMemo, useState } from 'react';
|
||||||
import { useIntl } from 'react-intl';
|
import { useIntl } from 'react-intl';
|
||||||
|
|
||||||
import { urls } from '@/app/urls';
|
import { urls } from '@/app/urls';
|
||||||
import { IconFolder } from '@/components/Icons';
|
import { IconFolderTree } from '@/components/Icons';
|
||||||
import BadgeLocation from '@/components/info/BadgeLocation';
|
import BadgeLocation from '@/components/info/BadgeLocation';
|
||||||
import { CProps } from '@/components/props';
|
import { CProps } from '@/components/props';
|
||||||
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
|
import DataTable, { createColumnHelper, IConditionalStyle, VisibilityState } from '@/components/ui/DataTable';
|
||||||
import FlexColumn from '@/components/ui/FlexColumn';
|
import FlexColumn from '@/components/ui/FlexColumn';
|
||||||
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import TextURL from '@/components/ui/TextURL';
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { useConceptNavigation } from '@/context/NavigationContext';
|
import { useConceptNavigation } from '@/context/NavigationContext';
|
||||||
import { useConceptOptions } from '@/context/OptionsContext';
|
import { useConceptOptions } from '@/context/OptionsContext';
|
||||||
|
@ -21,11 +23,13 @@ import { storage } from '@/utils/constants';
|
||||||
interface LibraryTableProps {
|
interface LibraryTableProps {
|
||||||
items: ILibraryItem[];
|
items: ILibraryItem[];
|
||||||
resetQuery: () => void;
|
resetQuery: () => void;
|
||||||
|
folderMode: boolean;
|
||||||
|
toggleFolderMode: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const columnHelper = createColumnHelper<ILibraryItem>();
|
const columnHelper = createColumnHelper<ILibraryItem>();
|
||||||
|
|
||||||
function LibraryTable({ items, resetQuery }: LibraryTableProps) {
|
function LibraryTable({ items, resetQuery, folderMode, toggleFolderMode }: LibraryTableProps) {
|
||||||
const router = useConceptNavigation();
|
const router = useConceptNavigation();
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const { getUserLabel } = useUsers();
|
const { getUserLabel } = useUsers();
|
||||||
|
@ -50,14 +54,31 @@ function LibraryTable({ items, resetQuery }: LibraryTableProps) {
|
||||||
});
|
});
|
||||||
}, [windowSize]);
|
}, [windowSize]);
|
||||||
|
|
||||||
|
const handleToggleFolder = useCallback(
|
||||||
|
(event: CProps.EventMouse) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
toggleFolderMode();
|
||||||
|
},
|
||||||
|
[toggleFolderMode]
|
||||||
|
);
|
||||||
|
|
||||||
const columns = useMemo(
|
const columns = useMemo(
|
||||||
() => [
|
() => [
|
||||||
|
...(folderMode
|
||||||
|
? []
|
||||||
|
: [
|
||||||
columnHelper.accessor('location', {
|
columnHelper.accessor('location', {
|
||||||
id: 'location',
|
id: 'location',
|
||||||
header: () => (
|
header: () => (
|
||||||
<div className='pl-2 max-h-[1rem] translate-y-[-0.125rem]'>
|
<MiniButton
|
||||||
<IconFolder size='1.25rem' className='clr-text-controls' />
|
noPadding
|
||||||
</div>
|
noHover
|
||||||
|
className='pl-2 max-h-[1rem] translate-y-[-0.125rem]'
|
||||||
|
onClick={handleToggleFolder}
|
||||||
|
titleHtml='Переключение в режим Проводник'
|
||||||
|
icon={<IconFolderTree size='1.25rem' className='clr-text-controls' />}
|
||||||
|
/>
|
||||||
),
|
),
|
||||||
size: 50,
|
size: 50,
|
||||||
minSize: 50,
|
minSize: 50,
|
||||||
|
@ -65,7 +86,8 @@ function LibraryTable({ items, resetQuery }: LibraryTableProps) {
|
||||||
enableSorting: true,
|
enableSorting: true,
|
||||||
cell: props => <BadgeLocation location={props.getValue()} />,
|
cell: props => <BadgeLocation location={props.getValue()} />,
|
||||||
sortingFn: 'text'
|
sortingFn: 'text'
|
||||||
}),
|
})
|
||||||
|
]),
|
||||||
columnHelper.accessor('alias', {
|
columnHelper.accessor('alias', {
|
||||||
id: 'alias',
|
id: 'alias',
|
||||||
header: 'Шифр',
|
header: 'Шифр',
|
||||||
|
@ -116,7 +138,7 @@ function LibraryTable({ items, resetQuery }: LibraryTableProps) {
|
||||||
sortDescFirst: true
|
sortDescFirst: true
|
||||||
})
|
})
|
||||||
],
|
],
|
||||||
[intl, getUserLabel, windowSize]
|
[intl, getUserLabel, windowSize, handleToggleFolder, folderMode]
|
||||||
);
|
);
|
||||||
|
|
||||||
const tableHeight = useMemo(() => calculateHeight('2.2rem'), [calculateHeight]);
|
const tableHeight = useMemo(() => calculateHeight('2.2rem'), [calculateHeight]);
|
||||||
|
@ -139,10 +161,10 @@ function LibraryTable({ items, resetQuery }: LibraryTableProps) {
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={items}
|
data={items}
|
||||||
headPosition='0'
|
headPosition='0'
|
||||||
className='text-xs sm:text-sm cc-scroll-y'
|
className={clsx('text-xs sm:text-sm cc-scroll-y', { 'border-l border-b': folderMode })}
|
||||||
style={{ maxHeight: tableHeight }}
|
style={{ maxHeight: tableHeight }}
|
||||||
noDataComponent={
|
noDataComponent={
|
||||||
<FlexColumn className='p-3 items-center min-h-[6rem]'>
|
<FlexColumn className='dense p-3 items-center min-h-[6rem]'>
|
||||||
<p>Список схем пуст</p>
|
<p>Список схем пуст</p>
|
||||||
<p className='flex gap-6'>
|
<p className='flex gap-6'>
|
||||||
<TextURL text='Создать схему' href='/library/create' />
|
<TextURL text='Создать схему' href='/library/create' />
|
||||||
|
|
|
@ -4,16 +4,16 @@ import clsx from 'clsx';
|
||||||
import { useCallback } from 'react';
|
import { useCallback } from 'react';
|
||||||
|
|
||||||
import { LocationIcon, SubscribeIcon, VisibilityIcon } from '@/components/DomainIcons';
|
import { LocationIcon, SubscribeIcon, VisibilityIcon } from '@/components/DomainIcons';
|
||||||
import { IconEditor, IconFolder, IconOwner } from '@/components/Icons';
|
import { IconEditor, IconFilterReset, IconFolder, IconFolderTree, IconOwner } from '@/components/Icons';
|
||||||
import BadgeHelp from '@/components/info/BadgeHelp';
|
import { CProps } from '@/components/props';
|
||||||
import Dropdown from '@/components/ui/Dropdown';
|
import Dropdown from '@/components/ui/Dropdown';
|
||||||
import DropdownButton from '@/components/ui/DropdownButton';
|
import DropdownButton from '@/components/ui/DropdownButton';
|
||||||
import MiniButton from '@/components/ui/MiniButton';
|
import MiniButton from '@/components/ui/MiniButton';
|
||||||
import SearchBar from '@/components/ui/SearchBar';
|
import SearchBar from '@/components/ui/SearchBar';
|
||||||
import SelectorButton from '@/components/ui/SelectorButton';
|
import SelectorButton from '@/components/ui/SelectorButton';
|
||||||
|
import { useAuth } from '@/context/AuthContext';
|
||||||
import useDropdown from '@/hooks/useDropdown';
|
import useDropdown from '@/hooks/useDropdown';
|
||||||
import { LocationHead } from '@/models/library';
|
import { LocationHead } from '@/models/library';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
|
||||||
import { prefixes } from '@/utils/constants';
|
import { prefixes } from '@/utils/constants';
|
||||||
import { describeLocationHead, labelLocationHead } from '@/utils/labels';
|
import { describeLocationHead, labelLocationHead } from '@/utils/labels';
|
||||||
import { tripleToggleColor } from '@/utils/utils';
|
import { tripleToggleColor } from '@/utils/utils';
|
||||||
|
@ -21,6 +21,7 @@ import { tripleToggleColor } from '@/utils/utils';
|
||||||
interface SearchPanelProps {
|
interface SearchPanelProps {
|
||||||
total: number;
|
total: number;
|
||||||
filtered: number;
|
filtered: number;
|
||||||
|
hasCustomFilter: boolean;
|
||||||
|
|
||||||
query: string;
|
query: string;
|
||||||
setQuery: React.Dispatch<React.SetStateAction<string>>;
|
setQuery: React.Dispatch<React.SetStateAction<string>>;
|
||||||
|
@ -29,6 +30,9 @@ interface SearchPanelProps {
|
||||||
head: LocationHead | undefined;
|
head: LocationHead | undefined;
|
||||||
setHead: React.Dispatch<React.SetStateAction<LocationHead | undefined>>;
|
setHead: React.Dispatch<React.SetStateAction<LocationHead | undefined>>;
|
||||||
|
|
||||||
|
folderMode: boolean;
|
||||||
|
toggleFolderMode: () => void;
|
||||||
|
|
||||||
isVisible: boolean | undefined;
|
isVisible: boolean | undefined;
|
||||||
toggleVisible: () => void;
|
toggleVisible: () => void;
|
||||||
isOwned: boolean | undefined;
|
isOwned: boolean | undefined;
|
||||||
|
@ -37,11 +41,14 @@ interface SearchPanelProps {
|
||||||
toggleSubscribed: () => void;
|
toggleSubscribed: () => void;
|
||||||
isEditor: boolean | undefined;
|
isEditor: boolean | undefined;
|
||||||
toggleEditor: () => void;
|
toggleEditor: () => void;
|
||||||
|
resetFilter: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
function SearchPanel({
|
function SearchPanel({
|
||||||
total,
|
total,
|
||||||
filtered,
|
filtered,
|
||||||
|
hasCustomFilter,
|
||||||
|
|
||||||
query,
|
query,
|
||||||
setQuery,
|
setQuery,
|
||||||
path,
|
path,
|
||||||
|
@ -49,6 +56,9 @@ function SearchPanel({
|
||||||
head,
|
head,
|
||||||
setHead,
|
setHead,
|
||||||
|
|
||||||
|
folderMode,
|
||||||
|
toggleFolderMode,
|
||||||
|
|
||||||
isVisible,
|
isVisible,
|
||||||
toggleVisible,
|
toggleVisible,
|
||||||
isOwned,
|
isOwned,
|
||||||
|
@ -56,8 +66,10 @@ function SearchPanel({
|
||||||
isSubscribed,
|
isSubscribed,
|
||||||
toggleSubscribed,
|
toggleSubscribed,
|
||||||
isEditor,
|
isEditor,
|
||||||
toggleEditor
|
toggleEditor,
|
||||||
|
resetFilter
|
||||||
}: SearchPanelProps) {
|
}: SearchPanelProps) {
|
||||||
|
const { user } = useAuth();
|
||||||
const headMenu = useDropdown();
|
const headMenu = useDropdown();
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
|
@ -68,6 +80,22 @@ function SearchPanel({
|
||||||
[headMenu, setHead]
|
[headMenu, setHead]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const handleToggleFolder = useCallback(() => {
|
||||||
|
headMenu.hide();
|
||||||
|
toggleFolderMode();
|
||||||
|
}, [headMenu, toggleFolderMode]);
|
||||||
|
|
||||||
|
const handleFolderClick = useCallback(
|
||||||
|
(event: CProps.EventMouse) => {
|
||||||
|
if (event.ctrlKey || event.metaKey) {
|
||||||
|
toggleFolderMode();
|
||||||
|
} else {
|
||||||
|
headMenu.toggle();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[headMenu, toggleFolderMode]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
@ -79,10 +107,11 @@ function SearchPanel({
|
||||||
'clr-input'
|
'clr-input'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className={clsx('px-3 self-center', 'min-w-[5.5rem]', 'select-none', 'whitespace-nowrap')}>
|
<div className={clsx('px-3 pt-1 self-center', 'min-w-[5.5rem]', 'select-none', 'whitespace-nowrap')}>
|
||||||
{filtered} из {total}
|
{filtered} из {total}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{user ? (
|
||||||
<div className='cc-icons'>
|
<div className='cc-icons'>
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Видимость'
|
title='Видимость'
|
||||||
|
@ -94,6 +123,7 @@ function SearchPanel({
|
||||||
icon={<SubscribeIcon value={true} className={tripleToggleColor(isSubscribed)} />}
|
icon={<SubscribeIcon value={true} className={tripleToggleColor(isSubscribed)} />}
|
||||||
onClick={toggleSubscribed}
|
onClick={toggleSubscribed}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MiniButton
|
<MiniButton
|
||||||
title='Я - Владелец'
|
title='Я - Владелец'
|
||||||
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
|
icon={<IconOwner size='1.25rem' className={tripleToggleColor(isOwned)} />}
|
||||||
|
@ -105,7 +135,15 @@ function SearchPanel({
|
||||||
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
|
icon={<IconEditor size='1.25rem' className={tripleToggleColor(isEditor)} />}
|
||||||
onClick={toggleEditor}
|
onClick={toggleEditor}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<MiniButton
|
||||||
|
title='Сбросить фильтры'
|
||||||
|
icon={<IconFilterReset size='1.25rem' className='icon-primary' />}
|
||||||
|
onClick={resetFilter}
|
||||||
|
disabled={!hasCustomFilter}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
|
|
||||||
<div className='flex items-center h-full mx-auto'>
|
<div className='flex items-center h-full mx-auto'>
|
||||||
<SearchBar
|
<SearchBar
|
||||||
|
@ -116,12 +154,12 @@ function SearchPanel({
|
||||||
value={query}
|
value={query}
|
||||||
onChange={setQuery}
|
onChange={setQuery}
|
||||||
/>
|
/>
|
||||||
|
{!folderMode ? (
|
||||||
<div ref={headMenu.ref} className='flex items-center h-full py-1 select-none'>
|
<div ref={headMenu.ref} className='flex items-center h-full py-1 select-none'>
|
||||||
<SelectorButton
|
<SelectorButton
|
||||||
transparent
|
transparent
|
||||||
className='h-full rounded-lg'
|
className='h-full rounded-lg'
|
||||||
title={head ? describeLocationHead(head) : 'Выберите каталог'}
|
titleHtml={(head ? describeLocationHead(head) : 'Выберите каталог') + '<br/>Ctrl + клик - Проводник'}
|
||||||
hideTitle={headMenu.isOpen}
|
hideTitle={headMenu.isOpen}
|
||||||
icon={
|
icon={
|
||||||
head ? (
|
head ? (
|
||||||
|
@ -130,11 +168,17 @@ function SearchPanel({
|
||||||
<IconFolder size='1.25rem' className='clr-text-controls' />
|
<IconFolder size='1.25rem' className='clr-text-controls' />
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
onClick={headMenu.toggle}
|
onClick={handleFolderClick}
|
||||||
text={head ?? '//'}
|
text={head ?? '//'}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<Dropdown isOpen={headMenu.isOpen} stretchLeft className='z-modalTooltip'>
|
<Dropdown isOpen={headMenu.isOpen} stretchLeft className='z-modalTooltip'>
|
||||||
|
<DropdownButton className='w-[10rem]' title='Переключение в режим Проводник' onClick={handleToggleFolder}>
|
||||||
|
<div className='inline-flex items-center gap-3'>
|
||||||
|
<IconFolderTree size='1rem' className='clr-text-controls' />
|
||||||
|
<span>проводник...</span>
|
||||||
|
</div>
|
||||||
|
</DropdownButton>
|
||||||
<DropdownButton className='w-[10rem]' onClick={() => handleChange(undefined)}>
|
<DropdownButton className='w-[10rem]' onClick={() => handleChange(undefined)}>
|
||||||
<div className='inline-flex items-center gap-3'>
|
<div className='inline-flex items-center gap-3'>
|
||||||
<IconFolder size='1rem' className='clr-text-controls' />
|
<IconFolder size='1rem' className='clr-text-controls' />
|
||||||
|
@ -158,19 +202,19 @@ function SearchPanel({
|
||||||
})}
|
})}
|
||||||
</Dropdown>
|
</Dropdown>
|
||||||
</div>
|
</div>
|
||||||
|
) : null}
|
||||||
|
{!folderMode ? (
|
||||||
<SearchBar
|
<SearchBar
|
||||||
id='path_search'
|
id='path_search'
|
||||||
placeholder='Путь'
|
placeholder='Путь'
|
||||||
noIcon
|
noIcon
|
||||||
noBorder
|
noBorder
|
||||||
className='min-w-[5rem]'
|
className='min-w-[4.5rem] sm:min-w-[5rem]'
|
||||||
value={path}
|
value={path}
|
||||||
onChange={setPath}
|
onChange={setPath}
|
||||||
/>
|
/>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<BadgeHelp topic={HelpTopic.UI_LIBRARY} className='max-w-[28rem] text-sm' offset={5} place='right-start' />
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { describeHelpTopic, labelHelpTopic } from '@/utils/labels';
|
import { describeHelpTopic, labelHelpTopic, removeTags } from '@/utils/labels';
|
||||||
|
|
||||||
import LinkTopic from '../../components/ui/LinkTopic';
|
import LinkTopic from '../../components/ui/LinkTopic';
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ interface TopicItemProps {
|
||||||
function TopicItem({ topic }: TopicItemProps) {
|
function TopicItem({ topic }: TopicItemProps) {
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<LinkTopic text={labelHelpTopic(topic)} topic={topic} /> – {describeHelpTopic(topic)}
|
<LinkTopic text={labelHelpTopic(topic)} topic={topic} /> – {removeTags(describeHelpTopic(topic))}
|
||||||
</li>
|
</li>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,24 @@
|
||||||
|
import useWindowSize from '@/hooks/useWindowSize';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
|
||||||
import HelpAccess from './items/HelpAccess';
|
import HelpAccess from './items/HelpAccess';
|
||||||
import HelpAPI from './items/HelpAPI';
|
import HelpAPI from './items/HelpAPI';
|
||||||
import HelpConcept from './items/HelpConcept';
|
import HelpConcept from './items/HelpConcept';
|
||||||
|
import HelpConceptOSS from './items/HelpConceptOSS';
|
||||||
import HelpConceptRelations from './items/HelpConceptRelations';
|
import HelpConceptRelations from './items/HelpConceptRelations';
|
||||||
import HelpConceptSynthesis from './items/HelpConceptSynthesis';
|
import HelpConceptSynthesis from './items/HelpConceptSynthesis';
|
||||||
import HelpConceptSystem from './items/HelpConceptSystem';
|
import HelpConceptSystem from './items/HelpConceptSystem';
|
||||||
|
import HelpContributors from './items/HelpContributors';
|
||||||
import HelpCstAttributes from './items/HelpCstAttributes';
|
import HelpCstAttributes from './items/HelpCstAttributes';
|
||||||
import HelpCstClass from './items/HelpCstClass';
|
import HelpCstClass from './items/HelpCstClass';
|
||||||
import HelpCstEditor from './items/HelpCstEditor';
|
import HelpCstEditor from './items/HelpCstEditor';
|
||||||
import HelpCstStatus from './items/HelpCstStatus';
|
import HelpCstStatus from './items/HelpCstStatus';
|
||||||
import HelpDocs from './items/HelpDocs';
|
|
||||||
import HelpExteor from './items/HelpExteor';
|
import HelpExteor from './items/HelpExteor';
|
||||||
import HelpFormulaTree from './items/HelpFormulaTree';
|
import HelpFormulaTree from './items/HelpFormulaTree';
|
||||||
|
import HelpInfo from './items/HelpInfo';
|
||||||
import HelpInterface from './items/HelpInterface';
|
import HelpInterface from './items/HelpInterface';
|
||||||
import HelpLibrary from './items/HelpLibrary';
|
import HelpLibrary from './items/HelpLibrary';
|
||||||
|
import HelpOssGraph from './items/HelpOssGraph';
|
||||||
import HelpPortal from './items/HelpPortal';
|
import HelpPortal from './items/HelpPortal';
|
||||||
import HelpPrivacy from './items/HelpPrivacy';
|
import HelpPrivacy from './items/HelpPrivacy';
|
||||||
import HelpRSFormCard from './items/HelpRSFormCard';
|
import HelpRSFormCard from './items/HelpRSFormCard';
|
||||||
|
@ -31,17 +35,21 @@ import HelpTermGraph from './items/HelpTermGraph';
|
||||||
import HelpTerminologyControl from './items/HelpTerminologyControl';
|
import HelpTerminologyControl from './items/HelpTerminologyControl';
|
||||||
import HelpVersions from './items/HelpVersions';
|
import HelpVersions from './items/HelpVersions';
|
||||||
|
|
||||||
|
// PDF Viewer setup
|
||||||
|
const OFFSET_X_SMALL = 32;
|
||||||
|
const OFFSET_X_LARGE = 280;
|
||||||
|
|
||||||
|
const MIN_SIZE_SMALL = 300;
|
||||||
|
const MIN_SIZE_LARGE = 600;
|
||||||
|
|
||||||
interface TopicPageProps {
|
interface TopicPageProps {
|
||||||
topic: HelpTopic;
|
topic: HelpTopic;
|
||||||
}
|
}
|
||||||
|
|
||||||
function TopicPage({ topic }: TopicPageProps) {
|
function TopicPage({ topic }: TopicPageProps) {
|
||||||
if (topic === HelpTopic.MAIN) return <HelpPortal />;
|
const size = useWindowSize();
|
||||||
|
|
||||||
if (topic === HelpTopic.DOCS) return <HelpDocs />;
|
if (topic === HelpTopic.MAIN) return <HelpPortal />;
|
||||||
if (topic === HelpTopic.RULES) return <HelpRules />;
|
|
||||||
if (topic === HelpTopic.PRIVACY) return <HelpPrivacy />;
|
|
||||||
if (topic === HelpTopic.API) return <HelpAPI />;
|
|
||||||
|
|
||||||
if (topic === HelpTopic.INTERFACE) return <HelpInterface />;
|
if (topic === HelpTopic.INTERFACE) return <HelpInterface />;
|
||||||
if (topic === HelpTopic.UI_LIBRARY) return <HelpLibrary />;
|
if (topic === HelpTopic.UI_LIBRARY) return <HelpLibrary />;
|
||||||
|
@ -53,12 +61,14 @@ function TopicPage({ topic }: TopicPageProps) {
|
||||||
if (topic === HelpTopic.UI_FORMULA_TREE) return <HelpFormulaTree />;
|
if (topic === HelpTopic.UI_FORMULA_TREE) return <HelpFormulaTree />;
|
||||||
if (topic === HelpTopic.UI_CST_STATUS) return <HelpCstStatus />;
|
if (topic === HelpTopic.UI_CST_STATUS) return <HelpCstStatus />;
|
||||||
if (topic === HelpTopic.UI_CST_CLASS) return <HelpCstClass />;
|
if (topic === HelpTopic.UI_CST_CLASS) return <HelpCstClass />;
|
||||||
|
if (topic === HelpTopic.UI_OSS_GRAPH) return <HelpOssGraph />;
|
||||||
|
|
||||||
if (topic === HelpTopic.CONCEPTUAL) return <HelpConcept />;
|
if (topic === HelpTopic.CONCEPTUAL) return <HelpConcept />;
|
||||||
if (topic === HelpTopic.CC_SYSTEM) return <HelpConceptSystem />;
|
if (topic === HelpTopic.CC_SYSTEM) return <HelpConceptSystem />;
|
||||||
if (topic === HelpTopic.CC_CONSTITUENTA) return <HelpCstAttributes />;
|
if (topic === HelpTopic.CC_CONSTITUENTA) return <HelpCstAttributes />;
|
||||||
if (topic === HelpTopic.CC_RELATIONS) return <HelpConceptRelations />;
|
if (topic === HelpTopic.CC_RELATIONS) return <HelpConceptRelations />;
|
||||||
if (topic === HelpTopic.CC_SYNTHESIS) return <HelpConceptSynthesis />;
|
if (topic === HelpTopic.CC_SYNTHESIS) return <HelpConceptSynthesis />;
|
||||||
|
if (topic === HelpTopic.CC_OSS) return <HelpConceptOSS />;
|
||||||
|
|
||||||
if (topic === HelpTopic.RSLANG) return <HelpRSLang />;
|
if (topic === HelpTopic.RSLANG) return <HelpRSLang />;
|
||||||
if (topic === HelpTopic.RSL_TYPES) return <HelpRSLangTypes />;
|
if (topic === HelpTopic.RSL_TYPES) return <HelpRSLangTypes />;
|
||||||
|
@ -70,6 +80,19 @@ function TopicPage({ topic }: TopicPageProps) {
|
||||||
if (topic === HelpTopic.TERM_CONTROL) return <HelpTerminologyControl />;
|
if (topic === HelpTopic.TERM_CONTROL) return <HelpTerminologyControl />;
|
||||||
if (topic === HelpTopic.ACCESS) return <HelpAccess />;
|
if (topic === HelpTopic.ACCESS) return <HelpAccess />;
|
||||||
if (topic === HelpTopic.VERSIONS) return <HelpVersions />;
|
if (topic === HelpTopic.VERSIONS) return <HelpVersions />;
|
||||||
|
|
||||||
|
if (topic === HelpTopic.INFO) return <HelpInfo />;
|
||||||
|
if (topic === HelpTopic.INFO_RULES) return <HelpRules />;
|
||||||
|
if (topic === HelpTopic.INFO_CONTRIB) return <HelpContributors />;
|
||||||
|
if (topic === HelpTopic.INFO_PRIVACY)
|
||||||
|
return (
|
||||||
|
<HelpPrivacy
|
||||||
|
offsetXpx={size.isSmall ? OFFSET_X_SMALL : OFFSET_X_LARGE}
|
||||||
|
minWidth={size.isSmall ? MIN_SIZE_SMALL : MIN_SIZE_LARGE}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
if (topic === HelpTopic.INFO_API) return <HelpAPI />;
|
||||||
|
|
||||||
if (topic === HelpTopic.EXTEOR) return <HelpExteor />;
|
if (topic === HelpTopic.EXTEOR) return <HelpExteor />;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ interface ViewTopicProps {
|
||||||
|
|
||||||
function ViewTopic({ topic }: ViewTopicProps) {
|
function ViewTopic({ topic }: ViewTopicProps) {
|
||||||
return (
|
return (
|
||||||
<AnimateFade key={topic} className='py-2 pl-6 pr-3 mx-auto'>
|
<AnimateFade key={topic} className='px-3 py-2 mx-auto'>
|
||||||
<TopicPage topic={topic} />
|
<TopicPage topic={topic} />
|
||||||
</AnimateFade>
|
</AnimateFade>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,7 +11,7 @@ function HelpAPI() {
|
||||||
С описанием интерфейса можно ознакомиться <TextURL text='по ссылке' href={external_urls.restAPI} />.
|
С описанием интерфейса можно ознакомиться <TextURL text='по ссылке' href={external_urls.restAPI} />.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<TextURL text='Принять участие в разработке' href={external_urls.git_repo} />
|
<TextURL text='Принять участие в разработке' href={external_urls.git_portal} />
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,8 +1,31 @@
|
||||||
|
import { IconHide, IconImmutable, IconPrivate, IconProtected, IconPublic } from '@/components/Icons';
|
||||||
|
|
||||||
function HelpAccess() {
|
function HelpAccess() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Организация доступов</h1>
|
<h1>Организация доступов</h1>
|
||||||
<p>TBD.</p>
|
<p>Редактирование контента осуществляется Редакторами и Владельцом.</p>
|
||||||
|
<p>Редактирование прав и доступов осуществляется Владельцом.</p>
|
||||||
|
<p>
|
||||||
|
Доступ к контенту на Портале может быть ограничен владельцем каждой схемы в рамках <b>политики доступа</b>.
|
||||||
|
</p>
|
||||||
|
<li>
|
||||||
|
<IconPublic className='inline-icon icon-green' /> публичная политика не ограничивает чтение схемы
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconProtected className='inline-icon icon-blue' /> защитная политика запрещает доступ для всех кроме редакторов
|
||||||
|
и владельца схемы
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconPrivate className='inline-icon icon-red' /> личная политика оставляет доступ к схеме только владельцу
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconHide className='inline-icon' /> режим скрытия схемы из списка в Библиотеке не ограничивает доступ к схеме
|
||||||
|
по прямой ссылке
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconImmutable className='inline-icon' /> режим защиты от редактирования предохраняет от случайных изменений
|
||||||
|
</li>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
import LinkTopic from '@/components/ui/LinkTopic';
|
||||||
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
|
||||||
|
function HelpConceptOSS() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Операционная схема синтеза</h1>
|
||||||
|
<p>
|
||||||
|
Работа со сложными предметными областями требует многократного{' '}
|
||||||
|
<LinkTopic text='синтеза' topic={HelpTopic.CC_SYNTHESIS} /> для построения целевых понятий. Последовательность
|
||||||
|
синтезов концептуальных схем задается с помощью <b>Операционной схемы синтеза (ОСС)</b> в форме Графа синтеза.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Отдельные операции в рамках ОСС задаются <b>таблицами отождествлений</b> понятий из синтезируемых схем. Таким
|
||||||
|
образом <LinkTopic text='конституенты' topic={HelpTopic.CC_CONSTITUENTA} /> в каждой КС разделяются на
|
||||||
|
наследованные, отождествленные и дописанные.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Портал поддерживает <b>сквозные изменения</b> в рамках ОСС. Изменения, внесенные в исходные концептуальные схемы
|
||||||
|
автоматически проносятся через граф синтеза (путем обновления наследованных конституент). Формальные определения
|
||||||
|
наследованных конституент можно редактировать только путем изменения исходных конституент.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HelpConceptOSS;
|
|
@ -0,0 +1,285 @@
|
||||||
|
import LinkTopic from '@/components/ui/LinkTopic';
|
||||||
|
import TextURL from '@/components/ui/TextURL';
|
||||||
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
import { external_urls } from '@/utils/constants';
|
||||||
|
|
||||||
|
function HelpInfo() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Благодарности разработчикам и исследователям</h1>
|
||||||
|
<p>
|
||||||
|
История инструментов работы с концептуальными схемами начинается с 1970-х годов и продолжается в настоящее
|
||||||
|
время. Здесь представлена скромная попытка перечислить вклад различных людей в развитие инструментов и
|
||||||
|
математического аппарата, лежащего в основе экспликации концептуальных схем.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
В списке указан год окончания работ над соответствующим результатом или год публикации соответствующей статьи.
|
||||||
|
Курсивом выделены комментарии к значимости указанного результата.
|
||||||
|
</p>
|
||||||
|
<p>Любые добавления и поправки приветствуются.</p>
|
||||||
|
<div className='flex flex-col gap-3'>
|
||||||
|
<li>1973 Никаноров С.П., Персиц Д.Б. Формальное проектирование целостных СОУ.</li>
|
||||||
|
<li>
|
||||||
|
1975–1981 Никаноров С.П., Персиц Д.Б., Айзенштат А.В., Закс Б.А. Экспериментальная система пакетов прикладных
|
||||||
|
программ автоматизированного проектирования систем организационного управления (АСП СОУ).
|
||||||
|
</li>
|
||||||
|
<li>1976 Поспелов Д.А., Чернышев С.Б. Метод построения формально-логической модели большой размерности.</li>
|
||||||
|
<li>
|
||||||
|
1977 Персиц Д.Б., Савелов Е.В., Тищенко А.В. Теоретические основы АСП СОУ,{' '}
|
||||||
|
<i>
|
||||||
|
сформировавшие базу для развития формализации предметных областей с помощью экспликации концептуальных схем.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1980 Никаноров С.П., Персиц Д.Б., Егоров Б.Б., Никитина Н.К., Ашихмин В.С., Астрина И.В., Тищенко А.В. Блок
|
||||||
|
документирования в АСП СОУ.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1986 Никаноров С.П., Кучкаров З.А., Никитина Н.К., Крюков И.А., Комаров В.Г. Система автоматизированного
|
||||||
|
проектирования концептуального уровня баз данных (МАКС),{' '}
|
||||||
|
<i>
|
||||||
|
заложивший основу для хранения концептуальных схем в базах данных и ставший первым редактором
|
||||||
|
родоструктурной экспликации в группе Никитиной.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1987 Иванов А.Ю., Кучкаров З.А. Разработка концептуальных и математических средств описания процессов принятия
|
||||||
|
решений.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1989 Кучкаров З.А., Остапов А.В. Методические вопросы концептуализации предметных областей,{' '}
|
||||||
|
<i>
|
||||||
|
как пример одной из работ Остапова, значительно расширившего технику экспликации и практику применения
|
||||||
|
"бескванторных" выражений.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1990 Никитина Н.К., Постников В.В. Синтаксический анализатор текста рода структуры для МАКС,{' '}
|
||||||
|
<i>являющийся первой попыткой реализовать автоматизированную проверку синтаксиса родов структур.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1993 Костюк А.В., Никитина Н.К., Юдкин Ю.Ю. Программа визуализации М-графов, представляющих родовую структуру.
|
||||||
|
</li>
|
||||||
|
<li>1993 Никитина Н.К., Чувашов Е.В. Система проектирования баз данных по их концептуальной модели.</li>
|
||||||
|
<li>
|
||||||
|
1993 Никаноров С.П., Кучкаров З.А., Остапов А.В., Шульпекин А.Н., Коваль А.Г., Костюк А.В. Программа
|
||||||
|
операционализации текстов концептуальных моделей, эксплицированных в аппарате родов структур Экстеор 1,{' '}
|
||||||
|
<i>ставший первым редактором родоструктурной экспликации в группе Кучкарова.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1993 Кучкаров З.А., Лавров В., Крайнев А., Шульпекин А.Н., Симонов М. Автоматический генератор
|
||||||
|
PROLOG-программ, формирующих предметные интерпретации родоструктурных экспликаций Инттеор.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1994 Кучкаров З.А., Ким В.Л. Разработка родоструктурных конструктов для библиотеки моделей и исследование
|
||||||
|
возможностей их развития.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1996 Коваль А.Г., Кучкаров З.А., Костюк А.В., Кононенко А.А., Син Ю.Е., Маклаков Ю.И. Программа
|
||||||
|
родоструктурного синтеза операционализированных терминальных концептуальных моделей Экстеор 2,{' '}
|
||||||
|
<i>ставшая первой версией реализации родоструктурного аппарата на C++ под Windows.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1996 Никаноров С.П., Никитина Н.К., Климишин В.В. Автоматизированная система "Библиотека концептуальных схем",{' '}
|
||||||
|
<i>впервые определившая паспорт концептуальной схемы.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1997 Никитина Н.К., Юрьев О.И. Система поддержки процессов концептуального анализа и проектирования ПРОКСИМА
|
||||||
|
1.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1998 Никитина Н.К., Гараева Ю.Р. Синтаксический анализатор выражений на языке родоструктурной экспликации для
|
||||||
|
ПРОКСИМА 1.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1998 Син Ю.Е. Разработка и исследование класса теоретико-модельных операций для технологической линии
|
||||||
|
концептуального проектирования.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1999 Кучкаров З.А., Кононенко А.А. Программа преобразования родоструктурного синтеза операционализированных
|
||||||
|
терминальных концептуальных моделей Экстеор 3,{' '}
|
||||||
|
<i>впервые включившая операционную схему синтеза (дерево синтеза).</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1999 Никитина Н.К., Ландин Н.А. Разработка автоматизированной подсистемы, реализующей операции отслоения и
|
||||||
|
рассечения над концептуальными схемами.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
1999 Юрьев О.И., Зверев В.Ю. Разработка и создание экспериментальной версии автоматизированной системы
|
||||||
|
"Библиотека проектов систем организационного управления".
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2000 Кучкаров З.А., Кононенко А.А., Син Ю.Е. Программа генерации концептуально определенной предметно
|
||||||
|
интерпретированной сети организационных процедур Оргтеор,{' '}
|
||||||
|
<i>
|
||||||
|
позволившая строить процессные схемы по графу термов концептуальной схемы и впервые включившая модуль
|
||||||
|
терминологических преобразований текстовых описаний.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2000 Кононенко А.А., Майоров В.А. Программа автоматизированной генерации структуры данных и их визуализации по
|
||||||
|
концептуальной модели БДтеор,{' '}
|
||||||
|
<i>
|
||||||
|
определившая проблемы интерфейса наполнения концептуальной модели в сложных ступенях и предложившая
|
||||||
|
библиотеку Kernel для удержания интерпретации с помощью М-графа.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>2000 Тищенко А.В. Шкалы множеств и родов структур.</li>
|
||||||
|
<li>
|
||||||
|
2000 Тищенко А.В., Акименков А.М., Ключников А.В. Система операций над концептуальными схемами,
|
||||||
|
представленными в родоструктурной форме.
|
||||||
|
</li>
|
||||||
|
<li>2000 Ключников А.В. Эквивалентность теорий родов структур.</li>
|
||||||
|
<li>
|
||||||
|
2001 Кучкаров З.А., Никитин А.В. Исследование и построение типологии изменений теоретико-множественных
|
||||||
|
интерпретаций класса декартового произведения.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2001 Кононенко А.А., Майоров В.А. Программа преобразования сети процедур из формата Оргтеор в формат BPWin
|
||||||
|
(IDEF0).
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2001 Майоров В.А. Программа построения формального выражения путем выбора альтернатив Grammar,{' '}
|
||||||
|
<i>предложившая альтернативной подход к построению корректных формальных выражений.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2004 Гараева Ю.Р., Пономарев И.Н. Семантико-синтаксический анализатор текстов родов структур Бурбакизатор,{' '}
|
||||||
|
<i>
|
||||||
|
впервые включивший полный грамматический анализ родов структур и проверку биективной переносимости
|
||||||
|
выражения.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2003 Юдкин Ю.Ю., Кудюкин Д.А. Разработка и испытание компьютерной программы, формирующей
|
||||||
|
теоретико-множественную интерпретацию терма частной родоструктурной теории.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2004 Кононенко А.А. Генерация кода на языке программирования C++ по тексту концептуальной схемы,
|
||||||
|
эксплицированной в родах структур.
|
||||||
|
</li>
|
||||||
|
<li>2006 Кучкаров З.А., Никаноров С.П. Библиотека моделей.</li>
|
||||||
|
<li>2006 Кучкаров З.А., Лавров В.А. Полные системы простых теоретико-множественных операций.</li>
|
||||||
|
<li>
|
||||||
|
2006 Солнцев С.В., Присакарь С.В. Введение количественных отношений в методологию концептуального анализа и
|
||||||
|
проектирования, в том числе в язык родоструктурной экспликации.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2007 Пономарев И.Н. Учебное пособие: Введение в математическую логику и роды структур,{' '}
|
||||||
|
<i>
|
||||||
|
являющееся наиболее полным описанием теории родов структур, используемой в родоструктурных экспликациях.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2008 Пономарев И.Н. Об эквивалентной представимости рода структуры с помощью заданной типовой характеристики.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2008 Кононенко А.А., Кучкаров З.А., Никаноров С.П., Никитина Н.К. Технология концептуального проектирования,
|
||||||
|
— <i>монография, собравшая исторический обзор и перспективы развития технологического направления.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2010 Кононенко А.А., Грязнов А.Д. Исследование и построение транслятора концептуальной схемы в концептуальную
|
||||||
|
модель.
|
||||||
|
</li>
|
||||||
|
<li>2010 Никаноров С.П. Введение в аппарат ступеней.</li>
|
||||||
|
<li>
|
||||||
|
2012 Кононенко А.А., Елисов Д.Н. Использование механизма XSD-схем для хранения и операционализации
|
||||||
|
концептуальных схем и концептуальных моделей с помощью XML.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2013 Кононенко А.А., Борисов И.Р. Исследование, разработка и экспериментальная программная реализация операций
|
||||||
|
над концептуальными моделями,{' '}
|
||||||
|
<i>
|
||||||
|
впервые реализовавшая модуль прямого вычисления интерпретации формального выражения, встроенный в Экстеор
|
||||||
|
3.5.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>2013 Пономарев И.Н., Липатов А.А. Операции над родами структур и пример автоматизации их выполнения.</li>
|
||||||
|
<li>
|
||||||
|
2014 Борисов И.Р., Баширов Р.М. Исследования и программная реализации оптимальной структуры данных для
|
||||||
|
вычисления интерпретации концептуальных схем.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2014 Борисов И.Р. Программный комплекс Экстеор 4,{' '}
|
||||||
|
<i>
|
||||||
|
включавший доработанный модуль операционного синтеза и синтаксический анализатор на базе грамматики,
|
||||||
|
предложенной Пономаревым И.Н.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2014 Борисов И.Р. Концептуальные конструкции в задаче синтеза систем на примере Экологического кодекса,
|
||||||
|
—{' '}
|
||||||
|
<i>
|
||||||
|
статья, вводящая понятие концептуальных конструкций как промежуточных форм для операционализации
|
||||||
|
концептуальных схем.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>2015 Иванов А.Ю. Аппарат ступеней С.П. Никанорова и возможное развитие идей по его использованию.</li>
|
||||||
|
<li>
|
||||||
|
2016 Борисов И.Р., Баширов Р.М. Исследование области компьютерной лингвистики и разработка модулей
|
||||||
|
терминологического контроля в Экстеор 4 и Microsoft Office Word,{' '}
|
||||||
|
<i>
|
||||||
|
являющееся основой библиотеки <TextURL text='cctext' href={external_urls.git_cctext} />.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2016 Борисов И.Р. Программный комплекс Экстеор 4.5,{' '}
|
||||||
|
<i>
|
||||||
|
включавший текстовый модуль и полностью переработанное ядро, выделенное в отдельную библиотеку (впоследствии
|
||||||
|
— <TextURL text='ConceptCore' href={external_urls.git_core} />
|
||||||
|
).
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2017 Иванов А.Ю. Введение в технологию концептуализации предметных областей социологии: основы полагания ядра
|
||||||
|
теории (на примере родственных отношений).
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2017 Борисов И.Р., Мурадов А.К. Организация операций над системами понятий посредством графических
|
||||||
|
интерфейсов, <i>заложивший основу для технологии Концепт.Блоки и блока графического синтеза.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2018 Борисов И.Р., Князев А.В. Изучение методов концептуальной расчистки, разметки текстов и разработка
|
||||||
|
программных средств их автоматизации,{' '}
|
||||||
|
<i> — диплом, сформировавший основу для технологий Концепт.Разметка и Концепт.Майнинг.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2018 Никитин А.В., Болотин П.В. Исследование типологии изменения теоретико-множественной интерпретации класса
|
||||||
|
множества подмножеств.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2019 Борисов И.Р., Широкова Л.Р. Исследование возможностей применения методов машинного обучения для решения
|
||||||
|
задач расчистки текстов. Разработка прототипа программного модуля, —{' '}
|
||||||
|
<i>первая попытка внедрения технологий ИИ в текстовый модуль.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2020 Борисов И.Р., Пакулина Т.А. Исследование применения методов машинного обучения для выделения именованных
|
||||||
|
сущностей в текстах интервью. Экспериментальная разработка программного модуля расчистки текстов,{' '}
|
||||||
|
<i>ставшего расширением технологии Концепт.Расчистка.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2020 Программный комплекс Экстеор 4.7, включающий значительное расширение выразительных средств языка родов
|
||||||
|
структур (рекурсивные и императивные выражения, фильтры, ASCII синтаксис).
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2021 Борисов И.Р., Демешко А.Б. Исследование и разработка программного модуля формирования текстов функций на
|
||||||
|
основе концепта функциональная структура,{' '}
|
||||||
|
<i>дополнившего текстовый модуль возможностью работы с глагольными формами.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2023 Борисов И.Р., Тулисов А.В. Разработка инструмента экспликации концептуальных схем в родоструктурной форме
|
||||||
|
через веб-интерфейс, — <i>разработка прототипа интерфейса КонцептПортал.</i>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
2024 Борисов И.Р. Программный комплекс <LinkTopic text='Экстеор 4.9' topic={HelpTopic.EXTEOR} />,
|
||||||
|
поддерживающий работу со схемами, выгруженными из КонцептПортал.{' '}
|
||||||
|
<i>
|
||||||
|
Функционал ConceptCore (С++) стал доступен в Python через обертку{' '}
|
||||||
|
<TextURL text='pyconcept' href={external_urls.git_core} />.
|
||||||
|
</i>
|
||||||
|
</li>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HelpInfo;
|
|
@ -1,16 +0,0 @@
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
|
||||||
|
|
||||||
import Subtopics from '../Subtopics';
|
|
||||||
|
|
||||||
function HelpDocs() {
|
|
||||||
return (
|
|
||||||
<div>
|
|
||||||
<h1>Документы</h1>
|
|
||||||
<p>TBD.</p>
|
|
||||||
|
|
||||||
<Subtopics headTopic={HelpTopic.DOCS} />
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
export default HelpDocs;
|
|
|
@ -1,19 +1,26 @@
|
||||||
import TextURL from '@/components/ui/TextURL';
|
import TextURL from '@/components/ui/TextURL';
|
||||||
import { external_urls } from '@/utils/constants';
|
import { external_urls, PARAMETER } from '@/utils/constants';
|
||||||
|
|
||||||
function HelpExteor() {
|
function HelpExteor() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Экстеор</h1>
|
<h1>Экстеор</h1>
|
||||||
<p>Экстеор 4.9 — редактор текстов систем понятий эксплицированных в родах структур</p>
|
<p>Экстеор 4.9 — редактор текстов систем понятий эксплицированных в родах структур.</p>
|
||||||
<p>
|
<p>
|
||||||
Портал превосходит Экстеор в части редактирования экспликаций, но вычисление интерпретации доступно только в
|
Портал превосходит Экстеор в части редактирования экспликаций, но вычисление интерпретации доступно только в
|
||||||
Экстеоре. Также следует использовать Экстеор для выгрузки экспликаций в Word для последующей печати
|
Экстеор. Также следует использовать Экстеор для выгрузки экспликаций в Word для последующей печати.
|
||||||
</p>
|
</p>
|
||||||
<p>Экстеор доступен на операционной системы Windows 10+</p>
|
|
||||||
<p>
|
<p>
|
||||||
Скачать установщик: <TextURL href={external_urls.exteor64} text='64bit' /> |{' '}
|
Скачать установщик: <TextURL href={external_urls.exteor64} text='64bit' /> |{' '}
|
||||||
<TextURL href={external_urls.exteor32} text='32bit' />
|
<TextURL href={external_urls.exteor32} text='32bit' /> (Windows 10 и выше)
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Текущая версия: <b>{PARAMETER.exteorVersion}</b>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Экстеор не поддерживает автоматическое обновление. Если в выгруженной схеме присутствуют неожиданные диагностики
|
||||||
|
или ошибки, то попробуйте скачать новую версию по ссылкам выше.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2>Основные функции</h2>
|
<h2>Основные функции</h2>
|
||||||
|
|
|
@ -5,10 +5,8 @@ function HelpFormulaTree() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Дерево разбора выражения</h1>
|
<h1>Дерево разбора выражения</h1>
|
||||||
<p>
|
<p>Дерево получено путем семантических преобразований дерева синтаксического разбора.</p>
|
||||||
Дерево разбора получено путем семантических преобразований дерева синтаксического разбора. Оно отражает
|
<p>Оно отражает структуру грамматически корректного выражения языка родов структур.</p>
|
||||||
структуру грамматически корректного выражения языка родов структур.
|
|
||||||
</p>
|
|
||||||
<li>Порядок узлов в рамках одного уровня может отличаться от их порядка в выражении</li>
|
<li>Порядок узлов в рамках одного уровня может отличаться от их порядка в выражении</li>
|
||||||
<li>При наведении курсора на узел в тексте выделяется соответствующий ему фрагмент</li>
|
<li>При наведении курсора на узел в тексте выделяется соответствующий ему фрагмент</li>
|
||||||
<li>Текст в узле дерева соответствует элементу языка</li>
|
<li>Текст в узле дерева соответствует элементу языка</li>
|
||||||
|
|
19
rsconcept/frontend/src/pages/ManualsPage/items/HelpInfo.tsx
Normal file
19
rsconcept/frontend/src/pages/ManualsPage/items/HelpInfo.tsx
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
|
|
||||||
|
import Subtopics from '../Subtopics';
|
||||||
|
|
||||||
|
function HelpInfo() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Справочная информация и документы</h1>
|
||||||
|
<p>
|
||||||
|
Раздел содержит различные документы, задающие правовой статус Портала,
|
||||||
|
<br />а также документацию для разработчиков.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<Subtopics headTopic={HelpTopic.INFO} />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HelpInfo;
|
|
@ -1,4 +1,15 @@
|
||||||
import { IconFolder, IconSearch, IconShow, IconSortAsc, IconSortDesc } from '@/components/Icons';
|
import {
|
||||||
|
IconFilterReset,
|
||||||
|
IconFolder,
|
||||||
|
IconFolderClosed,
|
||||||
|
IconFolderEmpty,
|
||||||
|
IconFolderOpened,
|
||||||
|
IconFolderTree,
|
||||||
|
IconSearch,
|
||||||
|
IconShow,
|
||||||
|
IconSortAsc,
|
||||||
|
IconSortDesc
|
||||||
|
} from '@/components/Icons';
|
||||||
|
|
||||||
function HelpLibrary() {
|
function HelpLibrary() {
|
||||||
return (
|
return (
|
||||||
|
@ -6,8 +17,9 @@ function HelpLibrary() {
|
||||||
<h1>Библиотека схем</h1>
|
<h1>Библиотека схем</h1>
|
||||||
<p>В библиотеке собраны концептуальные схемы, эксплицированные в родоструктурном аппарате</p>
|
<p>В библиотеке собраны концептуальные схемы, эксплицированные в родоструктурном аппарате</p>
|
||||||
|
|
||||||
<h2>Интерфейс</h2>
|
<li>клик по строке - переход к редактированию схемы</li>
|
||||||
<li>Ctrl + клик по строке откроет схему в новой вкладке</li>
|
<li>Ctrl + клик по строке откроет схему в новой вкладке</li>
|
||||||
|
<li>Фильтры атрибутов три позиции: да/нет/не применять</li>
|
||||||
<li>
|
<li>
|
||||||
<IconShow size='1rem' className='inline-icon' /> фильтры атрибутов применяются по клику
|
<IconShow size='1rem' className='inline-icon' /> фильтры атрибутов применяются по клику
|
||||||
</li>
|
</li>
|
||||||
|
@ -21,6 +33,32 @@ function HelpLibrary() {
|
||||||
<li>
|
<li>
|
||||||
<IconFolder size='1rem' className='inline-icon' /> фильтр по расположению
|
<IconFolder size='1rem' className='inline-icon' /> фильтр по расположению
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFilterReset size='1rem' className='inline-icon' /> сбросить фильтры
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFolderTree size='1rem' className='inline-icon' /> переключение между Проводник и Поиск
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<h2>Режим: Проводник</h2>
|
||||||
|
<li>клик по папке отображает справа файлы в ней</li>
|
||||||
|
<li>Ctrl + клик по папке копирует путь в буфер обмена</li>
|
||||||
|
<li>клик по иконке сворачивает/разворачивает вложенные</li>
|
||||||
|
<li>
|
||||||
|
<IconFolderEmpty size='1rem' className='inline-icon clr-text-default' /> папка без файлов
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFolderEmpty size='1rem' className='inline-icon' /> папка с вложенными без файлов
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFolder size='1rem' className='inline-icon' /> папка без вложенных
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFolderClosed size='1rem' className='inline-icon' /> папка с вложенными и файлами
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<IconFolderOpened size='1rem' className='inline-icon icon-green' /> развернутая папка
|
||||||
|
</li>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,10 @@
|
||||||
|
function HelpOssGraph() {
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<h1>Граф синтеза</h1>
|
||||||
|
<p>TBD.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default HelpOssGraph;
|
|
@ -39,7 +39,7 @@ function HelpPortal() {
|
||||||
|
|
||||||
<h2>Разделы Справки</h2>
|
<h2>Разделы Справки</h2>
|
||||||
{[
|
{[
|
||||||
HelpTopic.DOCS,
|
HelpTopic.INFO,
|
||||||
HelpTopic.INTERFACE,
|
HelpTopic.INTERFACE,
|
||||||
HelpTopic.CONCEPTUAL,
|
HelpTopic.CONCEPTUAL,
|
||||||
HelpTopic.RSLANG,
|
HelpTopic.RSLANG,
|
||||||
|
@ -55,11 +55,11 @@ function HelpPortal() {
|
||||||
<h2>Лицензирование и раскрытие информации</h2>
|
<h2>Лицензирование и раскрытие информации</h2>
|
||||||
<li>Пользователи Портала сохраняют авторские права на создаваемый ими контент</li>
|
<li>Пользователи Портала сохраняют авторские права на создаваемый ими контент</li>
|
||||||
<li>
|
<li>
|
||||||
Политика обработки данных доступна по <LinkTopic text='ссылке' topic={HelpTopic.PRIVACY} />
|
Политика обработки данных доступна по <LinkTopic text='ссылке' topic={HelpTopic.INFO_PRIVACY} />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Портал является проектом с открытым исходным кодом, доступным на{' '}
|
Портал является проектом с открытым исходным кодом, доступным на{' '}
|
||||||
<TextURL text='Github' href={external_urls.git_repo} />
|
<TextURL text='Github' href={external_urls.git_portal} />
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
Данный сайт использует доменное имя и серверные мощности{' '}
|
Данный сайт использует доменное имя и серверные мощности{' '}
|
||||||
|
|
|
@ -1,10 +1,15 @@
|
||||||
import PDFViewer from '@/components/ui/PDFViewer';
|
import PDFViewer from '@/components/ui/PDFViewer';
|
||||||
import { resources } from '@/utils/constants';
|
import { resources } from '@/utils/constants';
|
||||||
|
|
||||||
function HelpPrivacy() {
|
interface HelpPrivacyProps {
|
||||||
|
offsetXpx: number;
|
||||||
|
minWidth: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function HelpPrivacy({ offsetXpx, minWidth }: HelpPrivacyProps) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<PDFViewer file={resources.privacy_policy} />
|
<PDFViewer file={resources.privacy_policy} offsetXpx={offsetXpx} minWidth={minWidth} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,54 @@
|
||||||
|
import { urls } from '@/app/urls';
|
||||||
|
import TextURL from '@/components/ui/TextURL';
|
||||||
|
import { external_urls } from '@/utils/constants';
|
||||||
|
|
||||||
function HelpRules() {
|
function HelpRules() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<h1>Правила Портала</h1>
|
<h1>Правила поведения участников Портала</h1>
|
||||||
<p>TBD.</p>
|
|
||||||
|
<p>
|
||||||
|
Мы стремимся предоставить возможность участия в работе Портала как можно большему количеству людей. Мы считаем,
|
||||||
|
что сообщества участников у нас должны быть как можно более разнообразными и открытыми для новых участников. Мы
|
||||||
|
хотим, чтобы эти сообщества представляли собой позитивное, безопасное и здоровое окружение для всех, кто
|
||||||
|
присоединяется или хочет присоединиться к ним. Мы стремимся сохранить такое окружение, в том числе путем
|
||||||
|
принятия этих Правил поведения. Кроме того, мы хотим защитить наши проекты от тех, кто портит или искажает их
|
||||||
|
содержание, поэтому к участникам, нарушающим Правила будут применяться санкции, определяемые Администрацией
|
||||||
|
Портала.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Поведение в рамках Портала основано на уважении, вежливости, коллегиальности, солидарности и социальной
|
||||||
|
ответственности. Это относится ко всем читателям, участникам и администраторам в их взаимодействии без
|
||||||
|
исключений, основанных на возрасте, умственных или физических возможностях, внешнем виде, национальном,
|
||||||
|
религиозном, этническом и культурном происхождении, касте, социальном классе, уровне владения языком,
|
||||||
|
сексуальной ориентации, гендерной идентичности, поле или сфере работы. Мы также не будем делать исключения на
|
||||||
|
основании статуса, навыков или достижений.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h2>Ожидаемое поведение</h2>
|
||||||
|
<li>взаимное уважением, поддержка в отношениях с участниками Портала.</li>
|
||||||
|
<li>
|
||||||
|
пожелания по доработке, найденные ошибки и иные предложения следует направлять по адресу email:{' '}
|
||||||
|
<TextURL href={external_urls.mail_portal} text='portal@acconcept.ru' />.
|
||||||
|
</li>
|
||||||
|
|
||||||
|
<h2>Неприемлемое поведение</h2>
|
||||||
|
<li>оскорбления, угрозы, сексуальное домогательство, троллинг и преследование других участников.</li>
|
||||||
|
<li>
|
||||||
|
раскрытие персональных данных (доксинг) участников Портала. Не распространяется на персональные данные,
|
||||||
|
раскрытые участниками для отображения на Портале. Эти данные можно изменить в{' '}
|
||||||
|
<TextURL text='профиле' href={urls.profile} />.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
злоупотребление властью, привилегиями или влиянием, включая использование статусов и доступов, предоставленных
|
||||||
|
Порталом в личных целях, не связанных с разработкой контента, развитием и продвижением Портала.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
вандализм, намеренное добавление неуместного контента, или препятствование, затруднение или другого рода
|
||||||
|
осложнение создания (и/или поддержания) контента, созданного другими участниками.
|
||||||
|
</li>
|
||||||
|
<li>нарушение работоспособности Портала, в том числе путем использования уязвимостей и ошибок в коде.</li>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,8 +26,8 @@ function HelpTermGraph() {
|
||||||
const { colors } = useConceptOptions();
|
const { colors } = useConceptOptions();
|
||||||
return (
|
return (
|
||||||
<div className='flex flex-col'>
|
<div className='flex flex-col'>
|
||||||
<div className='flex'>
|
<div className='flex flex-col sm:flex-row'>
|
||||||
<div className='dense w-[14rem]'>
|
<div className='w-full sm:w-[14rem]'>
|
||||||
<h1>Настройка графа</h1>
|
<h1>Настройка графа</h1>
|
||||||
<li>Цвет – покраска узлов</li>
|
<li>Цвет – покраска узлов</li>
|
||||||
<li>Граф – расположение</li>
|
<li>Граф – расположение</li>
|
||||||
|
@ -43,9 +43,9 @@ function HelpTermGraph() {
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider vertical margins='mx-3 mt-3' />
|
<Divider vertical margins='mx-3 mt-3' className='hidden sm:block' />
|
||||||
|
|
||||||
<div className='dense w-[21rem]'>
|
<div className='w-full sm:w-[21rem]'>
|
||||||
<h1>Изменение узлов</h1>
|
<h1>Изменение узлов</h1>
|
||||||
<li>Клик на конституенту – выделение</li>
|
<li>Клик на конституенту – выделение</li>
|
||||||
<li>
|
<li>
|
||||||
|
@ -66,10 +66,10 @@ function HelpTermGraph() {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider margins='my-3' />
|
<Divider margins='my-3' className='hidden sm:block' />
|
||||||
|
|
||||||
<div className='flex mb-3'>
|
<div className='flex mb-3 flex-col-reverse sm:flex-row'>
|
||||||
<div className='dense w-[14rem]'>
|
<div className='w-full sm:w-[14rem]'>
|
||||||
<h1>Общие</h1>
|
<h1>Общие</h1>
|
||||||
<li>
|
<li>
|
||||||
<IconFilter className='inline-icon' /> Открыть настройки
|
<IconFilter className='inline-icon' /> Открыть настройки
|
||||||
|
@ -82,7 +82,7 @@ function HelpTermGraph() {
|
||||||
</li>
|
</li>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Divider vertical margins='mx-3' />
|
<Divider vertical margins='mx-3' className='hidden sm:block' />
|
||||||
|
|
||||||
<div className='dense w-[21rem]'>
|
<div className='dense w-[21rem]'>
|
||||||
<h1>Выделение</h1>
|
<h1>Выделение</h1>
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { useOSS } from '@/context/OssContext';
|
||||||
import { ILibraryUpdateData, LibraryItemType } from '@/models/library';
|
import { ILibraryUpdateData, LibraryItemType } from '@/models/library';
|
||||||
import AccessToolbar from '@/pages/RSFormPage/EditorRSFormCard/AccessToolbar';
|
import AccessToolbar from '@/pages/RSFormPage/EditorRSFormCard/AccessToolbar';
|
||||||
import { limits, patterns } from '@/utils/constants';
|
import { limits, patterns } from '@/utils/constants';
|
||||||
|
import { information } from '@/utils/labels';
|
||||||
|
|
||||||
import { useOssEdit } from '../OssEditContext';
|
import { useOssEdit } from '../OssEditContext';
|
||||||
|
|
||||||
|
@ -81,7 +82,7 @@ function FormOSS({ id, isModified, setIsModified }: FormOSSProps) {
|
||||||
visible: visible,
|
visible: visible,
|
||||||
read_only: readOnly
|
read_only: readOnly
|
||||||
};
|
};
|
||||||
update(data, () => toast.success('Изменения сохранены'));
|
update(data, () => toast.success(information.changesSaved));
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
|
@ -10,6 +10,7 @@ import Overlay from '@/components/ui/Overlay';
|
||||||
import { useAccessMode } from '@/context/AccessModeContext';
|
import { useAccessMode } from '@/context/AccessModeContext';
|
||||||
import { HelpTopic } from '@/models/miscellaneous';
|
import { HelpTopic } from '@/models/miscellaneous';
|
||||||
import { UserLevel } from '@/models/user';
|
import { UserLevel } from '@/models/user';
|
||||||
|
import { PARAMETER } from '@/utils/constants';
|
||||||
import { prepareTooltip } from '@/utils/labels';
|
import { prepareTooltip } from '@/utils/labels';
|
||||||
|
|
||||||
import { useOssEdit } from '../OssEditContext';
|
import { useOssEdit } from '../OssEditContext';
|
||||||
|
@ -57,7 +58,7 @@ function RSFormToolbar({ modified, anonymous, subscribed, onSubmit, onDestroy }:
|
||||||
onClick={onDestroy}
|
onClick={onDestroy}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
<BadgeHelp topic={HelpTopic.UI_RS_CARD} offset={4} className='max-w-[30rem]' />
|
<BadgeHelp topic={HelpTopic.UI_RS_CARD} offset={4} className={PARAMETER.TOOLTIP_WIDTH} />
|
||||||
</Overlay>
|
</Overlay>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user